import java.util.*;
import org.xwt.js.*;
import org.xwt.util.*;
+import java.io.*;
/**
* This class encapsulates a single trap placed on a given node. The
return null;
}
}
-
+
+ private static JS.CompiledFunction cascadeHelper = null;
+ private static String cascadeHelperText =
+ "return function(q) { var ret = arguments.doTrap;" +
+ "if (ret != false && !arguments.didCascade) arguments.cascade = q; };";
+ static {
+ try {
+ cascadeHelper = JS.parse("cascadeHelper", 1, new StringReader(cascadeHelperText));
+ cascadeHelper = (JS.CompiledFunction)new JS.Thread(cascadeHelper).resume();
+ } catch (Exception e) {
+ Log.log(Trap.class, e);
+ }
+ }
+
public void perform(Object val) {
try {
if (f.getNumFormalArgs() == 0) cascade(val);
- TrapArgs ta = new TrapArgs(this, val);
- JS.Thread.current().setTailCall(f, ta);
- // FIXME: re-add autocascades
- //if (ret != Boolean.FALSE && !ta.cascadeHappened) cascade(val);
+ else JS.Thread.current().setTailCall(cascadeHelper, new TrapArgs(this, val));
} catch (Exception e) {
Log.log(this, "Exception thrown from within trap: " + e);
+ e.printStackTrace();
}
}
// common case
if(!(key instanceof String)) return super.get(key);
if (key.equals("trapee")) return t.trapee;
+ if (key.equals("doTrap")) { JS.Thread.current().setTailCall(t.f, this); return null; }
+ if (key.equals("didCascade")) return cascadeHappened ? Boolean.TRUE : Boolean.FALSE;
if (key.equals("trapname")) return t.name;
if (key.equals("cascade")) return t.cascade();
if (key.equals("callee")) return t.f;
// Fields and Accessors ///////////////////////////////////////////////
/** the number of formal arguments */
- int numFormalArgs = 0;
+ int numFormalArgs = 20;
/** the source code file that this block was drawn from */
String sourceName;
ret.arg = this.arg;
ret.line = this.line;
ret.size = this.size;
+ ret.numFormalArgs = this.numFormalArgs;
return ret;
}
// Invoking the Bytecode ///////////////////////////////////////////////////////
/** returns false if the thread has been paused */
- static void eval(final JS.Thread cx) throws JS.Exn {
- OUTER: for(; cx.currentCompiledFunction == null || cx.pc<((CompiledFunctionImpl)cx.currentCompiledFunction).size; cx.pc++) {
+ static Object eval(final JS.Thread cx) throws JS.Exn {
+ OUTER: for(;; cx.pc++) {
try {
- if (cx.paused || cx.currentCompiledFunction == null) return;
+ if (cx.paused) return null;
+ cx.bind();
if (cx.tailCallFunction != null) {
cx.stack.pop(); // discard actual return value
cx.pc -= 2;
cx.scope = new FunctionScope("unknown", cx.currentCompiledFunction.parentScope);
cx.pc = 0;
}
+ if (cx.currentCompiledFunction == null) return cx.stack.pop();
+ if (cx.pc >= ((CompiledFunctionImpl)cx.currentCompiledFunction).size) return cx.stack.pop();
String label = null;
int curOP = cx.currentCompiledFunction.op[cx.pc];
Object curArg = cx.currentCompiledFunction.arg[cx.pc];
throw e;
} // end try/catch
} // end for
- // 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.");
}
// Debugging //////////////////////////////////////////////////////////////////////
public static JS.Thread current() { return (JS.Thread)javaThreadToJSThread.get(java.lang.Thread.currentThread()); }
- public void resume() { bind(); paused = false; CompiledFunctionImpl.eval(this); }
+ public Object resume() { bind(); paused = false; Object ret = CompiledFunctionImpl.eval(this); unbind(); return ret; }
public void pause() { paused = true; unbind(); }
public void bind() { javaThreadToJSThread.put(java.lang.Thread.currentThread(), this); }
- public void unbind() { if (current() == this) javaThreadToJSThread.put(java.lang.Thread.currentThread(), this); }
+ public void unbind() { if (current() == this) javaThreadToJSThread.remove(java.lang.Thread.currentThread()); }
public int getLine() { return currentCompiledFunction == null ? -1 : currentCompiledFunction.getLine(this); }
public String getSourceName() { return currentCompiledFunction == null ? null : currentCompiledFunction.getSourceName(); }
b2.add(parserLine, PUT);
while(peekToken() != RP) { // run through the list of argument names
+ numArgs++;
if (peekToken() == NAME) {
consume(NAME); // a named argument
String varName = string;
b2.add(parserLine, DUP); // dup the args array
- b2.add(parserLine, GET, new Integer(numArgs)); // retrieve it from the arguments array
+ b2.add(parserLine, GET, new Integer(numArgs - 1)); // retrieve it from the arguments array
b2.add(parserLine, TOPSCOPE);
b2.add(parserLine, SWAP);
b2.add(parserLine, DECLARE, varName); // declare the name
}
if (peekToken() == RP) break;
consume(COMMA);
- numArgs++;
}
consume(RP);
- b2.numFormalArgs = numArgs + 1;
+ b2.numFormalArgs = numArgs;
b2.add(parserLine, POP); // pop off the arguments array
b2.add(parserLine, POP); // pop off TOPSCOPE