diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 8c019a8a7a4..8d6fbb7be16 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2688,7 +2688,7 @@ EmitDestructuringDecls(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, Parse if (pn->isKind(PNK_ARRAY)) { for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { - if (pn2->isKind(PNK_COMMA)) + if (pn2->isKind(PNK_ELISION)) continue; emitter = (pn2->isKind(PNK_NAME)) ? EmitDestructuringDecl @@ -2908,8 +2908,8 @@ EmitDestructuringOpsHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JS_ASSERT(bce->stackDepth >= stackDepth + 1); } - /* Nullary comma node makes a hole in the array destructurer. */ - if (pn3->isKind(PNK_COMMA) && pn3->isArity(PN_NULLARY)) { + /* Elision node makes a hole in the array destructurer. */ + if (pn3->isKind(PNK_ELISION)) { JS_ASSERT(pn->isKind(PNK_ARRAY)); JS_ASSERT(pn2 == pn3); if (Emit1(cx, bce, JSOP_POP) < 0) @@ -2984,7 +2984,7 @@ EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, } /* MaybeEmitGroupAssignment won't call us if rhs is holey. */ - JS_ASSERT(!(pn->isKind(PNK_COMMA) && pn->isArity(PN_NULLARY))); + JS_ASSERT(!pn->isKind(PNK_ELISION)); if (!EmitTree(cx, bce, pn)) return false; ++limit; @@ -3001,7 +3001,7 @@ EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, if (!EmitUnaliasedVarOp(cx, JSOP_GETLOCAL, slot, bce)) return false; - if (pn->isKind(PNK_COMMA) && pn->isArity(PN_NULLARY)) { + if (pn->isKind(PNK_ELISION)) { if (Emit1(cx, bce, JSOP_POP) < 0) return false; } else { @@ -5542,7 +5542,7 @@ EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (nspread && !EmitNumberOp(cx, 0, bce)) return false; for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { - if (pn2->isKind(PNK_COMMA) && pn2->isArity(PN_NULLARY)) { + if (pn2->isKind(PNK_ELISION)) { if (Emit1(cx, bce, JSOP_HOLE) < 0) return false; } else { diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index e44243a8758..d4f5c34b0e4 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -49,6 +49,10 @@ class FullParseHandler LazyScript * const lazyOuterFunction_; size_t lazyInnerFunctionIndex; + const TokenPos &pos() { + return tokenStream.currentToken().pos; + } + public: /* @@ -100,7 +104,7 @@ class FullParseHandler return dn; } ParseNode *newAtom(ParseNodeKind kind, JSAtom *atom, JSOp op = JSOP_NOP) { - ParseNode *pn = NullaryNode::create(kind, this); + ParseNode *pn = new_(kind, pos()); if (!pn) return NULL; pn->setOp(op); @@ -108,7 +112,7 @@ class FullParseHandler return pn; } ParseNode *newNumber(double value, DecimalPoint decimalPoint = NoDecimal) { - ParseNode *pn = NullaryNode::create(PNK_NUMBER, this); + ParseNode *pn = new_(PNK_NUMBER, pos()); if (!pn) return NULL; pn->initNumber(value, decimalPoint); @@ -130,8 +134,8 @@ class FullParseHandler return new_(cond, thenExpr, elseExpr); } - ParseNode *newNullary(ParseNodeKind kind) { - return NullaryNode::create(kind, this); + ParseNode *newElision() { + return new_(PNK_ELISION, pos()); } ParseNode *newUnary(ParseNodeKind kind, ParseNode *kid, JSOp op = JSOP_NOP) { diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index fe913db666d..600d48260b5 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -530,7 +530,7 @@ Parser::cloneLeftHandSide(ParseNode *opn) pn2 = handler.new_(PNK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target); } else if (opn2->isArity(PN_NULLARY)) { - JS_ASSERT(opn2->isKind(PNK_COMMA)); + JS_ASSERT(opn2->isKind(PNK_ELISION)); pn2 = cloneParseTree(opn2); } else { pn2 = cloneLeftHandSide(opn2); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 044074edd3f..474f4a2a048 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -75,6 +75,7 @@ class UpvarCookie F(DOT) \ F(ELEM) \ F(ARRAY) \ + F(ELISION) \ F(STATEMENTLIST) \ F(LABEL) \ F(OBJECT) \ @@ -359,7 +360,7 @@ enum ParseNodeKind * PNK_GENEXP list Exactly like PNK_CALL, used for the implicit call * in the desugaring of a generator-expression. * PNK_ARRAY list pn_head: list of pn_count array element exprs - * [,,] holes are represented by PNK_COMMA nodes + * [,,] holes are represented by PNK_ELISION nodes * pn_xflags: PN_ENDCOMMA if extra comma at end * PNK_OBJECT list pn_head: list of pn_count binary PNK_COLON nodes * PNK_COLON binary key-value pair in object initializer or @@ -728,11 +729,6 @@ struct ParseNode /* Return true if this node appears in a Directive Prologue. */ bool isDirectivePrologueMember() const { return pn_prologue; } -#ifdef JS_HAS_DESTRUCTURING - /* Return true if this represents a hole in an array literal. */ - bool isArrayHole() const { return isKind(PNK_COMMA) && isArity(PN_NULLARY); } -#endif - #ifdef JS_HAS_GENERATOR_EXPRS ParseNode *generatorExpr() const { JS_ASSERT(isKind(PNK_GENEXP)); @@ -822,6 +818,9 @@ struct ParseNode struct NullaryNode : public ParseNode { + NullaryNode(ParseNodeKind kind, const TokenPos &pos) + : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {} + static inline NullaryNode *create(ParseNodeKind kind, FullParseHandler *handler) { return (NullaryNode *) ParseNode::create(kind, PN_NULLARY, handler); } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fd717fea767..b18269558dd 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3088,8 +3088,7 @@ Parser::checkDestructuring(BindData *data, if (left->isKind(PNK_ARRAY)) { for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) { - /* Nullary comma is an elision; binary comma is an expression.*/ - if (!pn->isArrayHole()) { + if (!pn->isKind(PNK_ELISION)) { if (pn->isKind(PNK_ARRAY) || pn->isKind(PNK_OBJECT)) { ok = checkDestructuring(data, pn, false); } else { @@ -6618,9 +6617,8 @@ Parser::primaryExpr(TokenKind tt) break; if (tt == TOK_COMMA) { - /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ tokenStream.matchToken(TOK_COMMA); - pn2 = handler.newNullary(PNK_COMMA); + pn2 = handler.newElision(); if (!pn2) return null(); handler.setListFlag(pn, PNX_SPECIALARRAYINIT | PNX_NONCONST); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 7a237c0196e..3a6d17d5aff 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -71,7 +71,7 @@ class SyntaxParseHandler Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; } Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; } - Node newNullary(ParseNodeKind kind) { return NodeGeneric; } + Node newElision() { return NodeGeneric; } Node newUnary(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { if (kind == PNK_SEMI && kid == NodeString) diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 4798f73835e..43fed35235f 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -2516,7 +2516,7 @@ ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst) for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { JS_ASSERT(pn->pn_pos.encloses(next->pn_pos)); - if (next->isKind(PNK_COMMA) && next->pn_count == 0) { + if (next->isKind(PNK_ELISION)) { elts.infallibleAppend(NullValue()); } else { RootedValue expr(cx); @@ -2696,10 +2696,7 @@ ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValu return false; for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { - /* Comma expressions can't occur inside patterns, so no need to test pn_count. */ - JS_ASSERT_IF(next->isKind(PNK_COMMA), next->pn_count == 0); - - if (next->isKind(PNK_COMMA)) { + if (next->isKind(PNK_ELISION)) { elts.infallibleAppend(NullValue()); } else { RootedValue patt(cx);