[modules] Support parsing anonymous default exports
This includes anonymous Function, Generator, and Class declarations when preceded by 'export default'. Parsing only at the moment, nothing useful is done with the parsed Function/ClassLiteral. BUG=v8:1569 LOG=n Review URL: https://codereview.chromium.org/1589173002 Cr-Commit-Position: refs/heads/master@{#33344}
This commit is contained in:
parent
b099e861ef
commit
25532be593
@ -1275,6 +1275,7 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
|
|||||||
scope_->set_class_declaration_group_start(
|
scope_->set_class_declaration_group_start(
|
||||||
scanner()->peek_location().beg_pos);
|
scanner()->peek_location().beg_pos);
|
||||||
}
|
}
|
||||||
|
Consume(Token::CLASS);
|
||||||
return ParseClassDeclaration(NULL, ok);
|
return ParseClassDeclaration(NULL, ok);
|
||||||
case Token::CONST:
|
case Token::CONST:
|
||||||
if (allow_const()) {
|
if (allow_const()) {
|
||||||
@ -1559,17 +1560,47 @@ Statement* Parser::ParseExportDefault(bool* ok) {
|
|||||||
Expect(Token::DEFAULT, CHECK_OK);
|
Expect(Token::DEFAULT, CHECK_OK);
|
||||||
Scanner::Location default_loc = scanner()->location();
|
Scanner::Location default_loc = scanner()->location();
|
||||||
|
|
||||||
|
const AstRawString* default_string = ast_value_factory()->default_string();
|
||||||
ZoneList<const AstRawString*> names(1, zone());
|
ZoneList<const AstRawString*> names(1, zone());
|
||||||
Statement* result = NULL;
|
Statement* result = nullptr;
|
||||||
|
Expression* default_export = nullptr;
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case Token::FUNCTION:
|
case Token::FUNCTION: {
|
||||||
// TODO(ES6): Support parsing anonymous function declarations here.
|
Consume(Token::FUNCTION);
|
||||||
result = ParseFunctionDeclaration(&names, CHECK_OK);
|
int pos = position();
|
||||||
|
bool is_generator = Check(Token::MUL);
|
||||||
|
if (peek() == Token::LPAREN) {
|
||||||
|
// FunctionDeclaration[+Default] ::
|
||||||
|
// 'function' '(' FormalParameters ')' '{' FunctionBody '}'
|
||||||
|
//
|
||||||
|
// GeneratorDeclaration[+Default] ::
|
||||||
|
// 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
|
||||||
|
default_export = ParseFunctionLiteral(
|
||||||
|
default_string, Scanner::Location::invalid(),
|
||||||
|
kSkipFunctionNameCheck,
|
||||||
|
is_generator ? FunctionKind::kGeneratorFunction
|
||||||
|
: FunctionKind::kNormalFunction,
|
||||||
|
pos, FunctionLiteral::kDeclaration, FunctionLiteral::kNormalArity,
|
||||||
|
language_mode(), CHECK_OK);
|
||||||
|
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
||||||
|
} else {
|
||||||
|
result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Token::CLASS:
|
case Token::CLASS:
|
||||||
// TODO(ES6): Support parsing anonymous class declarations here.
|
Consume(Token::CLASS);
|
||||||
|
if (peek() == Token::EXTENDS || peek() == Token::LBRACE) {
|
||||||
|
// ClassDeclaration[+Default] ::
|
||||||
|
// 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
|
||||||
|
default_export =
|
||||||
|
ParseClassLiteral(default_string, Scanner::Location::invalid(),
|
||||||
|
false, position(), CHECK_OK);
|
||||||
|
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
||||||
|
} else {
|
||||||
result = ParseClassDeclaration(&names, CHECK_OK);
|
result = ParseClassDeclaration(&names, CHECK_OK);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@ -1584,19 +1615,18 @@ Statement* Parser::ParseExportDefault(bool* ok) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AstRawString* default_string = ast_value_factory()->default_string();
|
|
||||||
|
|
||||||
DCHECK_LE(names.length(), 1);
|
DCHECK_LE(names.length(), 1);
|
||||||
if (names.length() == 1) {
|
if (names.length() == 1) {
|
||||||
scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
|
scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
|
||||||
if (!*ok) {
|
if (!*ok) {
|
||||||
ParserTraits::ReportMessageAt(
|
ParserTraits::ReportMessageAt(
|
||||||
default_loc, MessageTemplate::kDuplicateExport, default_string);
|
default_loc, MessageTemplate::kDuplicateExport, default_string);
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO(ES6): Assign result to a const binding with the name "*default*"
|
// TODO(ES6): Assign result to a const binding with the name "*default*"
|
||||||
// and add an export entry with "*default*" as the local name.
|
// and add an export entry with "*default*" as the local name.
|
||||||
|
USE(default_export);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1687,6 +1717,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Token::CLASS:
|
case Token::CLASS:
|
||||||
|
Consume(Token::CLASS);
|
||||||
result = ParseClassDeclaration(&names, CHECK_OK);
|
result = ParseClassDeclaration(&names, CHECK_OK);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2090,14 +2121,22 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
|
|||||||
|
|
||||||
Statement* Parser::ParseFunctionDeclaration(
|
Statement* Parser::ParseFunctionDeclaration(
|
||||||
ZoneList<const AstRawString*>* names, bool* ok) {
|
ZoneList<const AstRawString*>* names, bool* ok) {
|
||||||
// FunctionDeclaration ::
|
|
||||||
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
|
|
||||||
// GeneratorDeclaration ::
|
|
||||||
// 'function' '*' Identifier '(' FormalParameterListopt ')'
|
|
||||||
// '{' FunctionBody '}'
|
|
||||||
Expect(Token::FUNCTION, CHECK_OK);
|
Expect(Token::FUNCTION, CHECK_OK);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
bool is_generator = Check(Token::MUL);
|
bool is_generator = Check(Token::MUL);
|
||||||
|
return ParseFunctionDeclaration(pos, is_generator, names, ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Statement* Parser::ParseFunctionDeclaration(
|
||||||
|
int pos, bool is_generator, ZoneList<const AstRawString*>* names,
|
||||||
|
bool* ok) {
|
||||||
|
// FunctionDeclaration ::
|
||||||
|
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
||||||
|
// GeneratorDeclaration ::
|
||||||
|
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
||||||
|
//
|
||||||
|
// 'function' and '*' (if present) have been consumed by the caller.
|
||||||
bool is_strict_reserved = false;
|
bool is_strict_reserved = false;
|
||||||
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
|
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
|
||||||
&is_strict_reserved, CHECK_OK);
|
&is_strict_reserved, CHECK_OK);
|
||||||
@ -2148,6 +2187,8 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
|||||||
// ClassDeclaration ::
|
// ClassDeclaration ::
|
||||||
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
|
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
|
||||||
//
|
//
|
||||||
|
// 'class' is expected to be consumed by the caller.
|
||||||
|
//
|
||||||
// A ClassDeclaration
|
// A ClassDeclaration
|
||||||
//
|
//
|
||||||
// class C { ... }
|
// class C { ... }
|
||||||
@ -2158,7 +2199,6 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
|||||||
//
|
//
|
||||||
// so rewrite it as such.
|
// so rewrite it as such.
|
||||||
|
|
||||||
Expect(Token::CLASS, CHECK_OK);
|
|
||||||
if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
|
if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
|
||||||
ReportMessage(MessageTemplate::kSloppyLexical);
|
ReportMessage(MessageTemplate::kSloppyLexical);
|
||||||
*ok = false;
|
*ok = false;
|
||||||
|
@ -744,6 +744,9 @@ class Parser : public ParserBase<ParserTraits> {
|
|||||||
bool* ok);
|
bool* ok);
|
||||||
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
|
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
|
Statement* ParseFunctionDeclaration(int pos, bool is_generator,
|
||||||
|
ZoneList<const AstRawString*>* names,
|
||||||
|
bool* ok);
|
||||||
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
Statement* ParseNativeDeclaration(bool* ok);
|
Statement* ParseNativeDeclaration(bool* ok);
|
||||||
|
@ -5539,6 +5539,7 @@ TEST(ComputedPropertyNameShorthandError) {
|
|||||||
TEST(BasicImportExportParsing) {
|
TEST(BasicImportExportParsing) {
|
||||||
i::FLAG_harmony_modules = true;
|
i::FLAG_harmony_modules = true;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
const char* kSources[] = {
|
const char* kSources[] = {
|
||||||
"export let x = 0;",
|
"export let x = 0;",
|
||||||
"export var y = 0;",
|
"export var y = 0;",
|
||||||
@ -5550,7 +5551,11 @@ TEST(BasicImportExportParsing) {
|
|||||||
"var a, b, c; export { a, b as baz, c };",
|
"var a, b, c; export { a, b as baz, c };",
|
||||||
"var d, e; export { d as dreary, e, };",
|
"var d, e; export { d as dreary, e, };",
|
||||||
"export default function f() {}",
|
"export default function f() {}",
|
||||||
|
"export default function() {}",
|
||||||
|
"export default function*() {}",
|
||||||
"export default class C {}",
|
"export default class C {}",
|
||||||
|
"export default class {}"
|
||||||
|
"export default class extends C {}"
|
||||||
"export default 42",
|
"export default 42",
|
||||||
"var x; export default x = 7",
|
"var x; export default x = 7",
|
||||||
"export { Q } from 'somemodule.js';",
|
"export { Q } from 'somemodule.js';",
|
||||||
@ -5577,6 +5582,7 @@ TEST(BasicImportExportParsing) {
|
|||||||
"import { static as s } from 'm.js';",
|
"import { static as s } from 'm.js';",
|
||||||
"import { let as l } from 'm.js';",
|
"import { let as l } from 'm.js';",
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
i::Isolate* isolate = CcTest::i_isolate();
|
i::Isolate* isolate = CcTest::i_isolate();
|
||||||
i::Factory* factory = isolate->factory();
|
i::Factory* factory = isolate->factory();
|
||||||
@ -5633,6 +5639,7 @@ TEST(BasicImportExportParsing) {
|
|||||||
TEST(ImportExportParsingErrors) {
|
TEST(ImportExportParsingErrors) {
|
||||||
i::FLAG_harmony_modules = true;
|
i::FLAG_harmony_modules = true;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
const char* kErrorSources[] = {
|
const char* kErrorSources[] = {
|
||||||
"export {",
|
"export {",
|
||||||
"var a; export { a",
|
"var a; export { a",
|
||||||
@ -5661,6 +5668,10 @@ TEST(ImportExportParsingErrors) {
|
|||||||
"var a, b; export { a as c, b as c };",
|
"var a, b; export { a as c, b as c };",
|
||||||
"export default function f(){}; export default class C {};",
|
"export default function f(){}; export default class C {};",
|
||||||
"export default function f(){}; var a; export { a as default };",
|
"export default function f(){}; var a; export { a as default };",
|
||||||
|
"export function() {}",
|
||||||
|
"export function*() {}",
|
||||||
|
"export class {}",
|
||||||
|
"export class extends C {}",
|
||||||
|
|
||||||
"import from;",
|
"import from;",
|
||||||
"import from 'm.js';",
|
"import from 'm.js';",
|
||||||
@ -5689,11 +5700,8 @@ TEST(ImportExportParsingErrors) {
|
|||||||
"import * as x, * as y from 'm.js';",
|
"import * as x, * as y from 'm.js';",
|
||||||
"import {x}, {y} from 'm.js';",
|
"import {x}, {y} from 'm.js';",
|
||||||
"import * as x, {y} from 'm.js';",
|
"import * as x, {y} from 'm.js';",
|
||||||
|
|
||||||
// TODO(ES6): These two forms should be supported
|
|
||||||
"export default function() {};",
|
|
||||||
"export default class {};"
|
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
i::Isolate* isolate = CcTest::i_isolate();
|
i::Isolate* isolate = CcTest::i_isolate();
|
||||||
i::Factory* factory = isolate->factory();
|
i::Factory* factory = isolate->factory();
|
||||||
|
Loading…
Reference in New Issue
Block a user