From 091d00f1bd22f821d3926c46dd1d6cf7fbc746f4 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 14 Jul 2019 16:37:57 -0400 Subject: 1339395 - Part 2: Add parser support for rest and spread object properties. --- js/src/builtin/ReflectParse.cpp | 12 +++++++++++ js/src/frontend/BytecodeEmitter.cpp | 12 +++++++++++ js/src/frontend/FullParseHandler.h | 12 +++++++++++ js/src/frontend/Parser.cpp | 42 ++++++++++++++++++++++++++++++------ js/src/frontend/SyntaxParseHandler.h | 1 + 5 files changed, 73 insertions(+), 6 deletions(-) (limited to 'js') diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 3495ede2f..8e8bb2417 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3222,6 +3222,8 @@ ASTSerializer::property(ParseNode* pn, MutableHandleValue dst) return expression(pn->pn_kid, &val) && builder.prototypeMutation(val, &pn->pn_pos, dst); } + if (pn->isKind(PNK_SPREAD)) + return expression(pn, dst); PropKind kind; switch (pn->getOp()) { @@ -3342,6 +3344,16 @@ ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst) return false; for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) { + if (propdef->isKind(PNK_SPREAD)) { + RootedValue target(cx); + RootedValue spread(cx); + if (!pattern(propdef->pn_kid, &target)) + return false; + if(!builder.spreadExpression(target, &propdef->pn_pos, &spread)) + return false; + elts.infallibleAppend(spread); + continue; + } LOCAL_ASSERT(propdef->isKind(PNK_MUTATEPROTO) != propdef->isOp(JSOP_INITPROP)); RootedValue key(cx); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c2eae4344..f9a1f8675 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5815,6 +5815,11 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla return false; for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { + if (member->isKind(PNK_SPREAD)) { + // FIXME: Implement + continue; + } + ParseNode* subpattern; if (member->isKind(PNK_MUTATEPROTO)) subpattern = member->pn_kid; @@ -9449,6 +9454,13 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, continue; } + if (propdef->isKind(PNK_SPREAD)) { + MOZ_ASSERT(type == ObjectLiteral); + objp.set(nullptr); + // FIXME: implement + continue; + } + bool extraPop = false; if (type == ClassBody && propdef->as().isStatic()) { extraPop = true; diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index d34cdf43d..2d7f57e1e 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -395,6 +395,18 @@ class FullParseHandler return true; } + MOZ_MUST_USE bool addSpreadProperty(ParseNode* literal, uint32_t begin, ParseNode* inner) { + MOZ_ASSERT(literal->isKind(PNK_OBJECT)); + MOZ_ASSERT(literal->isArity(PN_LIST)); + + setListFlag(literal, PNX_NONCONST); + ParseNode* spread = newSpread(begin, inner); + if (!spread) + return false; + literal->append(spread); + return true; + } + MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn, JSOp op) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 585eef59d..47e0f943d 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4367,9 +4367,20 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y break; if (tt == TOK_TRIPLEDOT) { - // TODO: rest-binding property - error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); - return null(); + // rest-binding property + tokenStream.consumeKnownToken(TOK_TRIPLEDOT); + uint32_t begin = pos().begin; + + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + + Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!inner) + return null(); + + if (!handler.addSpreadProperty(literal, begin, inner)) + return null(); } else { TokenPos namePos = tokenStream.nextToken().pos; @@ -4439,6 +4450,10 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y return null(); if (!matched) break; + if (tt == TOK_TRIPLEDOT) { + error(JSMSG_REST_WITH_COMMA); + return null(); + } } MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, @@ -9693,9 +9708,22 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* break; if (tt == TOK_TRIPLEDOT) { - // TODO: object spread - error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); - return null(); + // object spread + tokenStream.consumeKnownToken(TOK_TRIPLEDOT); + uint32_t begin = pos().begin; + + TokenPos innerPos; + if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand)) + return null(); + + Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited, + possibleError); + if (!inner) + return null(); + if (possibleError) + checkDestructuringAssignmentTarget(inner, innerPos, possibleError); + if (!handler.addSpreadProperty(literal, begin, inner)) + return null(); } else { TokenPos namePos = tokenStream.nextToken().pos; @@ -9860,6 +9888,8 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); if (!matched) break; + if (tt == TOK_TRIPLEDOT && possibleError) + possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA); } MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 7de6a242e..a604b599f 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -298,6 +298,7 @@ class SyntaxParseHandler MOZ_MUST_USE bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } MOZ_MUST_USE bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } MOZ_MUST_USE bool addShorthand(Node literal, Node name, Node expr) { return true; } + MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; } MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } -- cgit v1.2.3