Commit b89c0a96 authored by rossberg@chromium.org's avatar rossberg@chromium.org

AST extensions and parsing for import & export declarations.

R=jkummerow@chromium.org
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/9496003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10866 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b4a0a4dd
......@@ -1008,6 +1008,8 @@ CaseClause::CaseClause(Isolate* isolate,
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)
......
......@@ -63,6 +63,8 @@ namespace internal {
V(VariableDeclaration) \
V(FunctionDeclaration) \
V(ModuleDeclaration) \
V(ImportDeclaration) \
V(ExportDeclaration) \
#define MODULE_NODE_LIST(V) \
V(ModuleLiteral) \
......@@ -544,6 +546,48 @@ class ModuleDeclaration: public Declaration {
};
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:
......@@ -2580,6 +2624,21 @@ class AstNodeFactory BASE_EMBEDDED {
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);
VISIT_AND_RETURN(ModuleLiteral, module)
......
......@@ -63,6 +63,14 @@ void BreakableStatementChecker::VisitModuleDeclaration(
ModuleDeclaration* decl) {
}
void BreakableStatementChecker::VisitImportDeclaration(
ImportDeclaration* decl) {
}
void BreakableStatementChecker::VisitExportDeclaration(
ExportDeclaration* decl) {
}
void BreakableStatementChecker::VisitModuleLiteral(ModuleLiteral* module) {
}
......@@ -622,6 +630,16 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) {
}
void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
EmitDeclaration(decl->proxy(), decl->mode(), NULL);
}
void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
// TODO(rossberg)
}
void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
// TODO(rossberg)
}
......
......@@ -6932,7 +6932,17 @@ void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
// TODO(rossberg)
UNREACHABLE();
}
void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
UNREACHABLE();
}
void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
UNREACHABLE();
}
......
......@@ -1184,10 +1184,10 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels,
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 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels,
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 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels,
}
Block* Parser::ParseModuleDeclaration(bool* ok) {
Block* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
// ModuleDeclaration:
// 'module' Identifier Module
......@@ -1229,6 +1229,7 @@ Block* Parser::ParseModuleDeclaration(bool* ok) {
// TODO(rossberg): Add initialization statement to block.
if (names) names->Add(name);
return block;
}
......@@ -1236,19 +1237,26 @@ Block* Parser::ParseModuleDeclaration(bool* ok) {
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);
Module* result = ParseModulePath(CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
default:
return ParseModuleUrl(ok);
default: {
ExpectContextualKeyword("at", CHECK_OK);
Module* result = ParseModuleUrl(CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
}
}
......@@ -1317,31 +1325,122 @@ Module* Parser::ParseModuleVariable(bool* ok) {
Module* Parser::ParseModuleUrl(bool* ok) {
// Module:
// 'at' String
// 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);
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)
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 @@ Statement* Parser::ParseBlockElement(ZoneStringList* labels,
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 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
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 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
*ok = false;
return NULL;
}
return ParseFunctionDeclaration(ok);
return ParseFunctionDeclaration(NULL, ok);
}
case Token::DEBUGGER:
......@@ -1708,7 +1807,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
}
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 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
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::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
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 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
Block* Parser::ParseVariableDeclarations(
VariableDeclarationContext var_context,
VariableDeclarationProperties* decl_props,
ZoneStringList* names,
Handle<String>* out,
bool* ok) {
// VariableDeclarations ::
......@@ -1965,6 +2067,7 @@ Block* Parser::ParseVariableDeclarations(
*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 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
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 @@ 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, 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
......@@ -4576,6 +4680,18 @@ void Parser::ExpectSemicolon(bool* 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() {
return factory()->NewLiteral(isolate()->factory()->undefined_value());
}
......
......@@ -581,23 +581,26 @@ class Parser {
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 @@ class Parser {
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()) {
......
......@@ -83,6 +83,22 @@ void PrettyPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
}
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) {
VisitBlock(node->body());
}
......@@ -771,6 +787,19 @@ void AstPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
}
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) {
VisitBlock(node->body());
}
......
......@@ -212,6 +212,8 @@ void Processor::VisitWithStatement(WithStatement* node) {
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) {}
......
......@@ -36,19 +36,39 @@ module A2 = A;
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;
......@@ -76,6 +96,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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment