throw new JSExn("invalid resource specifier " + url);
}
case "thread.sleep": sleep(JS.toInt(a)); return null;
- case "regexp": return new JSRegexp(a, null);
+ case "regexp": return JS.newRegexp(a, null);
case "net.rpc.xml": return new XMLRPC(JS.toString(a), "");
case "crypto.rsa": /* FEATURE */ return null;
case "crypto.md5": /* FEATURE */ return null;
case 2:
//#jswitch(name)
case "stream.watch": return new Stream.ProgressWatcher(a, b);
- case "regexp": return new JSRegexp(a, b);
+ case "regexp": return JS.newRegexp(a, b);
//#end
case 3:
//#jswitch(name)
}
}
- public static final JSMath ibexMath = new JSMath() {
+ public static final JS ibexMath = new JS() {
// FEATURE: find a cleaner way to do this
private JS gs = /*new JSScope.Global();*/ null; // FIXME: Global scope
public JS get(JS key) throws JSExn {
case "NaN": return METHOD;
case "Infinity": return METHOD;
//#end
- return super.get(key);
+ return MATH.get(key);
}
public JS callMethod(JS name, JS a, JS b, JS c, JS[] rest, int nargs) throws JSExn {
//#jswitch(name)
case "NaN": return gs.callMethod(name,a,b,c,rest,nargs);
case "Infinity": return gs.callMethod(name,a,b,c,rest,nargs);
//#end
- return super.callMethod(name,a,b,c,rest,nargs);
+ return MATH.callMethod(name,a,b,c,rest,nargs);
}
};
System.err.println(" -l user@host email log to user@host");
System.err.println(" -l host:port emit log to TCP socket");
System.err.println(" -l <file> write log to a file on disk");
- System.err.println(" -a check assertions");
+ //System.err.println(" -a check assertions");
System.err.println(" -w <window-id> reserved for libibex");
System.err.println(" -p dump profiling information [not yet supported]");
Runtime.getRuntime().exit(-1);
int startargs = 0;
while (true) {
if (startargs > args.length - 1) printUsage();
- else if (args[startargs].equals("-a")) JS.checkAssertions = true;
+ // FEATURE: This should be enabled at the parser level - there shouldn't even be an assert bytecode
+ /*else if (args[startargs].equals("-a")) JS.checkAssertions = true;*/
else if (args[startargs].equals("-l")) {
startargs++;
StringTokenizer opts = new StringTokenizer(args[startargs], ",");
case DUP: stack.push(stack.peek()); break;
case NEWSCOPE: scope = new JSScope(scope); break;
case OLDSCOPE: scope = scope.getParentScope(); break;
- case ASSERT: {
- JS o = stack.pop();
- if (JS.checkAssertions && !JS.toBoolean(o))
- throw je("ibex.assertion.failed");
- break;
- }
+ case ASSERT: if (!JS.toBoolean(stack.pop())) throw je("ibex.assertion.failed"); break;
case BITNOT: stack.push(JS.N(~JS.toLong(stack.pop()))); break;
case BANG: stack.push(JS.B(!JS.toBoolean(stack.pop()))); break;
case NEWFUNCTION: stack.push(((JSFunction)arg)._cloneWithNewParentScope(scope)); break;
/** The minimum set of functionality required for objects which are manipulated by JavaScript */
public abstract class JS {
-
- public static boolean checkAssertions = false;
-
public static final JS METHOD = new JS() { };
public final JS unclone() { return _unclone(); }
public final JS jsclone() throws JSExn { return new Clone(this); }
public final boolean equals(Object o) { return this == o || ((o instanceof JS) && jsequals((JS)o)); }
- // FIXME: Remove this, eventually
- public final String toString() { throw new Error("you shouldn't use toString() on JS objects"); }
+ public final String toString() {
+ // Discourage people from using toString()
+ String s = "JS Object [class=" + getClass().getName() + "]";
+ String ext = extendedToString();
+ return ext == null ? s : s + " " + ext;
+ }
// These are only used internally by org.ibex.js
Trap getTrap(JS key) { return null; }
void putTrap(JS key, Trap value) throws JSExn { throw new JSExn("traps cannot be placed on this object (class=" + this.getClass().getName() +")"); }
String coerceToString() throws JSExn { throw new JSExn("can't coerce to a string (class=" + getClass().getName() +")"); }
- String debugToString() { return "[class=" + getClass().getName() + "]"; }
boolean jsequals(JS o) { return this == o; }
+ String extendedToString() { return null; }
public static class O extends JS implements Cloneable {
private Hash entries;
public static boolean toBoolean(JS o) {
if(o == null) return false;
if(o instanceof JSNumber) return ((JSNumber)o).toBoolean();
- if(o instanceof JSString) return ((JSString)o).length() != 0;
+ if(o instanceof JSString) return ((JSString)o).s.length() != 0;
return true;
}
//#repeat long/int/double/float toLong/toInt/toDouble/toFloat Long/Integer/Double/Float parseLong/parseInt/parseDouble/parseFloat
public static String debugToString(JS o) {
try { return toString(o); }
- catch(JSExn e) { return o.debugToString(); }
+ catch(JSExn e) { return o.toString(); }
}
public static boolean isInt(JS o) {
if(o instanceof JSString) return true;
return false;
}
+
+ public static JS newArray() { return new JSArray(); }
+ public static JS newRegexp(JS pat, JS flags) throws JSExn { return new JSRegexp(pat,flags); }
// Instance Methods ////////////////////////////////////////////////////////////////////
public final static JS NaN = new JSNumber.D(Double.NaN);
public final static JS ZERO = new JSNumber.I(0);
public final static JS ONE = new JSNumber.I(1);
+ public final static JS MATH = new JSMath();
public static final JS T = new JSNumber.B(true);
public static final JS F = new JSNumber.B(false);
private static final int CACHE_SIZE = 65536 / 4; // must be a power of two
private static final JSString[] stringCache = new JSString[CACHE_SIZE];
- public static final JS S(String s) {
+ public static final JS S(String s) {
if(s == null) return null;
int slot = s.hashCode()&(CACHE_SIZE-1);
JSString ret = stringCache[slot];
if(ret == null || !ret.s.equals(s)) stringCache[slot] = ret = new JSString(s);
return ret;
}
+ public static final JS S(String s, boolean intern) { return intern ? JSString.intern(s) : S(s); }
public static final JS N(double d) { return new JSNumber.D(d); }
public static final JS N(long l) { return new JSNumber.L(l); }
import java.util.*;
/** A JavaScript JSArray */
-public class JSArray extends JS.BT {
+class JSArray extends JS.BT {
private static final Object NULL = new Object();
public JSArray() { }
// Debugging //////////////////////////////////////////////////////////////////////
- String debugToString() { return "JSFunction [" + sourceName + ":" + firstLine + "]"; }
+ String extendedToString() { return "[" + sourceName + ":" + firstLine + "]"; }
String dump() { return dump(""); }
private String dump(String prefix) {
package org.ibex.js;
/** The JavaScript Math object */
-public class JSMath extends JS {
-
- public static JSMath singleton = new JSMath();
-
+class JSMath extends JS {
private static final JS E = JS.N(java.lang.Math.E);
private static final JS PI = JS.N(java.lang.Math.PI);
private static final JS LN10 = JS.N(java.lang.Math.log(10));
import gnu.regexp.*;
/** A JavaScript regular expression object */
-public class JSRegexp extends JS {
+class JSRegexp extends JS {
private boolean global;
private RE re;
private int lastIndex;
return sb.toString();
}
- public static JS stringMatch(JS o, JS arg0) throws JSExn {
+ static JS stringMatch(JS o, JS arg0) throws JSExn {
String s = JS.toString(o);
RE re;
JSRegexp regexp = null;
return ret;
}
- public static JS stringSearch(JS o, JS arg0) throws JSExn {
+ static JS stringSearch(JS o, JS arg0) throws JSExn {
String s = JS.toString(o);
RE re = arg0 instanceof JSRegexp ? ((JSRegexp)arg0).re : newRE(JS.toString(arg0),0);
REMatch match = re.getMatch(s);
return match == null ? N(-1) : N(match.getStartIndex());
}
- public static JS stringReplace(JS o, JS arg0, JS arg1) throws JSExn {
+ static JS stringReplace(JS o, JS arg0, JS arg1) throws JSExn {
String s = JS.toString(o);
RE re;
JSFunction replaceFunc = null;
}
- public static JS stringSplit(JS s_, JS arg0, JS arg1, int nargs) throws JSExn {
+ static JS stringSplit(JS s_, JS arg0, JS arg1, int nargs) throws JSExn {
String s = JS.toString(s_);
int limit = nargs < 2 ? Integer.MAX_VALUE : JS.toInt(arg1);
if(limit < 0) limit = Integer.MAX_VALUE;
return ret;
}
- public static RE newRE(String pattern, int flags) throws JSExn {
+ private static RE newRE(String pattern, int flags) throws JSExn {
try {
return new RE(pattern,flags,RESyntax.RE_SYNTAX_PERL5);
} catch(REException e) {
import org.ibex.util.*;
-final class JSString extends JSPrimitive {
+class JSString extends JSPrimitive {
final String s;
public JSString(String s) { this.s = s; }
public int hashCode() { return s.hashCode(); }
}
}
- int length() { return s.length(); }
-
- private static Hash internHash = new Hash();
+ private final static Hash internHash = new Hash();
static synchronized JS intern(String s) {
- JS js = (JS)internHash.get(s);
- if(js == null) internHash.put(s,js = new JSString(s));
- return js;
+ synchronized(internHash) {
+ JS js = (JS)internHash.get(s);
+ if(js == null) internHash.put(s,js = new Intern(s));
+ return js;
+ }
+ }
+ static class Intern extends JSString {
+ public Intern(String s) { super(s); }
+ protected void finalize() { synchronized(internHash) { internHash.put(s,null); } }
}
- JS intern() { return intern(s); }
String coerceToString() { return s; }
}
* be totally independent of the others (ie separate stream position
* and state) although they draw from the same data source.
*/
+// FEATURE: Should this be in org.ibex.js?
public abstract class Stream extends JS implements JS.Cloneable {
// Public Interface //////////////////////////////////////////////////////////////////////////////
} catch (Exception e) {
if (Log.on) {
Log.info(Platform.class, "WPAD detection failed due to:");
- if (e instanceof JSExn) {
+ // I have no idea what this was supposed to do
+ /*if (e instanceof JSExn) {
try {
org.ibex.js.JSArray arr = new org.ibex.js.JSArray();
arr.addElement(((JSExn)e).getObject());
} catch (Exception e2) {
Log.info(Platform.class, e);
}
- }
- else Log.info(Platform.class, e);
+ }*/
+ Log.info(Platform.class, e);
}
return null;
}
objects.addElement(null);
} else if (value.endsWith("arrayType") || value.endsWith("JSArray") || key.endsWith("arrayType")) {
objects.removeElementAt(objects.size() - 1);
- objects.addElement(new JSArray());
+ objects.addElement(JS.newArray());
}
}
}
if (objects.size() < 2) return;
// our parent "should" be an aggregate type -- add ourselves to it.
- if (parent != null && parent instanceof JSArray) {
+ // FIXME: Can we get away without JSArray being public?
+ /*if (parent != null && parent instanceof JSArray) {
objects.removeElementAt(objects.size() - 1);
((JSArray)parent).addElement(me);
- } else if (parent != null && parent instanceof JS) {
+ } else */ if (parent != null && parent instanceof JS) {
objects.removeElementAt(objects.size() - 1);
try {
((JS)parent).put(JS.S(name), me);
}*/
}
- protected String buildRequest(JSArray args) throws JSExn, IOException {
+ protected String buildRequest(JS[] args) throws JSExn, IOException {
// build up the request
StringBuffer content = new StringBuffer();
content.append("SOAPAction: " + action + "\r\n\r\n");
content.append(method);
content.append(nameSpace != null ? " xmlns=\"" + nameSpace + "\"" : "");
content.append(">\r\n");
- if (args.length() > 0) {
- Enumeration e = ((JS)args.elementAt(0)).keys();
+ if (args.length > 0) {
+ Enumeration e = args[0].keys();
while(e.hasMoreElements()) {
- Object key = e.nextElement();
- appendObject((String)key, args.elementAt(0).get((JS)key), content);
+ JS key = e.nextElement();
+ appendObject(JS.toString(key), args[0].get(key), content);
}
}
content.append(" </" + method + "></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n");
case "data":
int i;
for(i=objects.size() - 1; objects.elementAt(i) != null; i--);
- JSArray arr = new JSArray();
+ JS arr = JS.newArray();
try {
for(int j = i + 1; j<objects.size(); j++) arr.put(JS.N(j - i - 1), (JS)objects.elementAt(j));
} catch (JSExn e) {
// Send ///////////////////////////////////////////////////////////////////////////
- protected String buildRequest(JSArray args) throws JSExn, IOException {
+ protected String buildRequest(JS[] args) throws JSExn, IOException {
StringBuffer content = new StringBuffer();
content.append("\r\n");
content.append("<?xml version=\"1.0\"?>\n");
content.append(method);
content.append("</methodName>\n");
content.append(" <params>\n");
- for(int i=0; i<args.length(); i++) {
+ for(int i=0; i<args.length; i++) {
content.append(" <param>\n");
- appendObject(args.elementAt(i), content);
+ appendObject(args[i], content);
content.append(" </param>\n");
}
content.append(" </params>\n");
// Call Sequence //////////////////////////////////////////////////////////////////////////
public final JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- JSArray args = new JSArray();
- for(int i=0; i<nargs; i++) args.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
- return call(args);
- }
-
- public final JS call(final JSArray args) throws JSExn {
+ final JS[] args = new JS[nargs];
+ for(int i=0;i<nargs;i++) args[i]= i==0?a0:i==1?a1:i==2?a2:rest[i-3];
try {
final JS.UnpauseCallback callback = JS.pause();
- new java.lang.Thread() { public void run() { call(callback, args); } }.start();
+ new java.lang.Thread() { public void run() { call(callback,args); } }.start();
return null; // doesn't matter since we paused
} catch (NotPauseableException npe) {
throw new JSExn("cannot invoke an XML-RPC call in the foreground thread");
}
}
- final void call(final JS.UnpauseCallback callback, final JSArray args) {
+ final void call(final JS.UnpauseCallback callback, JS[] args) {
try {
if (Log.rpc) Log.info(this, "call to " + url + " : " + method);
if (tracker == null) tracker = new Hash();