From 49dffbfee615d9105c6e6bb1fda67e5647addd22 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:01:10 +0000 Subject: [PATCH] 2003/06/16 06:24:31 darcs-hash:20040130070110-2ba56-0a7361aee9acf285fcd833bf889fa7d54cf051d9.gz --- src/org/xwt/js/CompiledFunction.java | 5 +- src/org/xwt/js/Context.java | 9 +- src/org/xwt/js/Lexer.java | 10 +- src/org/xwt/js/Parser.java | 511 +++++++++++++++++++--------------- 4 files changed, 307 insertions(+), 228 deletions(-) diff --git a/src/org/xwt/js/CompiledFunction.java b/src/org/xwt/js/CompiledFunction.java index cddaeca..ac14075 100644 --- a/src/org/xwt/js/CompiledFunction.java +++ b/src/org/xwt/js/CompiledFunction.java @@ -90,6 +90,7 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To // Adding and Altering Bytecodes /////////////////////////////////////////////////// + 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= 0; j--) arguments.setElementAt(t.pop(), j); - // FIXME: we really need to distinguish between compiled functions and callables JS.Callable f = (JS.Callable)t.pop(); if (f == null) throw je("attempted to call null"); try { @@ -271,6 +271,7 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To if (o instanceof Context.TryMarker) { t.push(exn); pc = ((Context.TryMarker)o).location - 1; + s = ((Context.TryMarker)o).scope; continue OUTER; } } diff --git a/src/org/xwt/js/Context.java b/src/org/xwt/js/Context.java index ee00fc8..8533f34 100644 --- a/src/org/xwt/js/Context.java +++ b/src/org/xwt/js/Context.java @@ -42,7 +42,6 @@ public class Context { return ret; } - public static class TryMarker { public int location; public TryMarker(int location) { this.location = location; } } public static class CallMarker { public CallMarker() { } } public static class LoopMarker { public int location; @@ -52,5 +51,13 @@ public class Context { this.label = label; } } + public static class TryMarker { + public int location; + public JS.Scope scope; + public TryMarker(int location, JS.Scope scope) { + this.location = location; + this.scope = scope; + } + } } diff --git a/src/org/xwt/js/Lexer.java b/src/org/xwt/js/Lexer.java index f4c386e..eb3f69a 100644 --- a/src/org/xwt/js/Lexer.java +++ b/src/org/xwt/js/Lexer.java @@ -44,8 +44,11 @@ class Lexer implements Tokens { /** if the token just parsed was a NAME or STRING, this is the string value */ protected String string = null; - /** the line number of the current token */ - protected int line = 0; + /** the line number of the most recently lexed token */ + private int line = 0; + + /** the line number of the most recently parsed token */ + protected int parserLine = 0; /** the column number of the current token */ protected int col = 0; @@ -57,6 +60,7 @@ class Lexer implements Tokens { public Lexer(Reader r, String sourceName, int line) throws IOException { this.sourceName = sourceName; this.line = line; + this.parserLine = line; in = new SmartReader(r); } @@ -352,7 +356,7 @@ class Lexer implements Tokens { lastread = reader.read(); if (accumulator != null) accumulator.append((char)lastread); if (lastread != '\n' && lastread != '\r') col++; - if (lastread == '\n') { line++; col = 0; } + if (lastread == '\n') { parserLine = ++line; col = 0; } return lastread; } diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index e82b408..76f223b 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -1,23 +1,34 @@ // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt.js; -// FIXME: line number accuracy -// FIXME: scope management - import org.xwt.util.*; import java.io.*; /** * Parses a stream of lexed tokens into a tree of CompiledFunction's. * - - * There are three kinds of things we parse: blocks, statements, - * expressions. Expressions are a special type of statement that - * evaluates to a value (for example, "break" is not an expression, - * but "3+2" is). AssignmentTargets are a special kind of expression - * that can be 'put' to (for example, "foo()" is not an - * assignmentTarget, but "foo[7]" is). FIXME. - + * There are three kinds of things we parse: blocks, statements, and + * expressions. + * + * - Expressions are a special type of statement that evaluates to a + * value (for example, "break" is not an expression, * but "3+2" + * is). Some tokens sequences start expressions (for * example, + * literal numbers) and others continue an expression which * has + * already been begun (for example, '+'). Finally, some * + * expressions are valid targets for an assignment operation; after + * * each of these expressions, continueExprAfterAssignable() is + * called * to check for an assignment operation. + * + * - A statement ends with a semicolon and does not return a value. + * + * - A block is a single statement or a sequence of statements + * surrounded by curly braces. + * + * Each parsing method saves the parserLine before doing its actual + * work and restores it afterwards. This ensures that parsing a + * subexpression does not modify the line number until a token + * *after* the subexpression has been consumed by the parent + * expression. * * Technically it would be a better design for this class to build an * intermediate parse tree and use that to emit bytecode. Here's the @@ -73,9 +84,31 @@ class Parser extends Lexer implements ByteCodes { static byte[] precedence = new byte[MAX_TOKEN + 1]; static boolean[] isRightAssociative = new boolean[MAX_TOKEN + 1]; static { - isRightAssociative[ASSIGN] = true; - - precedence[ASSIGN] = 1; + isRightAssociative[ASSIGN] = + isRightAssociative[ASSIGN_BITOR] = + isRightAssociative[ASSIGN_BITXOR] = + isRightAssociative[ASSIGN_BITAND] = + isRightAssociative[ASSIGN_LSH] = + isRightAssociative[ASSIGN_RSH] = + isRightAssociative[ASSIGN_URSH] = + isRightAssociative[ASSIGN_ADD] = + isRightAssociative[ASSIGN_SUB] = + isRightAssociative[ASSIGN_MUL] = + isRightAssociative[ASSIGN_DIV] = + isRightAssociative[ASSIGN_MOD] = true; + + precedence[ASSIGN] = + precedence[ASSIGN_BITOR] = + precedence[ASSIGN_BITXOR] = + precedence[ASSIGN_BITAND] = + precedence[ASSIGN_LSH] = + precedence[ASSIGN_RSH] = + precedence[ASSIGN_URSH] = + precedence[ASSIGN_ADD] = + precedence[ASSIGN_SUB] = + precedence[ASSIGN_MUL] = + precedence[ASSIGN_DIV] = + precedence[ASSIGN_MOD] = 1; precedence[HOOK] = 2; precedence[COMMA] = 3; precedence[OR] = precedence[AND] = 4; @@ -92,8 +125,7 @@ class Parser extends Lexer implements ByteCodes { precedence[BITNOT] = 15; precedence[INC] = precedence[DEC] = 16; precedence[LP] = 17; - precedence[LB] = 18; - precedence[DOT] = 19; + precedence[DOT] = precedence[LB] = 18; } @@ -109,8 +141,13 @@ class Parser extends Lexer implements ByteCodes { * of precedence below minPrecedence and append the * bytecodes for that expression to appendTo; the * appended bytecodes MUST grow the stack by exactly one element. - */ + */ private void startExpr(CompiledFunction appendTo, int minPrecedence) throws IOException { + int saveParserLine = parserLine; + _startExpr(appendTo, minPrecedence); + parserLine = saveParserLine; + } + private void _startExpr(CompiledFunction appendTo, int minPrecedence) throws IOException { int tok = getToken(); CompiledFunction b = appendTo; @@ -118,36 +155,36 @@ class Parser extends Lexer implements ByteCodes { case -1: throw new ParserException("expected expression"); // all of these simply push values onto the stack - case NUMBER: b.add(line, LITERAL, number); break; - case STRING: b.add(line, LITERAL, string); break; - case THIS: b.add(line, TOPSCOPE, null); break; - case NULL: b.add(line, LITERAL, null); break; - case TRUE: case FALSE: b.add(line, LITERAL, new Boolean(tok == TRUE)); break; + case NUMBER: b.add(parserLine, LITERAL, number); break; + case STRING: b.add(parserLine, LITERAL, string); break; + case THIS: b.add(parserLine, TOPSCOPE, null); break; + case NULL: b.add(parserLine, LITERAL, null); break; + case TRUE: case FALSE: b.add(parserLine, LITERAL, new Boolean(tok == TRUE)); break; case LB: { - b.add(line, ARRAY, new Integer(0)); // push an array onto the stack + b.add(parserLine, ARRAY, new Integer(0)); // push an array onto the stack int size0 = b.size(); int i = 0; if (peekToken() != RB) - while(true) { // iterate over the initialization values + while(true) { // iterate over the initialization values int size = b.size(); if (peekToken() == COMMA || peekToken() == RB) - b.add(line, LITERAL, null); // for stuff like [1,,2,] + b.add(parserLine, LITERAL, null); // for stuff like [1,,2,] else - startExpr(b, -1); // push the value onto the stack - b.add(line, LITERAL, new Integer(i++)); // push the index in the array to place it into - b.add(line, PUT); // put it into the array - b.add(line, POP); // discard the value remaining on the stack + startExpr(b, -1); // push the value onto the stack + b.add(parserLine, LITERAL, new Integer(i++)); // push the index in the array to place it into + b.add(parserLine, PUT); // put it into the array + b.add(parserLine, POP); // discard the value remaining on the stack if (peekToken() == RB) break; consume(COMMA); } - b.set(size0 - 1, new Integer(i)); // back at the ARRAY instruction, write the size of the array + b.set(size0 - 1, new Integer(i)); // back at the ARRAY instruction, write the size of the array consume(RB); break; } case SUB: { // negative literal (like "3 * -1") consume(NUMBER); - b.add(line, LITERAL, new Double(number.doubleValue() * -1)); + b.add(parserLine, LITERAL, new Double(number.doubleValue() * -1)); break; } case LP: { // grouping (not calling) @@ -157,26 +194,28 @@ class Parser extends Lexer implements ByteCodes { } case INC: case DEC: { // prefix (not postfix) startExpr(b, precedence[tok]); - b.set(b.size() - 1, tok, new Boolean(true)); // FIXME, ugly; need startAssignTarget + if (b.get(b.size() - 1) != GET) + throw new ParserException("prefixed increment/decrement can only be performed on a valid assignment target"); + b.set(b.size() - 1, tok, new Boolean(true)); break; } case BANG: case BITNOT: case TYPEOF: { startExpr(b, precedence[tok]); - b.add(line, tok); + b.add(parserLine, tok); break; } case LC: { // object constructor - b.add(line, OBJECT, null); // put an object on the stack + b.add(parserLine, OBJECT, null); // put an object on the stack if (peekToken() != RC) while(true) { if (peekToken() != NAME && peekToken() != STRING) throw new ParserException("expected NAME or STRING"); getToken(); - b.add(line, LITERAL, string); // grab the key + b.add(parserLine, LITERAL, string); // grab the key consume(COLON); startExpr(b, -1); // grab the value - b.add(line, PUT); // put the value into the object - b.add(line, POP); // discard the remaining value + b.add(parserLine, PUT); // put the value into the object + b.add(parserLine, POP); // discard the remaining value if (peekToken() == RC) break; consume(COMMA); if (peekToken() == RC) break; // we permit {,,} -- I'm not sure if ECMA does @@ -184,62 +223,51 @@ class Parser extends Lexer implements ByteCodes { consume(RC); break; } - case NAME: { // FIXME; this is an lvalue - String name = string; - if (peekToken() == ASSIGN) { - consume(ASSIGN); - b.add(line, TOPSCOPE); - b.add(line, LITERAL, name); - startExpr(b, minPrecedence); - b.add(line, PUT); - b.add(line, SWAP); - b.add(line, POP); - } else { - b.add(line, TOPSCOPE); - b.add(line, LITERAL, name); - b.add(line, GET); - } - break; + case NAME: { + b.add(parserLine, TOPSCOPE); + b.add(parserLine, LITERAL, string); + continueExprAfterAssignable(b); + break; } case FUNCTION: { consume(LP); int numArgs = 0; - CompiledFunction b2 = new CompiledFunction(sourceName, line, null); - b.add(line, NEWFUNCTION, b2); + CompiledFunction b2 = new CompiledFunction(sourceName, parserLine, null); + b.add(parserLine, NEWFUNCTION, b2); // function prelude; arguments array is already on the stack - b2.add(line, TOPSCOPE); // push the scope onto the stack - b2.add(line, SWAP); // swap 'this' and 'arguments' + b2.add(parserLine, TOPSCOPE); // push the scope onto the stack + b2.add(parserLine, SWAP); // swap 'this' and 'arguments' - b2.add(line, LITERAL, "arguments"); // declare arguments (equivalent to 'var arguments;') - b2.add(line, DECLARE); + b2.add(parserLine, LITERAL, "arguments"); // declare arguments (equivalent to 'var arguments;') + b2.add(parserLine, DECLARE); - b2.add(line, LITERAL, "arguments"); // set this.arguments and leave the value on the stack - b2.add(line, SWAP); - b2.add(line, PUT); - b2.add(line, SWAP); - b2.add(line, POP); + b2.add(parserLine, LITERAL, "arguments"); // set this.arguments and leave the value on the stack + b2.add(parserLine, SWAP); + b2.add(parserLine, PUT); + b2.add(parserLine, SWAP); + b2.add(parserLine, POP); - while(peekToken() != RP) { // run through the list of argument names + while(peekToken() != RP) { // run through the list of argument names if (peekToken() == NAME) { - consume(NAME); // a named argument + consume(NAME); // a named argument - b2.add(line, LITERAL, string); // declare the name - b2.add(line, DECLARE); + b2.add(parserLine, LITERAL, string); // declare the name + b2.add(parserLine, DECLARE); - b2.add(line, LITERAL, new Integer(numArgs)); // retrieve it from the arguments array - b2.add(line, GET_PRESERVE); - b2.add(line, SWAP); - b2.add(line, POP); + b2.add(parserLine, LITERAL, new Integer(numArgs)); // retrieve it from the arguments array + b2.add(parserLine, GET_PRESERVE); + b2.add(parserLine, SWAP); + b2.add(parserLine, POP); - b2.add(line, TOPSCOPE); // put it to the current scope - b2.add(line, SWAP); - b2.add(line, LITERAL, string); - b2.add(line, SWAP); - b2.add(line, PUT); + b2.add(parserLine, TOPSCOPE); // put it to the current scope + b2.add(parserLine, SWAP); + b2.add(parserLine, LITERAL, string); + b2.add(parserLine, SWAP); + b2.add(parserLine, PUT); - b2.add(line, POP); // clean the stack - b2.add(line, POP); + b2.add(parserLine, POP); // clean the stack + b2.add(parserLine, POP); } if (peekToken() == RP) break; consume(COMMA); @@ -247,12 +275,12 @@ class Parser extends Lexer implements ByteCodes { } consume(RP); - b2.add(line, POP); // pop off the arguments array + b2.add(parserLine, POP); // pop off the arguments array - parseStatement(b2, null); // the function body + parseStatement(b2, null); // the function body - b2.add(line, LITERAL, null); // in case we "fall out the bottom", return NULL - b2.add(line, RETURN); + b2.add(parserLine, LITERAL, null); // in case we "fall out the bottom", return NULL + b2.add(parserLine, RETURN); break; } @@ -263,6 +291,60 @@ class Parser extends Lexer implements ByteCodes { continueExpr(b, minPrecedence); } + + /** + * Assuming that a complete assignable (lvalue) has just been + * parsed and the object and key are on the stack, + * continueExprAfterAssignable will attempt to parse an + * expression that modifies the assignable. This method always + * decreases the stack depth by exactly one element. + */ + private void continueExprAfterAssignable(CompiledFunction b) throws IOException { + int saveParserLine = parserLine; + _continueExprAfterAssignable(b); + parserLine = saveParserLine; + } + private void _continueExprAfterAssignable(CompiledFunction b) throws IOException { + if (b == null) throw new Error("got null b; this should never happen"); + int tok = getToken(); + switch(tok) { + case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH: + case ASSIGN_ADD: case ASSIGN_SUB: case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: { + b.add(parserLine, GET_PRESERVE); + startExpr(b, -1); + b.add(parserLine, tok - 1); + b.add(parserLine, PUT); + b.add(parserLine, SWAP); + b.add(parserLine, POP); + break; + } + case INC: case DEC: { // postfix + b.add(parserLine, GET_PRESERVE); + b.add(parserLine, LITERAL, new Integer(1)); + b.add(parserLine, tok == INC ? ADD : SUB); + b.add(parserLine, PUT); + b.add(parserLine, SWAP); + b.add(parserLine, POP); + b.add(parserLine, LITERAL, new Integer(1)); + b.add(parserLine, tok == INC ? SUB : ADD); + break; + } + case ASSIGN: { + startExpr(b, -1); + b.add(parserLine, PUT); + b.add(parserLine, SWAP); + b.add(parserLine, POP); + break; + } + default: { + pushBackToken(); + b.add(parserLine, GET); + return; + } + } + } + + /** * Assuming that a complete expression has just been parsed, * continueExpr will attempt to extend this expression by @@ -275,6 +357,11 @@ class Parser extends Lexer implements ByteCodes { * depth. */ private void continueExpr(CompiledFunction b, int minPrecedence) throws IOException { + int saveParserLine = parserLine; + _continueExpr(b, minPrecedence); + parserLine = saveParserLine; + } + private void _continueExpr(CompiledFunction b, int minPrecedence) throws IOException { if (b == null) throw new Error("got null b; this should never happen"); int tok = getToken(); if (tok == -1) return; @@ -284,20 +371,6 @@ class Parser extends Lexer implements ByteCodes { } switch (tok) { - case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH: - case ASSIGN_ADD: case ASSIGN_SUB: case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: { - b.set(b.size() - 1, b.GET_PRESERVE, new Boolean(true)); // FIXME should use AssignTarget - startExpr(b, precedence[tok - 1]); - b.add(line, tok - 1); - b.add(line, PUT); - b.add(line, SWAP); - b.add(line, POP); - break; - } - case INC: case DEC: { // postfix - b.set(b.size() - 1, tok, new Boolean(false)); // FIXME use assignmenttarget - break; - } case LP: { // invocation (not grouping) int i = 0; while(peekToken() != RP) { @@ -309,60 +382,43 @@ class Parser extends Lexer implements ByteCodes { consume(COMMA); } consume(RP); - b.add(line, CALL, new Integer(i)); + b.add(parserLine, CALL, new Integer(i)); break; } case BITOR: case BITXOR: case BITAND: case SHEQ: case SHNE: case LSH: case RSH: case URSH: case ADD: case MUL: case DIV: case MOD: case GT: case GE: case EQ: case NE: case LT: case LE: case SUB: { startExpr(b, precedence[tok]); - b.add(line, tok); + b.add(parserLine, tok); break; } case OR: case AND: { - b.add(line, tok == AND ? b.JF : b.JT, new Integer(0)); // test to see if we can short-circuit + b.add(parserLine, tok == AND ? b.JF : b.JT, new Integer(0)); // test to see if we can short-circuit int size = b.size(); - startExpr(b, precedence[tok]); // otherwise check the second value - b.add(line, JMP, new Integer(2)); // leave the second value on the stack and jump to the end - b.add(line, LITERAL, tok == AND ? new Boolean(false) : new Boolean(true)); // target of the short-circuit jump is here - b.set(size - 1, new Integer(b.size() - size)); // write the target of the short-circuit jump + startExpr(b, precedence[tok]); // otherwise check the second value + b.add(parserLine, JMP, new Integer(2)); // leave the second value on the stack and jump to the end + b.add(parserLine, LITERAL, tok == AND ? + new Boolean(false) : new Boolean(true)); // target of the short-circuit jump is here + b.set(size - 1, new Integer(b.size() - size)); // write the target of the short-circuit jump break; } - case DOT: { // FIXME, assigntarget + case DOT: { consume(NAME); - String target = string; - if (peekToken() == ASSIGN) { - consume(ASSIGN); - b.add(line, LITERAL, target); - startExpr(b, -1); - b.add(line, PUT); - b.add(line, SWAP); - b.add(line, POP); - } else { - b.add(line, LITERAL, target); - b.add(line, GET); - } - break; + b.add(parserLine, LITERAL, string); + continueExprAfterAssignable(b); + break; } case LB: { // subscripting (not array constructor) startExpr(b, -1); consume(RB); - if (peekToken() == ASSIGN) { // FIXME: assigntarget - consume(ASSIGN); - startExpr(b, -1); - b.add(line, PUT); - b.add(line, SWAP); - b.add(line, POP); - } else { - b.add(line, GET); - } - break; + continueExprAfterAssignable(b); + break; } case HOOK: { - b.add(line, JF, new Integer(0)); // jump to the if-false expression + b.add(parserLine, JF, new Integer(0)); // jump to the if-false expression int size = b.size(); startExpr(b, -1); // write the if-true expression - b.add(line, JMP, new Integer(0)); // if true, jump *over* the if-false expression + b.add(parserLine, JMP, new Integer(0)); // if true, jump *over* the if-false expression b.set(size - 1, new Integer(b.size() - size + 1)); // now we know where the target of the jump is consume(COLON); size = b.size(); @@ -382,6 +438,11 @@ class Parser extends Lexer implements ByteCodes { /** Parse a block of statements which must be surrounded by LC..RC. */ void parseBlock(CompiledFunction b) throws IOException { parseBlock(b, null); } void parseBlock(CompiledFunction b, String label) throws IOException { + int saveParserLine = parserLine; + _parseBlock(b, label); + parserLine = saveParserLine; + } + void _parseBlock(CompiledFunction b, String label) throws IOException { if (peekToken() == -1) return; else if (peekToken() != LC) parseStatement(b, null); else { @@ -393,43 +454,48 @@ class Parser extends Lexer implements ByteCodes { /** Parse a single statement, consuming the RC or SEMI which terminates it. */ void parseStatement(CompiledFunction b, String label) throws IOException { + int saveParserLine = parserLine; + _parseStatement(b, label); + parserLine = saveParserLine; + } + void _parseStatement(CompiledFunction b, String label) throws IOException { int tok = peekToken(); if (tok == -1) return; switch(tok = getToken()) { case THROW: case ASSERT: case RETURN: { if (tok == RETURN && peekToken() == SEMI) - b.add(line, LITERAL, null); + b.add(parserLine, LITERAL, null); else startExpr(b, -1); - b.add(line, tok); + b.add(parserLine, tok); consume(SEMI); break; } case BREAK: case CONTINUE: { if (peekToken() == NAME) consume(NAME); - b.add(line, tok, string); + b.add(parserLine, tok, string); consume(SEMI); break; } case VAR: { - b.add(line, TOPSCOPE); // push the current scope + b.add(parserLine, TOPSCOPE); // push the current scope while(true) { consume(NAME); String name = string; - b.add(line, LITERAL, name); // push the name to be declared - b.add(line, DECLARE); // declare it - if (peekToken() == ASSIGN) { // if there is an '=' after the variable name - b.add(line, LITERAL, name); // put the var name back on the stack + b.add(parserLine, LITERAL, name); // push the name to be declared + b.add(parserLine, DECLARE); // declare it + if (peekToken() == ASSIGN) { // if there is an '=' after the variable name + b.add(parserLine, LITERAL, name); // put the var name back on the stack consume(ASSIGN); startExpr(b, -1); - b.add(line, PUT); // assign it - b.add(line, POP); // clean the stack + b.add(parserLine, PUT); // assign it + b.add(parserLine, POP); // clean the stack } if (peekToken() != COMMA) break; consume(COMMA); } - b.add(line, POP); // pop off the topscope + b.add(parserLine, POP); // pop off the topscope if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI); break; } @@ -438,51 +504,51 @@ class Parser extends Lexer implements ByteCodes { startExpr(b, -1); consume(RP); - b.add(line, JF, new Integer(0)); // if false, jump to the else-block + b.add(parserLine, JF, new Integer(0)); // if false, jump to the else-block int size = b.size(); parseStatement(b, null); if (peekToken() == ELSE) { consume(ELSE); - b.add(line, JMP, new Integer(0)); // if we took the true-block, jump over the else-block + b.add(parserLine, JMP, new Integer(0)); // if we took the true-block, jump over the else-block b.set(size - 1, new Integer(b.size() - size + 1)); size = b.size(); parseStatement(b, null); } - b.set(size - 1, new Integer(b.size() - size + 1)); // regardless of which branch we took, b[size] needs to point here + b.set(size - 1, new Integer(b.size() - size + 1)); // regardless of which branch we took, b[size] needs to point here break; } case WHILE: { consume(LP); - if (label != null) b.add(line, LABEL, label); - b.add(line, LOOP); + if (label != null) b.add(parserLine, LABEL, label); + b.add(parserLine, LOOP); int size = b.size(); - b.add(line, POP); // discard the first-iteration indicator + b.add(parserLine, POP); // discard the first-iteration indicator startExpr(b, -1); - b.add(line, JT, new Integer(2)); // if the while() clause is true, jump over the BREAK - b.add(line, BREAK); + b.add(parserLine, JT, new Integer(2)); // if the while() clause is true, jump over the BREAK + b.add(parserLine, BREAK); consume(RP); parseStatement(b, null); - b.add(line, CONTINUE); // if we fall out of the end, definately continue - b.set(size - 1, new Integer(b.size() - size + 1)); // end of the loop + b.add(parserLine, CONTINUE); // if we fall out of the end, definately continue + b.set(size - 1, new Integer(b.size() - size + 1)); // end of the loop break; } case SWITCH: { consume(LP); - if (label != null) b.add(line, LABEL, label); - b.add(line, LOOP); + if (label != null) b.add(parserLine, LABEL, label); + b.add(parserLine, LOOP); int size0 = b.size(); startExpr(b, -1); consume(RP); consume(LC); while(true) - if (peekToken() == CASE) { // we compile CASE statements like a bunch of if..else's + if (peekToken() == CASE) { // we compile CASE statements like a bunch of if..else's consume(CASE); - b.add(line, DUP); // duplicate the switch() value; we'll consume one copy + b.add(parserLine, DUP); // duplicate the switch() value; we'll consume one copy startExpr(b, -1); consume(COLON); - b.add(line, EQ); // check if we should do this case-block - b.add(line, JF, new Integer(0)); // if not, jump to the next one + b.add(parserLine, EQ); // check if we should do this case-block + b.add(parserLine, JF, new Integer(0)); // if not, jump to the next one int size = b.size(); while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) parseStatement(b, null); b.set(size - 1, new Integer(1 + b.size() - size)); @@ -492,7 +558,7 @@ class Parser extends Lexer implements ByteCodes { while(peekToken() != CASE && peekToken() != DEFAULT && peekToken() != RC) parseStatement(b, null); } else if (peekToken() == RC) { consume(RC); - b.add(line, BREAK); // break out of the loop if we 'fall through' + b.add(parserLine, BREAK); // break out of the loop if we 'fall through' break; } else { throw new ParserException("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]); @@ -502,16 +568,16 @@ class Parser extends Lexer implements ByteCodes { } case DO: { - if (label != null) b.add(line, LABEL, label); - b.add(line, LOOP); + if (label != null) b.add(parserLine, LABEL, label); + b.add(parserLine, LOOP); int size = b.size(); parseStatement(b, null); consume(WHILE); consume(LP); startExpr(b, -1); - b.add(line, JT, new Integer(2)); // check the while() clause; jump over the BREAK if true - b.add(line, BREAK); - b.add(line, CONTINUE); + b.add(parserLine, JT, new Integer(2)); // check the while() clause; jump over the BREAK if true + b.add(parserLine, BREAK); + b.add(parserLine, CONTINUE); consume(RP); consume(SEMI); b.set(size - 1, new Integer(b.size() - size + 1)); // end of the loop; write this location to the LOOP instruction @@ -519,27 +585,26 @@ class Parser extends Lexer implements ByteCodes { } case TRY: { - b.add(line, TRY); + b.add(parserLine, TRY); int size = b.size(); - parseStatement(b, null); // parse the expression to be TRYed - b.add(line, POP); // pop the TryMarker - b.add(line, JMP); // jump forward to the end of the catch block + parseStatement(b, null); // parse the expression to be TRYed + b.add(parserLine, POP); // pop the TryMarker + b.add(parserLine, JMP); // jump forward to the end of the catch block int size2 = b.size(); - b.set(size - 1, new Integer(b.size() - size + 1)); // the TRY argument points at the start of the CATCH block + b.set(size - 1, new Integer(b.size() - size + 1)); // the TRY argument points at the start of the CATCH block if (peekToken() == CATCH) { getToken(); consume(LP); consume(NAME); consume(RP); - // FIXME, we need an extra scope here - b.add(line, TOPSCOPE); // the exception is on top of the stack; put it to the chosen name - b.add(line, SWAP); - b.add(line, LITERAL); - b.add(line, SWAP); - b.add(line, PUT); - b.add(line, POP); - b.add(line, POP); + b.add(parserLine, TOPSCOPE); // the exception is on top of the stack; put it to the chosen name + b.add(parserLine, SWAP); + b.add(parserLine, LITERAL); + b.add(parserLine, SWAP); + b.add(parserLine, PUT); + b.add(parserLine, POP); + b.add(parserLine, POP); parseStatement(b, null); } @@ -558,77 +623,77 @@ class Parser extends Lexer implements ByteCodes { consume(LP); tok = getToken(); - boolean hadVar = false; // if it's a for..in, we ignore the VAR + boolean hadVar = false; // if it's a for..in, we ignore the VAR if (tok == VAR) { hadVar = true; tok = getToken(); } String varName = string; - boolean forIn = peekToken() == IN; // determine if this is a for..in loop or not + boolean forIn = peekToken() == IN; // determine if this is a for..in loop or not pushBackToken(tok, varName); if (forIn) { - b.add(line, NEWSCOPE); - b.add(line, LITERAL, varName); // declare the new variable - b.add(line, DECLARE); + b.add(parserLine, NEWSCOPE); // for-loops always create new scopes + b.add(parserLine, LITERAL, varName); // declare the new variable + b.add(parserLine, DECLARE); - b.add(line, LOOP); // we actually only add this to ensure that BREAK works - b.add(line, POP); // discard the first-iteration indicator + b.add(parserLine, LOOP); // we actually only add this to ensure that BREAK works + b.add(parserLine, POP); // discard the first-iteration indicator int size = b.size(); consume(NAME); consume(IN); startExpr(b, -1); - b.add(line, PUSHKEYS); // push the keys as an array; check the length - b.add(line, LITERAL, "length"); - b.add(line, GET); + b.add(parserLine, PUSHKEYS); // push the keys as an array; check the length + b.add(parserLine, LITERAL, "length"); + b.add(parserLine, GET); consume(RP); - b.add(line, LITERAL, new Integer(1)); // decrement the length - b.add(line, SUB); - b.add(line, DUP); - b.add(line, LITERAL, new Integer(0)); // see if we've exhausted all the elements - b.add(line, LT); - b.add(line, JF, new Integer(2)); - b.add(line, BREAK); // if we have, then BREAK - b.add(line, GET_PRESERVE); // get the key out of the keys array - b.add(line, LITERAL, varName); - b.add(line, PUT); // write it to this[varName] - parseStatement(b, null); // do some stuff - b.add(line, CONTINUE); // continue if we fall out the bottom - - b.set(size - 1, new Integer(b.size() - size + 1)); // BREAK to here - b.add(line, OLDSCOPE); // restore the scope + b.add(parserLine, LITERAL, new Integer(1)); // decrement the length + b.add(parserLine, SUB); + b.add(parserLine, DUP); + b.add(parserLine, LITERAL, new Integer(0)); // see if we've exhausted all the elements + b.add(parserLine, LT); + b.add(parserLine, JF, new Integer(2)); + b.add(parserLine, BREAK); // if we have, then BREAK + b.add(parserLine, GET_PRESERVE); // get the key out of the keys array + b.add(parserLine, LITERAL, varName); + b.add(parserLine, PUT); // write it to this[varName] + parseStatement(b, null); // do some stuff + b.add(parserLine, CONTINUE); // continue if we fall out the bottom + + b.set(size - 1, new Integer(b.size() - size + 1)); // BREAK to here + b.add(parserLine, OLDSCOPE); // restore the scope } else { - if (hadVar) pushBackToken(VAR, null); // yeah, this actually matters - b.add(line, NEWSCOPE); // grab a fresh scope + if (hadVar) pushBackToken(VAR, null); // yeah, this actually matters + b.add(parserLine, NEWSCOPE); // grab a fresh scope - parseStatement(b, null); // initializer - CompiledFunction e2 = // we need to put the incrementor before the test - new CompiledFunction(sourceName, line, null); // so we save the test here + parseStatement(b, null); // initializer + CompiledFunction e2 = // we need to put the incrementor before the test + new CompiledFunction(sourceName, parserLine, null); // so we save the test here if (peekToken() != SEMI) startExpr(e2, -1); else - e2.add(line, b.LITERAL, Boolean.TRUE); // handle the for(foo;;foo) case + e2.add(parserLine, b.LITERAL, Boolean.TRUE); // handle the for(foo;;foo) case consume(SEMI); - if (label != null) b.add(line, LABEL, label); - b.add(line, LOOP); + if (label != null) b.add(parserLine, LABEL, label); + b.add(parserLine, LOOP); int size2 = b.size(); - b.add(line, JT, new Integer(0)); // if we're on the first iteration, jump over the incrementor + b.add(parserLine, JT, new Integer(0)); // if we're on the first iteration, jump over the incrementor int size = b.size(); - if (peekToken() != RP) { // do the increment thing + if (peekToken() != RP) { // do the increment thing startExpr(b, -1); - b.add(line, POP); + b.add(parserLine, POP); } b.set(size - 1, new Integer(b.size() - size + 1)); consume(RP); - b.paste(e2); // ok, *now* test if we're done yet - b.add(line, JT, new Integer(2)); // break out if we don't meet the test - b.add(line, BREAK); + b.paste(e2); // ok, *now* test if we're done yet + b.add(parserLine, JT, new Integer(2)); // break out if we don't meet the test + b.add(parserLine, BREAK); parseStatement(b, null); - b.add(line, CONTINUE); // if we fall out the bottom, CONTINUE - b.set(size2 - 1, new Integer(b.size() - size2 + 1)); // end of the loop + b.add(parserLine, CONTINUE); // if we fall out the bottom, CONTINUE + b.set(size2 - 1, new Integer(b.size() - size2 + 1)); // end of the loop - b.add(line, OLDSCOPE); // get our scope back + b.add(parserLine, OLDSCOPE); // get our scope back } break; } @@ -642,24 +707,26 @@ class Parser extends Lexer implements ByteCodes { } else { // expression pushBackToken(NAME, possiblyTheLabel); startExpr(b, -1); - b.add(line, POP); + b.add(parserLine, POP); if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI); break; } } - case SEMI: return; // yep, the null statement is valid + case SEMI: return; // yep, the null statement is valid case LC: { // blocks are statements too pushBackToken(); + b.add(parserLine, NEWSCOPE); parseBlock(b, label); + b.add(parserLine, OLDSCOPE); break; } default: { // hope that it's an expression pushBackToken(); startExpr(b, -1); - b.add(line, POP); + b.add(parserLine, POP); if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI); break; } @@ -669,7 +736,7 @@ class Parser extends Lexer implements ByteCodes { // ParserException ////////////////////////////////////////////////////////////////////// - private class ParserException extends IOException { public ParserException(String s) { super(sourceName + ":" + line + " " + s); } } + private class ParserException extends IOException { public ParserException(String s) { super(sourceName + ":" + parserLine + " " + s); } } } -- 1.7.10.4