Chromium Code Reviews| Index: src/parsing/preparser.cc |
| diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc |
| index 526e45e31dc0266bcbc22d7f4e8548eefc172043..d73a2fc383c3d5d5c06e5676c547fa036474f2fd 100644 |
| --- a/src/parsing/preparser.cc |
| +++ b/src/parsing/preparser.cc |
| @@ -140,9 +140,9 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction( |
| PreParserExpression PreParserTraits::ParseClassLiteral( |
| PreParserIdentifier name, Scanner::Location class_name_location, |
| - bool name_is_strict_reserved, int pos, bool* ok) { |
| - return pre_parser_->ParseClassLiteral(name, class_name_location, |
| - name_is_strict_reserved, pos, ok); |
| + bool name_is_strict_reserved, int pos, bool ambient, bool* ok) { |
| + return pre_parser_->ParseClassLiteral( |
| + name, class_name_location, name_is_strict_reserved, pos, ambient, ok); |
| } |
| @@ -160,7 +160,8 @@ PreParserExpression PreParserTraits::ParseClassLiteral( |
| // it is used) are generally omitted. |
| -PreParser::Statement PreParser::ParseStatementListItem(bool* ok) { |
| +PreParser::Statement PreParser::ParseStatementListItem(bool top_level, |
| + bool* ok) { |
| // ECMA 262 6th Edition |
| // StatementListItem[Yield, Return] : |
| // Statement[?Yield, ?Return] |
| @@ -178,24 +179,34 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) { |
| // LexicalDeclaration[In, Yield] : |
| // LetOrConst BindingList[?In, ?Yield] ; |
| + // Allow ambient variable, function, and class declarations. |
| + bool ambient = |
| + scope_->typed() && CheckContextualKeyword(CStrVector("declare")); |
| + if (ambient && !top_level) { |
| + *ok = false; |
| + ReportMessage(MessageTemplate::kIllegalDeclare); |
| + return Statement::Default(); |
| + } |
| switch (peek()) { |
| case Token::FUNCTION: |
| - return ParseFunctionDeclaration(ok); |
| + return ParseFunctionDeclaration(ambient, ok); |
| case Token::CLASS: |
| - return ParseClassDeclaration(ok); |
| + return ParseClassDeclaration(ambient, ok); |
| case Token::CONST: |
| if (allow_const()) { |
| - return ParseVariableStatement(kStatementListItem, ok); |
| + return ParseVariableStatement(kStatementListItem, ambient, ok); |
| } |
| break; |
| + case Token::VAR: |
| + return ParseVariableStatement(kStatementListItem, ambient, ok); |
| case Token::LET: |
| if (IsNextLetKeyword()) { |
| - return ParseVariableStatement(kStatementListItem, ok); |
| + return ParseVariableStatement(kStatementListItem, ambient, ok); |
| } |
| break; |
| case Token::IDENTIFIER: |
| case Token::FUTURE_STRICT_RESERVED_WORD: { |
| - if (!scope_->typed()) break; |
| + if (!scope_->typed() || ambient) break; |
| int pos = peek_position(); |
| if (CheckContextualKeyword(CStrVector("type"))) { |
| return ParseTypeAliasDeclaration(pos, ok); |
| @@ -204,15 +215,20 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) { |
| } |
| break; |
| } |
| - // TODO(nikolaos): ambient |
| default: |
| break; |
| } |
| + if (ambient) { |
| + *ok = false; |
| + ReportMessageAt(scanner()->peek_location(), |
| + MessageTemplate::kBadAmbientDeclaration); |
| + return Statement::Default(); |
| + } |
| return ParseStatement(kAllowLabelledFunctionStatement, ok); |
| } |
| -void PreParser::ParseStatementList(int end_token, bool* ok, |
| +void PreParser::ParseStatementList(int end_token, bool top_level, bool* ok, |
| Scanner::BookmarkScope* bookmark) { |
| // SourceElements :: |
| // (Statement)* <end_token> |
| @@ -229,7 +245,7 @@ void PreParser::ParseStatementList(int end_token, bool* ok, |
| } |
| bool starts_with_identifier = peek() == Token::IDENTIFIER; |
| Scanner::Location token_loc = scanner()->peek_location(); |
| - Statement statement = ParseStatementListItem(ok); |
| + Statement statement = ParseStatementListItem(top_level, ok); |
| if (!*ok) return; |
| if (directive_prologue) { |
| @@ -308,7 +324,7 @@ PreParser::Statement PreParser::ParseScopedStatement(bool legacy, bool* ok) { |
| (legacy && allow_harmony_restrictive_declarations())) { |
| return ParseSubStatement(kDisallowLabelledFunctionStatement, ok); |
| } else { |
| - return ParseFunctionDeclaration(CHECK_OK); |
| + return ParseFunctionDeclaration(false, CHECK_OK); |
| } |
| } |
| @@ -397,7 +413,7 @@ PreParser::Statement PreParser::ParseSubStatement( |
| return ParseDebuggerStatement(ok); |
| case Token::VAR: |
| - return ParseVariableStatement(kStatement, ok); |
| + return ParseVariableStatement(kStatement, false, ok); |
| default: |
| return ParseExpressionOrLabelledStatement(allow_function, ok); |
| @@ -405,7 +421,8 @@ PreParser::Statement PreParser::ParseSubStatement( |
| } |
| -PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { |
| +PreParser::Statement PreParser::ParseFunctionDeclaration(bool ambient, |
| + bool* ok) { |
| // FunctionDeclaration :: |
| // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' |
| // GeneratorDeclaration :: |
| @@ -417,18 +434,20 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { |
| bool is_strict_reserved = false; |
| Identifier name = ParseIdentifierOrStrictReservedWord( |
| &is_strict_reserved, CHECK_OK); |
| + typesystem::TypeFlags type_flags = |
| + ambient ? typesystem::kAmbient : typesystem::kAllowSignature; |
| ParseFunctionLiteral(name, scanner()->location(), |
| is_strict_reserved ? kFunctionNameIsStrictReserved |
| : kFunctionNameValidityUnknown, |
| is_generator ? FunctionKind::kGeneratorFunction |
| : FunctionKind::kNormalFunction, |
| pos, FunctionLiteral::kDeclaration, language_mode(), |
| - typesystem::kAllowSignature, CHECK_OK); |
| + type_flags, CHECK_OK); |
| return Statement::FunctionDeclaration(); |
| } |
| -PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) { |
| +PreParser::Statement PreParser::ParseClassDeclaration(bool ambient, bool* ok) { |
| Expect(Token::CLASS, CHECK_OK); |
| if (!allow_harmony_sloppy() && is_sloppy(language_mode())) { |
| ReportMessage(MessageTemplate::kSloppyLexical); |
| @@ -441,7 +460,7 @@ PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) { |
| Identifier name = |
| ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); |
| ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos, |
| - CHECK_OK); |
| + ambient, CHECK_OK); |
| return Statement::Default(); |
| } |
| @@ -453,7 +472,7 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) { |
| Expect(Token::LBRACE, CHECK_OK); |
| Statement final = Statement::Default(); |
| while (peek() != Token::RBRACE) { |
| - final = ParseStatementListItem(CHECK_OK); |
| + final = ParseStatementListItem(false, CHECK_OK); |
| } |
| Expect(Token::RBRACE, ok); |
| return final; |
| @@ -461,13 +480,13 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) { |
| PreParser::Statement PreParser::ParseVariableStatement( |
| - VariableDeclarationContext var_context, |
| - bool* ok) { |
| + VariableDeclarationContext var_context, bool ambient, bool* ok) { |
| // VariableStatement :: |
| // VariableDeclarations ';' |
| - Statement result = ParseVariableDeclarations( |
| - var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK); |
| + Statement result = |
| + ParseVariableDeclarations(var_context, nullptr, nullptr, nullptr, nullptr, |
| + nullptr, ambient, CHECK_OK); |
| ExpectSemicolon(CHECK_OK); |
| return result; |
| } |
| @@ -481,7 +500,7 @@ PreParser::Statement PreParser::ParseVariableStatement( |
| PreParser::Statement PreParser::ParseVariableDeclarations( |
| VariableDeclarationContext var_context, int* num_decl, bool* is_lexical, |
| bool* is_binding_pattern, Scanner::Location* first_initializer_loc, |
| - Scanner::Location* bindings_loc, bool* ok) { |
| + Scanner::Location* bindings_loc, bool ambient, bool* ok) { |
| // VariableDeclarations :: |
| // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] |
| // |
| @@ -554,6 +573,12 @@ PreParser::Statement PreParser::ParseVariableDeclarations( |
| ParseValidType(CHECK_OK); |
| } |
| + // Skip initializers, for ambient declarations. |
|
rossberg
2016/04/20 15:16:35
Nit: maybe don't say "skip initializers", but "no
nickie
2016/04/21 13:57:10
Done.
|
| + if (ambient) { |
| + nvars++; |
| + continue; |
| + } |
| + |
| Scanner::Location variable_loc = scanner()->location(); |
| nvars++; |
| if (Check(Token::ASSIGN)) { |
| @@ -625,7 +650,7 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement( |
| // ES#sec-labelled-function-declarations Labelled Function Declarations |
| if (peek() == Token::FUNCTION && is_sloppy(language_mode())) { |
| if (allow_function == kAllowLabelledFunctionStatement) { |
| - return ParseFunctionDeclaration(ok); |
| + return ParseFunctionDeclaration(false, ok); |
| } else { |
| return ParseScopedStatement(true, ok); |
| } |
| @@ -779,7 +804,7 @@ PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) { |
| while (token != Token::CASE && |
| token != Token::DEFAULT && |
| token != Token::RBRACE) { |
| - statement = ParseStatementListItem(CHECK_OK); |
| + statement = ParseStatementListItem(false, CHECK_OK); |
| token = peek(); |
| } |
| } |
| @@ -834,7 +859,7 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { |
| Scanner::Location bindings_loc = Scanner::Location::invalid(); |
| ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical, |
| &is_binding_pattern, &first_initializer_loc, |
| - &bindings_loc, CHECK_OK); |
| + &bindings_loc, false, CHECK_OK); |
| if (CheckInOrOf(&mode, ok)) { |
| if (!*ok) return Statement::Default(); |
| if (decl_count != 1) { |
| @@ -1055,15 +1080,16 @@ PreParser::Expression PreParser::ParseFunctionLiteral( |
| parenthesized_function_ = false; |
| // Parse optional type annotation. |
| - if (scope_->typed() && |
| - !(type_flags & typesystem::kDisallowTypeAnnotation) && |
| + if (scope_->typed() && !(type_flags & typesystem::kDisallowTypeAnnotation) && |
| Check(Token::COLON)) { // Braces required here. |
| ParseValidType(CHECK_OK); |
| } |
| - // Allow for a function signature (i.e., a literal without body). |
| - if (peek() != Token::LBRACE && scope_->typed() && |
| - (type_flags & typesystem::kAllowSignature)) { |
| + // Allow or even enforce a function signature (i.e., literal without body), |
| + // In that case, return a nullptr instead of a function literal. |
| + if ((type_flags & typesystem::kDisallowBody) || |
| + (peek() != Token::LBRACE && scope_->typed() && |
| + (type_flags & typesystem::kAllowSignature))) { |
| ExpectSemicolon(CHECK_OK); |
| return this->EmptyExpression(); |
| } |
| @@ -1072,7 +1098,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral( |
| if (is_lazily_parsed) { |
| ParseLazyFunctionLiteralBody(CHECK_OK); |
| } else { |
| - ParseStatementList(Token::RBRACE, CHECK_OK); |
| + ParseStatementList(Token::RBRACE, false, CHECK_OK); |
| } |
| Expect(Token::RBRACE, CHECK_OK); |
| @@ -1100,7 +1126,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral( |
| void PreParser::ParseLazyFunctionLiteralBody(bool* ok, |
| Scanner::BookmarkScope* bookmark) { |
| int body_start = position(); |
| - ParseStatementList(Token::RBRACE, ok, bookmark); |
| + ParseStatementList(Token::RBRACE, false, ok, bookmark); |
| if (!*ok) return; |
| if (bookmark && bookmark->HasBeenReset()) return; |
| @@ -1116,7 +1142,7 @@ void PreParser::ParseLazyFunctionLiteralBody(bool* ok, |
| PreParserExpression PreParser::ParseClassLiteral( |
| PreParserIdentifier name, Scanner::Location class_name_location, |
| - bool name_is_strict_reserved, int pos, bool* ok) { |
| + bool name_is_strict_reserved, int pos, bool ambient, bool* ok) { |
| // All parts of a ClassDeclaration and ClassExpression are strict code. |
| if (name_is_strict_reserved) { |
| ReportMessageAt(class_name_location, |
| @@ -1172,7 +1198,7 @@ PreParserExpression PreParser::ParseClassLiteral( |
| ExpressionClassifier classifier(this); |
| ParsePropertyDefinition(&checker, in_class, has_extends, is_static, |
| &is_computed_name, &has_seen_constructor, |
| - &classifier, &name, CHECK_OK); |
| + &classifier, &name, ambient, CHECK_OK); |
| ValidateExpression(&classifier, CHECK_OK); |
| } |
| @@ -1212,7 +1238,7 @@ PreParserExpression PreParser::ParseDoExpression(bool* ok) { |
| { |
| BlockState block_state(&scope_, block_scope); |
| while (peek() != Token::RBRACE) { |
| - ParseStatementListItem(CHECK_OK); |
| + ParseStatementListItem(false, CHECK_OK); |
| } |
| Expect(Token::RBRACE, CHECK_OK); |
| return PreParserExpression::Default(); |