diff options
author | Gaming4JC <g4jc@hyperbola.info> | 2019-06-09 22:30:59 -0400 |
---|---|---|
committer | Gaming4JC <g4jc@hyperbola.info> | 2019-07-18 22:38:38 -0400 |
commit | 57a8b65fc0c4bd12149855d972aea05828e4d6e7 (patch) | |
tree | 0424a2beee269c32695ae81a38106405863e6cf6 /js/src/frontend/Parser.cpp | |
parent | f39640128068a3816a9bfc28d619f8fa8f161435 (diff) | |
download | UXP-57a8b65fc0c4bd12149855d972aea05828e4d6e7.tar UXP-57a8b65fc0c4bd12149855d972aea05828e4d6e7.tar.gz UXP-57a8b65fc0c4bd12149855d972aea05828e4d6e7.tar.lz UXP-57a8b65fc0c4bd12149855d972aea05828e4d6e7.tar.xz UXP-57a8b65fc0c4bd12149855d972aea05828e4d6e7.zip |
1339963 - Part 1: Split Parser::exportDeclaration.
Diffstat (limited to 'js/src/frontend/Parser.cpp')
-rw-r--r-- | js/src/frontend/Parser.cpp | 659 |
1 files changed, 450 insertions, 209 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fc4b0e965..16d4a377a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4692,8 +4692,10 @@ Parser<ParseHandler>::declarationList(YieldHandling yieldHandling, template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isConst) +Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind) { + MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let); + /* * Parse body-level lets without a new block object. ES6 specs * that an execution environment's initial lexical environment @@ -4705,7 +4707,8 @@ Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isCon * * See 8.1.1.1.6 and the note in 13.2.1. */ - Node decl = declarationList(yieldHandling, isConst ? PNK_CONST : PNK_LET); + Node decl = declarationList(yieldHandling, + kind == DeclarationKind::Const ? PNK_CONST : PNK_LET); if (!decl || !matchOrInsertSemicolonAfterExpression()) return null(); @@ -4994,279 +4997,517 @@ Parser<SyntaxParseHandler>::checkExportedNamesForDeclaration(Node node) } template<> -ParseNode* -Parser<FullParseHandler>::exportDeclaration() +bool +Parser<FullParseHandler>::checkExportedNameForClause(ParseNode* node) { - MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); + return checkExportedName(node->pn_atom); +} - if (!pc->atModuleLevel()) { - error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); +template<> +bool +Parser<SyntaxParseHandler>::checkExportedNameForClause(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::checkExportedNameForFunction(ParseNode* node) +{ + return checkExportedName(node->pn_funbox->function()->explicitName()); +} + +template<> +bool +Parser<SyntaxParseHandler>::checkExportedNameForFunction(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::checkExportedNameForClass(ParseNode* node) +{ + const ClassNode& cls = node->as<ClassNode>(); + MOZ_ASSERT(cls.names()); + return checkExportedName(cls.names()->innerBinding()->pn_atom); +} + +template<> +bool +Parser<SyntaxParseHandler>::checkExportedNameForClass(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::processExport(ParseNode* node) +{ + return pc->sc()->asModuleContext()->builder.processExport(node); +} + +template<> +bool +Parser<SyntaxParseHandler>::processExport(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::processExportFrom(ParseNode* node) +{ + return pc->sc()->asModuleContext()->builder.processExportFrom(node); +} + +template<> +bool +Parser<SyntaxParseHandler>::processExportFrom(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportFrom(uint32_t begin, Node specList) +{ + if (!abortIfSyntaxParser()) return null(); - } - uint32_t begin = pos().begin; + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FROM)); - Node kid; - TokenKind tt; - if (!tokenStream.getToken(&tt)) + if (!abortIfSyntaxParser()) return null(); - switch (tt) { - case TOK_LC: { - kid = handler.newList(PNK_EXPORT_SPEC_LIST); - if (!kid) - return null(); - while (true) { - // Handle the forms |export {}| and |export { ..., }| (where ... - // is non empty), by escaping the loop early if the next token - // is }. - if (!tokenStream.getToken(&tt)) - return null(); + MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); - if (tt == TOK_RC) - break; + Node moduleSpec = stringLiteral(); + if (!moduleSpec) + return null(); - if (!TokenKindIsPossibleIdentifierName(tt)) { - error(JSMSG_NO_BINDING_NAME); - return null(); - } + if (!matchOrInsertSemicolonAfterNonExpression()) + return null(); - Node bindingName = newName(tokenStream.currentName()); - if (!bindingName) - return null(); + Node node = handler.newExportFromDeclaration(begin, specList, moduleSpec); + if (!node) + return null(); - bool foundAs; - if (!tokenStream.matchToken(&foundAs, TOK_AS)) - return null(); - if (foundAs) - MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME); + if (!processExportFrom(node)) + return null(); - Node exportName = newName(tokenStream.currentName()); - if (!exportName) - return null(); + return node; +} - if (!checkExportedName(exportName->pn_atom)) - return null(); +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportBatch(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); - Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName); - if (!exportSpec) - return null(); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_MUL)); - handler.addList(kid, exportSpec); + Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + if (!kid) + return null(); - TokenKind next; - if (!tokenStream.getToken(&next)) - return null(); + // Handle the form |export *| by adding a special export batch + // specifier to the list. + Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos()); + if (!exportSpec) + return null(); - if (next == TOK_RC) - break; + handler.addList(kid, exportSpec); - if (next != TOK_COMMA) { - error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST); - return null(); - } - } + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + if (tt != TOK_FROM) { + error(JSMSG_FROM_AFTER_EXPORT_STAR); + return null(); + } - // Careful! If |from| follows, even on a new line, it must start a - // FromClause: - // - // export { x } - // from "foo"; // a single ExportDeclaration - // - // But if it doesn't, we might have an ASI opportunity in Operand - // context: - // - // export { x } // ExportDeclaration, terminated by ASI - // fro\u006D // ExpressionStatement, the name "from" - // - // In that case let matchOrInsertSemicolonAfterNonExpression sort out - // ASI or any necessary error. - bool matched; - if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand)) - return null(); + return exportFrom(begin, kid); +} - if (matched) { - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportClause(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); - Node moduleSpec = stringLiteral(); - if (!moduleSpec) - return null(); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); - if (!matchOrInsertSemicolonAfterNonExpression()) - return null(); + Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + if (!kid) + return null(); - ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); - if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node)) - return null(); + TokenKind tt; + while (true) { + // Handle the forms |export {}| and |export { ..., }| (where ... is non + // empty), by escaping the loop early if the next token is }. + if (!tokenStream.getToken(&tt)) + return null(); + + if (tt == TOK_RC) + break; - return node; + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_NO_BINDING_NAME); + return null(); } - if (!matchOrInsertSemicolonAfterNonExpression()) + Node bindingName = newName(tokenStream.currentName()); + if (!bindingName) return null(); - break; - } - case TOK_MUL: { - kid = handler.newList(PNK_EXPORT_SPEC_LIST); - if (!kid) + bool foundAs; + if (!tokenStream.matchToken(&foundAs, TOK_AS)) + return null(); + if (foundAs) + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME); + + Node exportName = newName(tokenStream.currentName()); + if (!exportName) return null(); - // Handle the form |export *| by adding a special export batch - // specifier to the list. - Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos()); + if (!checkExportedNameForClause(exportName)) + return null(); + + Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName); if (!exportSpec) return null(); handler.addList(kid, exportSpec); - if (!tokenStream.getToken(&tt)) + TokenKind next; + if (!tokenStream.getToken(&next)) return null(); - if (tt != TOK_FROM) { - error(JSMSG_FROM_AFTER_EXPORT_STAR); + + if (next == TOK_RC) + break; + + if (next != TOK_COMMA) { + error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST); return null(); } + } - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); + // Careful! If |from| follows, even on a new line, it must start a + // FromClause: + // + // export { x } + // from "foo"; // a single ExportDeclaration + // + // But if it doesn't, we might have an ASI opportunity in Operand context: + // + // export { x } // ExportDeclaration, terminated by ASI + // fro\u006D // ExpressionStatement, the name "from" + // + // In that case let matchOrInsertSemicolonAfterNonExpression sort out ASI + // or any necessary error. + bool matched; + if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand)) + return null(); - Node moduleSpec = stringLiteral(); - if (!moduleSpec) - return null(); + if (matched) + return exportFrom(begin, kid); - if (!matchOrInsertSemicolonAfterNonExpression()) - return null(); + if (!matchOrInsertSemicolonAfterNonExpression()) + return null(); - ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); - if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node)) - return null(); + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); - return node; + if (!processExport(node)) + return null(); - } + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportVariableStatement(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_VAR)); + + Node kid = declarationList(YieldIsName, PNK_VAR); + if (!kid) + return null(); + if (!matchOrInsertSemicolonAfterExpression()) + return null(); + if (!checkExportedNamesForDeclaration(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); + + Node kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); + if (!kid) + return null(); + + if (!checkExportedNameForFunction(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportClassDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + + Node kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired); + if (!kid) + return null(); + + if (!checkExportedNameForClass(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportLexicalDeclaration(uint32_t begin, DeclarationKind kind) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let); + MOZ_ASSERT_IF(kind == DeclarationKind::Const, tokenStream.isCurrentTokenType(TOK_CONST)); + MOZ_ASSERT_IF(kind == DeclarationKind::Let, tokenStream.isCurrentTokenType(TOK_LET)); + + Node kid = lexicalDeclaration(YieldIsName, kind); + if (!kid) + return null(); + if (!checkExportedNamesForDeclaration(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin, + FunctionAsyncKind asyncKind + /* = SyncFunction */) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); + + Node kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName, asyncKind); + if (!kid) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefaultClassDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + + Node kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName); + if (!kid) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefaultAssignExpr(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + RootedPropertyName name(context, context->names().starDefaultStar); + Node nameNode = newName(name); + if (!nameNode) + return null(); + if (!noteDeclaredName(name, DeclarationKind::Const, pos())) + return null(); + + Node kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited); + if (!kid) + return null(); + if (!matchOrInsertSemicolonAfterExpression()) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, nameNode, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefault(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_DEFAULT)); + + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + if (!checkExportedName(context->names().default_)) + return null(); + switch (tt) { case TOK_FUNCTION: - kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); - if (!kid) - return null(); + return exportDefaultFunctionDeclaration(begin); - if (!checkExportedName(kid->pn_funbox->function()->explicitName())) + case TOK_ASYNC: { + TokenKind nextSameLine = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); - break; - case TOK_CLASS: { - kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired); - if (!kid) - return null(); + if (nextSameLine == TOK_FUNCTION) { + tokenStream.consumeKnownToken(TOK_FUNCTION); + return exportDefaultFunctionDeclaration(begin, AsyncFunction); + } - const ClassNode& cls = kid->as<ClassNode>(); - MOZ_ASSERT(cls.names()); - if (!checkExportedName(cls.names()->innerBinding()->pn_atom)) - return null(); - break; + tokenStream.ungetToken(); + return exportDefaultAssignExpr(begin); } - case TOK_VAR: - kid = declarationList(YieldIsName, PNK_VAR); - if (!kid) - return null(); - if (!matchOrInsertSemicolonAfterExpression()) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + case TOK_CLASS: + return exportDefaultClassDeclaration(begin); - case TOK_DEFAULT: { - if (!tokenStream.getToken(&tt, TokenStream::Operand)) - return null(); + default: + tokenStream.ungetToken(); + return exportDefaultAssignExpr(begin); + } +} - if (!checkExportedName(context->names().default_)) - return null(); +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDeclaration() +{ + if (!abortIfSyntaxParser()) + return null(); - ParseNode* nameNode = nullptr; - switch (tt) { - case TOK_FUNCTION: - kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName); - if (!kid) - return null(); - break; - case TOK_CLASS: - kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName); - if (!kid) - return null(); - break; - default: { - if (tt == TOK_ASYNC) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); + MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); - if (nextSameLine == TOK_FUNCTION) { - tokenStream.consumeKnownToken(nextSameLine); - kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction); - if (!kid) - return null(); - break; - } - } + if (!pc->atModuleLevel()) { + error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + return null(); + } - tokenStream.ungetToken(); - RootedPropertyName name(context, context->names().starDefaultStar); - nameNode = newName(name); - if (!nameNode) - return null(); - if (!noteDeclaredName(name, DeclarationKind::Const, pos())) - return null(); - kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited); - if (!kid) - return null(); - if (!matchOrInsertSemicolonAfterExpression()) - return null(); - break; - } - } + uint32_t begin = pos().begin; - ParseNode* node = handler.newExportDefaultDeclaration(kid, nameNode, - TokenPos(begin, pos().end)); - if (!node || !pc->sc()->asModuleContext()->builder.processExport(node)) - return null(); + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + switch (tt) { + case TOK_MUL: + return exportBatch(begin); - return node; - } + case TOK_LC: + return exportClause(begin); + + case TOK_VAR: + return exportVariableStatement(begin); + + case TOK_FUNCTION: + return exportFunctionDeclaration(begin); + + case TOK_CLASS: + return exportClassDeclaration(begin); case TOK_CONST: - kid = lexicalDeclaration(YieldIsName, /* isConst = */ true); - if (!kid) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + return exportLexicalDeclaration(begin, DeclarationKind::Const); case TOK_LET: - kid = lexicalDeclaration(YieldIsName, /* isConst = */ false); - if (!kid) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + return exportLexicalDeclaration(begin, DeclarationKind::Let); + + case TOK_DEFAULT: + return exportDefault(begin); default: error(JSMSG_DECLARATION_AFTER_EXPORT); return null(); } - - ParseNode* node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); - if (!node || !pc->sc()->asModuleContext()->builder.processExport(node)) - return null(); - - return node; -} - -template<> -SyntaxParseHandler::Node -Parser<SyntaxParseHandler>::exportDeclaration() -{ - JS_ALWAYS_FALSE(abortIfSyntaxParser()); - return SyntaxParseHandler::NodeFailure; } template <typename ParseHandler> @@ -7132,7 +7373,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling, return null(); if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling)) - return lexicalDeclaration(yieldHandling, /* isConst = */ false); + return lexicalDeclaration(yieldHandling, DeclarationKind::Let); if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; @@ -7228,7 +7469,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling, case TOK_CONST: // [In] is the default behavior, because for-loops specially parse // their heads to handle |in| in this situation. - return lexicalDeclaration(yieldHandling, /* isConst = */ true); + return lexicalDeclaration(yieldHandling, DeclarationKind::Const); // ImportDeclaration (only inside modules) case TOK_IMPORT: |