Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Unified Diff: src/parsing/parser.cc

Issue 1871923003: Add parsing for ambient declarations (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@types-devel
Patch Set: Minor fixes to address code review comments Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | src/parsing/preparser.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698