public void put(Object name, Object value, boolean ignoretraps) { put(name, value, ignoretraps, null); }
public void put(Object name_, Object value, boolean ignoretraps, RootProxy rp) {
if (name_ instanceof Number) { put(((Number)name_).intValue(), value); return; }
- String name = (String)name_;
+ if (!(name_ instanceof String)) { super.put(name_,value); return; }
+ String name = name_.toString();
if (name == null) return; // FIXME, shouldn't be necessary
if (name.startsWith("xwt_")) {
if (Log.on) Log.logJS(this, "attempt to set reserved property " + name);
}
for(int i=0; keys != null && i<keys.length; i++) {
- // FIXME: make sure that if exceptions are thrown in here, the line number of the offending XML is logged
- if (keys[i] == null) { }
- else if (keys[i].equals("border") || keys[i].equals("image") &&
- !vals[i].toString().startsWith("http://") && !vals[i].toString().startsWith("https://")) {
- String s = Resources.resolve(vals[i].toString() + ".png", importlist);
- if (s != null) b.put(keys[i], s.substring(0, s.length() - 4));
- else if (Log.on) Log.log(this, "unable to resolve image " + vals[i].toString() + " referenced in attributes of " + nodeName);
+ try {
+ if (keys[i] == null) { }
+ else if (keys[i].equals("border") || keys[i].equals("image") &&
+ !vals[i].toString().startsWith("http://") && !vals[i].toString().startsWith("https://")) {
+ String s = Resources.resolve(vals[i].toString() + ".png", importlist);
+ if (s != null) b.put(keys[i], s.substring(0, s.length() - 4));
+ else if (Log.on) Log.log(this, "unable to resolve image " + vals[i].toString() + " referenced in attributes of " + nodeName);
+ }
+ else b.put(keys[i], vals[i]);
+ } catch(JS.Exn e) {
+ if(Log.on) Log.log(this,"WARNING: uncaught ecmascript exception while putting attr \"" + keys[i] +
+ "\" of " + nodeName + " : " + e.getMessage());
}
- else b.put(keys[i], vals[i]);
}
if (redirect != null && !"self".equals(redirect)) b.redirect = redir;
private Trap() { allTraps.put(myWeak, dummy); }
/** perform this trap -- arg.length == 0 if this is a get; otherwise it contains a single element to be put */
- public Object perform(JS.Array args) {
+ public Object perform(JS.Array args) throws JS.Exn {
TrapContext tc = TrapContext.get();
// save both thread-locals on the stack and update their values
if (args.length() > 0 && !isreadtrap && !tc.putCascadeHappened) cascadeFunction.call(args);
return ret;
-
- } catch (JS.Exn e) {
- if (Log.on) Log.log(this, e);
-
+
} finally {
// restore the thread-locals
tc.putCascadeHappened = save_putCascadeHappened;
tc.currentTrap = save_currentTrap;
tc.trapDepth--;
}
- return null;
}
/** removes this trap */
* and FALSE for all subsequent iterations */
public static final byte LOOP = -22;
+
+ public static final String[] bytecodeToString = new String[] {
+ "", "", "LITERAL", "ARRAY", "OBJECT", "NEWFUNCTION", "DECLARE", "TOPSCOPE",
+ "GET", "GET_PRESERVE", "PUT", "JT", "JF", "JMP", "POP", "CALL", "PUSHKEYS",
+ "SWAP", "NEWSCOPE", "OLDSCOPE", "DUP", "LABEL", "LOOP"
+ };
}
p.parseStatement(this, null);
if (s == size()) break;
}
- add(-1, Tokens.RETURN);
+ add(-1, LITERAL, null);
+ add(-1, RETURN);
}
public Object call(JS.Array args) throws JS.Exn { return call(args, new FunctionScope(sourceName, parentScope)); }
cx.stack.push(args);
eval(scope);
Object ret = cx.stack.pop();
- if (cx.stack.size() > size) Log.logJS(this, "warning, stack grew by " + (cx.stack.size() - size) + " elements during call");
+ // FIXME: if we catch an exception in Java, JS won't notice and the stack will be messed up
+ if (cx.stack.size() > size)
+ // this should never happen
+ throw new Error("ERROR: stack grew by " + (cx.stack.size() - size) + " elements during call");
return ret;
} finally {
cx.currentCompiledFunction = saved;
size++;
return this;
}
+
+ public int getLine(int pc) {
+ if(pc < 0 || pc >= size) return -1;
+ return line[pc];
+ }
// Invoking the Bytecode ///////////////////////////////////////////////////////
- int pc = 0;
void eval(JS.Scope s) {
final JS.Thread cx = JS.Thread.fromJavaThread(java.lang.Thread.currentThread());
final Vec t = cx.stack;
+ int pc;
+ int lastPC = -1;
OUTER: for(pc=0; pc<size; pc++) {
String label = null;
- cx.line = line[pc];
+ cx.pc = lastPC = pc;
switch(op[pc]) {
case LITERAL: t.push(arg[pc]); break;
case OBJECT: t.push(new JS.Obj()); break;
} }
}
}
+ // this should never happen, we will ALWAYS have a RETURN at the end of the func
+ throw new Error("Just fell out of CompiledFunction::eval() loop. Last PC was " + lastPC);
}
+ // Debugging //////////////////////////////////////////////////////////////////////
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(1024);
+ sb.append("\n" + sourceName + ": " + firstLine + "\n");
+ for (int i=0; i < size; i++) {
+ sb.append(i);
+ sb.append(": ");
+ if (op[i] < 0)
+ sb.append(bytecodeToString[-op[i]]);
+ else
+ sb.append(codeToString[op[i]]);
+ sb.append(" ");
+ sb.append(arg[i] == null ? "(no arg)" : arg[i]);
+ if((op[i] == JF || op[i] == JT || op[i] == JMP) && arg[i] != null && arg[i] instanceof Number) {
+ sb.append(" jump to ");
+ sb.append(i+((Number) arg[i]).intValue());
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
// Helpers for Number, String, and Boolean ////////////////////////////////////////
// Exception Stuff ////////////////////////////////////////////////////////////////
static class EvaluatorException extends RuntimeException { public EvaluatorException(String s) { super(s); } }
- EvaluatorException ee(String s) { throw new EvaluatorException(sourceName + ":" + line[pc] + " " + s); }
- JS.Exn je(String s) { throw new JS.Exn(sourceName + ":" + line[pc] + " " + s); }
+ EvaluatorException ee(String s) { throw new EvaluatorException(sourceName + ":" + JS.Thread.currentJSThread().getLine() + " " + s); }
+ JS.Exn je(String s) { throw new JS.Exn(sourceName + ":" + JS.Thread.currentJSThread().getLine() + " " + s); }
// FunctionScope /////////////////////////////////////////////////////////////////
CompiledFunction currentCompiledFunction = null;
Vec stack = new Vec();
- int line = -1;
+ int pc;
/** binds this thread to the current Java Thread */
public void bindToCurrentJavaThread() { javaThreadToJSThread.put(java.lang.Thread.currentThread(), this); }
/** returns the line of code that is currently executing */
- public int getLine() { return line; }
+ public int getLine() { return currentCompiledFunction == null ? -1 : currentCompiledFunction.getLine(pc); }
/** returns the name of the source code file which declared the currently executing function */
public String getSourceName() { return currentCompiledFunction == null ? null : currentCompiledFunction.getSourceName(); }
return ret;
}
+ public static JS.Thread currentJSThread() {
+ return fromJavaThread(java.lang.Thread.currentThread());
+ }
}
}
put("min", min);
put("pow", pow);
put("random", random);
+ put("round",round);
put("sin", sin);
put("sqrt", sqrt);
put("tan", tan);
}
}
re = newRE(pattern,flags);
- put("source",pattern);
- put("global",wrapBool(global));
- put("ignoreCase",wrapBool(flags & RE.REG_ICASE));
- put("multiline",wrapBool(flags & RE.REG_MULTILINE));
+ _put("source",pattern);
+ _put("global",wrapBool(global));
+ _put("ignoreCase",wrapBool(flags & RE.REG_ICASE));
+ _put("multiline",wrapBool(flags & RE.REG_MULTILINE));
}
// FIXME: Do whatever we need to do to take advantage of the GETCALL bytecode when its available
final JS.Callable execFN = new JS.Callable() { public Object call(JS.Array args) { return exec(args); } };
final JS.Callable testFN = new JS.Callable() { public Object call(JS.Array args) { return test(args); } };
final JS.Callable toStringFN = new JS.Callable() { public Object call(JS.Array args) { return Regexp.this.toString(); } };
- put("exec",execFN);
- put("test",testFN);
- put("toString",toStringFN);
+ _put("exec",execFN);
+ _put("test",testFN);
+ _put("toString",toStringFN);
}
- public Object get(Object key) {
+ // gcj bug...
+ public Object get(Object key) { return _get(key); }
+ public void put(Object key,Object value) { _put(key,value); }
+
+ public Object _get(Object key) {
if(key.equals("lastIndex")) return new Integer(lastIndex);
return super.get(key);
}
- public void put(Object key, Object value) {
+ public void _put(Object key, Object value) {
if(key.equals("lastIndex")) lastIndex = JS.toNumber(value).intValue();
super.put(key,value);
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append('/');
- sb.append(get("source"));
+ sb.append(_get("source"));
sb.append('/');
if(global) sb.append('g');
- if(Boolean.TRUE.equals(get("ignoreCase"))) sb.append('i');
- if(Boolean.TRUE.equals(get("multiline"))) sb.append('m');
+ if(Boolean.TRUE.equals(_get("ignoreCase"))) sb.append('i');
+ if(Boolean.TRUE.equals(_get("multiline"))) sb.append('m');
return sb.toString();
}