case -1: throw pe("expected expression");
// all of these simply push values onto the stack
- case NUMBER: b.add(parserLine, LITERAL, number); break;
- case STRING: b.add(parserLine, LITERAL, string); break;
+ case NUMBER: b.add(parserLine, LITERAL, JS.N(number)); break;
+ case STRING: b.add(parserLine, LITERAL, JSString.intern(string)); break;
case NULL: b.add(parserLine, LITERAL, null); break;
- case TRUE: case FALSE: b.add(parserLine, LITERAL, JS.B(tok == TRUE)); break;
+ case TRUE: case FALSE: b.add(parserLine, LITERAL, tok == TRUE ? JS.T : JS.F); break;
// (.foo) syntax
case DOT: {
consume(NAME);
b.add(parserLine, TOPSCOPE);
- b.add(parserLine, LITERAL, "");
+ b.add(parserLine, LITERAL, JSString.intern(""));
b.add(parserLine, GET);
- b.add(parserLine, LITERAL, string);
+ b.add(parserLine, LITERAL, JSString.intern(string));
b.add(parserLine, GET);
continueExpr(b, minPrecedence);
break;
consume(RB);
break;
}
- case SUB: { // negative literal (like "3 * -1")
- consume(NUMBER);
- b.add(parserLine, LITERAL, JS.N(number.doubleValue() * -1));
+ case SUB: case ADD: {
+ if(peekToken() == NUMBER) { // literal
+ consume(NUMBER);
+ b.add(parserLine, LITERAL, JS.N(number.doubleValue() * (tok == SUB ? -1 : 1)));
+ } else { // unary +/- operator
+ if(tok == SUB) b.add(parserLine, LITERAL, JS.ZERO);
+ // BITNOT has the same precedence as the unary +/- operators
+ startExpr(b,precedence[BITNOT]);
+ if(tok == ADD) b.add(parserLine, LITERAL, JS.ZERO); // HACK to force expr into a numeric context
+ b.add(parserLine, SUB);
+ }
break;
}
case LP: { // grouping (not calling)
if (peekToken() != NAME && peekToken() != STRING)
throw pe("expected NAME or STRING");
getToken();
- b.add(parserLine, LITERAL, string); // grab the key
+ b.add(parserLine, LITERAL, JSString.intern(string)); // grab the key
consume(COLON);
startExpr(b, NO_COMMA); // grab the value
b.add(parserLine, PUT); // put the value into the object
}
case NAME: {
b.add(parserLine, TOPSCOPE);
- b.add(parserLine, LITERAL, string);
+ b.add(parserLine, LITERAL, JSString.intern(string));
continueExprAfterAssignable(b,minPrecedence);
break;
}
// function prelude; arguments array is already on the stack
b2.add(parserLine, TOPSCOPE);
b2.add(parserLine, SWAP);
- b2.add(parserLine, DECLARE, "arguments"); // declare arguments (equivalent to 'var arguments;')
+ b2.add(parserLine, DECLARE, JSString.intern("arguments")); // declare arguments (equivalent to 'var arguments;')
b2.add(parserLine, SWAP); // set this.arguments and leave the value on the stack
b2.add(parserLine, PUT);
numArgs++;
if (peekToken() == NAME) {
consume(NAME); // a named argument
- String varName = string;
+ JS varName = JSString.intern(string);
b2.add(parserLine, DUP); // dup the args array
b2.add(parserLine, GET, JS.N(numArgs - 1)); // retrieve it from the arguments array
// Method calls are implemented by doing a GET_PRESERVE
// first. If the object supports method calls, it will
// return JS.METHOD
- int n = parseArgs(b, 2);
b.add(parserLine, GET_PRESERVE);
+ int n = parseArgs(b);
b.add(parserLine, CALLMETHOD, JS.N(n));
break;
}
switch (tok) {
case LP: { // invocation (not grouping)
- int n = parseArgs(b, 1);
+ int n = parseArgs(b);
b.add(parserLine, CALL, JS.N(n));
break;
}
} else {
consume(NAME);
}
- b.add(parserLine, LITERAL, string);
+ b.add(parserLine, LITERAL, JSString.intern(string));
continueExprAfterAssignable(b,minPrecedence);
break;
}
}
// parse a set of comma separated function arguments, assume LP has already been consumed
- // if swap is true, (because the function is already on the stack) we will SWAP after each argument to keep it on top
- private int parseArgs(JSFunction b, int pushdown) throws IOException {
+ private int parseArgs(JSFunction b) throws IOException {
int i = 0;
while(peekToken() != RP) {
i++;
if (peekToken() != COMMA) {
startExpr(b, NO_COMMA);
- b.add(parserLine, SWAP, JS.N(pushdown));
if (peekToken() == RP) break;
}
consume(COMMA);
b.add(parserLine, TOPSCOPE); // push the current scope
while(true) {
consume(NAME);
- b.add(parserLine, DECLARE, string); // declare it
+ b.add(parserLine, DECLARE, JSString.intern(string)); // declare it
if (peekToken() == ASSIGN) { // if there is an '=' after the variable name
consume(ASSIGN);
startExpr(b, NO_COMMA);
// extended Ibex catch block: catch(e faultCode "foo.bar.baz")
consume(NAME);
b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, string);
+ b.add(parserLine, LITERAL, JSString.intern(string));
b.add(parserLine, GET);
b.add(parserLine, DUP);
b.add(parserLine, LITERAL, null);
b.add(parserLine, NEWSCOPE);
b.add(parserLine, TOPSCOPE);
b.add(parserLine, SWAP);
- b.add(parserLine, LITERAL,exceptionVar);
+ b.add(parserLine, LITERAL,JSString.intern(exceptionVar));
b.add(parserLine, DECLARE);
b.add(parserLine, SWAP);
b.add(parserLine, PUT);
consume(RP);
b.add(parserLine, PUSHKEYS);
- b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, "length");
- b.add(parserLine, GET);
- // Stack is now: n, keys, obj, ...
int size = b.size;
b.add(parserLine, LOOP);
b.add(parserLine, POP);
- // Stack is now: LoopMarker, n, keys, obj, ...
- // NOTE: This will break if the interpreter ever becomes more strict
- // and prevents bytecode from messing with the Markers
- b.add(parserLine, SWAP, JS.N(3));
- // Stack is now: Tn, keys, obj, LoopMarker, ...
-
- b.add(parserLine, LITERAL, JS.N(1));
- b.add(parserLine, SUB);
- b.add(parserLine, DUP);
- // Stack is now: index, keys, obj, LoopMarker
- b.add(parserLine, LITERAL, JS.ZERO);
- b.add(parserLine, LT);
- // Stack is now index<0, index, keys, obj, LoopMarker, ...
-
- b.add(parserLine, JF, JS.N(5)); // if we're >= 0 jump 5 down (to NEWSCOPE)
- // Move the LoopMarker back into place - this is sort of ugly
- b.add(parserLine, SWAP, JS.N(3));
- b.add(parserLine, SWAP, JS.N(3));
- b.add(parserLine, SWAP, JS.N(3));
- // Stack is now: LoopMarker, -1, keys, obj, ...
- b.add(parserLine, BREAK);
+ b.add(parserLine,SWAP); // get the keys enumeration object on top
+ b.add(parserLine,DUP);
+ b.add(parserLine,GET,JS.S("hasMoreElements"));
+ int size2 = b.size;
+ b.add(parserLine,JT);
+ b.add(parserLine,SWAP);
+ b.add(parserLine,BREAK);
+ b.set(size2, JS.N(b.size - size2));
+ b.add(parserLine,DUP);
+ b.add(parserLine,GET,JS.S("nextElement"));
+
b.add(parserLine, NEWSCOPE);
- if(hadVar) {
- b.add(parserLine, DECLARE, varName);
- b.add(parserLine, POP);
- }
- // Stack is now: index, keys, obj, LoopMarker, ...
- b.add(parserLine, GET_PRESERVE); // key, index, keys, obj, LoopMarker, ...
- b.add(parserLine, TOPSCOPE); // scope, key, index, keys, obj, LoopMarker, ...
- b.add(parserLine, SWAP); // key, scope, index, keys, obj, LoopMarker, ...
- b.add(parserLine, LITERAL, varName); // varName, key, scope, index, keys, obj, LoopMaker, ...
- b.add(parserLine, SWAP); // key, varName, scope, index, keys, obj, LoopMarker, ...
- b.add(parserLine, PUT); // key, scope, index, keys, obj, LoopMarker, ...
- b.add(parserLine, POP); // scope, index, keys, obj, LoopMarker
- b.add(parserLine, POP); // index, keys, obj, LoopMarker, ...
- // Move the LoopMarker back into place - this is sort of ugly
- b.add(parserLine, SWAP, JS.N(3));
- b.add(parserLine, SWAP, JS.N(3));
- b.add(parserLine, SWAP, JS.N(3));
+ b.add(parserLine,TOPSCOPE);
+ b.add(parserLine,SWAP);
+ b.add(parserLine, hadVar ? DECLARE : LITERAL, JSString.intern(varName));
+ b.add(parserLine,SWAP);
+ b.add(parserLine,PUT);
+ b.add(parserLine,POP);
+ b.add(parserLine,POP);
+ b.add(parserLine,SWAP);
parseStatement(b, null);
// jump here on break
b.set(size, JS.N(b.size - size));
- b.add(parserLine, POP); // N
- b.add(parserLine, POP); // KEYS
- b.add(parserLine, POP); // OBJ
-
+ b.add(parserLine, POP);
} else {
if (hadVar) pushBackToken(VAR, null); // yeah, this actually matters
b.add(parserLine, NEWSCOPE); // grab a fresh scope
if (peekToken() != SEMI)
startExpr(e2, -1);
else
- e2.add(parserLine, JSFunction.LITERAL, Boolean.TRUE); // handle the for(foo;;foo) case
+ e2.add(parserLine, JSFunction.LITERAL, JS.T); // handle the for(foo;;foo) case
consume(SEMI);
if (label != null) b.add(parserLine, LABEL, label);
b.add(parserLine, LOOP);