Bug 1339963 - Part 1: Split Parser::exportDeclaration. r=jwalden

This commit is contained in:
Tooru Fujisawa 2017-02-22 16:11:35 +09:00
Родитель 68a70f5550
Коммит 7248e52372
3 изменённых файлов: 525 добавлений и 250 удалений

Просмотреть файл

@ -4647,8 +4647,10 @@ Parser<ParseHandler>::declarationList(YieldHandling yieldHandling,
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node 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 * Parse body-level lets without a new block object. ES6 specs
* that an execution environment's initial lexical environment * that an execution environment's initial lexical environment
@ -4660,7 +4662,8 @@ Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isCon
* *
* See 8.1.1.1.6 and the note in 13.2.1. * 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()) if (!decl || !matchOrInsertSemicolonAfterExpression())
return null(); return null();
@ -4949,32 +4952,162 @@ Parser<SyntaxParseHandler>::checkExportedNamesForDeclaration(Node node)
} }
template<> template<>
ParseNode* bool
Parser<FullParseHandler>::exportDeclaration() Parser<FullParseHandler>::checkExportedNameForClause(ParseNode* node)
{ {
MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); return checkExportedName(node->pn_atom);
}
if (!pc->atModuleLevel()) { template<>
error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); 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(); return null();
}
uint32_t begin = pos().begin; MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FROM));
Node kid; if (!abortIfSyntaxParser())
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null(); return null();
switch (tt) {
case TOK_LC: { MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
kid = handler.newList(PNK_EXPORT_SPEC_LIST);
Node moduleSpec = stringLiteral();
if (!moduleSpec)
return null();
if (!matchOrInsertSemicolonAfterNonExpression())
return null();
Node node = handler.newExportFromDeclaration(begin, specList, moduleSpec);
if (!node)
return null();
if (!processExportFrom(node))
return null();
return node;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::exportBatch(uint32_t begin)
{
if (!abortIfSyntaxParser())
return null();
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_MUL));
Node kid = handler.newList(PNK_EXPORT_SPEC_LIST);
if (!kid) if (!kid)
return null(); 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();
handler.addList(kid, exportSpec);
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
if (tt != TOK_FROM) {
error(JSMSG_FROM_AFTER_EXPORT_STAR);
return null();
}
return exportFrom(begin, kid);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::exportClause(uint32_t begin)
{
if (!abortIfSyntaxParser())
return null();
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
Node kid = handler.newList(PNK_EXPORT_SPEC_LIST);
if (!kid)
return null();
TokenKind tt;
while (true) { while (true) {
// Handle the forms |export {}| and |export { ..., }| (where ... // Handle the forms |export {}| and |export { ..., }| (where ... is non
// is non empty), by escaping the loop early if the next token // empty), by escaping the loop early if the next token is }.
// is }.
if (!tokenStream.getToken(&tt)) if (!tokenStream.getToken(&tt))
return null(); return null();
@ -5000,7 +5133,7 @@ Parser<FullParseHandler>::exportDeclaration()
if (!exportName) if (!exportName)
return null(); return null();
if (!checkExportedName(exportName->pn_atom)) if (!checkExportedNameForClause(exportName))
return null(); return null();
Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName); Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName);
@ -5028,200 +5161,308 @@ Parser<FullParseHandler>::exportDeclaration()
// export { x } // export { x }
// from "foo"; // a single ExportDeclaration // from "foo"; // a single ExportDeclaration
// //
// But if it doesn't, we might have an ASI opportunity in Operand // But if it doesn't, we might have an ASI opportunity in Operand context:
// context:
// //
// export { x } // ExportDeclaration, terminated by ASI // export { x } // ExportDeclaration, terminated by ASI
// fro\u006D // ExpressionStatement, the name "from" // fro\u006D // ExpressionStatement, the name "from"
// //
// In that case let matchOrInsertSemicolonAfterNonExpression sort out // In that case let matchOrInsertSemicolonAfterNonExpression sort out ASI
// ASI or any necessary error. // or any necessary error.
bool matched; bool matched;
if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand)) if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand))
return null(); return null();
if (matched) { if (matched)
MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); return exportFrom(begin, kid);
Node moduleSpec = stringLiteral();
if (!moduleSpec)
return null();
if (!matchOrInsertSemicolonAfterNonExpression()) if (!matchOrInsertSemicolonAfterNonExpression())
return null(); return null();
ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node)) if (!node)
return null();
if (!processExport(node))
return null(); return null();
return node; return node;
} }
if (!matchOrInsertSemicolonAfterNonExpression()) template <typename ParseHandler>
return null(); typename ParseHandler::Node
break; Parser<ParseHandler>::exportVariableStatement(uint32_t begin)
} {
if (!abortIfSyntaxParser())
case TOK_MUL: {
kid = handler.newList(PNK_EXPORT_SPEC_LIST);
if (!kid)
return null(); return null();
// Handle the form |export *| by adding a special export batch MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_VAR));
// specifier to the list.
Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos());
if (!exportSpec)
return null();
handler.addList(kid, exportSpec); Node kid = declarationList(YieldIsName, PNK_VAR);
if (!tokenStream.getToken(&tt))
return null();
if (tt != TOK_FROM) {
error(JSMSG_FROM_AFTER_EXPORT_STAR);
return null();
}
MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
Node moduleSpec = stringLiteral();
if (!moduleSpec)
return null();
if (!matchOrInsertSemicolonAfterNonExpression())
return null();
ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec);
if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node))
return null();
return node;
}
case TOK_FUNCTION:
kid = functionStmt(YieldIsKeyword, NameRequired);
if (!kid)
return null();
if (!checkExportedName(kid->pn_funbox->function()->explicitName()))
return null();
break;
case TOK_CLASS: {
kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired);
if (!kid)
return null();
const ClassNode& cls = kid->as<ClassNode>();
MOZ_ASSERT(cls.names());
if (!checkExportedName(cls.names()->innerBinding()->pn_atom))
return null();
break;
}
case TOK_VAR:
kid = declarationList(YieldIsName, PNK_VAR);
if (!kid) if (!kid)
return null(); return null();
if (!matchOrInsertSemicolonAfterExpression()) if (!matchOrInsertSemicolonAfterExpression())
return null(); return null();
if (!checkExportedNamesForDeclaration(kid)) if (!checkExportedNamesForDeclaration(kid))
return null(); return null();
break;
case TOK_DEFAULT: { 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(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(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)) if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null(); return null();
if (!checkExportedName(context->names().default_)) if (!checkExportedName(context->names().default_))
return null(); return null();
ParseNode* nameNode = nullptr;
switch (tt) { switch (tt) {
case TOK_FUNCTION: case TOK_FUNCTION:
kid = functionStmt(YieldIsKeyword, AllowDefaultName); return exportDefaultFunctionDeclaration(begin);
if (!kid)
return null(); case TOK_ASYNC: {
break;
case TOK_CLASS:
kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName);
if (!kid)
return null();
break;
default: {
if (tt == TOK_ASYNC) {
TokenKind nextSameLine = TOK_EOF; TokenKind nextSameLine = TOK_EOF;
if (!tokenStream.peekTokenSameLine(&nextSameLine)) if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null(); return null();
if (nextSameLine == TOK_FUNCTION) { if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(nextSameLine); tokenStream.consumeKnownToken(TOK_FUNCTION);
kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction); return exportDefaultFunctionDeclaration(begin, AsyncFunction);
if (!kid)
return null();
break;
}
} }
tokenStream.ungetToken(); tokenStream.ungetToken();
RootedPropertyName name(context, context->names().starDefaultStar); return exportDefaultAssignExpr(begin);
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;
}
} }
ParseNode* node = handler.newExportDefaultDeclaration(kid, nameNode, case TOK_CLASS:
TokenPos(begin, pos().end)); return exportDefaultClassDeclaration(begin);
if (!node || !pc->sc()->asModuleContext()->builder.processExport(node))
default:
tokenStream.ungetToken();
return exportDefaultAssignExpr(begin);
}
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::exportDeclaration()
{
if (!abortIfSyntaxParser())
return null(); return null();
return node; MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT);
if (!pc->atModuleLevel()) {
error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
return null();
} }
uint32_t begin = pos().begin;
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
switch (tt) {
case TOK_MUL:
return exportBatch(begin);
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: case TOK_CONST:
kid = lexicalDeclaration(YieldIsName, /* isConst = */ true); return exportLexicalDeclaration(begin, DeclarationKind::Const);
if (!kid)
return null();
if (!checkExportedNamesForDeclaration(kid))
return null();
break;
case TOK_LET: case TOK_LET:
kid = lexicalDeclaration(YieldIsName, /* isConst = */ false); return exportLexicalDeclaration(begin, DeclarationKind::Let);
if (!kid)
return null(); case TOK_DEFAULT:
if (!checkExportedNamesForDeclaration(kid)) return exportDefault(begin);
return null();
break;
default: default:
error(JSMSG_DECLARATION_AFTER_EXPORT); error(JSMSG_DECLARATION_AFTER_EXPORT);
return null(); 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> template <typename ParseHandler>
@ -7088,7 +7329,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
return null(); return null();
if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling)) if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling))
return lexicalDeclaration(yieldHandling, /* isConst = */ false); return lexicalDeclaration(yieldHandling, DeclarationKind::Let);
if (tt == TOK_ASYNC) { if (tt == TOK_ASYNC) {
TokenKind nextSameLine = TOK_EOF; TokenKind nextSameLine = TOK_EOF;
@ -7183,7 +7424,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
case TOK_CONST: case TOK_CONST:
// [In] is the default behavior, because for-loops specially parse // [In] is the default behavior, because for-loops specially parse
// their heads to handle |in| in this situation. // their heads to handle |in| in this situation.
return lexicalDeclaration(yieldHandling, /* isConst = */ true); return lexicalDeclaration(yieldHandling, DeclarationKind::Const);
// ImportDeclaration (only inside modules) // ImportDeclaration (only inside modules)
case TOK_IMPORT: case TOK_IMPORT:

Просмотреть файл

@ -1192,10 +1192,27 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
// continues a LexicalDeclaration. // continues a LexicalDeclaration.
bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling); bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling);
Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst); Node lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind);
Node importDeclaration(); Node importDeclaration();
bool processExport(Node node);
bool processExportFrom(Node node);
Node exportFrom(uint32_t begin, Node specList);
Node exportBatch(uint32_t begin);
Node exportClause(uint32_t begin);
Node exportFunctionDeclaration(uint32_t begin);
Node exportVariableStatement(uint32_t begin);
Node exportClassDeclaration(uint32_t begin);
Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind);
Node exportDefaultFunctionDeclaration(uint32_t begin,
FunctionAsyncKind asyncKind = SyncFunction);
Node exportDefaultClassDeclaration(uint32_t begin);
Node exportDefaultAssignExpr(uint32_t begin);
Node exportDefault(uint32_t begin);
Node exportDeclaration(); Node exportDeclaration();
Node expressionStatement(YieldHandling yieldHandling, Node expressionStatement(YieldHandling yieldHandling,
InvokedPrediction invoked = PredictUninvoked); InvokedPrediction invoked = PredictUninvoked);
@ -1324,6 +1341,9 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
bool namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet); bool namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet);
bool checkExportedName(JSAtom* exportName); bool checkExportedName(JSAtom* exportName);
bool checkExportedNamesForDeclaration(Node node); bool checkExportedNamesForDeclaration(Node node);
bool checkExportedNameForClause(Node node);
bool checkExportedNameForFunction(Node node);
bool checkExportedNameForClass(Node node);
enum ClassContext { ClassStatement, ClassExpression }; enum ClassContext { ClassStatement, ClassExpression };
Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, Node classDefinition(YieldHandling yieldHandling, ClassContext classContext,

Просмотреть файл

@ -241,6 +241,10 @@ class SyntaxParseHandler
return NodeUnparenthesizedUnary; return NodeUnparenthesizedUnary;
} }
Node newNullary(ParseNodeKind kind, JSOp op, const TokenPos& pos) {
return NodeGeneric;
}
Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) { Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) {
return NodeUnparenthesizedUnary; return NodeUnparenthesizedUnary;
} }
@ -308,6 +312,16 @@ class SyntaxParseHandler
MOZ_MUST_USE bool prependInitialYield(Node stmtList, Node gen) { return true; } MOZ_MUST_USE bool prependInitialYield(Node stmtList, Node gen) { return true; }
Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; } Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; }
Node newExportDeclaration(Node kid, const TokenPos& pos) {
return NodeGeneric;
}
Node newExportFromDeclaration(uint32_t begin, Node exportSpecSet, Node moduleSpec) {
return NodeGeneric;
}
Node newExportDefaultDeclaration(Node kid, Node maybeBinding, const TokenPos& pos) {
return NodeGeneric;
}
Node newSetThis(Node thisName, Node value) { return value; } Node newSetThis(Node thisName, Node value) { return value; }
Node newExprStatement(Node expr, uint32_t end) { Node newExprStatement(Node expr, uint32_t end) {