Ignore:
Timestamp:
Aug 4, 2015, 2:26:49 PM (10 years ago)
Author:
Yusuke Suzuki
Message:

[ES6] Support Module Syntax
https://bugs.webkit.org/show_bug.cgi?id=147422

Reviewed by Saam Barati.

Source/JavaScriptCore:

This patch introduces ES6 Modules syntax parsing part.
In this patch, ASTBuilder just produces the corresponding nodes to the ES6 Modules syntax,
and this patch does not include the code generator part.

Modules require 2 phase parsing. In the first pass, we just analyze the dependent modules
and do not execute the body or construct the AST. And after analyzing all the dependent
modules, we will parse the dependent modules next.
After all analyzing part is done, we will start the second pass. In the second pass, we
will parse the module, produce the AST, and execute the body.
If we don't do so, we need to create all the ASTs in the module's dependent graph at first
because the given module can be executed after the all dependent modules are executed. It
means that we need to hold so many parser arenas. To avoid this, the first pass only extracts
the dependent modules' information.

In this patch, we don't add this analyzing part yet. This patch only implements the second pass.
This patch aims at just implementing the syntax parsing functionality correctly.
After this patch is landed, we will create the ModuleDependencyAnalyzer that inherits SyntaxChecker
to collect the dependent modules fast[1].

To test the parsing, we added the "checkModuleSyntax" function into jsc shell.
By using this, we can parse the given string as the module.

[1]: https://bugs.webkit.org/show_bug.cgi?id=147353

  • bytecompiler/NodesCodegen.cpp:

(JSC::ModuleProgramNode::emitBytecode):
(JSC::ImportDeclarationNode::emitBytecode):
(JSC::ExportAllDeclarationNode::emitBytecode):
(JSC::ExportDefaultDeclarationNode::emitBytecode):
(JSC::ExportLocalDeclarationNode::emitBytecode):
(JSC::ExportNamedDeclarationNode::emitBytecode):

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionCheckModuleSyntax):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createModuleSpecifier):
(JSC::ASTBuilder::createImportSpecifier):
(JSC::ASTBuilder::createImportSpecifierList):
(JSC::ASTBuilder::appendImportSpecifier):
(JSC::ASTBuilder::createImportDeclaration):
(JSC::ASTBuilder::createExportAllDeclaration):
(JSC::ASTBuilder::createExportDefaultDeclaration):
(JSC::ASTBuilder::createExportLocalDeclaration):
(JSC::ASTBuilder::createExportNamedDeclaration):
(JSC::ASTBuilder::createExportSpecifier):
(JSC::ASTBuilder::createExportSpecifierList):
(JSC::ASTBuilder::appendExportSpecifier):

  • parser/Keywords.table:
  • parser/NodeConstructors.h:

(JSC::ModuleSpecifierNode::ModuleSpecifierNode):
(JSC::ImportSpecifierNode::ImportSpecifierNode):
(JSC::ImportDeclarationNode::ImportDeclarationNode):
(JSC::ExportAllDeclarationNode::ExportAllDeclarationNode):
(JSC::ExportDefaultDeclarationNode::ExportDefaultDeclarationNode):
(JSC::ExportLocalDeclarationNode::ExportLocalDeclarationNode):
(JSC::ExportNamedDeclarationNode::ExportNamedDeclarationNode):
(JSC::ExportSpecifierNode::ExportSpecifierNode):

  • parser/Nodes.cpp:

(JSC::ModuleProgramNode::ModuleProgramNode):

  • parser/Nodes.h:

(JSC::ModuleProgramNode::startColumn):
(JSC::ModuleProgramNode::endColumn):
(JSC::ModuleSpecifierNode::moduleName):
(JSC::ImportSpecifierNode::importedName):
(JSC::ImportSpecifierNode::localName):
(JSC::ImportSpecifierListNode::specifiers):
(JSC::ImportSpecifierListNode::append):
(JSC::ImportDeclarationNode::specifierList):
(JSC::ImportDeclarationNode::moduleSpecifier):
(JSC::ExportAllDeclarationNode::moduleSpecifier):
(JSC::ExportDefaultDeclarationNode::declaration):
(JSC::ExportLocalDeclarationNode::declaration):
(JSC::ExportSpecifierNode::exportedName):
(JSC::ExportSpecifierNode::localName):
(JSC::ExportSpecifierListNode::specifiers):
(JSC::ExportSpecifierListNode::append):
(JSC::ExportNamedDeclarationNode::specifierList):
(JSC::ExportNamedDeclarationNode::moduleSpecifier):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseModuleSourceElements):
(JSC::Parser<LexerType>::parseVariableDeclaration):
(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::tryParseDestructuringPatternExpression):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::parseFormalParameters):
(JSC::Parser<LexerType>::parseFunctionParameters):
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClassDeclaration):
(JSC::Parser<LexerType>::parseModuleSpecifier):
(JSC::Parser<LexerType>::parseImportClauseItem):
(JSC::Parser<LexerType>::parseImportDeclaration):
(JSC::Parser<LexerType>::parseExportSpecifier):
(JSC::Parser<LexerType>::parseExportDeclaration):
(JSC::Parser<LexerType>::parseMemberExpression):

  • parser/Parser.h:

(JSC::isIdentifierOrKeyword):
(JSC::ModuleScopeData::create):
(JSC::ModuleScopeData::exportedBindings):
(JSC::ModuleScopeData::exportName):
(JSC::ModuleScopeData::exportBinding):
(JSC::Scope::Scope):
(JSC::Scope::setIsModule):
(JSC::Scope::moduleScopeData):
(JSC::Parser::matchContextualKeyword):
(JSC::Parser::matchIdentifierOrKeyword):
(JSC::Parser::isofToken): Deleted.

  • parser/ParserModes.h:
  • parser/ParserTokens.h:
  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createModuleSpecifier):
(JSC::SyntaxChecker::createImportSpecifier):
(JSC::SyntaxChecker::createImportSpecifierList):
(JSC::SyntaxChecker::appendImportSpecifier):
(JSC::SyntaxChecker::createImportDeclaration):
(JSC::SyntaxChecker::createExportAllDeclaration):
(JSC::SyntaxChecker::createExportDefaultDeclaration):
(JSC::SyntaxChecker::createExportLocalDeclaration):
(JSC::SyntaxChecker::createExportNamedDeclaration):
(JSC::SyntaxChecker::createExportSpecifier):
(JSC::SyntaxChecker::createExportSpecifierList):
(JSC::SyntaxChecker::appendExportSpecifier):

  • runtime/CommonIdentifiers.cpp:

(JSC::CommonIdentifiers::CommonIdentifiers):

  • runtime/CommonIdentifiers.h:
  • runtime/Completion.cpp:

(JSC::checkModuleSyntax):

  • runtime/Completion.h:
  • tests/stress/modules-syntax-error-with-names.js: Added.

(shouldThrow):

  • tests/stress/modules-syntax-error.js: Added.

(shouldThrow):
(checkModuleSyntaxError.checkModuleSyntaxError.checkModuleSyntaxError):

  • tests/stress/modules-syntax.js: Added.

(prototype.checkModuleSyntax):
(checkModuleSyntax):

  • tests/stress/tagged-templates-syntax.js:

LayoutTests:

'export' and 'import' are changed from FutureReservedWord to Keyword in ES6.
http://www.ecma-international.org/ecma-262/6.0/#sec-keywords
And restrict 'super' use under the Script / Module contexts.

  • js/dom/reserved-words-as-property-expected.txt:
  • sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.10-expected.txt:
  • sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt:
  • sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.27-expected.txt:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r187760 r187890  
    210210    , m_defaultConstructorKind(defaultConstructorKind)
    211211    , m_thisTDZMode(thisTDZMode)
     212    , m_codeType(codeType)
    212213{
    213214    m_lexer = std::make_unique<LexerType>(vm, builtinMode);
     
    221222    if (codeType == JSParserCodeType::Function)
    222223        scope->setIsFunction();
     224    if (codeType == JSParserCodeType::Module)
     225        scope->setIsModule();
    223226    if (strictMode == JSParserStrictMode::Strict)
    224227        scope->setStrictMode();
     
    268271        if (isArrowFunctionBodyExpression)
    269272            sourceElements = parseArrowFunctionSingleExpressionBodySourceElements(context);
     273#if ENABLE(ES6_MODULES)
     274        else if (m_codeType == JSParserCodeType::Module)
     275            sourceElements = parseModuleSourceElements(context);
     276#endif
    270277        else
    271278            sourceElements = parseSourceElements(context, CheckForStrictMode);
     
    404411    return sourceElements;
    405412}
     413
     414template <typename LexerType>
     415template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseModuleSourceElements(TreeBuilder& context)
     416{
     417    TreeSourceElements sourceElements = context.createSourceElements();
     418
     419    // FIXME: When some sort of ModuleAnalyzer TreeBuilder is landed,
     420    // this SyntaxChecker will be replaced with typedef under the TreeBuilder,
     421    // like TreeBuilder::ModuleStatementItemBuilder.
     422    // https://bugs.webkit.org/show_bug.cgi?id=147353
     423    SyntaxChecker moduleStatementItemBuilder(const_cast<VM*>(m_vm), m_lexer.get());
     424
     425    while (true) {
     426        if (match(IMPORT) || match(EXPORT)) {
     427            TreeStatement statement = 0;
     428            if (match(IMPORT))
     429                statement = parseImportDeclaration(context);
     430            else
     431                statement = parseExportDeclaration(context);
     432
     433            if (!statement)
     434                break;
     435            context.appendStatement(sourceElements, statement);
     436        } else {
     437            const Identifier* directive = 0;
     438            unsigned directiveLiteralLength = 0;
     439            if (!parseStatementListItem(moduleStatementItemBuilder, directive, &directiveLiteralLength))
     440                break;
     441        }
     442    }
     443
     444    propagateError();
     445
     446    for (const auto& uid : currentScope()->moduleScopeData().exportedBindings())
     447        semanticFailIfFalse(currentScope()->hasDeclaredVariable(uid) || currentScope()->hasLexicallyDeclaredVariable(uid), "Exported binding '", uid.get(), "' needs to refer to a top-level declared variable");
     448
     449    return sourceElements;
     450}
     451
    406452template <typename LexerType>
    407453template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementListItem(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
     
    452498
    453499template <typename LexerType>
    454 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVariableDeclaration(TreeBuilder& context, DeclarationType declarationType)
     500template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVariableDeclaration(TreeBuilder& context, DeclarationType declarationType, ExportType exportType)
    455501{
    456502    ASSERT(match(VAR) || match(LET) || match(CONSTTOKEN));
     
    463509    JSTextPosition scratch3;
    464510    bool scratchBool;
    465     TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType, scratchBool);
     511    TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType, exportType, scratchBool);
    466512    propagateError();
    467513    failIfFalse(autoSemiColon(), "Expected ';' after variable declaration");
     
    518564
    519565template <typename LexerType>
    520 template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext, DeclarationType declarationType, bool& forLoopConstDoesNotHaveInitializer)
     566template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext, DeclarationType declarationType, ExportType exportType, bool& forLoopConstDoesNotHaveInitializer)
    521567{
    522568    ASSERT(declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::VarDeclaration || declarationType == DeclarationType::ConstDeclaration);
     
    556602                }
    557603            }
     604            semanticFailIfTrue(exportType == ExportType::Exported && !currentScope()->moduleScopeData().exportName(*name), "Cannot export a duplicate name '", name->impl(), "'");
     605
    558606            if (hasInitializer) {
    559607                JSTextPosition varDivot = tokenStartPosition() + 1;
     
    577625        } else {
    578626            lastIdent = 0;
    579             auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), nullptr, nullptr, assignmentContext);
     627            auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), exportType, nullptr, nullptr, assignmentContext);
    580628            failIfFalse(pattern, "Cannot parse this destructuring pattern");
    581629            hasInitializer = match(EQUAL);
     
    605653
    606654template <typename LexerType>
    607 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
     655template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
    608656{
    609657    ASSERT(!name.isNull());
     
    657705        }
    658706    }
     707
     708    semanticFailIfTrue(exportType == ExportType::Exported && !currentScope()->moduleScopeData().exportName(name), "Cannot export a duplicate name '", name.impl(), "'");
    659709    return context.createBindingLocation(token.m_location, name, token.m_startPosition, token.m_endPosition, bindingContext);
    660710}
     
    692742template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context, AssignmentContext bindingContext)
    693743{
    694     return parseDestructuringPattern(context, DestructureToExpressions, nullptr, nullptr, bindingContext);
    695 }
    696 
    697 template <typename LexerType>
    698 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
     744    return parseDestructuringPattern(context, DestructureToExpressions, ExportType::NotExported, nullptr, nullptr, bindingContext);
     745}
     746
     747template <typename LexerType>
     748template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
    699749{
    700750    failIfStackOverflow();
     
    725775                JSTokenLocation location = m_token.m_location;
    726776                next();
    727                 auto innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     777                auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    728778                if (kind == DestructureToExpressions && !innerPattern)
    729779                    return 0;
     
    738788
    739789            JSTokenLocation location = m_token.m_location;
    740             auto innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     790            auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    741791            if (kind == DestructureToExpressions && !innerPattern)
    742792                return 0;
     
    775825                next();
    776826                if (consume(COLON))
    777                     innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     827                    innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    778828                else
    779                     innerPattern = createBindingPattern(context, kind, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
     829                    innerPattern = createBindingPattern(context, kind, exportType, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
    780830            } else {
    781831                JSTokenType tokenType = m_token.m_type;
     
    808858                    failWithMessage("Expected a ':' prior to a named destructuring property");
    809859                }
    810                 innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
     860                innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    811861            }
    812862            if (kind == DestructureToExpressions && !innerPattern)
     
    833883        }
    834884        failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
    835         pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext, duplicateIdentifier);
     885        pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, depth, m_token, bindingContext, duplicateIdentifier);
    836886        next();
    837887        break;
     
    914964        else
    915965            RELEASE_ASSERT_NOT_REACHED();
    916         decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, declarationType, forLoopConstDoesNotHaveInitializer);
     966        decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, declarationType, ExportType::NotExported, forLoopConstDoesNotHaveInitializer);
    917967        m_allowsIn = true;
    918968        propagateError();
     
    14581508    const Identifier* duplicateParameter = nullptr;
    14591509    bool hasDestructuringPattern = false;
    1460     auto parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter, &hasDestructuringPattern);
     1510    auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
    14611511    failIfFalse(parameter, "Cannot parse parameter pattern");
    14621512    auto defaultValue = parseDefaultValueForDestructuringPattern(context);
     
    14661516    parameterCount++;
    14671517    while (consume(COMMA)) {
    1468         parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter, &hasDestructuringPattern);
     1518        parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
    14691519        failIfFalse(parameter, "Cannot parse parameter pattern");
    14701520        defaultValue = parseDefaultValueForDestructuringPattern(context);
     
    15471597            } else {
    15481598                functionInfo.parameterCount = 1;
    1549                 auto parameter = parseDestructuringPattern(context, DestructureToParameters);
     1599                auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported);
    15501600                failIfFalse(parameter, "Cannot parse parameter pattern");
    15511601                context.appendParameter(parameterList, parameter, 0);
     
    15671617        failIfTrue(match(CLOSEPAREN), "setter functions must have one parameter");
    15681618        const Identifier* duplicateParameter = nullptr;
    1569         auto parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter);
     1619        auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter);
    15701620        failIfFalse(parameter, "setter functions must have one parameter");
    15711621        auto defaultValue = parseDefaultValueForDestructuringPattern(context);
     
    17961846
    17971847template <typename LexerType>
    1798 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context)
     1848template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType)
    17991849{
    18001850    ASSERT(match(FUNCTION));
     
    18071857    failIfFalse(functionInfo.name, "Function statements must have a name");
    18081858    failIfTrueIfStrict(declareVariable(functionInfo.name) & DeclarationResult::InvalidStrictMode, "Cannot declare a function named '", functionInfo.name->impl(), "' in strict mode");
     1859    semanticFailIfTrue(exportType == ExportType::Exported && !currentScope()->moduleScopeData().exportName(*functionInfo.name), "Cannot export a duplicate function name: '", functionInfo.name->impl(), "'");
    18091860    return context.createFuncDeclStatement(location, functionInfo);
    18101861}
     
    18121863#if ENABLE(ES6_CLASS_SYNTAX)
    18131864template <typename LexerType>
    1814 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseClassDeclaration(TreeBuilder& context)
     1865template <class TreeBuilder> TreeStatement Parser<LexerType>::parseClassDeclaration(TreeBuilder& context, ExportType exportType)
    18151866{
    18161867    ASSERT(match(CLASSTOKEN));
     
    18261877    if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
    18271878        internalFailWithMessage(false, "Cannot declare a class twice: '", info.className->impl(), "'");
     1879    semanticFailIfTrue(exportType == ExportType::Exported && !currentScope()->moduleScopeData().exportName(*info.className), "Cannot export a duplicate class name: '", info.className->impl(), "'");
    18281880
    18291881    JSTextPosition classEnd = lastTokenEndPosition();
     
    21472199
    21482200    return context.createIfStatement(ifLocation, condition, trueBlock, statementStack.last(), start, end);
     2201}
     2202
     2203template <typename LexerType>
     2204template <class TreeBuilder> typename TreeBuilder::ModuleSpecifier Parser<LexerType>::parseModuleSpecifier(TreeBuilder& context)
     2205{
     2206    // ModuleSpecifier represents the module name imported by the script.
     2207    // http://www.ecma-international.org/ecma-262/6.0/#sec-imports
     2208    // http://www.ecma-international.org/ecma-262/6.0/#sec-exports
     2209    JSTokenLocation specifierLocation(tokenLocation());
     2210    failIfFalse(match(STRING), "Imported modules names must be string literals");
     2211    const Identifier* moduleName = m_token.m_data.ident;
     2212    next();
     2213    return context.createModuleSpecifier(specifierLocation, *moduleName);
     2214}
     2215
     2216template <typename LexerType>
     2217template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerType>::parseImportClauseItem(TreeBuilder& context, ImportSpecifierType specifierType)
     2218{
     2219    // Produced node is the item of the ImportClause.
     2220    // That is the ImportSpecifier, ImportedDefaultBinding or NameSpaceImport.
     2221    // http://www.ecma-international.org/ecma-262/6.0/#sec-imports
     2222    JSTokenLocation specifierLocation(tokenLocation());
     2223    JSToken localNameToken;
     2224    const Identifier* importedName = nullptr;
     2225    const Identifier* localName = nullptr;
     2226
     2227    switch (specifierType) {
     2228    case ImportSpecifierType::NamespaceImport: {
     2229        // NameSpaceImport :
     2230        // * as ImportedBinding
     2231        // e.g.
     2232        //     * as namespace
     2233        ASSERT(match(TIMES));
     2234        importedName = &m_vm->propertyNames->timesIdentifier;
     2235        next();
     2236
     2237        failIfFalse(matchContextualKeyword(m_vm->propertyNames->as), "Expected 'as' before imported binding name");
     2238        next();
     2239
     2240        matchOrFail(IDENT, "Expected a variable name for the import declaration");
     2241        localNameToken = m_token;
     2242        localName = m_token.m_data.ident;
     2243        next();
     2244        break;
     2245    }
     2246
     2247    case ImportSpecifierType::NamedImport: {
     2248        // ImportSpecifier :
     2249        // ImportedBinding
     2250        // IdentifierName as ImportedBinding
     2251        // e.g.
     2252        //     A
     2253        //     A as B
     2254        ASSERT(matchIdentifierOrKeyword());
     2255        localNameToken = m_token;
     2256        localName = m_token.m_data.ident;
     2257        importedName = localName;
     2258        next();
     2259
     2260        if (matchContextualKeyword(m_vm->propertyNames->as)) {
     2261            next();
     2262            matchOrFail(IDENT, "Expected a variable name for the import declaration");
     2263            localNameToken = m_token;
     2264            localName = m_token.m_data.ident;
     2265            next();
     2266        }
     2267        break;
     2268    }
     2269
     2270    case ImportSpecifierType::DefaultImport: {
     2271        // ImportedDefaultBinding :
     2272        // ImportedBinding
     2273        ASSERT(match(IDENT));
     2274        localNameToken = m_token;
     2275        localName = m_token.m_data.ident;
     2276        importedName = &m_vm->propertyNames->defaultKeyword;
     2277        next();
     2278        break;
     2279    }
     2280    }
     2281
     2282    semanticFailIfTrue(localNameToken.m_type & KeywordTokenFlag, "Cannot use keyword as imported binding name");
     2283    DeclarationResultMask declarationResult = declareVariable(localName, DeclarationType::ConstDeclaration);
     2284    if (declarationResult != DeclarationResult::Valid) {
     2285        failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare an imported binding named ", localName->impl(), " in strict mode");
     2286        if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
     2287            internalFailWithMessage(false, "Cannot declare an imported binding name twice: '", localName->impl(), "'");
     2288    }
     2289
     2290    return context.createImportSpecifier(specifierLocation, *importedName, *localName);
     2291}
     2292
     2293template <typename LexerType>
     2294template <class TreeBuilder> TreeStatement Parser<LexerType>::parseImportDeclaration(TreeBuilder& context)
     2295{
     2296    // http://www.ecma-international.org/ecma-262/6.0/#sec-imports
     2297    ASSERT(match(IMPORT));
     2298    JSTokenLocation importLocation(tokenLocation());
     2299    next();
     2300
     2301    auto specifierList = context.createImportSpecifierList();
     2302
     2303    if (match(STRING)) {
     2304        // import ModuleSpecifier ;
     2305        auto moduleSpecifier = parseModuleSpecifier(context);
     2306        failIfFalse(moduleSpecifier, "Cannot parse the module name");
     2307        failIfFalse(autoSemiColon(), "Expected a ';' following a targeted import declaration");
     2308        return context.createImportDeclaration(importLocation, specifierList, moduleSpecifier);
     2309    }
     2310
     2311    bool isFinishedParsingImport = false;
     2312    if (match(IDENT)) {
     2313        // ImportedDefaultBinding :
     2314        // ImportedBinding
     2315        auto specifier = parseImportClauseItem(context, ImportSpecifierType::DefaultImport);
     2316        failIfFalse(specifier, "Cannot parse the default import");
     2317        context.appendImportSpecifier(specifierList, specifier);
     2318        if (match(COMMA))
     2319            next();
     2320        else
     2321            isFinishedParsingImport = true;
     2322    }
     2323
     2324    if (!isFinishedParsingImport) {
     2325        if (match(TIMES)) {
     2326            // import NameSpaceImport FromClause ;
     2327            auto specifier = parseImportClauseItem(context, ImportSpecifierType::NamespaceImport);
     2328            failIfFalse(specifier, "Cannot parse the namespace import");
     2329            context.appendImportSpecifier(specifierList, specifier);
     2330        } else if (match(OPENBRACE)) {
     2331            // NamedImports :
     2332            // { }
     2333            // { ImportsList }
     2334            // { ImportsList , }
     2335            next();
     2336
     2337            while (!match(CLOSEBRACE)) {
     2338                failIfFalse(matchIdentifierOrKeyword(), "Expected an imported name for the import declaration");
     2339                auto specifier = parseImportClauseItem(context, ImportSpecifierType::NamedImport);
     2340                failIfFalse(specifier, "Cannot parse the named import");
     2341                context.appendImportSpecifier(specifierList, specifier);
     2342                if (!consume(COMMA))
     2343                    break;
     2344            }
     2345            handleProductionOrFail(CLOSEBRACE, "}", "end", "import list");
     2346        } else
     2347            failWithMessage("Expected namespace import or import list");
     2348    }
     2349
     2350    // FromClause :
     2351    // from ModuleSpecifier
     2352
     2353    failIfFalse(matchContextualKeyword(m_vm->propertyNames->from), "Expected 'from' before imported module name");
     2354    next();
     2355
     2356    auto moduleSpecifier = parseModuleSpecifier(context);
     2357    failIfFalse(moduleSpecifier, "Cannot parse the module name");
     2358    failIfFalse(autoSemiColon(), "Expected a ';' following a targeted import declaration");
     2359
     2360    return context.createImportDeclaration(importLocation, specifierList, moduleSpecifier);
     2361}
     2362
     2363template <typename LexerType>
     2364template <class TreeBuilder> typename TreeBuilder::ExportSpecifier Parser<LexerType>::parseExportSpecifier(TreeBuilder& context, Vector<const Identifier*>& maybeLocalNames, bool& hasKeywordForLocalBindings)
     2365{
     2366    // ExportSpecifier :
     2367    // IdentifierName
     2368    // IdentifierName as IdentifierName
     2369    // http://www.ecma-international.org/ecma-262/6.0/#sec-exports
     2370    ASSERT(matchIdentifierOrKeyword());
     2371    JSTokenLocation specifierLocation(tokenLocation());
     2372    if (m_token.m_type & KeywordTokenFlag)
     2373        hasKeywordForLocalBindings = true;
     2374    const Identifier* localName = m_token.m_data.ident;
     2375    const Identifier* exportedName = localName;
     2376    next();
     2377
     2378    if (matchContextualKeyword(m_vm->propertyNames->as)) {
     2379        next();
     2380        failIfFalse(matchIdentifierOrKeyword(), "Expected an exported name for the export declaration");
     2381        exportedName = m_token.m_data.ident;
     2382        next();
     2383    }
     2384
     2385    semanticFailIfFalse(currentScope()->moduleScopeData().exportName(*exportedName), "Cannot export a duplicate name '", exportedName->impl(), "'");
     2386    maybeLocalNames.append(localName);
     2387    return context.createExportSpecifier(specifierLocation, *localName, *exportedName);
     2388}
     2389
     2390template <typename LexerType>
     2391template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclaration(TreeBuilder& context)
     2392{
     2393    // http://www.ecma-international.org/ecma-262/6.0/#sec-exports
     2394    ASSERT(match(EXPORT));
     2395    JSTokenLocation exportLocation(tokenLocation());
     2396    next();
     2397
     2398    switch (m_token.m_type) {
     2399    case TIMES: {
     2400        // export * FromClause ;
     2401        next();
     2402
     2403        failIfFalse(matchContextualKeyword(m_vm->propertyNames->from), "Expected 'from' before exported module name");
     2404        next();
     2405        auto moduleSpecifier = parseModuleSpecifier(context);
     2406        failIfFalse(moduleSpecifier, "Cannot parse the 'from' clause");
     2407        failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
     2408        return context.createExportAllDeclaration(exportLocation, moduleSpecifier);
     2409    }
     2410
     2411    case DEFAULT: {
     2412        // export default HoistableDeclaration[Default]
     2413        // export default ClassDeclaration[Default]
     2414        // export default [lookahead not-in {function, class}] AssignmentExpression[In] ;
     2415
     2416        next();
     2417
     2418        TreeStatement result = 0;
     2419        bool hasName = false;
     2420        bool isFunctionOrClassDeclaration = false;
     2421        SavePoint savePoint = createSavePoint();
     2422        if (match(FUNCTION)
     2423#if ENABLE(ES6_CLASS_SYNTAX)
     2424                || match(CLASSTOKEN)
     2425#endif
     2426                ) {
     2427            isFunctionOrClassDeclaration = true;
     2428            next();
     2429            // FIXME: When landing ES6 generators, we need to take care of that '*' comes.
     2430            hasName = match(IDENT);
     2431            restoreSavePoint(savePoint);
     2432        }
     2433
     2434        if (hasName) {
     2435            if (match(FUNCTION))
     2436                result = parseFunctionDeclaration(context);
     2437#if ENABLE(ES6_CLASS_SYNTAX)
     2438            else {
     2439                ASSERT(match(CLASSTOKEN));
     2440                result = parseClassDeclaration(context);
     2441            }
     2442#endif
     2443        } else {
     2444            JSTokenLocation location(tokenLocation());
     2445            JSTextPosition start = tokenStartPosition();
     2446            TreeExpression expression = parseAssignmentExpression(context);
     2447            failIfFalse(expression, "Cannot parse expression");
     2448            result = context.createExprStatement(location, expression, start, tokenEndPosition());
     2449            if (!isFunctionOrClassDeclaration)
     2450                failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
     2451        }
     2452        failIfFalse(result, "Cannot parse the declaration");
     2453        semanticFailIfFalse(currentScope()->moduleScopeData().exportName(m_vm->propertyNames->defaultKeyword), "Cannot export 'default' name twice.");
     2454
     2455        return context.createExportDefaultDeclaration(exportLocation, result);
     2456    }
     2457
     2458    case OPENBRACE: {
     2459        // export ExportClause FromClause ;
     2460        // export ExportClause ;
     2461        //
     2462        // ExportClause :
     2463        // { }
     2464        // { ExportsList }
     2465        // { ExportsList , }
     2466        //
     2467        // ExportsList :
     2468        // ExportSpecifier
     2469        // ExportsList , ExportSpecifier
     2470
     2471        next();
     2472
     2473        auto specifierList = context.createExportSpecifierList();
     2474        Vector<const Identifier*> maybeLocalNames;
     2475
     2476        bool hasKeywordForLocalBindings = false;
     2477        while (!match(CLOSEBRACE)) {
     2478            failIfFalse(matchIdentifierOrKeyword(), "Expected a variable name for the export declaration");
     2479            auto specifier = parseExportSpecifier(context, maybeLocalNames, hasKeywordForLocalBindings);
     2480            failIfFalse(specifier, "Cannot parse the named export");
     2481            context.appendExportSpecifier(specifierList, specifier);
     2482            if (!consume(COMMA))
     2483                break;
     2484        }
     2485        handleProductionOrFail(CLOSEBRACE, "}", "end", "export list");
     2486
     2487        typename TreeBuilder::ModuleSpecifier moduleSpecifier = 0;
     2488        if (matchContextualKeyword(m_vm->propertyNames->from)) {
     2489            next();
     2490            moduleSpecifier = parseModuleSpecifier(context);
     2491            failIfFalse(moduleSpecifier, "Cannot parse the 'from' clause");
     2492        }
     2493        failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
     2494
     2495        if (!moduleSpecifier) {
     2496            semanticFailIfTrue(hasKeywordForLocalBindings, "Cannot use keyword as exported variable name");
     2497            // Since this export declaration does not have module specifier part, it exports the local bindings.
     2498            // While the export declaration with module specifier does not have any effect on the current module's scope,
     2499            // the export named declaration without module specifier references the the local binding names.
     2500            // For example,
     2501            //   export { A, B, C as D } from "mod"
     2502            // does not have effect on the current module's scope. But,
     2503            //   export { A, B, C as D }
     2504            // will reference the current module's bindings.
     2505            for (const Identifier* localName : maybeLocalNames) {
     2506                currentScope()->useVariable(localName, m_vm->propertyNames->eval == *localName);
     2507                currentScope()->moduleScopeData().exportBinding(*localName);
     2508            }
     2509        }
     2510
     2511        return context.createExportNamedDeclaration(exportLocation, specifierList, moduleSpecifier);
     2512    }
     2513
     2514    default: {
     2515        // export VariableStatement
     2516        // export Declaration
     2517        TreeStatement result = 0;
     2518        switch (m_token.m_type) {
     2519        case VAR:
     2520            result = parseVariableDeclaration(context, DeclarationType::VarDeclaration, ExportType::Exported);
     2521            break;
     2522
     2523        case CONSTTOKEN:
     2524            result = parseVariableDeclaration(context, DeclarationType::ConstDeclaration, ExportType::Exported);
     2525            break;
     2526
     2527        case LET:
     2528            result = parseVariableDeclaration(context, DeclarationType::LetDeclaration, ExportType::Exported);
     2529            break;
     2530
     2531        case FUNCTION:
     2532            result = parseFunctionDeclaration(context, ExportType::Exported);
     2533            break;
     2534
     2535#if ENABLE(ES6_CLASS_SYNTAX)
     2536        case CLASSTOKEN:
     2537            result = parseClassDeclaration(context, ExportType::Exported);
     2538            break;
     2539#endif
     2540
     2541        default:
     2542            failWithMessage("Expected either a declaration or a variable statement");
     2543            break;
     2544        }
     2545        failIfFalse(result, "Cannot parse the declaration");
     2546        return context.createExportLocalDeclaration(exportLocation, result);
     2547    }
     2548    }
     2549
     2550    RELEASE_ASSERT_NOT_REACHED();
     2551    return 0;
    21492552}
    21502553
     
    29273330
    29283331    if (baseIsSuper) {
     3332        semanticFailIfFalse(currentScope()->isFunction(), "super is only valid inside functions");
    29293333        base = context.createSuperExpr(location);
    29303334        next();
Note: See TracChangeset for help on using the changeset viewer.