Object key = t.pop();
JS target = (JS)t.peek();
if (target == null)
- throw new JS.Exn("tried to put a value to the " + key + " property on the null value");
+ throw new JS.Exn(sourceName + ":" + line + ": tried to put a value to the " + key +
+ " property on the null value");
target.put(key, val);
t.push(val);
break;
arguments.setSize(numArgs);
for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(t.pop(), j);
JS.Function f = (JS.Function)t.pop();
- if (f == null) throw new JS.Exn("attempted to call null");
+ if (f == null) throw new JS.Exn(sourceName + ":" + line + ": attempted to call null");
t.push(f.call(arguments));
break;
}
public Object doGet(final Object o, final Object v) {
if (o == null)
- throw new JS.Exn("tried to get property \"" + v + "\" from the null value");
+ throw new JS.Exn(sourceName + ":" + line + ": tried to get property \"" + v + "\" from the null value");
if (o instanceof String) {
if (v.equals("length")) return new Integer(((String)o).length());
- else if (v.equals("substring")) return new JS.Function() {
+ else if (v.equals("substring")) return new JS.Function(-1, "java", null, null) {
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(),
else throw new Error("String.substring() can only take one or two arguments");
}
};
- else if (v.equals("toLowerCase")) return new JS.Function() {
+ else if (v.equals("toLowerCase")) return new JS.Function(-1, "java", null, null) {
public Object _call(JS.Array args) {
return ((String)o).toLowerCase();
} };
- else if (v.equals("toUpperCase")) return new JS.Function() {
+ else if (v.equals("toUpperCase")) return new JS.Function(-1, "java", null, null) {
public Object _call(JS.Array args) {
return ((String)o).toString().toUpperCase();
} };
- else if (v.equals("charAt")) return new JS.Function() {
+ else if (v.equals("charAt")) return new JS.Function(-1, "java", null, null) {
public Object _call(JS.Array args) {
return ((String)o).charAt(JS.toNumber(args.elementAt(0)).intValue()) + "";
} };
- else if (v.equals("lastIndexOf")) return new JS.Function() {
+ else if (v.equals("lastIndexOf")) return new JS.Function(-1, "java", null, null) {
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.Function() {
+ else if (v.equals("indexOf")) return new JS.Function(-1, "java", null, null) {
public Object _call(JS.Array args) {
if (args.length() != 1) return null;
return new Integer(((String)o).indexOf(args.elementAt(0).toString()));
try {
return vec.elementAt(i);
} catch (ArrayIndexOutOfBoundsException e) {
- throw new JS.Exn(e.getMessage());
+ return null;
}
}
public void put(Object key, Object val) {
int line;
String sourceName;
Scope parentScope;
- public Function() { this(-1, "unknown", null, null); }
public Function(int line, String sourceName, ByteCodeBlock bytecodes, Scope parentScope) {
this.sourceName = sourceName;
this.line = line;
this.bytecodes = bytecodes;
this.parentScope = parentScope;
}
+ public Function cloneWithNewParentScope(Scope s) {
+ if (this.getClass() != Function.class)
+ throw new Error("org.xwt.js.JS.Function.cloneWithNewParentScope() is not valid for subclasses");
+ return new Function(line, sourceName, bytecodes, s);
+ }
public String getSourceName() throws JS.Exn { return sourceName; }
public int getLine() throws JS.Exn { return line; }
public Object _call(JS.Array args) throws JS.Exn, ByteCodeBlock.ControlTransferException {
if (bytecodes == null) throw new Error("tried to call() a JS.Function with bytecodes == null");
Vec stack = new Vec();
stack.push(args);
- return bytecodes.eval(new FunctionScope(sourceName, parentScope), stack);
+ return bytecodes.eval(args == null ? parentScope : new FunctionScope(sourceName, parentScope), stack);
}
public final Object call(JS.Array args) throws JS.Exn {
Function saved = (Function)currentFunction.get(Thread.currentThread());
- currentFunction.put(Thread.currentThread(), this);
+ if (!getSourceName().equals("java")) currentFunction.put(Thread.currentThread(), this);
try {
return _call(args);
} catch (ByteCodeBlock.ReturnException e) { // ignore
}
}
- public static class Script extends Function {
- Vector e = null;
- private Script(Vector e) { this.e = e; }
- public String getSourceName() throws JS.Exn { return ((ByteCodeBlock)e.elementAt(0)).getSourceName(); }
- public Object _call(JS.Array args) throws JS.Exn, ByteCodeBlock.ControlTransferException {
- Scope rootScope = (Scope)args.elementAt(0);
- for(int i=0; i<e.size(); i++) ((ByteCodeBlock)e.elementAt(i)).eval(rootScope, new Vec());
- return null;
- }
- public static Script parse(Reader r, String sourceName, int line) throws IOException {
- Parser p = new Parser(r, sourceName, line);
- try {
- Vector exprs = new Vector();
- while(true) {
- ByteCodeBlock ret = p.parseStatement();
- if (ret == null) break;
- exprs.addElement(ret);
- }
- return new Script(exprs);
- } catch (Exception e) {
- if (Log.on) Log.log(Parser.class, e);
- return null;
+ public static Function parse(Reader r, String sourceName, int line) throws IOException {
+ ByteCodeBlock b = new ByteCodeBlock(line, sourceName);
+ Parser p = new Parser(r, sourceName, line);
+ try {
+ while(true) {
+ int size = b.size();
+ p.parseStatement(false, b);
+ if (size == b.size()) break;
}
+ return new Function(line, sourceName, b, null);
+ } catch (Exception e) {
+ if (Log.on) Log.log(Parser.class, e);
+ return null;
}
}
/** for debugging */
public static void main(String[] s) throws Exception {
- Lexer l = new Lexer(new InputStreamReader(System.in));
+ Lexer l = new Lexer(new InputStreamReader(System.in), "stdin", 0);
int tok = 0;
while((tok = l.getToken()) != -1) System.out.println(codeToString[tok]);
}
protected int col = 0;
/** the name of the source code file being lexed */
- protected String sourceName = "unknown";
+ protected String sourceName;
private SmartReader in;
- public Lexer(Reader r) throws IOException { in = new SmartReader(r); }
+ public Lexer(Reader r, String sourceName, int line) throws IOException {
+ this.sourceName = sourceName;
+ this.line = line;
+ in = new SmartReader(r);
+ }
// Predicates ///////////////////////////////////////////////////////////////////////
// Constructors //////////////////////////////////////////////////////
- public Parser(Reader r, String sourceName, int line) throws IOException {
- super(r);
- this.sourceName = sourceName;
- this.line = line;
- }
+ public Parser(Reader r, String sourceName, int line) throws IOException { super(r, sourceName, line); }
/** for debugging */
public static void main(String[] s) throws Exception {
int tok = getToken();
int curLine = line;
if (tok == -1) return;
- if (minPrecedence > 0 && precedence[tok] != 0)
- if (precedence[tok] < minPrecedence || (precedence[tok] == minPrecedence && !isRightAssociative[tok]))
- { pushBackToken(); return; }
ByteCodeBlock b = appendTo;
}
case SUB: {
consume(NUMBER);
- continueExpr(b.add(ByteCodeBlock.LITERAL, new Double(number.doubleValue() * -1)), minPrecedence);
+ b.add(ByteCodeBlock.LITERAL, new Double(number.doubleValue() * -1));
+ continueExpr(b, minPrecedence);
return;
}
case LP: {
consume(LP);
tok = getToken();
- if (tok == VAR) tok = getToken();
+ boolean hadVar = false;
+ if (tok == VAR) { hadVar = true; tok = getToken(); }
String varName = string;
boolean forIn = peekToken() == IN;
pushBackToken(tok, varName);
break;
} else {
+ if (hadVar) pushBackToken(VAR, null);
ByteCodeBlock b2 = newbb(curLine);
b.add(SCOPE, b2);
b.add(POP);
int size = b2.size();
- startExpr(b2);
- if (b2.size() - size > 0) b2.add(POP);
- consume(SEMI);
+ parseStatement(false, b2);
ByteCodeBlock e2 = startExpr();
consume(SEMI);
if (e2 == null) e2 = newbb(curLine).add(b.LITERAL, null);
b3.add(JT, new Integer(2));
b3.add(BREAK);
parseStatement(false, b3);
- b3.add(BREAK);
+ b3.add(CONTINUE);
break;
}
}