Skip to content

Commit

Permalink
Disallow declarations as expression statements.
Browse files Browse the repository at this point in the history
Summary:
ExpressionStatements are no longer allowed to be parsed as declarations,
in an attempt to avoid ambiguity.

Add the simple checks for this.

`{`, `function`, and `class` are no longer allowed at the start of
expression statements.

To handle `let [`, we use the `lexer_.seek` function to reset the
`curCharPtr`; this case should be infrequent enough that going back
one token is acceptable.

Reviewed By: tmikov

Differential Revision: D17270833

fbshipit-source-id: 1e58560b2d89b6fc3f6971c98b15d339d15f0d85
  • Loading branch information
avp authored and facebook-github-bot committed Oct 14, 2019
1 parent 5e185ca commit 630c1ce
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
25 changes: 25 additions & 0 deletions lib/Parser/JSParserImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,31 @@ Optional<ESTree::EmptyStatementNode *> JSParserImpl::parseEmptyStatement() {
Optional<ESTree::Node *> JSParserImpl::parseExpressionOrLabelledStatement(
Param param) {
bool startsWithIdentifier = check(TokenKind::identifier);

// ES9.0 13.5
// Lookahead cannot be any of: {, function, async function, class, let [
// Allow execution to continue because the expression may be parsed,
// but report an error because it will be ambiguous whether the parse was
// correct.
if (checkN(TokenKind::l_brace, TokenKind::rw_function, TokenKind::rw_class)) {
// There's no need to stop reporting errors.
sm_.error(
tok_->getSourceRange(),
"declaration not allowed as expression statement");
}

if (check(letIdent_)) {
SMLoc letLoc = advance().Start;
if (check(TokenKind::l_square)) {
// let [
sm_.error(
{letLoc, tok_->getEndLoc()},
"ambiguous 'let [': either a 'let' binding or a member expression");
}
lexer_.seek(letLoc);
advance();
}

auto optExpr = parseExpression();
if (!optExpr)
return None;
Expand Down
21 changes: 21 additions & 0 deletions test/Parser/for-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the LICENSE
// file in the root directory of this source tree.
//
// RUN: (! %hermesc -dump-ast -pretty-json %s 2>&1 ) | %FileCheck --match-full-lines %s

for (;false;) function foo() {}
// CHECK: {{.*}}:8:15: error: declaration not allowed as expression statement
// CHECK: for (;false;) function foo() {}
// CHECK: ^~~~~~~~

for (;false;) class bar {}
// CHECK: {{.*}}:13:15: error: declaration not allowed as expression statement
// CHECK: for (;false;) class bar {}
// CHECK: ^~~~~

for (;false;) let [x] = 3;
// CHECK: {{.*}}:18:15: error: ambiguous 'let [': either a 'let' binding or a member expression
// CHECK: for (;false;) let [x] = 3;
// CHECK: ^~~~~
1 change: 1 addition & 0 deletions utils/testsuite/testsuite_blacklist.py
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,7 @@
# annexB
"mjsunit/es6/string-html.js",
"mjsunit/function-names.js",
"mjsunit/regress/regress-536751.js",
"test262/test/annexB/built-ins/Date/prototype/toGMTString/value.js",
"test262/test/annexB/built-ins/String/prototype/anchor/",
"test262/test/annexB/built-ins/String/prototype/big/",
Expand Down

0 comments on commit 630c1ce

Please sign in to comment.