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(); |