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