Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 3b9b69b4fac4d4a1ac5ae5614f0422fa12954953..3dfab294c8b4610c98c3db3edeac3469c8d767ba 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -654,6 +654,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, |
return result; |
} |
+ |
FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) { |
ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT); |
HistogramTimerScope timer(isolate()->counters()->parse_lazy()); |
@@ -1087,32 +1088,11 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder { |
}; |
-Statement* Parser::ParseSourceElement(ZoneStringList* labels, |
- bool* ok) { |
- // (Ecma 262 5th Edition, clause 14): |
- // SourceElement: |
- // Statement |
- // FunctionDeclaration |
- // |
- // In harmony mode we allow additionally the following productions |
- // SourceElement: |
- // LetDeclaration |
- // ConstDeclaration |
- |
- if (peek() == Token::FUNCTION) { |
- return ParseFunctionDeclaration(ok); |
- } else if (peek() == Token::LET || peek() == Token::CONST) { |
- return ParseVariableStatement(kSourceElement, ok); |
- } |
- return ParseStatement(labels, ok); |
-} |
- |
- |
void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, |
int end_token, |
bool* ok) { |
// SourceElements :: |
- // (SourceElement)* <end_token> |
+ // (ModuleElement)* <end_token> |
// Allocate a target stack to use for this set of source |
// elements. This way, all scripts and functions get their own |
@@ -1131,7 +1111,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, |
} |
Scanner::Location token_loc = scanner().peek_location(); |
- Statement* stat = ParseSourceElement(NULL, CHECK_OK); |
+ Statement* stat = ParseModuleElement(NULL, CHECK_OK); |
if (stat == NULL || stat->IsEmpty()) { |
directive_prologue = false; // End of directive prologue. |
continue; |
@@ -1187,6 +1167,194 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, |
} |
+Statement* Parser::ParseModuleElement(ZoneStringList* labels, |
+ bool* ok) { |
+ // (Ecma 262 5th Edition, clause 14): |
+ // SourceElement: |
+ // Statement |
+ // FunctionDeclaration |
+ // |
+ // In harmony mode we allow additionally the following productions |
+ // ModuleElement: |
+ // LetDeclaration |
+ // ConstDeclaration |
+ // ModuleDeclaration |
+ // ImportDeclaration |
+ // ExportDeclaration |
+ |
+ switch (peek()) { |
+ case Token::FUNCTION: |
+ return ParseFunctionDeclaration(ok); |
+ case Token::LET: |
+ case Token::CONST: |
+ return ParseVariableStatement(kModuleElement, ok); |
+ case Token::MODULE: |
+ return ParseModuleDeclaration(ok); |
+ case Token::IMPORT: |
+ return ParseImportDeclaration(ok); |
+ case Token::EXPORT: |
+ return ParseExportDeclaration(ok); |
+ default: |
+ return ParseStatement(labels, ok); |
+ } |
+} |
+ |
+ |
+Block* Parser::ParseModuleDeclaration(bool* ok) { |
+ // ModuleDeclaration: |
+ // 'module' Identifier Module |
+ |
+ // Create new block with one expected declaration. |
+ Block* block = factory()->NewBlock(NULL, 1, true); |
+ Expect(Token::MODULE, CHECK_OK); |
+ Handle<String> name = ParseIdentifier(CHECK_OK); |
+ // top_scope_->AddDeclaration( |
+ // factory()->NewModuleDeclaration(proxy, module, top_scope_)); |
+ VariableProxy* proxy = Declare(name, LET, NULL, true, CHECK_OK); |
+ Module* module = ParseModule(ok); |
+ // TODO(rossberg): Add initialization statement to block. |
+ USE(proxy); |
+ USE(module); |
+ return block; |
+} |
+ |
+ |
+Module* Parser::ParseModule(bool* ok) { |
+ // Module: |
+ // '{' ModuleElement '}' |
+ // '=' ModulePath |
+ // 'at' String |
+ |
+ switch (peek()) { |
+ case Token::LBRACE: |
+ return ParseModuleLiteral(ok); |
+ |
+ case Token::ASSIGN: |
+ Expect(Token::ASSIGN, CHECK_OK); |
+ return ParseModulePath(ok); |
+ |
+ default: |
+ return ParseModuleUrl(ok); |
+ } |
+} |
+ |
+ |
+Module* Parser::ParseModuleLiteral(bool* ok) { |
+ // Module: |
+ // '{' ModuleElement '}' |
+ |
+ // Construct block expecting 16 statements. |
+ Block* body = factory()->NewBlock(NULL, 16, false); |
+ Scope* scope = NewScope(top_scope_, MODULE_SCOPE); |
+ |
+ Expect(Token::LBRACE, CHECK_OK); |
+ scope->set_start_position(scanner().location().beg_pos); |
+ scope->SetLanguageMode(EXTENDED_MODE); |
+ |
+ { |
+ BlockState block_state(this, scope); |
+ TargetCollector collector; |
+ Target target(&this->target_stack_, &collector); |
+ Target target_body(&this->target_stack_, body); |
+ InitializationBlockFinder block_finder(top_scope_, target_stack_); |
+ |
+ while (peek() != Token::RBRACE) { |
+ Statement* stat = ParseModuleElement(NULL, CHECK_OK); |
+ if (stat && !stat->IsEmpty()) { |
+ body->AddStatement(stat); |
+ block_finder.Update(stat); |
+ } |
+ } |
+ } |
+ |
+ Expect(Token::RBRACE, CHECK_OK); |
+ scope->set_end_position(scanner().location().end_pos); |
+ body->set_block_scope(scope); |
+ return factory()->NewModuleLiteral(body); |
+} |
+ |
+ |
+Module* Parser::ParseModulePath(bool* ok) { |
+ // ModulePath: |
+ // Identifier |
+ // ModulePath '.' Identifier |
+ |
+ Module* result = ParseModuleVariable(CHECK_OK); |
+ |
+ while (Check(Token::PERIOD)) { |
+ Handle<String> name = ParseIdentifierName(CHECK_OK); |
+ result = factory()->NewModulePath(result, name); |
+ } |
+ |
+ return result; |
+} |
+ |
+ |
+Module* Parser::ParseModuleVariable(bool* ok) { |
+ // ModulePath: |
+ // Identifier |
+ |
+ Handle<String> name = ParseIdentifier(CHECK_OK); |
+ VariableProxy* proxy = top_scope_->NewUnresolved( |
+ factory(), name, scanner().location().beg_pos); |
+ return factory()->NewModuleVariable(proxy); |
+} |
+ |
+ |
+Module* Parser::ParseModuleUrl(bool* ok) { |
+ // Module: |
+ // 'at' String |
+ |
+ Expect(Token::IDENTIFIER, CHECK_OK); |
+ Handle<String> symbol = GetSymbol(CHECK_OK); |
+ if (!symbol->IsEqualTo(CStrVector("at"))) { |
+ *ok = false; |
+ ReportUnexpectedToken(scanner().current_token()); |
+ return NULL; |
+ } |
+ Expect(Token::STRING, CHECK_OK); |
+ symbol = GetSymbol(CHECK_OK); |
Lasse Reichstein Nielsen
2012/02/21 13:46:02
Great! :)
|
+ |
+ return factory()->NewModuleUrl(symbol); |
+} |
+ |
+ |
+Block* Parser::ParseImportDeclaration(bool* ok) { |
+ // TODO(rossberg) |
+ return NULL; |
+} |
+ |
+ |
+Block* Parser::ParseExportDeclaration(bool* ok) { |
+ // TODO(rossberg) |
+ return NULL; |
+} |
+ |
+ |
+Statement* Parser::ParseBlockElement(ZoneStringList* 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 |
+ |
+ switch (peek()) { |
+ case Token::FUNCTION: |
+ return ParseFunctionDeclaration(ok); |
+ case Token::LET: |
+ case Token::CONST: |
+ return ParseVariableStatement(kModuleElement, ok); |
+ default: |
+ return ParseStatement(labels, ok); |
+ } |
+} |
+ |
+ |
Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { |
// Statement :: |
// Block |
@@ -1344,7 +1512,8 @@ VariableProxy* Parser::Declare(Handle<String> name, |
// statically declared. |
if (declaration_scope->is_function_scope() || |
declaration_scope->is_strict_or_extended_eval_scope() || |
- declaration_scope->is_block_scope()) { |
+ declaration_scope->is_block_scope() || |
+ declaration_scope->is_module_scope()) { |
// Declare the variable in the function scope. |
var = declaration_scope->LocalLookup(name); |
if (var == NULL) { |
@@ -1574,10 +1743,10 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { |
Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { |
- // The harmony mode uses source elements instead of statements. |
+ // The harmony mode uses block elements instead of statements. |
// |
// Block :: |
- // '{' SourceElement* '}' |
+ // '{' BlockElement* '}' |
// Construct block expecting 16 statements. |
Block* body = factory()->NewBlock(labels, 16, false); |
@@ -1593,7 +1762,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { |
InitializationBlockFinder block_finder(top_scope_, target_stack_); |
while (peek() != Token::RBRACE) { |
- Statement* stat = ParseSourceElement(NULL, CHECK_OK); |
+ Statement* stat = ParseBlockElement(NULL, CHECK_OK); |
if (stat && !stat->IsEmpty()) { |
body->AddStatement(stat); |
block_finder.Update(stat); |
@@ -1614,10 +1783,8 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
// VariableDeclarations ';' |
Handle<String> ignore; |
- Block* result = ParseVariableDeclarations(var_context, |
- NULL, |
- &ignore, |
- CHECK_OK); |
+ Block* result = |
+ ParseVariableDeclarations(var_context, NULL, &ignore, CHECK_OK); |
ExpectSemicolon(CHECK_OK); |
return result; |
} |
@@ -1684,8 +1851,7 @@ Block* Parser::ParseVariableDeclarations( |
*ok = false; |
return NULL; |
case EXTENDED_MODE: |
- if (var_context != kSourceElement && |
- var_context != kForStatement) { |
+ if (var_context == kStatement) { |
// In extended mode 'const' declarations are only allowed in source |
// element positions. |
ReportMessage("unprotected_const", Vector<const char*>::empty()); |
@@ -1710,10 +1876,8 @@ Block* Parser::ParseVariableDeclarations( |
return NULL; |
} |
Consume(Token::LET); |
- if (var_context != kSourceElement && |
- var_context != kForStatement) { |
+ if (var_context == kStatement) { |
// Let declarations are only allowed in source element positions. |
- ASSERT(var_context == kStatement); |
ReportMessage("unprotected_let", Vector<const char*>::empty()); |
*ok = false; |
return NULL; |
@@ -2453,10 +2617,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { |
Handle<String> name; |
VariableDeclarationProperties decl_props = kHasNoInitializers; |
Block* variable_statement = |
- ParseVariableDeclarations(kForStatement, |
- &decl_props, |
- &name, |
- CHECK_OK); |
+ ParseVariableDeclarations(kForStatement, &decl_props, &name, CHECK_OK); |
bool accept_IN = !name.is_null() && decl_props != kHasInitializers; |
if (peek() == Token::IN && accept_IN) { |
// Rewrite a for-in statement of the form |