Scope* Parser::NewScope(Scope* parent, ScopeType scope_type) {
DCHECK(ast_value_factory());
+ DCHECK(scope_type != MODULE_SCOPE || allow_harmony_modules());
Scope* result = new (zone())
Scope(isolate(), zone(), parent, scope_type, ast_value_factory());
result->Initialize();
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
bool ok = true;
int beg_pos = scanner()->location().beg_pos;
- ParseSourceElements(body, Token::EOS, info->is_eval(), true, eval_scope,
- &ok);
+ if (info->is_module()) {
+ DCHECK(allow_harmony_modules());
+ Module* module = ParseModule(&ok);
+ if (ok) {
+ // TODO(adamk): Do something with returned Module
+ CHECK(module);
+ body->Add(factory()->NewEmptyStatement(RelocInfo::kNoPosition), zone());
+ }
+ } else {
+ ParseStatementList(body, Token::EOS, info->is_eval(), eval_scope, &ok);
+ }
if (ok && strict_mode() == STRICT) {
CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
}
-void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
- int end_token, bool is_eval, bool is_global,
- Scope** eval_scope, bool* ok) {
- // SourceElements ::
- // (ModuleElement)* <end_token>
+void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
+ bool is_eval, Scope** eval_scope, bool* ok) {
+ // StatementList ::
+ // (StatementListItem)* <end_token>
// Allocate a target stack to use for this set of source
// elements. This way, all scripts and functions get their own
// functions.
TargetScope scope(&this->target_stack_);
- DCHECK(processor != NULL);
+ DCHECK(body != NULL);
bool directive_prologue = true; // Parsing directive prologue.
while (peek() != end_token) {
}
Scanner::Location token_loc = scanner()->peek_location();
- Statement* stat;
- if (is_global && !is_eval) {
- stat = ParseModuleElement(NULL, CHECK_OK);
- } else {
- stat = ParseBlockElement(NULL, CHECK_OK);
- }
+ Statement* stat = ParseStatementListItem(CHECK_OK);
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
}
}
- processor->Add(stat, zone());
+ body->Add(stat, zone());
}
return 0;
}
-Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels,
- bool* ok) {
- // (Ecma 262 5th Edition, clause 14):
- // SourceElement:
+Statement* Parser::ParseStatementListItem(bool* ok) {
+ // (Ecma 262 6th Edition, 13.1):
+ // StatementListItem:
// Statement
- // FunctionDeclaration
- //
- // In harmony mode we allow additionally the following productions
- // ModuleElement:
- // LetDeclaration
- // ConstDeclaration
- // ModuleDeclaration
- // ImportDeclaration
- // ExportDeclaration
- // GeneratorDeclaration
+ // Declaration
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
case Token::CLASS:
return ParseClassDeclaration(NULL, ok);
- case Token::IMPORT:
- return ParseImportDeclaration(ok);
- case Token::EXPORT:
- return ParseExportDeclaration(ok);
case Token::CONST:
- return ParseVariableStatement(kModuleElement, NULL, ok);
+ case Token::VAR:
+ return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::LET:
DCHECK(allow_harmony_scoping());
if (strict_mode() == STRICT) {
- return ParseVariableStatement(kModuleElement, NULL, ok);
+ return ParseVariableStatement(kStatementListItem, NULL, ok);
}
// Fall through.
- default: {
- Statement* stmt = ParseStatement(labels, CHECK_OK);
- // Handle 'module' as a context-sensitive keyword.
- if (FLAG_harmony_modules &&
- peek() == Token::IDENTIFIER &&
- !scanner()->HasAnyLineTerminatorBeforeNext() &&
- stmt != NULL) {
- ExpressionStatement* estmt = stmt->AsExpressionStatement();
- if (estmt != NULL && estmt->expression()->AsVariableProxy() != NULL &&
- estmt->expression()->AsVariableProxy()->raw_name() ==
- ast_value_factory()->module_string() &&
- !scanner()->literal_contains_escapes()) {
- return ParseModuleDeclaration(NULL, ok);
- }
- }
- return stmt;
- }
- }
-}
-
-
-Statement* Parser::ParseModuleDeclaration(ZoneList<const AstRawString*>* names,
- bool* ok) {
- // ModuleDeclaration:
- // 'module' Identifier Module
-
- int pos = peek_position();
- const AstRawString* name =
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
-
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Module %.*s ", name->length(), name->raw_data());
-#endif
-
- Module* module = ParseModule(CHECK_OK);
- VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface());
- Declaration* declaration =
- factory()->NewModuleDeclaration(proxy, module, scope_, pos);
- Declare(declaration, true, CHECK_OK);
-
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Module %.*s ", name->length(), name->raw_data());
- if (FLAG_print_interfaces) {
- PrintF("module %.*s: ", name->length(), name->raw_data());
- module->interface()->Print();
+ default:
+ return ParseStatement(NULL, ok);
}
-#endif
-
- if (names) names->Add(name, zone());
- if (module->body() == NULL)
- return factory()->NewEmptyStatement(pos);
- else
- return factory()->NewModuleStatement(proxy, module->body(), pos);
}
-Module* Parser::ParseModule(bool* ok) {
- // Module:
- // '{' ModuleElement '}'
- // '=' ModulePath ';'
- // 'at' String ';'
+Statement* Parser::ParseModuleItem(bool* ok) {
+ // (Ecma 262 6th Edition, 15.2):
+ // ModuleItem :
+ // ImportDeclaration
+ // ExportDeclaration
+ // StatementListItem
switch (peek()) {
- case Token::LBRACE:
- return ParseModuleLiteral(ok);
-
- case Token::ASSIGN: {
- Expect(Token::ASSIGN, CHECK_OK);
- Module* result = ParseModulePath(CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return result;
- }
-
- default: {
- ExpectContextualKeyword(CStrVector("at"), CHECK_OK);
- Module* result = ParseModuleUrl(CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return result;
- }
+ case Token::IMPORT:
+ return ParseImportDeclaration(ok);
+ case Token::EXPORT:
+ return ParseExportDeclaration(ok);
+ default:
+ return ParseStatementListItem(ok);
}
}
-Module* Parser::ParseModuleLiteral(bool* ok) {
- // Module:
- // '{' ModuleElement '}'
+Module* Parser::ParseModule(bool* ok) {
+ // (Ecma 262 6th Edition, 15.2):
+ // Module :
+ // ModuleBody?
+ //
+ // ModuleBody :
+ // ModuleItem*
int pos = peek_position();
// Construct block expecting 16 statements.
#endif
Scope* scope = NewScope(scope_, MODULE_SCOPE);
- Expect(Token::LBRACE, CHECK_OK);
scope->set_start_position(scanner()->location().beg_pos);
scope->SetStrictMode(STRICT);
BlockState block_state(&scope_, scope);
Target target(&this->target_stack_, body);
- while (peek() != Token::RBRACE) {
- Statement* stat = ParseModuleElement(NULL, CHECK_OK);
+ while (peek() != Token::EOS) {
+ Statement* stat = ParseModuleItem(CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat, zone());
}
}
}
- Expect(Token::RBRACE, CHECK_OK);
scope->set_end_position(scanner()->location().end_pos);
body->set_scope(scope);
}
-Module* Parser::ParseModulePath(bool* ok) {
- // ModulePath:
- // Identifier
- // ModulePath '.' Identifier
-
- int pos = peek_position();
- Module* result = ParseModuleVariable(CHECK_OK);
- while (Check(Token::PERIOD)) {
- const AstRawString* name = ParseIdentifierName(CHECK_OK);
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Path .%.*s ", name->length(), name->raw_data());
-#endif
- Module* member = factory()->NewModulePath(result, name, pos);
- result->interface()->Add(name, member->interface(), zone(), ok);
- if (!*ok) {
-#ifdef DEBUG
- if (FLAG_print_interfaces) {
- PrintF("PATH TYPE ERROR at '%.*s'\n", name->length(), name->raw_data());
- PrintF("result: ");
- result->interface()->Print();
- PrintF("member: ");
- member->interface()->Print();
- }
-#endif
- ParserTraits::ReportMessage("invalid_module_path", name);
- return NULL;
- }
- result = member;
- }
-
- return result;
-}
-
-
-Module* Parser::ParseModuleVariable(bool* ok) {
- // ModulePath:
- // Identifier
-
- int pos = peek_position();
- const AstRawString* name =
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Module variable %.*s ", name->length(), name->raw_data());
-#endif
- VariableProxy* proxy = scope_->NewUnresolved(
- factory(), name, Interface::NewModule(zone()),
- scanner()->location().beg_pos);
-
- return factory()->NewModuleVariable(proxy, pos);
-}
-
-
Module* Parser::ParseModuleUrl(bool* ok) {
// Module:
// String
}
-Module* Parser::ParseModuleSpecifier(bool* ok) {
- // ModuleSpecifier:
- // String
- // ModulePath
-
- if (peek() == Token::STRING) {
- return ParseModuleUrl(ok);
- } else {
- return ParseModulePath(ok);
- }
-}
-
-
-Block* Parser::ParseImportDeclaration(bool* ok) {
+Statement* Parser::ParseImportDeclaration(bool* ok) {
// ImportDeclaration:
- // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
+ // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleUrl ';'
//
- // TODO(ES6): implement destructuring ImportSpecifiers
+ // TODO(ES6): implement current syntax
int pos = peek_position();
Expect(Token::IMPORT, CHECK_OK);
}
ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
- Module* module = ParseModuleSpecifier(CHECK_OK);
+ Module* module = ParseModuleUrl(CHECK_OK);
ExpectSemicolon(CHECK_OK);
- // Generate a separate declaration for each identifier.
- // TODO(ES6): once we implement destructuring, make that one declaration.
- Block* block = factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+ // TODO(ES6): Do something with ParseModuleUrl's return value.
+ USE(module);
+
for (int i = 0; i < names.length(); ++i) {
-#ifdef DEBUG
- if (FLAG_print_interface_details)
- PrintF("# Import %.*s ", name->length(), name->raw_data());
-#endif
- Interface* interface = Interface::NewUnknown(zone());
- module->interface()->Add(names[i], interface, zone(), ok);
- if (!*ok) {
-#ifdef DEBUG
- if (FLAG_print_interfaces) {
- PrintF("IMPORT TYPE ERROR at '%.*s'\n", name->length(),
- name->raw_data());
- PrintF("module: ");
- module->interface()->Print();
- }
-#endif
- ParserTraits::ReportMessage("invalid_module_path", name);
- return NULL;
- }
- VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
- Declaration* declaration =
- factory()->NewImportDeclaration(proxy, module, scope_, pos);
- Declare(declaration, true, CHECK_OK);
+ // TODO(ES6): Add an appropriate declaration for each name
}
- return block;
+ return factory()->NewEmptyStatement(pos);
}
// 'export' GeneratorDeclaration
// 'export' ModuleDeclaration
//
- // TODO(ES6): implement structuring ExportSpecifiers
+ // TODO(ES6): implement current syntax
Expect(Token::EXPORT, CHECK_OK);
int pos = position();
const AstRawString* name =
ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
- // Handle 'module' as a context-sensitive keyword.
- if (name != ast_value_factory()->module_string()) {
+ names.Add(name, zone());
+ while (peek() == Token::COMMA) {
+ Consume(Token::COMMA);
+ name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
names.Add(name, zone());
- while (peek() == Token::COMMA) {
- Consume(Token::COMMA);
- name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
- names.Add(name, zone());
- }
- ExpectSemicolon(CHECK_OK);
- result = factory()->NewEmptyStatement(pos);
- } else {
- result = ParseModuleDeclaration(&names, CHECK_OK);
}
+ ExpectSemicolon(CHECK_OK);
+ result = factory()->NewEmptyStatement(pos);
break;
}
case Token::VAR:
case Token::LET:
case Token::CONST:
- result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
+ result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
break;
default:
}
-Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels,
- bool* ok) {
- // (Ecma 262 5th Edition, clause 14):
- // SourceElement:
- // Statement
- // FunctionDeclaration
- //
- // In harmony mode we allow additionally the following productions
- // BlockElement (aka SourceElement):
- // LetDeclaration
- // ConstDeclaration
- // GeneratorDeclaration
- // ClassDeclaration
-
- switch (peek()) {
- case Token::FUNCTION:
- return ParseFunctionDeclaration(NULL, ok);
- case Token::CLASS:
- return ParseClassDeclaration(NULL, ok);
- case Token::CONST:
- return ParseVariableStatement(kModuleElement, NULL, ok);
- case Token::LET:
- DCHECK(allow_harmony_scoping());
- if (strict_mode() == STRICT) {
- return ParseVariableStatement(kModuleElement, NULL, ok);
- }
- // Fall through.
- default:
- return ParseStatement(labels, ok);
- }
-}
-
-
Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
// Statement ::
Target target(&this->target_stack_, body);
while (peek() != Token::RBRACE) {
- Statement* stat = ParseBlockElement(NULL, CHECK_OK);
+ Statement* stat = ParseStatementListItem(CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat, zone());
}
return ParseNativeDeclaration(ok);
}
- // Parsed expression statement, or the context-sensitive 'module' keyword.
- // Only expect semicolon in the former case.
- // Also detect attempts at 'let' declarations in sloppy mode.
- if (!FLAG_harmony_modules || peek() != Token::IDENTIFIER ||
- scanner()->HasAnyLineTerminatorBeforeNext() ||
- expr->AsVariableProxy() == NULL ||
- expr->AsVariableProxy()->raw_name() !=
- ast_value_factory()->module_string() ||
- scanner()->literal_contains_escapes()) {
- if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
- expr->AsVariableProxy()->raw_name() ==
- ast_value_factory()->let_string()) {
- ReportMessage("sloppy_lexical", NULL);
- *ok = false;
- return NULL;
- }
- ExpectSemicolon(CHECK_OK);
+ // Parsed expression statement, followed by semicolon.
+ // Detect attempts at 'let' declarations in sloppy mode.
+ if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
+ expr->AsVariableProxy()->raw_name() ==
+ ast_value_factory()->let_string()) {
+ ReportMessage("sloppy_lexical", NULL);
+ *ok = false;
+ return NULL;
}
+ ExpectSemicolon(CHECK_OK);
return factory()->NewExpressionStatement(expr, pos);
}
yield, RelocInfo::kNoPosition), zone());
}
- ParseSourceElements(body, Token::RBRACE, false, false, NULL, CHECK_OK);
+ ParseStatementList(body, Token::RBRACE, false, NULL, CHECK_OK);
if (is_generator) {
VariableProxy* get_proxy = factory()->NewVariableProxy(
// Flags: --harmony-modules
-// Test basic module syntax, with and without automatic semicolon insertion.
-
-module A {}
-
-module A1 = A
-module A2 = A;
-module A3 = A2
-
-module B {
- export vx
- export vy, lz, c, f
-
- var vx
- var vx, vy;
- var vx = 0, vy
- let lx, ly
- let lz = 1
- const c = 9
- function f() {}
-
- module C0 {}
-
- export module C {
- let x
- export module D { export let x }
- let y
- }
-
- let zz = ""
-
- export var x0
- export var x1, x2 = 6, x3
- export let y0
- export let y1 = 0, y2
- export const z0 = 0
- export const z1 = 2, z2 = 3
- export function f0() {}
- export module M1 {}
- export module M2 = C.D
- export module M3 at "http://where"
-
- import i0 from I
- import i1, i2, i3, M from I
- //import i4, i5 from "http://where"
-}
-
-module I {
- export let i0, i1, i2, i3;
- export module M {}
-}
-
-module C1 = B.C;
-module D1 = B.C.D
-module D2 = C1.D
-module D3 = D2
-
-module E1 at "http://where"
-module E2 at "http://where";
-module E3 = E1
-
-// Check that ASI does not interfere.
-
-module X
-{
-let x
-}
-
-module Y
-=
-X
-
-module Z
-at
-"file://local"
-
-import
-vx
-,
-vy
-from
-B
-
-
-module Wrap {
-export
-x
-,
-y
-
-var
-x
-,
-y
-
-export
-var
-v1 = 1
-
-export
-let
-v2 = 2
-
-export
-const
-v3 = 3
-
-export
-function
-f
-(
-)
-{
-}
-
-export
-module V
-{
-}
-}
-
-export A, A1, A2, A3, B, I, C1, D1, D2, D3, E1, E2, E3, X, Y, Z, Wrap, x, y, UU
-
-
-
-// Check that 'module' still works as an identifier.
-
-var module
-module = {}
-module["a"] = 6
-function module() {}
-function f(module) { return module }
-try {} catch (module) {}
-
-module
-v = 20
-
-
-
-// Check that module declarations are rejected in eval or local scope.
-
-module M { export let x; }
-
-assertThrows("export x;", SyntaxError); // It's using eval, so should throw.
+// Check that import/export declarations are rejected in eval or local scope.
+assertThrows("export x;", SyntaxError);
assertThrows("export let x;", SyntaxError);
-assertThrows("import x from M;", SyntaxError);
-assertThrows("module M {};", SyntaxError);
+assertThrows("import x from 'http://url';", SyntaxError);
assertThrows("{ export x; }", SyntaxError);
assertThrows("{ export let x; }", SyntaxError);
-assertThrows("{ import x from M; }", SyntaxError);
-assertThrows("{ module M {}; }", SyntaxError);
+assertThrows("{ import x from 'http://url'; }", SyntaxError);
assertThrows("function f() { export x; }", SyntaxError);
assertThrows("function f() { export let x; }", SyntaxError);
-assertThrows("function f() { import x from M; }", SyntaxError);
-assertThrows("function f() { module M {}; }", SyntaxError);
+assertThrows("function f() { import x from 'http://url'; }", SyntaxError);
assertThrows("function f() { { export x; } }", SyntaxError);
assertThrows("function f() { { export let x; } }", SyntaxError);
-assertThrows("function f() { { import x from M; } }", SyntaxError);
-assertThrows("function f() { { module M {}; } }", SyntaxError);
+assertThrows("function f() { { import x from 'http://url'; } }", SyntaxError);