precedence[ASSIGN_MOD] = 1;
precedence[HOOK] = 2;
precedence[COMMA] = 3;
- precedence[OR] = precedence[AND] = 4;
+ precedence[OR] = precedence[AND] = precedence[BANG] = 4;
precedence[GT] = precedence[GE] = 5;
precedence[BITOR] = 6;
precedence[BITXOR] = 7;
precedence[BITAND] = 8;
precedence[EQ] = precedence[NE] = 9;
- precedence[LT] = precedence[LE] = 10;
+ precedence[LT] = precedence[LE] = precedence[TYPEOF] = 10;
precedence[SHEQ] = precedence[SHNE] = 11;
precedence[LSH] = precedence[RSH] = precedence[URSH] = 12;
precedence[ADD] = precedence[SUB] = 13;
/** gets a token and throws an exception if it is not <tt>code</tt> */
private void consume(int code) throws IOException {
- if (getToken() != code) throw new ParserException("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op]));
+ if (getToken() != code) throw pe("expected " + codeToString[code] + ", got " + (op == -1 ? "EOF" : codeToString[op]));
}
/**
CompiledFunctionImpl b = appendTo;
switch (tok) {
- case -1: throw new ParserException("expected expression");
+ case -1: throw pe("expected expression");
// all of these simply push values onto the stack
case NUMBER: b.add(parserLine, LITERAL, number); break;
if (peekToken() != RB)
while(true) { // iterate over the initialization values
int size = b.size();
+ b.add(parserLine, LITERAL, new Integer(i++)); // push the index in the array to place it into
if (peekToken() == COMMA || peekToken() == RB)
b.add(parserLine, LITERAL, null); // for stuff like [1,,2,]
else
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;
case INC: case DEC: { // prefix (not postfix)
startExpr(b, precedence[tok]);
if (b.get(b.size() - 1) != GET)
- throw new ParserException("prefixed increment/decrement can only be performed on a valid assignment target");
+ throw pe("prefixed increment/decrement can only be performed on a valid assignment target");
b.set(b.size() - 1, tok, new Boolean(true));
break;
}
if (peekToken() != RC)
while(true) {
if (peekToken() != NAME && peekToken() != STRING)
- throw new ParserException("expected NAME or STRING");
+ throw pe("expected NAME or STRING");
getToken();
b.add(parserLine, LITERAL, string); // grab the key
consume(COLON);
break;
}
- default: throw new ParserException("expected expression, found " + codeToString[tok] + ", which cannot start an expression");
+ default: throw pe("expected expression, found " + codeToString[tok] + ", which cannot start an expression");
}
// attempt to continue the expression
b.add(parserLine, POP);
break;
}
+ case LP: {
+ int n = parseArgs(b);
+ b.add(parserLine,CALLMETHOD,new Integer(n));
+ break;
+ }
default: {
pushBackToken();
b.add(parserLine, GET);
switch (tok) {
case LP: { // invocation (not grouping)
- int i = 0;
- while(peekToken() != RP) {
- i++;
- if (peekToken() != COMMA) {
- startExpr(b, -1);
- if (peekToken() == RP) break;
- }
- consume(COMMA);
- }
- consume(RP);
- b.add(parserLine, CALL, new Integer(i));
+ int n = parseArgs(b);
+ b.add(parserLine, CALL, new Integer(n));
break;
}
case BITOR: case BITXOR: case BITAND: case SHEQ: case SHNE: case LSH:
continueExpr(b, minPrecedence); // try to continue the expression
}
+ // parse a set of comma separated function arguments, assume LP has already been consumed
+ private int parseArgs(CompiledFunctionImpl b) throws IOException {
+ int i = 0;
+ while(peekToken() != RP) {
+ i++;
+ if (peekToken() != COMMA) {
+ startExpr(b, -1);
+ if (peekToken() == RP) break;
+ }
+ consume(COMMA);
+ }
+ consume(RP);
+ return i;
+ }
+
/** Parse a block of statements which must be surrounded by LC..RC. */
void parseBlock(CompiledFunctionImpl b) throws IOException { parseBlock(b, null); }
void parseBlock(CompiledFunctionImpl b, String label) throws IOException {
consume(COMMA);
}
b.add(parserLine, POP); // pop off the topscope
- if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI);
+ if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
break;
}
case IF: {
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()]);
+ throw pe("expected CASE, DEFAULT, or RC; got " + codeToString[peekToken()]);
}
b.set(size0 - 1, new Integer(b.size() - size0 + 1)); // end of the loop
break;
pushBackToken(NAME, possiblyTheLabel);
startExpr(b, -1);
b.add(parserLine, POP);
- if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI);
+ if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
break;
}
}
pushBackToken();
startExpr(b, -1);
b.add(parserLine, POP);
- if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1) consume(SEMI);
+ if ((mostRecentlyReadToken != RC || peekToken() == SEMI) && peekToken() != -1 && mostRecentlyReadToken != SEMI) consume(SEMI);
break;
}
}
// ParserException //////////////////////////////////////////////////////////////////////
-
- private class ParserException extends IOException { public ParserException(String s) { super(sourceName + ":" + parserLine + " " + s); } }
+ private IOException pe(String s) { return new IOException(sourceName + ":" + parserLine + " " + s); }
}