Ignore:
Timestamp:
Jul 19, 2015, 9:57:44 AM (10 years ago)
Author:
[email protected]
Message:

[ES6] Add support for block scope const
https://bugs.webkit.org/show_bug.cgi?id=31813

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

'const' is now implemented in an ES6 spec compliant manner.
'const' variables are always block scoped and always live
either on the stack or in a JSLexicalEnvironment. 'const'
variables never live on the global object.

Inside the BytecodeGenerator, when assigning to a stack
'const' variable or a LocalClosureVar 'const' variable,
we will emit code that just throws a type error.
When assigning to a ClosureVar const variable, CodeBlock linking
will ensure that we perform a dynamic lookup of that variable so
that put_to_scope's slow path throws a type error.

The old 'const' implementation has been removed in this patch.

  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::pushLexicalScope):
(JSC::BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration):
(JSC::BytecodeGenerator::variable):
(JSC::BytecodeGenerator::variableForLocalEntry):
(JSC::BytecodeGenerator::createVariable):
(JSC::BytecodeGenerator::emitResolveScope):
(JSC::BytecodeGenerator::emitInstanceOf):
(JSC::BytecodeGenerator::emitGetById):
(JSC::BytecodeGenerator::isArgumentNumber):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
(JSC::BytecodeGenerator::emitEnumeration):
(JSC::BytecodeGenerator::variablePerSymbolTable): Deleted.
(JSC::BytecodeGenerator::emitInitGlobalConst): Deleted.

  • bytecompiler/BytecodeGenerator.h:

(JSC::Variable::Variable):
(JSC::Variable::isReadOnly):
(JSC::Variable::isSpecial):
(JSC::Variable::isConst):
(JSC::BytecodeGenerator::thisRegister):
(JSC::BytecodeGenerator::emitTypeOf):
(JSC::BytecodeGenerator::emitIn):

  • bytecompiler/NodesCodegen.cpp:

(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::CommaNode::emitBytecode):
(JSC::BindingNode::bindValue):
(JSC::ConstDeclNode::emitCodeSingle): Deleted.
(JSC::ConstDeclNode::emitBytecode): Deleted.
(JSC::ConstStatementNode::emitBytecode): Deleted.

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):

  • jit/JIT.h:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_put_to_arguments):
(JSC::JIT::emit_op_init_global_const): Deleted.

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_put_to_arguments):
(JSC::JIT::emit_op_init_global_const): Deleted.

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createDeclarationStatement):
(JSC::ASTBuilder::createEmptyVarExpression):
(JSC::ASTBuilder::createDebugger):
(JSC::ASTBuilder::appendStatement):
(JSC::ASTBuilder::createVarStatement): Deleted.
(JSC::ASTBuilder::createLetStatement): Deleted.
(JSC::ASTBuilder::createConstStatement): Deleted.
(JSC::ASTBuilder::appendConstDecl): Deleted.

  • parser/NodeConstructors.h:

(JSC::CommaNode::CommaNode):
(JSC::SourceElements::SourceElements):
(JSC::SwitchNode::SwitchNode):
(JSC::BlockNode::BlockNode):
(JSC::ConstStatementNode::ConstStatementNode): Deleted.
(JSC::ConstDeclNode::ConstDeclNode): Deleted.

  • parser/Nodes.h:

(JSC::ConstDeclNode::hasInitializer): Deleted.
(JSC::ConstDeclNode::ident): Deleted.

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseVariableDeclaration):
(JSC::Parser<LexerType>::parseWhileStatement):
(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseDefaultValueForDestructuringPattern):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::parseTryStatement):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseConstDeclaration): Deleted.
(JSC::Parser<LexerType>::parseConstDeclarationList): Deleted.

  • parser/Parser.h:

(JSC::isEvalNode):
(JSC::isEvalNode<EvalNode>):
(JSC::isArguments):
(JSC::isEval):
(JSC::isEvalOrArgumentsIdentifier):
(JSC::Scope::Scope):
(JSC::Scope::declareCallee):
(JSC::Scope::declareVariable):
(JSC::Scope::declareLexicalVariable):
(JSC::Scope::hasDeclaredVariable):
(JSC::Scope::allowsVarDeclarations):
(JSC::Scope::allowsLexicalDeclarations):
(JSC::Scope::declareParameter):
(JSC::Scope::declareBoundParameter):
(JSC::Parser::destructuringKindFromDeclarationType):
(JSC::Parser::assignmentContextFromDeclarationType):
(JSC::Parser::isEvalOrArguments):
(JSC::Parser::currentScope):
(JSC::Parser::popScope):
(JSC::Parser::declareVariable):
(JSC::Parser::hasDeclaredVariable):
(JSC::Parser::setStrictMode):
(JSC::Parser::strictMode):
(JSC::Parser::isValidStrictMode):
(JSC::Parser::declareParameter):
(JSC::Parser::declareBoundParameter):
(JSC::Parser::breakIsValid):

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createForInLoop):
(JSC::SyntaxChecker::createForOfLoop):
(JSC::SyntaxChecker::createEmptyStatement):
(JSC::SyntaxChecker::createDeclarationStatement):
(JSC::SyntaxChecker::createReturnStatement):
(JSC::SyntaxChecker::createBreakStatement):
(JSC::SyntaxChecker::createVarStatement): Deleted.
(JSC::SyntaxChecker::createLetStatement): Deleted.

  • parser/VariableEnvironment.h:

(JSC::VariableEnvironmentEntry::isCaptured):
(JSC::VariableEnvironmentEntry::isConst):
(JSC::VariableEnvironmentEntry::isVar):
(JSC::VariableEnvironmentEntry::isLet):
(JSC::VariableEnvironmentEntry::setIsCaptured):
(JSC::VariableEnvironmentEntry::setIsConst):
(JSC::VariableEnvironmentEntry::setIsVar):
(JSC::VariableEnvironmentEntry::setIsLet):
(JSC::VariableEnvironmentEntry::isConstant): Deleted.
(JSC::VariableEnvironmentEntry::setIsConstant): Deleted.

  • runtime/Executable.cpp:

(JSC::ProgramExecutable::initializeGlobalProperties):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::defineOwnProperty):
(JSC::JSGlobalObject::addGlobalVar):
(JSC::JSGlobalObject::addFunction):
(JSC::lastInPrototypeChain):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::finishCreation):
(JSC::JSGlobalObject::addVar):
(JSC::JSGlobalObject::addConst): Deleted.

  • runtime/JSLexicalEnvironment.cpp:

(JSC::JSLexicalEnvironment::symbolTablePut):

  • tests/stress/const-and-with-statement.js: Added.

(truth):
(assert):
(shouldThrowInvalidConstAssignment):
(.):

  • tests/stress/const-exception-handling.js: Added.

(truth):
(assert):
(.):

  • tests/stress/const-loop-semantics.js: Added.

(truth):
(assert):
(shouldThrowInvalidConstAssignment):
(.):

  • tests/stress/const-not-strict-mode.js: Added.

(truth):
(assert):
(shouldThrowTDZ):
(.):

  • tests/stress/const-semantics.js: Added.

(truth):
(assert):
(shouldThrowInvalidConstAssignment):
(.):

  • tests/stress/const-tdz.js: Added.

(truth):
(assert):
(shouldThrowTDZ):
(.):

Source/WebInspectorUI:

"const" variables do not live on the global object and are only
accessible within the "Program" they're defined in. Therefore,
the WebInspector global must be defined as "var" and not "const".

  • UserInterface/Base/WebInspector.js:

LayoutTests:

"const" variables do not live on the global object. They
are only available in the "Program" (read: JavaScript file or
script tag) that they're defined in. Tests have been updated
accordingly to switch the "const" variables assumed to be globals
into "var"s. "var" declared variables in the top level scope
of a program do live on the global object.

  • fast/canvas/webgl/compressed-tex-image.html:
  • fast/dom/event-handler-attributes.html:
  • fast/forms/listbox-visible-size.html:
  • js/arguments-expected.txt:
  • js/arrowfunction-syntax-errors-expected.txt:
  • js/const-expected.txt:
  • js/const-without-initializer-expected.txt:
  • js/constant-count-expected.txt:
  • js/dom/inc-const-valueOf-expected.txt:
  • js/dom/script-tests/inc-const-valueOf.js:

(testPreIncConstVarWithAssign):

  • js/function-toString-parentheses-expected.txt:
  • js/kde/const-expected.txt:
  • js/kde/resources/const.js:
  • js/parser-syntax-check-expected.txt:
  • js/script-tests/arguments.js:

(argumentsVarUndefined):
(argumentsConst):
(argumentCalleeInException):
(argumentsConstUndefined): Deleted.

  • js/script-tests/class-syntax-declaration.js:

(A):

  • js/script-tests/class-syntax-expression.js:
  • js/script-tests/const-without-initializer.js:
  • js/script-tests/const.js:

(shouldThrowInvalidConstAssignment):
(assert):
(f):
(tryCatch1):
(tryCatch2):
(with1):
(with2):
(.):

  • js/script-tests/constant-count.js:

(f):

  • js/script-tests/function-dot-arguments.js:

(assignConstInitTest2.g):
(assignConstInitTest2):

  • js/script-tests/function-toString-parentheses.js:
  • js/script-tests/parser-syntax-check.js:
  • sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.6-expected.txt:
  • sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T7-expected.txt:
  • sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T8-expected.txt:
  • sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T9-expected.txt:
  • sputnik/Conformance/08_Types/8.4_The_String_Type/S8.4_A13_T3-expected.txt:
  • sputnik/Conformance/08_Types/8.4_The_String_Type/S8.4_A14_T3-expected.txt:
  • sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T1-expected.txt:
  • sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T2-expected.txt:
  • sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T3-expected.txt:
  • sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T4-expected.txt:
  • sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T6-expected.txt:
  • sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T7-expected.txt:
  • sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T8-expected.txt:
  • transforms/3d/hit-testing/composited-hit-test.html:
  • transforms/3d/hit-testing/coplanar-with-camera.html:
  • transforms/3d/hit-testing/hover-rotated-negative-z.html:
  • transforms/3d/hit-testing/hover-rotated-with-children-negative-z.html:
  • transforms/3d/hit-testing/negative-zoffset-hit-test.html:
  • transforms/3d/hit-testing/overlapping-layers-hit-test.html:
  • transforms/3d/hit-testing/perspective-clipped.html:
  • transforms/3d/hit-testing/rotated-hit-test-with-child.html:
  • transforms/3d/hit-testing/rotated-hit-test.html:
  • transforms/3d/hit-testing/rotated-hit-test2.html:
  • transitions/resources/transition-test-helpers.js:

(roundNumber):

File:
1 edited

Legend:

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

    r186959 r187012  
    415415    switch (m_token.m_type) {
    416416    case CONSTTOKEN:
    417         result = parseConstDeclaration(context);
     417        result = parseVariableDeclaration(context, DeclarationType::ConstDeclaration);
    418418        break;
    419419    case LET: {
     
    427427        }
    428428        if (shouldParseVariableDeclaration)
    429             result = parseVariableDeclaration(context, DeclarationType::LexicalDeclaration);
     429            result = parseVariableDeclaration(context, DeclarationType::LetDeclaration);
    430430        else
    431431            result = parseExpressionOrLabelStatement(context); // Treat this as an IDENT. This is how ::parseStatement() handles IDENT.
     
    454454template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVariableDeclaration(TreeBuilder& context, DeclarationType declarationType)
    455455{
    456     ASSERT(match(VAR) || match(LET));
     456    ASSERT(match(VAR) || match(LET) || match(CONSTTOKEN));
    457457    JSTokenLocation location(tokenLocation());
    458458    int start = tokenLine();
     
    462462    TreeExpression scratch2 = 0;
    463463    JSTextPosition scratch3;
    464     TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType);
     464    bool scratchBool;
     465    TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType, scratchBool);
    465466    propagateError();
    466     failIfFalse(autoSemiColon(), "Expected ';' after var declaration");
    467    
    468     if (declarationType == DeclarationType::VarDeclaration)
    469         return context.createVarStatement(location, variableDecls, start, end);
    470     ASSERT(declarationType == DeclarationType::LexicalDeclaration);
    471     return context.createLetStatement(location, variableDecls, start, end);
    472 }
    473 
    474 template <typename LexerType>
    475 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseConstDeclaration(TreeBuilder& context)
    476 {
    477     ASSERT(match(CONSTTOKEN));
    478     JSTokenLocation location(tokenLocation());
    479     int start = tokenLine();
    480     int end = 0;
    481     TreeConstDeclList constDecls = parseConstDeclarationList(context);
    482     propagateError();
    483     failIfFalse(autoSemiColon(), "Expected ';' after const declaration");
    484    
    485     return context.createConstStatement(location, constDecls, start, end);
     467    failIfFalse(autoSemiColon(), "Expected ';' after variable declaration");
     468   
     469    return context.createDeclarationStatement(location, variableDecls, start, end);
    486470}
    487471
     
    534518
    535519template <typename LexerType>
    536 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)
    537 {
    538     ASSERT(declarationType == DeclarationType::LexicalDeclaration || declarationType == DeclarationType::VarDeclaration);
     520template <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)
     521{
     522    ASSERT(declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::VarDeclaration || declarationType == DeclarationType::ConstDeclaration);
    539523    TreeExpression head = 0;
    540524    TreeExpression tail = 0;
    541525    const Identifier* lastIdent;
    542526    JSToken lastIdentToken;
     527    AssignmentContext assignmentContext = assignmentContextFromDeclarationType(declarationType);
    543528    do {
    544529        lastIdent = 0;
     
    550535        bool hasInitializer = false;
    551536        if (match(IDENT) || isLETMaskedAsIDENT()) {
    552             failIfTrue(isLETMaskedAsIDENT() && declarationType == DeclarationType::LexicalDeclaration, "Can't use 'let' as an identifier name for a LexicalDeclaration");
     537            failIfTrue(match(LET) && (declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::ConstDeclaration),
     538                "Can't use 'let' as an identifier name for a LexicalDeclaration");
    553539            JSTextPosition varStart = tokenStartPosition();
    554540            JSTokenLocation varStartLocation(tokenLocation());
     
    559545            next();
    560546            hasInitializer = match(EQUAL);
    561             if (!declareVariable(name, declarationType)) {
    562                 if (declarationType == DeclarationType::LexicalDeclaration)
    563                     internalFailWithMessage(false, "Cannot declare a lexical variable twice: '", name->impl(), "'");
    564                 else if (strictMode())
    565                     internalFailWithMessage(false, "Cannot declare a variable named ", name->impl(), " in strict mode");
     547            DeclarationResultMask declarationResult = declareVariable(name, declarationType);
     548            if (declarationResult != DeclarationResult::Valid) {
     549                failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named ", name->impl(), " in strict mode");
     550                if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
     551                    if (declarationType == DeclarationType::LetDeclaration)
     552                        internalFailWithMessage(false, "Cannot declare a let variable twice: '", name->impl(), "'");
     553                    if (declarationType == DeclarationType::ConstDeclaration)
     554                        internalFailWithMessage(false, "Cannot declare a const variable twice: '", name->impl(), "'");
     555                    RELEASE_ASSERT_NOT_REACHED();
     556                }
    566557            }
    567558            if (hasInitializer) {
     
    574565                failIfFalse(initializer, "Expected expression as the intializer for the variable '", name->impl(), "'");
    575566               
    576                 node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition(), AssignmentContext::DeclarationStatement);
     567                node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition(), assignmentContext);
    577568            } else {
     569                if (declarationListContext == ForLoopContext && declarationType == DeclarationType::ConstDeclaration)
     570                    forLoopConstDoesNotHaveInitializer = true;
     571                failIfTrue(declarationListContext != ForLoopContext && declarationType == DeclarationType::ConstDeclaration, "const declared variable '", name->impl(), "'", " must have an initializer");
    578572                if (declarationType == DeclarationType::VarDeclaration)
    579573                    node = context.createEmptyVarExpression(varStartLocation, *name);
     
    583577        } else {
    584578            lastIdent = 0;
    585             auto pattern = parseDestructuringPattern(context, declarationType == DeclarationType::VarDeclaration ? DestructureToVariables : DestructureToLexicalVariables, AssignmentContext::DeclarationStatement);
     579            auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), assignmentContext);
    586580            failIfFalse(pattern, "Cannot parse this destructuring pattern");
    587581            hasInitializer = match(EQUAL);
     
    605599    } while (match(COMMA));
    606600    if (lastIdent)
    607         lastPattern = context.createBindingLocation(lastIdentToken.m_location, *lastIdent, lastIdentToken.m_startPosition, lastIdentToken.m_endPosition, AssignmentContext::DeclarationStatement);
     601        lastPattern = context.createBindingLocation(lastIdentToken.m_location, *lastIdent, lastIdentToken.m_startPosition, lastIdentToken.m_endPosition, assignmentContext);
    608602
    609603    return head;
     
    618612    if (depth) {
    619613        if (kind == DestructureToVariables)
    620             failIfFalseIfStrict(declareVariable(&name), "Cannot deconstruct to a variable named '", name.impl(), "' in strict mode");
    621         else if (kind == DestructureToLexicalVariables)
    622             semanticFailIfFalse(declareVariable(&name, DeclarationType::LexicalDeclaration), "Cannot declare a lexical variable twice: '", name.impl(), "'");
    623         else if (kind == DestructureToParameters) {
     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) {
    624622            auto bindingResult = declareBoundParameter(&name);
    625623            if (bindingResult == Scope::StrictBindingFailed && strictMode()) {
    626                 semanticFailIfTrue(m_vm->propertyNames->arguments == name || m_vm->propertyNames->eval == name, "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
     624                semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
    627625                if (m_lastFunctionName && name == *m_lastFunctionName)
    628626                    semanticFail("Cannot destructure to '", name.impl(), "' as it shadows the name of a strict mode function");
     
    642640    } else {
    643641        if (kind == DestructureToVariables)
    644             failIfFalseIfStrict(declareVariable(&name), "Cannot declare a variable named '", name.impl(), "' in strict mode");
    645         else if (kind == DestructureToLexicalVariables)
    646             semanticFailIfFalse(declareVariable(&name, DeclarationType::LexicalDeclaration), "Cannot declare a lexical variable twice: '", name.impl(), "'");
    647         else if (kind == DestructureToParameters) {
    648             bool declarationResult = declareParameter(&name);
    649             if (!declarationResult && strictMode()) {
    650                 semanticFailIfTrue(m_vm->propertyNames->arguments == name || m_vm->propertyNames->eval == name, "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
     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) {
     650            DeclarationResultMask declarationResult = declareParameter(&name);
     651            if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
     652                semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
    651653                if (m_lastFunctionName && name == *m_lastFunctionName)
    652654                    semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
     
    766768            JSTokenLocation location = m_token.m_location;
    767769            if (match(IDENT) || isLETMaskedAsIDENT()) {
    768                 failIfTrue(isLETMaskedAsIDENT() && kind == DestructureToLexicalVariables, "Can't use 'let' as an identifier name for a LexicalDeclaration");
     770                failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
    769771                propertyName = *m_token.m_data.ident;
    770772                JSToken identifierToken = m_token;
     
    828830            failWithMessage("Expected a parameter pattern or a ')' in parameter list");
    829831        }
    830         failIfTrue(isLETMaskedAsIDENT() && kind == DestructureToLexicalVariables, "Can't use 'let' as an identifier name for a LexicalDeclaration");
     832        failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
    831833        pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext);
    832834        next();
     
    846848    next(TreeBuilder::DontBuildStrings); // consume '='
    847849    return parseAssignmentExpression(context);
    848 }
    849 
    850 template <typename LexerType>
    851 template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
    852 {
    853     failIfTrue(strictMode(), "Const declarations are not supported in strict mode");
    854     TreeConstDeclList constDecls = 0;
    855     TreeConstDeclList tail = 0;
    856     do {
    857         JSTokenLocation location(tokenLocation());
    858         next();
    859         failIfFalse(match(IDENT), "Expected an identifier name in const declaration");
    860         const Identifier* name = m_token.m_data.ident;
    861         next();
    862         bool hasInitializer = match(EQUAL);
    863         // FIXME: This should be LexicalVariable when we support proper ES6 const semantics.
    864         declareVariable(name, DeclarationType::VarDeclaration, true);
    865         TreeExpression initializer = 0;
    866         if (hasInitializer) {
    867             next(TreeBuilder::DontBuildStrings); // consume '='
    868             initializer = parseAssignmentExpression(context);
    869             failIfFalse(!!initializer, "Unable to parse initializer");
    870         }
    871         tail = context.appendConstDecl(location, tail, name, initializer);
    872         if (!constDecls)
    873             constDecls = tail;
    874     } while (match(COMMA));
    875     return constDecls;
    876850}
    877851
     
    892866    bool isVarDeclaraton = match(VAR);
    893867    bool isLetDeclaration = match(LET);
     868    bool isConstDeclaration = match(CONSTTOKEN);
     869    bool forLoopConstDoesNotHaveInitializer = false;
    894870
    895871    VariableEnvironment dummySet;
     
    898874
    899875    auto gatherLexicalVariablesIfNecessary = [&] {
    900         if (isLetDeclaration) {
     876        if (isLetDeclaration || isConstDeclaration) {
    901877            ScopeRef scope = lexicalScope.scope();
    902878            lexicalVariables = &scope->finalizeLexicalEnvironment();
     
    906882
    907883    auto popLexicalScopeIfNecessary = [&] {
    908         if (isLetDeclaration)
     884        if (isLetDeclaration || isConstDeclaration)
    909885            popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
    910886    };
    911887
    912     if (isVarDeclaraton || isLetDeclaration) {
     888    if (isVarDeclaraton || isLetDeclaration || isConstDeclaration) {
    913889        /*
    914          for (var/let IDENT in expression) statement
    915          for (var/let varDeclarationList; expressionOpt; expressionOpt)
     890         for (var/let/const IDENT in/of expression) statement
     891         for (var/let/const varDeclarationList; expressionOpt; expressionOpt)
    916892         */
    917         if (isLetDeclaration) {
     893        if (isLetDeclaration || isConstDeclaration) {
    918894            ScopeRef newScope = pushScope();
    919895            newScope->setIsLexicalScope();
     
    927903        JSTextPosition initStart;
    928904        JSTextPosition initEnd;
    929         decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, isVarDeclaraton ? DeclarationType::VarDeclaration : DeclarationType::LexicalDeclaration);
     905        DeclarationType declarationType;
     906        if (isVarDeclaraton)
     907            declarationType = DeclarationType::VarDeclaration;
     908        else if (isLetDeclaration)
     909            declarationType = DeclarationType::LetDeclaration;
     910        else if (isConstDeclaration)
     911            declarationType = DeclarationType::ConstDeclaration;
     912        else
     913            RELEASE_ASSERT_NOT_REACHED();
     914        decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, declarationType, forLoopConstDoesNotHaveInitializer);
    930915        m_allowsIn = true;
    931916        propagateError();
     
    997982        next();
    998983        TreeExpression condition = 0;
     984        failIfTrue(forLoopConstDoesNotHaveInitializer && isConstDeclaration, "const variables in for loops must have initializers");
    999985       
    1000986        if (!match(SEMICOLON)) {
     
    12871273        next();
    12881274        AutoPopScopeRef catchScope(this, pushScope());
    1289         failIfFalseIfStrict(declareVariable(ident), "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
     1275        failIfTrueIfStrict(declareVariable(ident) & DeclarationResult::InvalidStrictMode, "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
    12901276        catchScope->preventAllVariableDeclarations();
    12911277        handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
     
    16011587            next();
    16021588            if (!nameIsInContainingScope)
    1603                 failIfFalseIfStrict(functionScope->declareVariable(functionInfo.name), "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
     1589                failIfTrueIfStrict(functionScope->declareVariable(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
    16041590        } else if (requirements == FunctionNeedsName) {
    16051591            if (match(OPENPAREN) && mode == NormalFunctionMode)
     
    17971783        functionKeywordStart, functionInfo, StandardFunctionParseType)), "Cannot parse this function");
    17981784    failIfFalse(functionInfo.name, "Function statements must have a name");
    1799     failIfFalseIfStrict(declareVariable(functionInfo.name), "Cannot declare a function named '", functionInfo.name->impl(), "' in strict mode");
     1785    failIfTrueIfStrict(declareVariable(functionInfo.name) & DeclarationResult::InvalidStrictMode, "Cannot declare a function named '", functionInfo.name->impl(), "' in strict mode");
    18001786    return context.createFuncDeclStatement(location, functionInfo);
    18011787}
     
    18371823        info.className = className;
    18381824        next();
    1839         failIfFalse(classScope->declareVariable(className), "'", className->impl(), "' is not a valid class name");
     1825        failIfTrue(classScope->declareVariable(className) & DeclarationResult::InvalidStrictMode, "'", className->impl(), "' is not a valid class name");
    18401826    } else if (requirements == FunctionNeedsName) {
    18411827        if (match(OPENBRACE))
     
    19131899            bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor;
    19141900            failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, isStaticMethod ? NormalFunctionMode : MethodMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method");
    1915             failIfFalse(ident && declareVariable(ident), "Cannot declare a method named '", methodInfo.name->impl(), "'");
     1901            failIfTrue(!ident || (declareVariable(ident) & DeclarationResult::InvalidStrictMode), "Cannot declare a method named '", methodInfo.name->impl(), "'");
    19161902            methodInfo.name = isConstructor ? className : ident;
    19171903
Note: See TracChangeset for help on using the changeset viewer.