Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index cfdbf1f2f9c8b24c212adb7ec2e0fae5750d8b10..1cfd6124d0f360f9d6324ce7c6c8ca2e84ad1ce5 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -759,9 +759,9 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral( |
ClassLiteral* ParserTraits::ParseClassLiteral( |
const AstRawString* 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) { |
return parser_->ParseClassLiteral(name, class_name_location, |
- name_is_strict_reserved, pos, ok); |
+ name_is_strict_reserved, pos, ambient, ok); |
} |
@@ -1272,27 +1272,35 @@ Statement* Parser::ParseStatementListItem(bool* ok) { |
// Statement |
// Declaration |
+ // Allow ambient variable, function, and class declarations. |
+ bool ambient = |
+ scope_->typed() && CheckContextualKeyword(CStrVector("declare")); |
+ if (ambient && !scope_->is_toplevel_scope()) { |
+ *ok = false; |
+ ReportMessage(MessageTemplate::kIllegalDeclare); |
+ return nullptr; |
+ } |
switch (peek()) { |
case Token::FUNCTION: |
- return ParseFunctionDeclaration(NULL, ok); |
+ return ParseFunctionDeclaration(NULL, ambient, ok); |
case Token::CLASS: |
Consume(Token::CLASS); |
- return ParseClassDeclaration(NULL, ok); |
+ return ParseClassDeclaration(NULL, ambient, ok); |
case Token::CONST: |
if (allow_const()) { |
- return ParseVariableStatement(kStatementListItem, NULL, ok); |
+ return ParseVariableStatement(kStatementListItem, NULL, ambient, ok); |
} |
break; |
case Token::VAR: |
- return ParseVariableStatement(kStatementListItem, NULL, ok); |
+ return ParseVariableStatement(kStatementListItem, NULL, ambient, ok); |
case Token::LET: |
if (IsNextLetKeyword()) { |
- return ParseVariableStatement(kStatementListItem, NULL, ok); |
+ return ParseVariableStatement(kStatementListItem, NULL, 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); |
@@ -1301,10 +1309,15 @@ Statement* Parser::ParseStatementListItem(bool* ok) { |
} |
break; |
} |
- // TODO(nikolaos): ambient |
default: |
break; |
} |
+ if (ambient) { |
+ *ok = false; |
+ ReportMessageAt(scanner()->peek_location(), |
+ MessageTemplate::kBadAmbientDeclaration); |
+ return nullptr; |
+ } |
return ParseStatement(NULL, kAllowLabelledFunctionStatement, ok); |
} |
@@ -1613,27 +1626,36 @@ Statement* Parser::ParseExportDefault(bool* ok) { |
ZoneList<const AstRawString*> names(1, zone()); |
Statement* result = nullptr; |
Expression* default_export = nullptr; |
+ |
+ // Allow ambient function and class declarations to be exported as default. |
+ int ambient_pos = peek_position(); |
+ bool ambient = |
+ scope_->typed() && CheckContextualKeyword(CStrVector("declare")); |
+ |
switch (peek()) { |
case Token::FUNCTION: { |
Consume(Token::FUNCTION); |
int pos = position(); |
bool is_generator = Check(Token::MUL); |
- if (peek() == Token::LPAREN || (scope_->typed() && Check(Token::LT))) { |
+ if (peek() == Token::LPAREN || (scope_->typed() && peek() == Token::LT)) { |
// FunctionDeclaration[+Default] :: |
// 'function' '(' FormalParameters ')' '{' FunctionBody '}' |
// |
// GeneratorDeclaration[+Default] :: |
// 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}' |
- default_export = ParseFunctionLiteral( |
- default_string, Scanner::Location::invalid(), |
- kSkipFunctionNameCheck, |
- is_generator ? FunctionKind::kGeneratorFunction |
- : FunctionKind::kNormalFunction, |
- pos, FunctionLiteral::kDeclaration, language_mode(), |
- typesystem::kAllowSignature, CHECK_OK); |
+ typesystem::TypeFlags type_flags = |
+ ambient ? typesystem::kAmbient : typesystem::kAllowSignature; |
+ default_export = |
+ ParseFunctionLiteral(default_string, Scanner::Location::invalid(), |
+ kSkipFunctionNameCheck, |
+ is_generator ? FunctionKind::kGeneratorFunction |
+ : FunctionKind::kNormalFunction, |
+ pos, FunctionLiteral::kDeclaration, |
+ language_mode(), type_flags, CHECK_OK); |
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
} else { |
- result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK); |
+ result = ParseFunctionDeclaration(pos, is_generator, &names, ambient, |
+ CHECK_OK); |
} |
break; |
} |
@@ -1645,14 +1667,21 @@ Statement* Parser::ParseExportDefault(bool* ok) { |
// 'class' ('extends' LeftHandExpression)? '{' ClassBody '}' |
default_export = |
ParseClassLiteral(default_string, Scanner::Location::invalid(), |
- false, position(), CHECK_OK); |
+ false, position(), ambient, CHECK_OK); |
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
} else { |
- result = ParseClassDeclaration(&names, CHECK_OK); |
+ result = ParseClassDeclaration(&names, ambient, CHECK_OK); |
} |
break; |
default: { |
+ if (ambient) { |
+ *ok = false; |
+ ReportMessageAt(scanner()->peek_location(), |
+ MessageTemplate::kBadAmbientDeclaration); |
+ return nullptr; |
+ } |
+ |
int pos = peek_position(); |
ExpressionClassifier classifier(this); |
Expression* expr = ParseAssignmentExpression(true, &classifier, CHECK_OK); |
@@ -1664,6 +1693,9 @@ Statement* Parser::ParseExportDefault(bool* ok) { |
} |
} |
+ // Exported ambients are not checked. |
+ if (ambient) return factory()->NewEmptyStatement(ambient_pos); |
+ |
DCHECK_LE(names.length(), 1); |
if (names.length() == 1) { |
scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok); |
@@ -1693,8 +1725,19 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { |
int pos = peek_position(); |
Expect(Token::EXPORT, CHECK_OK); |
+ // Allow exported ambient variable, function, and class declarations. |
+ bool ambient = |
+ scope_->typed() && CheckContextualKeyword(CStrVector("declare")); |
+ |
Statement* result = NULL; |
ZoneList<const AstRawString*> names(1, zone()); |
+ if (ambient && (peek() == Token::DEFAULT || peek() == Token::MUL || |
+ peek() == Token::LBRACE)) { |
+ *ok = false; |
+ ReportMessageAt(scanner()->peek_location(), |
+ MessageTemplate::kBadAmbientDeclaration); |
+ return nullptr; |
+ } |
switch (peek()) { |
case Token::DEFAULT: |
return ParseExportDefault(ok); |
@@ -1762,18 +1805,19 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { |
} |
case Token::FUNCTION: |
- result = ParseFunctionDeclaration(&names, CHECK_OK); |
+ result = ParseFunctionDeclaration(&names, ambient, CHECK_OK); |
break; |
case Token::CLASS: |
Consume(Token::CLASS); |
- result = ParseClassDeclaration(&names, CHECK_OK); |
+ result = ParseClassDeclaration(&names, ambient, CHECK_OK); |
break; |
case Token::VAR: |
case Token::LET: |
case Token::CONST: |
- result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK); |
+ result = |
+ ParseVariableStatement(kStatementListItem, &names, ambient, CHECK_OK); |
break; |
default: |
@@ -1782,6 +1826,9 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { |
return NULL; |
} |
+ // Exported ambients are not checked. |
+ if (ambient) return factory()->NewEmptyStatement(pos); |
+ |
// Extract declared names into export declarations. |
ModuleDescriptor* descriptor = scope_->module(); |
for (int i = 0; i < names.length(); ++i) { |
@@ -1899,7 +1946,7 @@ Statement* Parser::ParseSubStatement( |
return ParseDebuggerStatement(ok); |
case Token::VAR: |
- return ParseVariableStatement(kStatement, NULL, ok); |
+ return ParseVariableStatement(kStatement, NULL, false, ok); |
default: |
return ParseExpressionOrLabelledStatement(labels, allow_function, ok); |
@@ -2142,17 +2189,17 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { |
Statement* Parser::ParseFunctionDeclaration( |
- ZoneList<const AstRawString*>* names, bool* ok) { |
+ ZoneList<const AstRawString*>* names, bool ambient, bool* ok) { |
Expect(Token::FUNCTION, CHECK_OK); |
int pos = position(); |
bool is_generator = Check(Token::MUL); |
- return ParseFunctionDeclaration(pos, is_generator, names, ok); |
+ return ParseFunctionDeclaration(pos, is_generator, names, ambient, ok); |
} |
Statement* Parser::ParseFunctionDeclaration( |
int pos, bool is_generator, ZoneList<const AstRawString*>* names, |
- bool* ok) { |
+ bool ambient, bool* ok) { |
// FunctionDeclaration :: |
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}' |
// GeneratorDeclaration :: |
@@ -2165,6 +2212,8 @@ Statement* Parser::ParseFunctionDeclaration( |
FuncNameInferrer::State fni_state(fni_); |
if (fni_ != NULL) fni_->PushEnclosingName(name); |
+ typesystem::TypeFlags type_flags = |
+ ambient ? typesystem::kAmbient : typesystem::kAllowSignature; |
FunctionLiteral* fun = |
ParseFunctionLiteral(name, scanner()->location(), |
is_strict_reserved ? kFunctionNameIsStrictReserved |
@@ -2172,7 +2221,7 @@ Statement* Parser::ParseFunctionDeclaration( |
is_generator ? FunctionKind::kGeneratorFunction |
: FunctionKind::kNormalFunction, |
pos, FunctionLiteral::kDeclaration, language_mode(), |
- typesystem::kAllowSignature, CHECK_OK); |
+ type_flags, CHECK_OK); |
// Return no function declaration if just the signature was given. |
EmptyStatement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
if (fun == nullptr) return empty; |
@@ -2205,7 +2254,7 @@ Statement* Parser::ParseFunctionDeclaration( |
Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, |
- bool* ok) { |
+ bool ambient, bool* ok) { |
// ClassDeclaration :: |
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}' |
// |
@@ -2231,8 +2280,10 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, |
bool is_strict_reserved = false; |
const AstRawString* name = |
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); |
- ClassLiteral* value = ParseClassLiteral(name, scanner()->location(), |
- is_strict_reserved, pos, CHECK_OK); |
+ ClassLiteral* value = ParseClassLiteral( |
+ name, scanner()->location(), is_strict_reserved, pos, ambient, CHECK_OK); |
+ // Return no class declaration in case of an ambient. |
+ if (ambient) return factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
VariableProxy* proxy = NewUnresolved(name, LET); |
Declaration* declaration = |
@@ -2302,7 +2353,7 @@ Block* Parser::DeclarationParsingResult::BuildInitializationBlock( |
Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
ZoneList<const AstRawString*>* names, |
- bool* ok) { |
+ bool ambient, bool* ok) { |
// VariableStatement :: |
// VariableDeclarations ';' |
@@ -2319,8 +2370,8 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
// is inside an initializer block, it is ignored. |
DeclarationParsingResult parsing_result; |
- Block* result = |
- ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK); |
+ Block* result = ParseVariableDeclarations(var_context, &parsing_result, names, |
+ ambient, CHECK_OK); |
ExpectSemicolon(CHECK_OK); |
return result; |
} |
@@ -2328,7 +2379,7 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
Block* Parser::ParseVariableDeclarations( |
VariableDeclarationContext var_context, |
DeclarationParsingResult* parsing_result, |
- ZoneList<const AstRawString*>* names, bool* ok) { |
+ ZoneList<const AstRawString*>* names, bool ambient, bool* ok) { |
// VariableDeclarations :: |
// ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] |
// |
@@ -2400,6 +2451,12 @@ Block* Parser::ParseVariableDeclarations( |
} |
USE(type); // TODO(nikolaos): really use it! |
+ // Skip initializers, for ambient declarations. |
+ if (ambient) { |
+ first_declaration = false; |
+ continue; |
+ } |
+ |
Scanner::Location variable_loc = scanner()->location(); |
const AstRawString* single_name = |
pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name() |
@@ -2557,7 +2614,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement( |
// ES#sec-labelled-function-declarations Labelled Function Declarations |
if (peek() == Token::FUNCTION && is_sloppy(language_mode())) { |
if (allow_function == kAllowLabelledFunctionStatement) { |
- return ParseFunctionDeclaration(labels, ok); |
+ return ParseFunctionDeclaration(labels, false, ok); |
} else { |
return ParseScopedStatement(labels, true, ok); |
} |
@@ -3560,7 +3617,7 @@ Statement* Parser::ParseScopedStatement(ZoneList<const AstRawString*>* labels, |
Scope* body_scope = NewScope(scope_, BLOCK_SCOPE); |
BlockState block_state(&scope_, body_scope); |
Block* block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); |
- Statement* body = ParseFunctionDeclaration(NULL, CHECK_OK); |
+ Statement* body = ParseFunctionDeclaration(NULL, false, CHECK_OK); |
block->statements()->Add(body, zone()); |
body_scope->set_end_position(scanner()->location().end_pos); |
body_scope = body_scope->FinalizeBlockScope(); |
@@ -3587,7 +3644,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
if (peek() != Token::SEMICOLON) { |
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || |
(peek() == Token::LET && IsNextLetKeyword())) { |
- ParseVariableDeclarations(kForStatement, &parsing_result, nullptr, |
+ ParseVariableDeclarations(kForStatement, &parsing_result, nullptr, false, |
CHECK_OK); |
ForEachStatement::VisitMode mode = ForEachStatement::ENUMERATE; |
@@ -4225,10 +4282,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
} |
USE(result_type); // TODO(nikolaos): really use it! |
- // Allow for a function signature (i.e., a literal without body). |
+ // Allow or even enforce a function signature (i.e., literal without body), |
// In that case, return a nullptr instead of a function literal. |
- if (peek() != Token::LBRACE && scope_->typed() && |
- (type_flags & typesystem::kAllowSignature)) { |
+ if ((type_flags & typesystem::kDisallowBody) || |
+ (peek() != Token::LBRACE && scope_->typed() && |
+ (type_flags & typesystem::kAllowSignature))) { |
ExpectSemicolon(CHECK_OK); |
return nullptr; |
} |
@@ -4807,7 +4865,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( |
ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, |
Scanner::Location class_name_location, |
bool name_is_strict_reserved, int pos, |
- bool* ok) { |
+ bool ambient, bool* ok) { |
// All parts of a ClassDeclaration and ClassExpression are strict code. |
if (name_is_strict_reserved) { |
ReportMessageAt(class_name_location, |
@@ -4894,8 +4952,9 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, |
const AstRawString* property_name = nullptr; |
ObjectLiteral::Property* property = ParsePropertyDefinition( |
&checker, in_class, has_extends, is_static, &is_computed_name, |
- &has_seen_constructor, &classifier, &property_name, CHECK_OK); |
- // Ignore member variable declarations in typed mode. |
+ &has_seen_constructor, &classifier, &property_name, ambient, CHECK_OK); |
+ // Ignore member variable declarations, method signatures and members of |
+ // ambients in typed mode. |
if (property == nullptr) continue; |
RewriteNonPattern(&classifier, CHECK_OK); |