import java.io.*;
/** a JavaScript function, compiled into bytecode */
-public final class CompiledFunction extends JS.Callable implements ByteCodes, Tokens {
+public class CompiledFunctionImpl extends JS.Callable implements ByteCodes, Tokens {
// Fields and Accessors ///////////////////////////////////////////////
private int size = 0;
int size() { return size; }
- /** the scope in which this function was declared */
+ /** the scope in which this function was declared; by default this function is called in a fresh subscope of the parentScope */
private JS.Scope parentScope;
- JS.Scope getParentScope() { return parentScope; }
// Constructors ////////////////////////////////////////////////////////
- public CompiledFunction cloneWithNewParentScope(JS.Scope s) throws IOException {
- CompiledFunction ret = new CompiledFunction(sourceName, firstLine, s);
+ private CompiledFunctionImpl cloneWithNewParentScope(JS.Scope s) throws IOException {
+ CompiledFunctionImpl ret = new JS.CompiledFunction(sourceName, firstLine, null, s);
ret.paste(this);
return ret;
}
- CompiledFunction(String sourceName, int firstLine, JS.Scope parentScope) throws IOException {
+ protected CompiledFunctionImpl(String sourceName, int firstLine, Reader sourceCode, JS.Scope parentScope) throws IOException {
this.sourceName = sourceName;
this.firstLine = firstLine;
this.parentScope = parentScope;
- }
-
- CompiledFunction(String sourceName, int firstLine, Reader sourceCode, JS.Scope parentScope) throws IOException {
- this(sourceName, firstLine, parentScope);
+ if (sourceCode == null) return;
Parser p = new Parser(sourceCode, sourceName, firstLine);
try {
while(true) {
}
}
- public Object call(Array args) throws JS.Exn {
- CompiledFunction saved = (CompiledFunction)Context.currentFunction.get(Thread.currentThread());
+ public Object call(JS.Array args) throws JS.Exn { return call(args, new FunctionScope(sourceName, parentScope)); }
+ public Object call(JS.Array args, JS.Scope scope) throws JS.Exn {
+ CompiledFunctionImpl saved = (CompiledFunctionImpl)Context.currentFunction.get(Thread.currentThread());
try {
Context.currentFunction.put(Thread.currentThread(), this);
Context cx = Context.getContextForThread(Thread.currentThread());
int size = cx.stack.size();
cx.stack.push(new Context.CallMarker());
cx.stack.push(args);
-
- // FIXME, ugly
- eval(args == null ? parentScope : new FunctionScope(sourceName, parentScope));
-
+ eval(scope);
Object ret = cx.stack.pop();
if (cx.stack.size() > size)
Log.log(this, "warning, stack grew by " + (cx.stack.size() - size) +
int get(int pos) { return op[pos]; }
void set(int pos, int op_, Object arg_) { op[pos] = op_; arg[pos] = arg_; }
void set(int pos, Object arg_) { arg[pos] = arg_; }
- void paste(CompiledFunction other) { for(int i=0; i<other.size; i++) add(other.line[i], other.op[i], other.arg[i]); }
- CompiledFunction add(int line, int op_) { return add(line, op_, null); }
- CompiledFunction add(int line, int op_, Object arg_) {
+ void paste(CompiledFunctionImpl other) { for(int i=0; i<other.size; i++) add(other.line[i], other.op[i], other.arg[i]); }
+ CompiledFunctionImpl add(int line, int op_) { return add(line, op_, null); }
+ CompiledFunctionImpl add(int line, int op_, Object arg_) {
if (size == op.length - 1) {
int[] line2 = new int[op.length * 2]; System.arraycopy(this.line, 0, line2, 0, op.length); this.line = line2;
Object[] arg2 = new Object[op.length * 2]; System.arraycopy(arg, 0, arg2, 0, arg.length); arg = arg2;
switch(op[pc]) {
case LITERAL: t.push(arg[pc]); break;
case OBJECT: t.push(new JS.Obj()); break;
- case ARRAY: t.push(new Array(JS.toNumber(arg[pc]).intValue())); break;
+ case ARRAY: t.push(new JS.Array(JS.toNumber(arg[pc]).intValue())); break;
case DECLARE: s.declare((String)t.pop()); break;
case TOPSCOPE: t.push(s); break;
case JT: if (JS.toBoolean(t.pop())) pc += JS.toNumber(arg[pc]).intValue() - 1; break;
case POP: t.pop(); break;
case SWAP: { Object o1 = t.pop(); Object o2 = t.pop(); t.push(o1); t.push(o2); break; }
case DUP: t.push(t.peek()); break;
- case NEWSCOPE: s = new JS.Scope(s); break;
- case OLDSCOPE: s = s.getParentScope(); break;
+ case NEWSCOPE: /*s = new JS.Scope(s);*/ break;
+ case OLDSCOPE: /*s = s.getParentScope();*/ break;
case ASSERT: if (!JS.toBoolean(t.pop())) throw je("assertion failed"); break;
case BITNOT: t.push(new Long(~JS.toLong(t.pop()))); break;
case BANG: t.push(new Boolean(!JS.toBoolean(t.pop()))); break;
}
case NEWFUNCTION: {
- CompiledFunction bytes = (CompiledFunction)arg[pc];
try {
- t.push(bytes.cloneWithNewParentScope(s));
+ t.push(((CompiledFunctionImpl)arg[pc]).cloneWithNewParentScope(s));
} catch (IOException e) {
throw new Error("this should never happen");
}
case PUSHKEYS: {
Object o = t.peek();
Object[] keys = ((JS)o).keys();
- Array a = new Array();
+ JS.Array a = new JS.Array();
a.setSize(keys.length);
for(int j=0; j<keys.length; j++) a.setElementAt(keys[j], j);
t.push(a);
}
case CALL: {
- Array arguments = new Array();
+ JS.Array arguments = new JS.Array();
int numArgs = JS.toNumber(arg[pc]).intValue();
arguments.setSize(numArgs);
for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(t.pop(), j);
private Object getFromString(final String o, final Object v) {
if (v.equals("length")) return new Integer(((String)o).length());
else if (v.equals("substring")) return new JS.Callable() {
- public Object call(Array args) {
+ public Object call(JS.Array args) {
if (args.length() == 1) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue());
else if (args.length() == 2) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue(),
JS.toNumber(args.elementAt(1)).intValue());
}
};
else if (v.equals("toLowerCase")) return new JS.Callable() {
- public Object call(Array args) {
+ public Object call(JS.Array args) {
return ((String)o).toLowerCase();
} };
else if (v.equals("toUpperCase")) return new JS.Callable() {
- public Object call(Array args) {
+ public Object call(JS.Array args) {
return ((String)o).toString().toUpperCase();
} };
else if (v.equals("charAt")) return new JS.Callable() {
- public Object call(Array args) {
+ public Object call(JS.Array args) {
return ((String)o).charAt(JS.toNumber(args.elementAt(0)).intValue()) + "";
} };
else if (v.equals("lastIndexOf")) return new JS.Callable() {
- public Object call(Array args) {
+ public Object call(JS.Array args) {
if (args.length() != 1) return null;
return new Integer(((String)o).lastIndexOf(args.elementAt(0).toString()));
} };
else if (v.equals("indexOf")) return new JS.Callable() {
- public Object call(Array args) {
+ public Object call(JS.Array args) {
if (args.length() != 1) return null;
return new Integer(((String)o).indexOf(args.elementAt(0).toString()));
} };