+
+ if (minPrecedence != 0 && tok < precedence.length && precedence[tok] != 0 && precedence[tok] < minPrecedence)
+ return null;
+
+ // these case arms match the precedence of operators; each arm is a precedence level.
+ switch (tok) {
+
+ case COMMA: case ASSIGN: case GT: case GE: case OR: case AND:
+ case BITOR: case BITXOR: case BITAND: case EQ: case NE: case LT:
+ case LE: case SHEQ: case SHNE: case LSH: case RSH: case URSH:
+ case ADD: case SUB: case MUL: case DIV: case MOD:
+ return new Expr(tok, prefix, parseExpr(null, precedence[tok]));
+
+ case BITNOT: case INSTANCEOF:
+ return new Expr(tok, parseExpr(null, precedence[tok]));
+
+ // FIXME: this isn't 100% right
+ case INC: case DEC:
+ return new Expr(tok, prefix, (tok == INC || tok == DEC) ? null : parseExpr());
+
+ case LP:
+ while(peekToken() != RP) {
+ if (head == null) head = tail = parseExpr(); else tail = tail.next = parseExpr();
+ tok = getToken();
+ if (tok == RP) break;
+ if (tok != COMMA) throw new Error("expected comma or right paren");
+ }
+ return new Expr(LP, prefix, head);
+
+ case LB:
+ if (prefix != null) {
+ // subscripting
+ e1 = parseExpr();
+ if (getToken() != RB) throw new Error("expected a right brace");
+ return new Expr(LB, prefix, e1);
+ } else {
+ // array ctor
+ tok = getToken();
+ while(true) {
+ if (tok == RB) return new Expr(LB, prefix, head);
+ if (head == null) head = tail = parseExpr(); else tail = tail.next = parseExpr();
+ tok = getToken();
+ if (tok != COMMA && tok != RP) throw new Error("expected right bracket or comma");
+ }
+ }
+
+ case LC:
+ if (prefix != null) throw new Error("didn't expect non-null prefix");
+ tok = getToken();
+ while(true) {
+ if (tok == RP) return new Expr(LC, head);
+ if (tok != NAME) throw new Error("expecting name");
+ Expr name = parseExpr();
+ if (tok != COLON) throw new Error("expecting colon");
+ e1 = new Expr(COLON, name, parseExpr());
+ if (head == null) head = tail = e1; else tail = tail.next = e1;
+ tok = getToken();
+ if (tok != COMMA && tok != RP) throw new Error("expected right curly or comma");
+ }
+
+ case HOOK:
+ e2 = parseExpr();
+ if (getToken() != COLON) throw new Error("expected colon to close ?: expression");
+ e3 = parseExpr();
+ return new Expr(HOOK, prefix, e2, e3);