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
} else {
consume(NAME);
}
- b.add(parserLine, LITERAL, string);
+ b.add(parserLine, LITERAL, JSString.intern(string));
continueExprAfterAssignable(b,minPrecedence);
break;
}
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);
pushBackToken(tok, varName);
if (forIn) {
- b.add(parserLine, NEWSCOPE);
- b.add(parserLine, DECLARE, varName);
- b.add(parserLine, POP);
-
consume(NAME);
consume(IN);
startExpr(b,-1);
consume(RP);
+
b.add(parserLine, PUSHKEYS);
b.add(parserLine, DUP);
- b.add(parserLine, LITERAL, "length");
+ b.add(parserLine, LITERAL, JSString.intern("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));
+ 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, GET_PRESERVE);
- b.add(parserLine, TOPSCOPE);
- b.add(parserLine, SWAP);
- b.add(parserLine, LITERAL, varName);
- b.add(parserLine, SWAP);
- b.add(parserLine, PUT);
- b.add(parserLine, POP);
- b.add(parserLine, POP);
+ b.add(parserLine, NEWSCOPE);
+ if(hadVar) {
+ b.add(parserLine, DECLARE, JSString.intern(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, JSString.intern(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));
parseStatement(b, null);
+ b.add(parserLine, OLDSCOPE);
b.add(parserLine, CONTINUE);
+ // 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, OLDSCOPE);
-
+
} 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);