Revision: 10866
Author: [email protected]
Date: Wed Feb 29 04:12:52 2012
Log: AST extensions and parsing for import & export declarations.
[email protected]
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com/9496003
http://code.google.com/p/v8/source/detail?r=10866
Modified:
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/full-codegen.cc
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/parser.cc
/branches/bleeding_edge/src/parser.h
/branches/bleeding_edge/src/prettyprinter.cc
/branches/bleeding_edge/src/rewriter.cc
/branches/bleeding_edge/test/mjsunit/harmony/module-parsing.js
=======================================
--- /branches/bleeding_edge/src/ast.cc Tue Feb 28 07:32:06 2012
+++ /branches/bleeding_edge/src/ast.cc Wed Feb 29 04:12:52 2012
@@ -1008,6 +1008,8 @@
INCREASE_NODE_COUNT(VariableDeclaration)
INCREASE_NODE_COUNT(FunctionDeclaration)
INCREASE_NODE_COUNT(ModuleDeclaration)
+INCREASE_NODE_COUNT(ImportDeclaration)
+INCREASE_NODE_COUNT(ExportDeclaration)
INCREASE_NODE_COUNT(ModuleLiteral)
INCREASE_NODE_COUNT(ModuleVariable)
INCREASE_NODE_COUNT(ModulePath)
=======================================
--- /branches/bleeding_edge/src/ast.h Tue Feb 28 07:32:06 2012
+++ /branches/bleeding_edge/src/ast.h Wed Feb 29 04:12:52 2012
@@ -63,6 +63,8 @@
V(VariableDeclaration) \
V(FunctionDeclaration) \
V(ModuleDeclaration) \
+ V(ImportDeclaration) \
+ V(ExportDeclaration) \
#define MODULE_NODE_LIST(V) \
V(ModuleLiteral) \
@@ -544,6 +546,48 @@
};
+class ImportDeclaration: public Declaration {
+ public:
+ DECLARE_NODE_TYPE(ImportDeclaration)
+
+ Module* module() const { return module_; }
+ virtual InitializationFlag initialization() const {
+ return kCreatedInitialized;
+ }
+
+ protected:
+ template<class> friend class AstNodeFactory;
+
+ ImportDeclaration(VariableProxy* proxy,
+ Module* module,
+ Scope* scope)
+ : Declaration(proxy, LET, scope),
+ module_(module) {
+ }
+
+ private:
+ Module* module_;
+};
+
+
+class ExportDeclaration: public Declaration {
+ public:
+ DECLARE_NODE_TYPE(ExportDeclaration)
+
+ virtual InitializationFlag initialization() const {
+ return kCreatedInitialized;
+ }
+
+ protected:
+ template<class> friend class AstNodeFactory;
+
+ ExportDeclaration(VariableProxy* proxy,
+ Scope* scope)
+ : Declaration(proxy, LET, scope) {
+ }
+};
+
+
class Module: public AstNode {
// TODO(rossberg): stuff to come...
protected:
@@ -2579,6 +2623,21 @@
new(zone_) ModuleDeclaration(proxy, module, scope);
VISIT_AND_RETURN(ModuleDeclaration, decl)
}
+
+ ImportDeclaration* NewImportDeclaration(VariableProxy* proxy,
+ Module* module,
+ Scope* scope) {
+ ImportDeclaration* decl =
+ new(zone_) ImportDeclaration(proxy, module, scope);
+ VISIT_AND_RETURN(ImportDeclaration, decl)
+ }
+
+ ExportDeclaration* NewExportDeclaration(VariableProxy* proxy,
+ Scope* scope) {
+ ExportDeclaration* decl =
+ new(zone_) ExportDeclaration(proxy, scope);
+ VISIT_AND_RETURN(ExportDeclaration, decl)
+ }
ModuleLiteral* NewModuleLiteral(Block* body) {
ModuleLiteral* module = new(zone_) ModuleLiteral(body);
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Tue Feb 28 02:12:39 2012
+++ /branches/bleeding_edge/src/full-codegen.cc Wed Feb 29 04:12:52 2012
@@ -63,6 +63,14 @@
ModuleDeclaration* decl) {
}
+void BreakableStatementChecker::VisitImportDeclaration(
+ ImportDeclaration* decl) {
+}
+
+void BreakableStatementChecker::VisitExportDeclaration(
+ ExportDeclaration* decl) {
+}
+
void BreakableStatementChecker::VisitModuleLiteral(ModuleLiteral* module) {
}
@@ -620,6 +628,16 @@
void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) {
EmitDeclaration(decl->proxy(), decl->mode(), NULL);
}
+
+
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
+ EmitDeclaration(decl->proxy(), decl->mode(), NULL);
+}
+
+
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
+ // TODO(rossberg)
+}
void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Tue Feb 28 07:32:58 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Wed Feb 29 04:12:52 2012
@@ -6932,7 +6932,17 @@
void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
- // TODO(rossberg)
+ UNREACHABLE();
+}
+
+
+void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
+ UNREACHABLE();
+}
+
+
+void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
+ UNREACHABLE();
}
=======================================
--- /branches/bleeding_edge/src/parser.cc Tue Feb 28 07:32:06 2012
+++ /branches/bleeding_edge/src/parser.cc Wed Feb 29 04:12:52 2012
@@ -1184,10 +1184,10 @@
switch (peek()) {
case Token::FUNCTION:
- return ParseFunctionDeclaration(ok);
+ return ParseFunctionDeclaration(NULL, ok);
case Token::LET:
case Token::CONST:
- return ParseVariableStatement(kModuleElement, ok);
+ return ParseVariableStatement(kModuleElement, NULL, ok);
case Token::IMPORT:
return ParseImportDeclaration(ok);
case Token::EXPORT:
@@ -1205,7 +1205,7 @@
estmt->expression()->AsVariableProxy()->name()->Equals(
isolate()->heap()->module_symbol()) &&
!scanner().literal_contains_escapes()) {
- return ParseModuleDeclaration(ok);
+ return ParseModuleDeclaration(NULL, ok);
}
}
return stmt;
@@ -1214,7 +1214,7 @@
}
-Block* Parser::ParseModuleDeclaration(bool* ok) {
+Block* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
// ModuleDeclaration:
// 'module' Identifier Module
@@ -1229,6 +1229,7 @@
// TODO(rossberg): Add initialization statement to block.
+ if (names) names->Add(name);
return block;
}
@@ -1236,19 +1237,26 @@
Module* Parser::ParseModule(bool* ok) {
// Module:
// '{' ModuleElement '}'
- // '=' ModulePath
- // 'at' String
+ // '=' ModulePath ';'
+ // 'at' String ';'
switch (peek()) {
case Token::LBRACE:
return ParseModuleLiteral(ok);
- case Token::ASSIGN:
+ case Token::ASSIGN: {
Expect(Token::ASSIGN, CHECK_OK);
- return ParseModulePath(ok);
-
- default:
- return ParseModuleUrl(ok);
+ Module* result = ParseModulePath(CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return result;
+ }
+
+ default: {
+ ExpectContextualKeyword("at", CHECK_OK);
+ Module* result = ParseModuleUrl(CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return result;
+ }
}
}
@@ -1317,31 +1325,122 @@
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;
- }
+ // String
+
Expect(Token::STRING, CHECK_OK);
- symbol = GetSymbol(CHECK_OK);
+ Handle<String> symbol = GetSymbol(CHECK_OK);
return factory()->NewModuleUrl(symbol);
}
+
+
+Module* Parser::ParseModuleSpecifier(bool* ok) {
+ // ModuleSpecifier:
+ // String
+ // ModulePath
+
+ if (peek() == Token::STRING) {
+ return ParseModuleUrl(ok);
+ } else {
+ return ParseModulePath(ok);
+ }
+}
Block* Parser::ParseImportDeclaration(bool* ok) {
- // TODO(rossberg)
- return NULL;
+ // ImportDeclaration:
+ // 'import' IdentifierName (',' IdentifierName)* 'from'
ModuleSpecifier ';'
+ //
+ // TODO(ES6): implement destructuring ImportSpecifiers
+
+ Expect(Token::IMPORT, CHECK_OK);
+ ZoneStringList names(1);
+
+ Handle<String> name = ParseIdentifierName(CHECK_OK);
+ while (peek() == Token::COMMA) {
+ Consume(Token::COMMA);
+ name = ParseIdentifierName(CHECK_OK);
+ names.Add(name);
+ }
+
+ ExpectContextualKeyword("from", CHECK_OK);
+ Module* module = ParseModuleSpecifier(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);
+ for (int i = 0; i < names.length(); ++i) {
+ VariableProxy* proxy = NewUnresolved(names[i], LET);
+ Declaration* declaration =
+ factory()->NewImportDeclaration(proxy, module, top_scope_);
+ Declare(declaration, true, CHECK_OK);
+ // TODO(rossberg): Add initialization statement to block.
+ }
+
+
+ return block;
}
-Block* Parser::ParseExportDeclaration(bool* ok) {
- // TODO(rossberg)
- return NULL;
+Statement* Parser::ParseExportDeclaration(bool* ok) {
+ // ExportDeclaration:
+ // 'export' Identifier (',' Identifier)* ';'
+ // 'export' VariableDeclaration
+ // 'export' FunctionDeclaration
+ // 'export' ModuleDeclaration
+ //
+ // TODO(ES6): implement structuring ExportSpecifiers
+
+ Expect(Token::EXPORT, CHECK_OK);
+
+ Statement* result = NULL;
+ ZoneStringList names(1);
+ switch (peek()) {
+ case Token::IDENTIFIER: {
+ Handle<String> name = ParseIdentifier(CHECK_OK);
+ // Handle 'module' as a context-sensitive keyword.
+ if (!name->IsEqualTo(CStrVector("module"))) {
+ names.Add(name);
+ while (peek() == Token::COMMA) {
+ Consume(Token::COMMA);
+ name = ParseIdentifier(CHECK_OK);
+ names.Add(name);
+ }
+ ExpectSemicolon(CHECK_OK);
+ result = factory()->NewEmptyStatement();
+ } else {
+ result = ParseModuleDeclaration(&names, CHECK_OK);
+ }
+ break;
+ }
+
+ case Token::FUNCTION:
+ result = ParseFunctionDeclaration(&names, CHECK_OK);
+ break;
+
+ case Token::VAR:
+ case Token::LET:
+ case Token::CONST:
+ result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
+ break;
+
+ default:
+ *ok = false;
+ ReportUnexpectedToken(scanner().current_token());
+ return NULL;
+ }
+
+ // Extract declared names into export declarations.
+ for (int i = 0; i < names.length(); ++i) {
+ VariableProxy* proxy = NewUnresolved(names[i], LET);
+ Declaration* declaration =
+ factory()->NewExportDeclaration(proxy, top_scope_);
+ top_scope_->AddDeclaration(declaration);
+ }
+
+ ASSERT(result != NULL);
+ return result;
}
@@ -1359,10 +1458,10 @@
switch (peek()) {
case Token::FUNCTION:
- return ParseFunctionDeclaration(ok);
+ return ParseFunctionDeclaration(NULL, ok);
case Token::LET:
case Token::CONST:
- return ParseVariableStatement(kModuleElement, ok);
+ return ParseVariableStatement(kModuleElement, NULL, ok);
default:
return ParseStatement(labels, ok);
}
@@ -1404,7 +1503,7 @@
case Token::CONST: // fall through
case Token::LET:
case Token::VAR:
- stmt = ParseVariableStatement(kStatement, ok);
+ stmt = ParseVariableStatement(kStatement, NULL, ok);
break;
case Token::SEMICOLON:
@@ -1481,7 +1580,7 @@
*ok = false;
return NULL;
}
- return ParseFunctionDeclaration(ok);
+ return ParseFunctionDeclaration(NULL, ok);
}
case Token::DEBUGGER:
@@ -1708,7 +1807,7 @@
}
-Statement* Parser::ParseFunctionDeclaration(bool* ok) {
+Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool*
ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameterListopt ')' '{'
FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
@@ -1729,6 +1828,7 @@
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_);
Declare(declaration, true, CHECK_OK);
+ if (names) names->Add(name);
return factory()->NewEmptyStatement();
}
@@ -1795,13 +1895,14 @@
Block* Parser::ParseVariableStatement(VariableDeclarationContext
var_context,
+ ZoneStringList* names,
bool* ok) {
// VariableStatement ::
// VariableDeclarations ';'
Handle<String> ignore;
Block* result =
- ParseVariableDeclarations(var_context, NULL, &ignore, CHECK_OK);
+ ParseVariableDeclarations(var_context, NULL, names, &ignore,
CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@@ -1821,6 +1922,7 @@
Block* Parser::ParseVariableDeclarations(
VariableDeclarationContext var_context,
VariableDeclarationProperties* decl_props,
+ ZoneStringList* names,
Handle<String>* out,
bool* ok) {
// VariableDeclarations ::
@@ -1965,6 +2067,7 @@
*ok = false;
return NULL;
}
+ if (names) names->Add(name);
// Parse initialization expression if present and/or needed. A
// declaration of the form:
@@ -2617,7 +2720,7 @@
if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name;
Block* variable_statement =
- ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK);
+ ParseVariableDeclarations(kForStatement, NULL, NULL, &name,
CHECK_OK);
if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(factory(), name);
@@ -2646,7 +2749,8 @@
Handle<String> name;
VariableDeclarationProperties decl_props = kHasNoInitializers;
Block* variable_statement =
- ParseVariableDeclarations(kForStatement, &decl_props, &name,
CHECK_OK);
+ ParseVariableDeclarations(kForStatement, &decl_props, NULL, &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
@@ -4574,6 +4678,18 @@
}
Expect(Token::SEMICOLON, ok);
}
+
+
+void Parser::ExpectContextualKeyword(const char* keyword, bool* ok) {
+ Expect(Token::IDENTIFIER, ok);
+ if (!*ok) return;
+ Handle<String> symbol = GetSymbol(ok);
+ if (!*ok) return;
+ if (!symbol->IsEqualTo(CStrVector(keyword))) {
+ *ok = false;
+ ReportUnexpectedToken(scanner().current_token());
+ }
+}
Literal* Parser::GetLiteralUndefined() {
=======================================
--- /branches/bleeding_edge/src/parser.h Tue Feb 28 02:12:39 2012
+++ /branches/bleeding_edge/src/parser.h Wed Feb 29 04:12:52 2012
@@ -581,23 +581,26 @@
void* ParseSourceElements(ZoneList<Statement*>* processor,
int end_token, bool* ok);
Statement* ParseModuleElement(ZoneStringList* labels, bool* ok);
- Block* ParseModuleDeclaration(bool* ok);
+ Block* ParseModuleDeclaration(ZoneStringList* names, bool* ok);
Module* ParseModule(bool* ok);
Module* ParseModuleLiteral(bool* ok);
Module* ParseModulePath(bool* ok);
Module* ParseModuleVariable(bool* ok);
Module* ParseModuleUrl(bool* ok);
+ Module* ParseModuleSpecifier(bool* ok);
Block* ParseImportDeclaration(bool* ok);
- Block* ParseExportDeclaration(bool* ok);
+ Statement* ParseExportDeclaration(bool* ok);
Statement* ParseBlockElement(ZoneStringList* labels, bool* ok);
Statement* ParseStatement(ZoneStringList* labels, bool* ok);
- Statement* ParseFunctionDeclaration(bool* ok);
+ Statement* ParseFunctionDeclaration(ZoneStringList* names, bool* ok);
Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneStringList* labels, bool* ok);
Block* ParseVariableStatement(VariableDeclarationContext var_context,
+ ZoneStringList* names,
bool* ok);
Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
VariableDeclarationProperties*
decl_props,
+ ZoneStringList* names,
Handle<String>* out,
bool* ok);
Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
@@ -700,6 +703,7 @@
void Expect(Token::Value token, bool* ok);
bool Check(Token::Value token);
void ExpectSemicolon(bool* ok);
+ void ExpectContextualKeyword(const char* keyword, bool* ok);
Handle<String> LiteralString(PretenureFlag tenured) {
if (scanner().is_literal_ascii()) {
=======================================
--- /branches/bleeding_edge/src/prettyprinter.cc Tue Feb 28 02:12:39 2012
+++ /branches/bleeding_edge/src/prettyprinter.cc Wed Feb 29 04:12:52 2012
@@ -81,6 +81,22 @@
Visit(node->module());
Print(";");
}
+
+
+void PrettyPrinter::VisitImportDeclaration(ImportDeclaration* node) {
+ Print("import ");
+ PrintLiteral(node->proxy()->name(), false);
+ Print(" from ");
+ Visit(node->module());
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitExportDeclaration(ExportDeclaration* node) {
+ Print("export ");
+ PrintLiteral(node->proxy()->name(), false);
+ Print(";");
+}
void PrettyPrinter::VisitModuleLiteral(ModuleLiteral* node) {
@@ -769,6 +785,19 @@
PrintLiteralIndented("NAME", node->proxy()->name(), true);
Visit(node->module());
}
+
+
+void AstPrinter::VisitImportDeclaration(ImportDeclaration* node) {
+ IndentedScope indent(this, "IMPORT");
+ PrintLiteralIndented("NAME", node->proxy()->name(), true);
+ Visit(node->module());
+}
+
+
+void AstPrinter::VisitExportDeclaration(ExportDeclaration* node) {
+ IndentedScope indent(this, "EXPORT ");
+ PrintLiteral(node->proxy()->name(), true);
+}
void AstPrinter::VisitModuleLiteral(ModuleLiteral* node) {
=======================================
--- /branches/bleeding_edge/src/rewriter.cc Tue Feb 28 02:12:39 2012
+++ /branches/bleeding_edge/src/rewriter.cc Wed Feb 29 04:12:52 2012
@@ -212,6 +212,8 @@
void Processor::VisitVariableDeclaration(VariableDeclaration* node) {}
void Processor::VisitFunctionDeclaration(FunctionDeclaration* node) {}
void Processor::VisitModuleDeclaration(ModuleDeclaration* node) {}
+void Processor::VisitImportDeclaration(ImportDeclaration* node) {}
+void Processor::VisitExportDeclaration(ExportDeclaration* node) {}
void Processor::VisitModuleLiteral(ModuleLiteral* node) {}
void Processor::VisitModuleVariable(ModuleVariable* node) {}
void Processor::VisitModulePath(ModulePath* node) {}
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/module-parsing.js Fri Feb
24 07:53:09 2012
+++ /branches/bleeding_edge/test/mjsunit/harmony/module-parsing.js Wed Feb
29 04:12:52 2012
@@ -36,19 +36,39 @@
module A3 = A2
module B {
- var x
- var x, y;
- var x = 0, y
- let x, y
- let z = 1
+ export x
+ export y, z, c, f
+
+ var vx
+ var vx, vy;
+ var vx = 0, vy
+ let lx, ly
+ let lz = 1
const c = 9
function f() {}
+
module C {
let x
module D {}
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 from I
+ import i4, i5 from "http://where"
}
module C1 = B.C;
@@ -75,6 +95,45 @@
module Z
at
"file://local"
+
+import
+x
+,
+y
+from
+"file://local"
+
+module Wrap {
+export
+x
+,
+y
+
+export
+var
+v1 = 1
+
+export
+let
+v2 = 2
+
+export
+const
+v3 = 3
+
+export
+function
+f
+(
+)
+{
+}
+
+export
+module V
+{
+}
+}
// Check that 'module' still works as an identifier.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev