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, 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, 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));
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