Ignore:
Timestamp:
Jul 6, 2015, 3:18:58 PM (10 years ago)
Author:
[email protected]
Message:

JSC's parser should follow the ES6 spec with respect to parsing Declarations
https://bugs.webkit.org/show_bug.cgi?id=146621

Reviewed by Mark Lam.

Source/JavaScriptCore:

There were a few locations where JSC would allow declaration statements
in incorrect ways. JSC didn't distinguish between 'Statement' and
'StatementListItem' grammar productions. The relevant grammar is here:
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-statements

From the ECMA Script 6.0 spec:

  1. Section 13.6 The if Statement (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-if-statement) says that IfStatements only takes Statements for the "then-else" clauses, not StatementListItems. (Same with 'while/for/do-while' loop bodies).
  2. Section 13 ECMAScript Language: Statements and Declarations (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-ecmascript-language-statements-and-declarations) defines the syntax of Statements, and they do not include ClassDeclarations and LexicalDeclarations (const, let, see 13.3.1 Let and Const Declarations). Declarations can only be in the “then-else” clauses when embedded in a StatementListItem in a BlockStatement (see 13.2).

Hence, the following style of declarations are no longer allowed:

'if/for/while (condition) const x = 40;'
'if/for/while (condition) class C { }'

Instead, we mandate such declaration constructs are within a StatementList

(which is the production that JSC's Parser::parseSourceElements function parses):

'if/for/while (condition) { const x = 40; }'
'if/for/while (condition) { class C { } }'

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseSourceElements):
(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseVarDeclaration):
(JSC::Parser<LexerType>::parseStatement):
(JSC::Parser<LexerType>::parseExpressionStatement):

  • parser/Parser.h:

(JSC::Parser::getLabel):

LayoutTests:

  • js/parser-syntax-check-expected.txt:
  • js/script-tests/const.js:

(with1):
(with2):

  • js/script-tests/parser-syntax-check.js:
  • js/script-tests/statement-list-item-syntax-errors.js: Added.

(testSyntax):
(runTests):

  • js/statement-list-item-syntax-errors-expected.txt: Added.
  • js/statement-list-item-syntax-errors.html: Added.
  • sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.5-expected.txt:
File:
1 edited

Legend:

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

    r186279 r186379  
    370370#endif
    371371   
    372     while (TreeStatement statement = parseStatement(context, directive, &directiveLiteralLength)) {
     372    while (TreeStatement statement = parseStatementListItem(context, directive, &directiveLiteralLength)) {
    373373        if (mode == CheckForStrictMode && !seenNonDirective) {
    374374            if (directive) {
     
    402402    propagateError();
    403403    return sourceElements;
     404}
     405template <typename LexerType>
     406template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementListItem(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
     407{
     408    // The grammar is documented here:
     409    // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-statements
     410    TreeStatement result = 0;
     411    switch (m_token.m_type) {
     412    case CONSTTOKEN:
     413        result = parseConstDeclaration(context);
     414        break;
     415#if ENABLE(ES6_CLASS_SYNTAX)
     416    case CLASSTOKEN:
     417        result = parseClassDeclaration(context);
     418        break;
     419#endif
     420    default:
     421        // FIXME: This needs to consider 'let' in bug:
     422        // https://bugs.webkit.org/show_bug.cgi?id=142944
     423        result = parseStatement(context, directive, directiveLiteralLength);
     424        break;
     425    }
     426
     427    return result;
    404428}
    405429
     
    12641288        result = parseVarDeclaration(context);
    12651289        break;
    1266     case CONSTTOKEN:
    1267         result = parseConstDeclaration(context);
    1268         break;
    1269 #if ENABLE(ES6_CLASS_SYNTAX)
    1270     case CLASSTOKEN:
    1271         failIfFalse(m_statementDepth == 1, "Class declaration is not allowed in a lexically nested statement");
    1272         result = parseClassDeclaration(context);
    1273         break;
    1274 #endif
    12751290    case FUNCTION:
    12761291        failIfFalseIfStrict(m_statementDepth == 1, "Strict mode does not allow function declarations in a lexically nested statement");
     
    19391954template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionStatement(TreeBuilder& context)
    19401955{
     1956    switch (m_token.m_type) {
     1957    // Consult: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-expression-statement
     1958    // The ES6 spec mandates that we should fail from FUNCTION token here. We handle this case
     1959    // in parseStatement() which is the only caller of parseExpressionStatement().
     1960    // We actually allow FUNCTION in situations where it should not be allowed unless we're in strict mode.
     1961    case CLASSTOKEN:
     1962        failWithMessage("'class' declaration is not directly within a block statement");
     1963        break;
     1964    default:
     1965        // FIXME: when implementing 'let' we should fail when we see the token sequence "let [".
     1966        // https://bugs.webkit.org/show_bug.cgi?id=142944
     1967        break;
     1968    }
    19411969    JSTextPosition start = tokenStartPosition();
    19421970    JSTokenLocation location(tokenLocation());
Note: See TracChangeset for help on using the changeset viewer.