Commit 8e608570 authored by Jan Krems's avatar Jan Krems Committed by Commit Bot

Parsing import.meta expression

Rewrites import.meta expressions into null literals. Builds on top
of- and requires dynamic import parsing to simplify the implementation.

Adds a new --harmony-import-meta flag.

BUG=v8:6693

Change-Id: Iadb7ddf6bad8986bf3ad641dbd3826fe730b5f44
Reviewed-on: https://chromium-review.googlesource.com/702678
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48359}
parent a0887ed2
......@@ -4225,6 +4225,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_tostring)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_fields)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_object_rest_spread)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_meta)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_template_escapes)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrict_constructor_return)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_strict_legacy_accessor_builtins)
......
......@@ -187,9 +187,12 @@ DEFINE_BOOL(es_staging, false,
DEFINE_BOOL(harmony, false, "enable all completed harmony features")
DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
DEFINE_IMPLICATION(es_staging, harmony)
// Enabling import.meta requires to also enable import()
DEFINE_IMPLICATION(harmony_import_meta, harmony_dynamic_import)
// Features that are still work in progress (behind individual flags).
#define HARMONY_INPROGRESS(V) \
V(harmony_import_meta, "harmony import.meta property") \
V(harmony_array_prototype_values, "harmony Array.prototype.values") \
V(harmony_function_sent, "harmony function.sent") \
V(harmony_do_expressions, "harmony do-expressions") \
......
......@@ -317,6 +317,7 @@ class ErrorUtils : public AllStatic {
T(ImmutablePrototypeSet, \
"Immutable prototype object '%' cannot have their prototype set") \
T(ImportCallNotNewExpression, "Cannot use new with import") \
T(ImportMetaOutsideModule, "Cannot use 'import.meta' outside a module") \
T(IncompatibleMethodReceiver, "Method % called on incompatible receiver %") \
T(InstanceofNonobjectProto, \
"Function has non-object prototype '%' in instanceof check") \
......
......@@ -277,6 +277,7 @@ class ParserBase {
allow_harmony_class_fields_(false),
allow_harmony_object_rest_spread_(false),
allow_harmony_dynamic_import_(false),
allow_harmony_import_meta_(false),
allow_harmony_async_iteration_(false),
allow_harmony_template_escapes_(false) {}
......@@ -291,6 +292,7 @@ class ParserBase {
ALLOW_ACCESSORS(harmony_class_fields);
ALLOW_ACCESSORS(harmony_object_rest_spread);
ALLOW_ACCESSORS(harmony_dynamic_import);
ALLOW_ACCESSORS(harmony_import_meta);
ALLOW_ACCESSORS(harmony_async_iteration);
ALLOW_ACCESSORS(harmony_template_escapes);
......@@ -1125,7 +1127,7 @@ class ParserBase {
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool tagged,
bool* ok);
ExpressionT ParseSuperExpression(bool is_new, bool* ok);
ExpressionT ParseDynamicImportExpression(bool* ok);
ExpressionT ParseImportExpressions(bool* ok);
ExpressionT ParseNewTargetExpression(bool* ok);
void ParseFormalParameter(FormalParametersT* parameters, bool* ok);
......@@ -1500,6 +1502,7 @@ class ParserBase {
bool allow_harmony_class_fields_;
bool allow_harmony_object_rest_spread_;
bool allow_harmony_dynamic_import_;
bool allow_harmony_import_meta_;
bool allow_harmony_async_iteration_;
bool allow_harmony_template_escapes_;
......@@ -3378,7 +3381,8 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
if (peek() == Token::SUPER) {
const bool is_new = true;
result = ParseSuperExpression(is_new, CHECK_OK);
} else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) {
} else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT &&
(!allow_harmony_import_meta() || PeekAhead() == Token::LPAREN)) {
impl()->ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kImportCallNotNewExpression);
*ok = false;
......@@ -3486,7 +3490,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
const bool is_new = false;
result = ParseSuperExpression(is_new, CHECK_OK);
} else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) {
result = ParseDynamicImportExpression(CHECK_OK);
result = ParseImportExpressions(CHECK_OK);
} else {
result = ParsePrimaryExpression(is_async, CHECK_OK);
}
......@@ -3496,11 +3500,26 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseDynamicImportExpression(bool* ok) {
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseImportExpressions(
bool* ok) {
DCHECK(allow_harmony_dynamic_import());
Consume(Token::IMPORT);
int pos = position();
if (allow_harmony_import_meta() && peek() == Token::PERIOD) {
classifier()->RecordPatternError(
Scanner::Location(pos, scanner()->location().end_pos),
MessageTemplate::kInvalidDestructuringTarget);
ArrowFormalParametersUnexpectedToken();
ExpectMetaProperty(Token::META, "import.meta", pos, CHECK_OK);
if (!parsing_module_) {
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kImportMetaOutsideModule);
*ok = false;
return impl()->NullExpression();
}
return impl()->ExpressionFromLiteral(Token::NULL_LITERAL, pos);
}
Expect(Token::LPAREN, CHECK_OK);
ExpressionT arg = ParseAssignmentExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
......
......@@ -504,6 +504,7 @@ Parser::Parser(ParseInfo* info)
set_allow_harmony_class_fields(FLAG_harmony_class_fields);
set_allow_harmony_object_rest_spread(FLAG_harmony_object_rest_spread);
set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import);
set_allow_harmony_import_meta(FLAG_harmony_import_meta);
set_allow_harmony_async_iteration(FLAG_harmony_async_iteration);
set_allow_harmony_template_escapes(FLAG_harmony_template_escapes);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
......@@ -911,12 +912,15 @@ Statement* Parser::ParseModuleItem(bool* ok) {
return ParseExportDeclaration(ok);
}
// We must be careful not to parse a dynamic import expression as an import
// declaration.
if (next == Token::IMPORT &&
(!allow_harmony_dynamic_import() || PeekAhead() != Token::LPAREN)) {
ParseImportDeclaration(CHECK_OK);
return factory()->NewEmptyStatement(kNoSourcePosition);
if (next == Token::IMPORT) {
// We must be careful not to parse a dynamic import expression as an import
// declaration. Same for import.meta expressions.
Token::Value peek_ahead = PeekAhead();
if ((!allow_harmony_dynamic_import() || peek_ahead != Token::LPAREN) &&
(!allow_harmony_import_meta() || peek_ahead != Token::PERIOD)) {
ParseImportDeclaration(CHECK_OK);
return factory()->NewEmptyStatement(kNoSourcePosition);
}
}
return ParseStatementListItem(ok);
......
......@@ -295,6 +295,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
SET_ALLOW(harmony_class_fields);
SET_ALLOW(harmony_object_rest_spread);
SET_ALLOW(harmony_dynamic_import);
SET_ALLOW(harmony_import_meta);
SET_ALLOW(harmony_async_iteration);
SET_ALLOW(harmony_template_escapes);
SET_ALLOW(harmony_restrictive_generators);
......
......@@ -1437,6 +1437,8 @@ uc32 Scanner::ScanUnicodeEscape() {
KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('l') \
KEYWORD("let", Token::LET) \
KEYWORD_GROUP('m') \
KEYWORD("meta", Token::META) \
KEYWORD_GROUP('n') \
KEYWORD("name", Token::NAME) \
KEYWORD("new", Token::NEW) \
......
......@@ -187,6 +187,7 @@ namespace internal {
C(OF, "of", 0) \
C(TARGET, "target", 0) \
C(SENT, "sent", 0) \
C(META, "meta", 0) \
C(AS, "as", 0) \
C(FROM, "from", 0) \
C(NAME, "name", 0) \
......
......@@ -428,7 +428,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(18),
B(LdaConstant), U8(16),
B(Star), R(19),
......
......@@ -143,7 +143,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -432,7 +432,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -743,7 +743,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -991,7 +991,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......
......@@ -86,7 +86,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -227,7 +227,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -380,7 +380,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -523,7 +523,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(10),
B(LdaConstant), U8(10),
B(Star), R(11),
......
......@@ -90,7 +90,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(13),
B(LdaConstant), U8(7),
B(Star), R(14),
......@@ -268,7 +268,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(13),
B(LdaConstant), U8(11),
B(Star), R(14),
......@@ -422,7 +422,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(11),
B(LdaConstant), U8(9),
B(Star), R(12),
......@@ -524,7 +524,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(66),
B(LdaSmi), I8(67),
B(Star), R(17),
B(LdaConstant), U8(4),
B(Star), R(18),
......@@ -580,7 +580,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(16),
B(LdaConstant), U8(9),
B(Star), R(17),
......@@ -754,7 +754,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......@@ -953,7 +953,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(15),
B(LdaConstant), U8(14),
B(Star), R(16),
......@@ -1116,7 +1116,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(20),
B(LdaConstant), U8(7),
B(Star), R(21),
......@@ -1358,7 +1358,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(20),
B(LdaConstant), U8(9),
B(Star), R(21),
......
......@@ -257,7 +257,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(137),
B(Wide), B(LdaSmi), I16(138),
B(Star), R(14),
B(LdaConstant), U8(15),
B(Star), R(15),
......
......@@ -231,7 +231,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(66),
B(LdaSmi), I8(67),
B(Star), R(4),
B(LdaConstant), U8(1),
B(Star), R(5),
......
......@@ -1291,6 +1291,7 @@ enum ParserFlag {
kAllowHarmonyDynamicImport,
kAllowHarmonyAsyncIteration,
kAllowHarmonyTemplateEscapes,
kAllowHarmonyImportMeta,
};
enum ParserSyncTestResult {
......@@ -1308,6 +1309,7 @@ void SetGlobalFlags(i::EnumSet<ParserFlag> flags) {
i::FLAG_harmony_object_rest_spread =
flags.Contains(kAllowHarmonyObjectRestSpread);
i::FLAG_harmony_dynamic_import = flags.Contains(kAllowHarmonyDynamicImport);
i::FLAG_harmony_import_meta = flags.Contains(kAllowHarmonyImportMeta);
i::FLAG_harmony_async_iteration = flags.Contains(kAllowHarmonyAsyncIteration);
i::FLAG_harmony_template_escapes =
flags.Contains(kAllowHarmonyTemplateEscapes);
......@@ -1325,6 +1327,8 @@ void SetParserFlags(i::PreParser* parser, i::EnumSet<ParserFlag> flags) {
flags.Contains(kAllowHarmonyObjectRestSpread));
parser->set_allow_harmony_dynamic_import(
flags.Contains(kAllowHarmonyDynamicImport));
parser->set_allow_harmony_import_meta(
flags.Contains(kAllowHarmonyImportMeta));
parser->set_allow_harmony_async_iteration(
flags.Contains(kAllowHarmonyAsyncIteration));
parser->set_allow_harmony_template_escapes(
......@@ -7907,6 +7911,9 @@ TEST(DestructuringAssignmentNegativeTests) {
"{ new.target }",
"{ x: new.target }",
"{ x: new.target = 1 }",
"{ import.meta }",
"{ x: import.meta }",
"{ x: import.meta = 1 }",
"[x--]",
"[--x = 1]",
"[x()]",
......@@ -7914,6 +7921,8 @@ TEST(DestructuringAssignmentNegativeTests) {
"[this = 1]",
"[new.target]",
"[new.target = 1]",
"[import.meta]",
"[import.meta = 1]",
"[super]",
"[super = 1]",
"[function f() {}]",
......@@ -8314,6 +8323,106 @@ TEST(NewTarget) {
RunParserSyncTest(bad_context_data, data, kError);
}
TEST(ImportMetaSuccess) {
// clang-format off
const char* context_data[][2] = {
{"", ""},
{"'use strict';", ""},
{"function f() {", "}"},
{"'use strict'; function f() {", "}"},
{"var f = function() {", "}"},
{"'use strict'; var f = function() {", "}"},
{"({m: function() {", "}})"},
{"'use strict'; ({m: function() {", "}})"},
{"({m() {", "}})"},
{"'use strict'; ({m() {", "}})"},
{"({get x() {", "}})"},
{"'use strict'; ({get x() {", "}})"},
{"({set x(_) {", "}})"},
{"'use strict'; ({set x(_) {", "}})"},
{"class C {m() {", "}}"},
{"class C {get x() {", "}}"},
{"class C {set x(_) {", "}}"},
{NULL}
};
const char* data[] = {
"import.meta",
"() => { import.meta }",
"() => import.meta",
"if (1) { import.meta }",
"if (1) {} else { import.meta }",
"while (0) { import.meta }",
"do { import.meta } while (0)",
"import.meta.url",
"import.meta[0]",
"import.meta.couldBeMutable = true",
"import.meta()",
"new import.meta.MagicClass",
"new import.meta",
"t = [...import.meta]",
"f = {...import.meta}",
"delete import.meta",
NULL
};
// clang-format on
// Making sure the same *wouldn't* parse without the flags
RunModuleParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0, NULL, 0,
true, true);
static const ParserFlag flags[] = {
kAllowHarmonyImportMeta, kAllowHarmonyDynamicImport,
kAllowHarmonyObjectRestSpread,
};
// 2.1.1 Static Semantics: Early Errors
// ImportMeta
// * It is an early Syntax Error if Module is not the syntactic goal symbol.
RunParserSyncTest(context_data, data, kError, NULL, 0, flags,
arraysize(flags));
// Making sure the same wouldn't parse without the flags either
RunParserSyncTest(context_data, data, kError);
RunModuleParserSyncTest(context_data, data, kSuccess, NULL, 0, flags,
arraysize(flags));
}
TEST(ImportMetaFailure) {
// clang-format off
const char* context_data[][2] = {
{"var ", ""},
{"let ", ""},
{"const ", ""},
{"var [", "] = [1]"},
{"([", "] = [1])"},
{"({", "} = {1})"},
{"var {", " = 1} = 1"},
{"for (var ", " of [1]) {}"},
{NULL}
};
const char* data[] = {
"import.meta",
NULL
};
// clang-format on
static const ParserFlag flags[] = {
kAllowHarmonyImportMeta, kAllowHarmonyDynamicImport,
kAllowHarmonyObjectRestSpread,
};
RunParserSyncTest(context_data, data, kError, NULL, 0, flags,
arraysize(flags));
RunModuleParserSyncTest(context_data, data, kError, NULL, 0, flags,
arraysize(flags));
RunModuleParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0, NULL, 0,
true, true);
RunParserSyncTest(context_data, data, kError);
}
TEST(ConstSloppy) {
// clang-format off
......
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