Ignore:
Timestamp:
Jul 24, 2015, 11:40:58 AM (10 years ago)
Author:
[email protected]
Message:

[ES6] Add support for default parameters
https://bugs.webkit.org/show_bug.cgi?id=38409

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch implements ES6 default parameters according to the ES6
specification. This patch builds off the components introduced with
"let" scoping and parsing function parameters in the same parser
arena as the function itself. "let" scoping allows functions with default
parameter values to place their parameters under the TDZ. Parsing function
parameters in the same parser arena allows the FunctionParameters AST node
refer to ExpressionNodes.

The most subtle part of this patch is how we allocate lexical environments
when functions have default parameter values. If a function has default
parameter values then there must be a separate lexical environment for
its parameters. Then, the function's "var" lexical environment must have
the parameter lexical environment as its parent. The BytecodeGenerator
takes great care to not allocate the "var" lexical environment before its
really needed.

The "arguments" object for a function with default parameters will never be
a mapped arugments object. It will always be a cloned arugments object.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::~BytecodeGenerator):
(JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
(JSC::BytecodeGenerator::initializeNextParameter):
(JSC::BytecodeGenerator::initializeVarLexicalEnvironment):
(JSC::BytecodeGenerator::visibleNameForParameter):
(JSC::BytecodeGenerator::emitLoadGlobalObject):
(JSC::BytecodeGenerator::pushLexicalScopeInternal):
(JSC::BytecodeGenerator::pushLexicalScope):
(JSC::BytecodeGenerator::popLexicalScope):

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::lastOpcodeID):

  • bytecompiler/NodesCodegen.cpp:

(JSC::FunctionNode::emitBytecode):

  • jit/JITOperations.cpp:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createElementList):
(JSC::ASTBuilder::createFormalParameterList):
(JSC::ASTBuilder::appendParameter):
(JSC::ASTBuilder::createClause):
(JSC::ASTBuilder::createClauseList):

  • parser/Nodes.h:

(JSC::FunctionParameters::size):
(JSC::FunctionParameters::at):
(JSC::FunctionParameters::hasDefaultParameterValues):
(JSC::FunctionParameters::append):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::tryParseDestructuringPatternExpression):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseFormalParameters):
(JSC::Parser<LexerType>::parseFunctionParameters):

  • parser/Parser.h:

(JSC::Scope::declareParameter):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createElementList):
(JSC::SyntaxChecker::createFormalParameterList):
(JSC::SyntaxChecker::appendParameter):
(JSC::SyntaxChecker::createClause):
(JSC::SyntaxChecker::createClauseList):

  • tests/stress/es6-default-parameters.js: Added.

(assert):
(shouldThrow):
(shouldThrowSyntaxError):
(shouldThrowTDZ):
(basic):
(basicFunctionCaptureInDefault.basicFunctionCaptureInDefault.basicCaptured):
(basicCaptured.basicCaptured.tricky):
(strict):
(playground):
(scoping):
(augmentsArguments1):
(augmentsArguments2):
(augmentsArguments3):
(augmentsArguments4):
(augmentsArguments5):

LayoutTests:

  • js/destructuring-assignment-default-values-expected.txt:
  • js/parser-syntax-check-expected.txt:
  • js/script-tests/destructuring-assignment-default-values.js:

(shouldThrow): Deleted.

  • js/script-tests/parser-syntax-check.js:
File:
1 edited

Legend:

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

    r187205 r187351  
    577577        } else {
    578578            lastIdent = 0;
    579             auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), assignmentContext);
     579            auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), nullptr, nullptr, assignmentContext);
    580580            failIfFalse(pattern, "Cannot parse this destructuring pattern");
    581581            hasInitializer = match(EQUAL);
     
    605605
    606606template <typename LexerType>
    607 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext)
     607template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
    608608{
    609609    ASSERT(!name.isNull());
    610610   
    611611    ASSERT(name.impl()->isAtomic() || name.impl()->isSymbol());
    612     if (depth) {
    613         if (kind == DestructureToVariables)
    614             failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot deconstruct to a variable named '", name.impl(), "' in strict mode");
    615         else if (kind == DestructureToLet || kind == DestructureToConst) {
    616             DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
    617             if (declarationResult != DeclarationResult::Valid) {
    618                 failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
    619                 failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
    620             }
    621         } else if (kind == DestructureToParameters) {
     612
     613    if (kind == DestructureToVariables)
     614        failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named '", name.impl(), "' in strict mode");
     615    else if (kind == DestructureToLet || kind == DestructureToConst) {
     616        DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
     617        if (declarationResult != DeclarationResult::Valid) {
     618            failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
     619            failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
     620        }
     621    } else if (kind == DestructureToParameters) {
     622        if (depth) {
    622623            auto bindingResult = declareBoundParameter(&name);
    623624            if (bindingResult == Scope::StrictBindingFailed && strictMode()) {
     
    636637                semanticFail("Cannot destructure to a parameter named '", name.impl(), "'");
    637638            }
    638         }
    639 
    640     } else {
    641         if (kind == DestructureToVariables)
    642             failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named '", name.impl(), "' in strict mode");
    643         else if (kind == DestructureToLet || kind == DestructureToConst) {
    644             DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
    645             if (declarationResult != DeclarationResult::Valid) {
    646                 failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
    647                 failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
    648             }
    649         } else if (kind == DestructureToParameters) {
     639        } else {
    650640            DeclarationResultMask declarationResult = declareParameter(&name);
    651641            if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
     
    658648                semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
    659649            }
     650            if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
     651                // It's not always an error to define a duplicate parameter.
     652                // It's only an error when there are default parameter values or destructuring parameters.
     653                // We note this value now so we can check it later.
     654                if (duplicateIdentifier)
     655                    *duplicateIdentifier = &name;
     656            }
    660657        }
    661658    }
     
    695692template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context, AssignmentContext bindingContext)
    696693{
    697     return parseDestructuringPattern(context, DestructureToExpressions, bindingContext);
    698 }
    699 
    700 template <typename LexerType>
    701 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, AssignmentContext bindingContext, int depth)
     694    return parseDestructuringPattern(context, DestructureToExpressions, nullptr, nullptr, bindingContext);
     695}
     696
     697template <typename LexerType>
     698template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
    702699{
    703700    failIfStackOverflow();
     
    710707        next();
    711708
     709        if (hasDestructuringPattern)
     710            *hasDestructuringPattern = true;
     711
    712712        bool restElementWasFound = false;
    713713
     
    725725                JSTokenLocation location = m_token.m_location;
    726726                next();
    727                 auto innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
     727                auto innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    728728                if (kind == DestructureToExpressions && !innerPattern)
    729729                    return 0;
     
    738738
    739739            JSTokenLocation location = m_token.m_location;
    740             auto innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
     740            auto innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    741741            if (kind == DestructureToExpressions && !innerPattern)
    742742                return 0;
    743743            failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
    744744            TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
    745             failIfTrue(kind == DestructureToParameters && defaultValue,  "Default values in destructuring parameters are currently not supported");
    746745            context.appendArrayPatternEntry(arrayPattern, location, innerPattern, defaultValue);
    747746        } while (consume(COMMA));
     
    757756        auto objectPattern = context.createObjectPattern(m_token.m_location);
    758757        next();
     758
     759        if (hasDestructuringPattern)
     760            *hasDestructuringPattern = true;
    759761
    760762        do {
     
    773775                next();
    774776                if (consume(COLON))
    775                     innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
     777                    innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    776778                else
    777                     innerPattern = createBindingPattern(context, kind, *propertyName, depth, identifierToken, bindingContext);
     779                    innerPattern = createBindingPattern(context, kind, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
    778780            } else {
    779781                JSTokenType tokenType = m_token.m_type;
     
    806808                    failWithMessage("Expected a ':' prior to a named destructuring property");
    807809                }
    808                 innerPattern = parseDestructuringPattern(context, kind, bindingContext, depth + 1);
     810                innerPattern = parseDestructuringPattern(context, kind, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    809811            }
    810812            if (kind == DestructureToExpressions && !innerPattern)
     
    812814            failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
    813815            TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
    814             failIfTrue(kind == DestructureToParameters && defaultValue, "Default values in destructuring parameters are currently not supported");
    815816            ASSERT(propertyName);
    816817            context.appendObjectPatternEntry(objectPattern, location, wasString, *propertyName, innerPattern, defaultValue);
     
    832833        }
    833834        failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
    834         pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext);
     835        pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext, duplicateIdentifier);
    835836        next();
    836837        break;
     
    14471448template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeBuilder& context, TreeFormalParameterList list, unsigned& parameterCount)
    14481449{
    1449     auto parameter = parseDestructuringPattern(context, DestructureToParameters);
     1450#define failFromDuplicate() \
     1451    if (duplicateParameter) {\
     1452        semanticFailIfTrue(defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");\
     1453        semanticFailIfTrue(hasDestructuringPattern, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with destructuring parameters");\
     1454    }
     1455
     1456    const Identifier* duplicateParameter = nullptr;
     1457    bool hasDestructuringPattern = false;
     1458    auto parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter, &hasDestructuringPattern);
    14501459    failIfFalse(parameter, "Cannot parse parameter pattern");
    1451     context.appendParameter(list, parameter);
     1460    auto defaultValue = parseDefaultValueForDestructuringPattern(context);
     1461    propagateError();
     1462    failFromDuplicate();
     1463    context.appendParameter(list, parameter, defaultValue);
    14521464    parameterCount++;
    14531465    while (consume(COMMA)) {
    1454         parameter = parseDestructuringPattern(context, DestructureToParameters);
     1466        parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter, &hasDestructuringPattern);
    14551467        failIfFalse(parameter, "Cannot parse parameter pattern");
    1456         context.appendParameter(list, parameter);
     1468        defaultValue = parseDefaultValueForDestructuringPattern(context);
     1469        propagateError();
     1470        failFromDuplicate();
     1471        context.appendParameter(list, parameter, defaultValue);
    14571472        parameterCount++;
    14581473    }
    14591474    return true;
     1475#undef failFromDuplicate
    14601476}
    14611477
     
    15311547                auto parameter = parseDestructuringPattern(context, DestructureToParameters);
    15321548                failIfFalse(parameter, "Cannot parse parameter pattern");
    1533                 context.appendParameter(parameterList, parameter);
     1549                context.appendParameter(parameterList, parameter, 0);
    15341550            }
    15351551        }
     
    15481564    } else if (mode == SetterMode) {
    15491565        failIfTrue(match(CLOSEPAREN), "setter functions must have one parameter");
    1550         auto parameter = parseDestructuringPattern(context, DestructureToParameters);
     1566        const Identifier* duplicateParameter = nullptr;
     1567        auto parameter = parseDestructuringPattern(context, DestructureToParameters, &duplicateParameter);
    15511568        failIfFalse(parameter, "setter functions must have one parameter");
    1552         context.appendParameter(parameterList, parameter);
     1569        auto defaultValue = parseDefaultValueForDestructuringPattern(context);
     1570        propagateError();
     1571        semanticFailIfTrue(duplicateParameter && defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");
     1572        context.appendParameter(parameterList, parameter, defaultValue);
    15531573        functionInfo.parameterCount = 1;
    15541574        failIfTrue(match(COMMA), "setter functions must have one parameter");
Note: See TracChangeset for help on using the changeset viewer.