Commit fa293dd7 authored by adamk's avatar adamk Committed by Commit bot

Re-introduce ImportDeclaration to the parser

This also adds a new VariableMode, IMPORT, which will be
used to do appropriate binding for Import-declared Variables.

Only named imports are handled for now. "import *" and default
import syntaxes have had their TODOs adjusted to match the new
code structure.

BUG=v8:1569
LOG=n

Review URL: https://codereview.chromium.org/948303004

Cr-Commit-Position: refs/heads/master@{#26895}
parent d471ceff
......@@ -186,7 +186,6 @@ void AstNumberingVisitor::VisitImportDeclaration(ImportDeclaration* node) {
IncrementNodeCount();
DisableOptimization(kImportDeclaration);
VisitVariableProxy(node->proxy());
Visit(node->module());
}
......
......@@ -609,23 +609,27 @@ class ImportDeclaration FINAL : public Declaration {
public:
DECLARE_NODE_TYPE(ImportDeclaration)
Module* module() const { return module_; }
const AstRawString* import_name() const { return import_name_; }
const AstRawString* module_specifier() const { return module_specifier_; }
void set_module_specifier(const AstRawString* module_specifier) {
DCHECK(module_specifier_ == NULL);
module_specifier_ = module_specifier;
}
InitializationFlag initialization() const OVERRIDE {
return kCreatedInitialized;
return kNeedsInitialization;
}
protected:
ImportDeclaration(Zone* zone,
VariableProxy* proxy,
Module* module,
Scope* scope,
int pos)
: Declaration(zone, proxy, LET, scope, pos),
module_(module) {
}
ImportDeclaration(Zone* zone, VariableProxy* proxy,
const AstRawString* import_name,
const AstRawString* module_specifier, Scope* scope, int pos)
: Declaration(zone, proxy, IMPORT, scope, pos),
import_name_(import_name),
module_specifier_(module_specifier) {}
private:
Module* module_;
const AstRawString* import_name_;
const AstRawString* module_specifier_;
};
......@@ -3168,10 +3172,11 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
}
ImportDeclaration* NewImportDeclaration(VariableProxy* proxy,
Module* module,
Scope* scope,
int pos) {
return new (zone_) ImportDeclaration(zone_, proxy, module, scope, pos);
const AstRawString* import_name,
const AstRawString* module_specifier,
Scope* scope, int pos) {
return new (zone_) ImportDeclaration(zone_, proxy, import_name,
module_specifier, scope, pos);
}
ExportDeclaration* NewExportDeclaration(VariableProxy* proxy,
......
......@@ -173,6 +173,10 @@ static void GetAttributesAndBindingFlags(VariableMode mode,
? IMMUTABLE_CHECK_INITIALIZED_HARMONY
: IMMUTABLE_IS_INITIALIZED_HARMONY;
break;
case IMPORT:
// TODO(ES6)
UNREACHABLE();
break;
case DYNAMIC:
case DYNAMIC_GLOBAL:
case DYNAMIC_LOCAL:
......
......@@ -717,10 +717,12 @@ enum VariableMode {
CONST_LEGACY, // declared via legacy 'const' declarations
LET, // declared via 'let' declarations
LET, // declared via 'let' declarations (first lexical)
CONST, // declared via 'const' declarations
IMPORT, // declared via 'import' declarations (last lexical)
// Variables introduced by the compiler:
INTERNAL, // like VAR, but not user-visible (may or may not
// be in a context)
......@@ -748,17 +750,17 @@ inline bool IsDynamicVariableMode(VariableMode mode) {
inline bool IsDeclaredVariableMode(VariableMode mode) {
return mode >= VAR && mode <= CONST;
return mode >= VAR && mode <= IMPORT;
}
inline bool IsLexicalVariableMode(VariableMode mode) {
return mode == LET || mode == CONST;
return mode >= LET && mode <= IMPORT;
}
inline bool IsImmutableVariableMode(VariableMode mode) {
return mode == CONST || mode == CONST_LEGACY;
return mode == CONST || mode == CONST_LEGACY || mode == IMPORT;
}
......
......@@ -1284,13 +1284,12 @@ void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
}
Literal* Parser::ParseModuleSpecifier(bool* ok) {
const AstRawString* Parser::ParseModuleSpecifier(bool* ok) {
// ModuleSpecifier :
// StringLiteral
int pos = peek_position();
Expect(Token::STRING, CHECK_OK);
return factory()->NewStringLiteral(GetSymbol(scanner()), pos);
return GetSymbol(scanner());
}
......@@ -1342,9 +1341,7 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
}
void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* import_names,
ZoneList<const AstRawString*>* local_names,
bool* ok) {
ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
// NamedImports :
// '{' '}'
// '{' ImportsList '}'
......@@ -1360,6 +1357,8 @@ void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* import_names,
Expect(Token::LBRACE, CHECK_OK);
ZoneList<ImportDeclaration*>* result =
new (zone()) ZoneList<ImportDeclaration*>(1, zone());
while (peek() != Token::RBRACE) {
const AstRawString* import_name = ParseIdentifierName(CHECK_OK);
const AstRawString* local_name = import_name;
......@@ -1378,15 +1377,18 @@ void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* import_names,
ReportMessage("strict_eval_arguments");
return NULL;
}
import_names->Add(import_name, zone());
local_names->Add(local_name, zone());
VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
ImportDeclaration* declaration =
factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
Declare(declaration, true, CHECK_OK);
result->Add(declaration, zone());
if (peek() == Token::RBRACE) break;
Expect(Token::COMMA, CHECK_OK);
}
Expect(Token::RBRACE, CHECK_OK);
return NULL;
return result;
}
......@@ -1412,7 +1414,7 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
// 'import' ModuleSpecifier ';'
if (tok == Token::STRING) {
Literal* module_specifier = ParseModuleSpecifier(CHECK_OK);
const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
ExpectSemicolon(CHECK_OK);
// TODO(ES6): Add module to the requested modules of scope_->module().
USE(module_specifier);
......@@ -1424,11 +1426,11 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
if (tok != Token::MUL && tok != Token::LBRACE) {
imported_default_binding =
ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
// TODO(ES6): Add an appropriate declaration.
}
const AstRawString* module_instance_binding = NULL;
ZoneList<const AstRawString*> local_names(1, zone());
ZoneList<const AstRawString*> import_names(1, zone());
ZoneList<ImportDeclaration*>* named_declarations = NULL;
if (imported_default_binding == NULL || Check(Token::COMMA)) {
switch (peek()) {
case Token::MUL: {
......@@ -1436,11 +1438,12 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
ExpectContextualKeyword(CStrVector("as"), CHECK_OK);
module_instance_binding =
ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
// TODO(ES6): Add an appropriate declaration.
break;
}
case Token::LBRACE:
ParseNamedImports(&import_names, &local_names, CHECK_OK);
named_declarations = ParseNamedImports(pos, CHECK_OK);
break;
default:
......@@ -1451,23 +1454,21 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
}
ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
Literal* module = ParseModuleSpecifier(CHECK_OK);
USE(module);
const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
ExpectSemicolon(CHECK_OK);
if (module_instance_binding != NULL) {
// TODO(ES6): Bind name to the Module Instance Object of module.
// TODO(ES6): Set the module specifier for the module namespace binding.
}
if (imported_default_binding != NULL) {
// TODO(ES6): Add an appropriate declaration.
// TODO(ES6): Set the module specifier for the default binding.
}
const int length = import_names.length();
DCHECK_EQ(length, local_names.length());
for (int i = 0; i < length; ++i) {
// TODO(ES6): Add an appropriate declaration for each name
if (named_declarations != NULL) {
for (int i = 0; i < named_declarations->length(); ++i) {
named_declarations->at(i)->set_module_specifier(module_specifier);
}
}
return factory()->NewEmptyStatement(pos);
......@@ -1544,10 +1545,10 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
case Token::MUL: {
Consume(Token::MUL);
ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
Literal* module = ParseModuleSpecifier(CHECK_OK);
const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
ExpectSemicolon(CHECK_OK);
// TODO(ES6): scope_->module()->AddStarExport(...)
USE(module);
USE(module_specifier);
return factory()->NewEmptyStatement(pos);
}
......@@ -1569,7 +1570,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
ZoneList<const AstRawString*> local_names(1, zone());
ParseExportClause(&export_names, &export_locations, &local_names,
&reserved_loc, CHECK_OK);
Literal* indirect_export_module_specifier = NULL;
const AstRawString* indirect_export_module_specifier = NULL;
if (CheckContextualKeyword(CStrVector("from"))) {
indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK);
} else if (reserved_loc.IsValid()) {
......
......@@ -707,7 +707,7 @@ class Parser : public ParserBase<ParserTraits> {
Statement* ParseStatementListItem(bool* ok);
void* ParseModuleItemList(ZoneList<Statement*>* body, bool* ok);
Statement* ParseModuleItem(bool* ok);
Literal* ParseModuleSpecifier(bool* ok);
const AstRawString* ParseModuleSpecifier(bool* ok);
Statement* ParseImportDeclaration(bool* ok);
Statement* ParseExportDeclaration(bool* ok);
Statement* ParseExportDefault(bool* ok);
......@@ -715,8 +715,7 @@ class Parser : public ParserBase<ParserTraits> {
ZoneList<Scanner::Location>* export_locations,
ZoneList<const AstRawString*>* local_names,
Scanner::Location* reserved_loc, bool* ok);
void* ParseNamedImports(ZoneList<const AstRawString*>* import_names,
ZoneList<const AstRawString*>* local_names, bool* ok);
ZoneList<ImportDeclaration*>* ParseNamedImports(int pos, bool* ok);
Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseSubStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
......
......@@ -106,7 +106,6 @@ void CallPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
void CallPrinter::VisitImportDeclaration(ImportDeclaration* node) {
Find(node->module());
}
......@@ -481,7 +480,7 @@ void PrettyPrinter::VisitImportDeclaration(ImportDeclaration* node) {
Print("import ");
PrintLiteral(node->proxy()->name(), false);
Print(" from ");
Visit(node->module());
PrintLiteral(node->module_specifier()->string(), true);
Print(";");
}
......@@ -1213,7 +1212,7 @@ void AstPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
void AstPrinter::VisitImportDeclaration(ImportDeclaration* node) {
IndentedScope indent(this, "IMPORT");
PrintLiteralIndented("NAME", node->proxy()->name(), true);
Visit(node->module());
PrintLiteralIndented("FROM", node->module_specifier()->string(), true);
}
......
......@@ -790,7 +790,8 @@ RUNTIME_FUNCTION(Runtime_DeclareModules) {
case VAR:
case LET:
case CONST:
case CONST_LEGACY: {
case CONST_LEGACY:
case IMPORT: {
PropertyAttributes attr =
IsImmutableVariableMode(mode) ? FROZEN : SEALED;
Handle<AccessorInfo> info =
......
......@@ -799,7 +799,6 @@ void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
RECURSE(Visit(declaration->module()));
}
......
......@@ -20,6 +20,7 @@ const char* Variable::Mode2String(VariableMode mode) {
case CONST_LEGACY: return "CONST_LEGACY";
case LET: return "LET";
case CONST: return "CONST";
case IMPORT: return "IMPORT";
case DYNAMIC: return "DYNAMIC";
case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
......
......@@ -5218,11 +5218,11 @@ TEST(ModuleParsingInternals) {
isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
128 * 1024);
static const char kSource[] = "let x = 5; export { x as y };";
static const char kSource[] =
"let x = 5; export { x as y }; import { q as z } from 'm.js';";
i::Handle<i::String> source = factory->NewStringFromAsciiChecked(kSource);
i::Handle<i::Script> script = factory->NewScript(source);
i::CompilationInfoWithZone info(script);
i::AstValueFactory avf(info.zone(), isolate->heap()->HashSeed());
i::Parser parser(&info, isolate->stack_guard()->real_climit(),
isolate->heap()->HashSeed(), isolate->unicode_cache());
parser.set_allow_harmony_modules(true);
......@@ -5233,15 +5233,21 @@ TEST(ModuleParsingInternals) {
CHECK_EQ(i::MODULE_SCOPE, func->scope()->scope_type());
i::ModuleDescriptor* descriptor = func->scope()->module();
CHECK_NOT_NULL(descriptor);
const i::AstRawString* name_x = avf.GetOneByteString("x");
const i::AstRawString* name_y = avf.GetOneByteString("y");
int num_exports = 0;
for (auto it = descriptor->iterator(); !it.done(); it.Advance()) {
++num_exports;
CHECK(*name_x == *it.local_name());
CHECK(*name_y == *it.export_name());
CHECK(it.local_name()->IsOneByteEqualTo("x"));
CHECK(it.export_name()->IsOneByteEqualTo("y"));
}
CHECK_EQ(1, num_exports);
i::ZoneList<i::Declaration*>* declarations = func->scope()->declarations();
CHECK_EQ(2, declarations->length());
CHECK(declarations->at(0)->proxy()->raw_name()->IsOneByteEqualTo("x"));
i::ImportDeclaration* import_decl =
declarations->at(1)->AsImportDeclaration();
CHECK(import_decl->import_name()->IsOneByteEqualTo("q"));
CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("z"));
CHECK(import_decl->module_specifier()->IsOneByteEqualTo("m.js"));
}
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// MODULE
let foo = 42;
import { bar as foo } from "mod";
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared
import { bar as foo } from "mod";
^^^
SyntaxError: Identifier 'foo' has already been declared
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// MODULE
let foo = 42;
import { foo } from "mod";
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared
import { foo } from "mod";
^^^
SyntaxError: Identifier 'foo' has already been declared
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