Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 72f2298..08caeab 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -31,6 +31,8 @@
#include "src/v8.h"
+#include "src/ast.h"
+#include "src/ast-numbering.h"
#include "src/ast-value-factory.h"
#include "src/compiler.h"
#include "src/execution.h"
@@ -317,8 +319,8 @@
i::PreParser preparser(&scanner, &log, stack_limit);
preparser.set_allow_lazy(true);
- preparser.set_allow_natives_syntax(true);
- preparser.set_allow_arrow_functions(true);
+ preparser.set_allow_natives(true);
+ preparser.set_allow_harmony_arrow_functions(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
CHECK(!log.HasError());
@@ -452,14 +454,14 @@
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
i::ScriptData* sd = log.GetScriptData();
- i::ParseData pd(sd);
- pd.Initialize();
+ i::ParseData* pd = i::ParseData::FromCachedData(sd);
+ pd->Initialize();
int first_function =
static_cast<int>(strstr(program, "function") - program);
int first_lbrace = first_function + i::StrLength("function () ");
CHECK_EQ('{', program[first_lbrace]);
- i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
+ i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
CHECK(!entry1.is_valid());
int second_function =
@@ -467,10 +469,11 @@
int second_lbrace =
second_function + i::StrLength("function () ");
CHECK_EQ('{', program[second_lbrace]);
- i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
+ i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
CHECK(entry2.is_valid());
CHECK_EQ('}', program[entry2.end_pos() - 1]);
delete sd;
+ delete pd;
}
@@ -496,7 +499,7 @@
i::PreParser preparser(&scanner, &log, stack_limit);
preparser.set_allow_lazy(true);
- preparser.set_allow_arrow_functions(true);
+ preparser.set_allow_harmony_arrow_functions(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
}
@@ -917,6 +920,142 @@
}
+TEST(ScopeUsesArgumentsSuperThis) {
+ static const struct {
+ const char* prefix;
+ const char* suffix;
+ } surroundings[] = {
+ { "function f() {", "}" },
+ { "var f = () => {", "}" },
+ };
+
+ enum Expected {
+ NONE = 0,
+ ARGUMENTS = 1,
+ SUPER_PROPERTY = 2,
+ SUPER_CONSTRUCTOR_CALL = 4,
+ THIS = 8,
+ INNER_ARGUMENTS = 16,
+ INNER_SUPER_PROPERTY = 32,
+ INNER_SUPER_CONSTRUCTOR_CALL = 64,
+ INNER_THIS = 128
+ };
+
+ static const struct {
+ const char* body;
+ int expected;
+ } source_data[] = {
+ {"", NONE},
+ {"return this", THIS},
+ {"return arguments", ARGUMENTS},
+ {"return super()", SUPER_CONSTRUCTOR_CALL},
+ {"return super.x", SUPER_PROPERTY},
+ {"return arguments[0]", ARGUMENTS},
+ {"return this + arguments[0]", ARGUMENTS | THIS},
+ {"return this + arguments[0] + super.x",
+ ARGUMENTS | SUPER_PROPERTY | THIS},
+ {"return x => this + x", INNER_THIS},
+ {"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
+ {"this.foo = 42;", THIS},
+ {"this.foo();", THIS},
+ {"if (foo()) { this.f() }", THIS},
+ {"if (foo()) { super.f() }", SUPER_PROPERTY},
+ {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
+ {"while (true) { this.f() }", THIS},
+ {"while (true) { super.f() }", SUPER_PROPERTY},
+ {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
+ // Multiple nesting levels must work as well.
+ {"while (true) { while (true) { while (true) return this } }", THIS},
+ {"while (true) { while (true) { while (true) return super() } }",
+ SUPER_CONSTRUCTOR_CALL},
+ {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
+ {"if (1) { return () => { while (true) new super() } }", NONE},
+ {"if (1) { return () => { while (true) new new super() } }", NONE},
+ // Note that propagation of the inner_uses_this() value does not
+ // cross boundaries of normal functions onto parent scopes.
+ {"return function (x) { return this + x }", NONE},
+ {"return function (x) { return super() + x }", NONE},
+ {"var x = function () { this.foo = 42 };", NONE},
+ {"var x = function () { super.foo = 42 };", NONE},
+ {"if (1) { return function () { while (true) new this() } }", NONE},
+ {"if (1) { return function () { while (true) new super() } }", NONE},
+ {"return function (x) { return () => this }", NONE},
+ {"return function (x) { return () => super() }", NONE},
+ // Flags must be correctly set when using block scoping.
+ {"\"use strict\"; while (true) { let x; this, arguments; }",
+ INNER_ARGUMENTS | INNER_THIS},
+ {"\"use strict\"; while (true) { let x; this, super(), arguments; }",
+ INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
+ {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
+ {"\"use strict\"; if (foo()) { let x; super.f() }",
+ INNER_SUPER_PROPERTY},
+ {"\"use strict\"; if (1) {"
+ " let x; return function () { return this + super() + arguments }"
+ "}",
+ NONE},
+ };
+
+ i::Isolate* isolate = CcTest::i_isolate();
+ i::Factory* factory = isolate->factory();
+
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
+ 128 * 1024);
+
+ for (unsigned j = 0; j < arraysize(surroundings); ++j) {
+ for (unsigned i = 0; i < arraysize(source_data); ++i) {
+ int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
+ i::StrLength(surroundings[j].suffix) +
+ i::StrLength(source_data[i].body);
+ i::ScopedVector<char> program(kProgramByteSize + 1);
+ i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
+ source_data[i].body, surroundings[j].suffix);
+ i::Handle<i::String> source =
+ factory->NewStringFromUtf8(i::CStrVector(program.start()))
+ .ToHandleChecked();
+ i::Handle<i::Script> script = factory->NewScript(source);
+ i::CompilationInfoWithZone info(script);
+ i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(),
+ isolate->unicode_cache()};
+ i::Parser parser(&info, &parse_info);
+ parser.set_allow_harmony_arrow_functions(true);
+ parser.set_allow_harmony_classes(true);
+ parser.set_allow_harmony_scoping(true);
+ info.MarkAsGlobal();
+ parser.Parse();
+ CHECK(i::Rewriter::Rewrite(&info));
+ CHECK(i::Scope::Analyze(&info));
+ CHECK(info.function() != NULL);
+
+ i::Scope* script_scope = info.function()->scope();
+ CHECK(script_scope->is_script_scope());
+ CHECK_EQ(1, script_scope->inner_scopes()->length());
+
+ i::Scope* scope = script_scope->inner_scopes()->at(0);
+ CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
+ scope->uses_arguments());
+ CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
+ scope->uses_super_property());
+ CHECK_EQ((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) != 0,
+ scope->uses_super_constructor_call());
+ CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
+ CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
+ scope->inner_uses_arguments());
+ CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
+ scope->inner_uses_super_property());
+ CHECK_EQ((source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) != 0,
+ scope->inner_uses_super_constructor_call());
+ CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
+ scope->inner_uses_this());
+ }
+ }
+}
+
+
TEST(ScopePositions) {
v8::internal::FLAG_harmony_scoping = true;
@@ -974,11 +1113,10 @@
" infunction;\n"
" }", "\n"
" more;", i::FUNCTION_SCOPE, i::SLOPPY },
- // TODO(aperez): Change to use i::ARROW_SCOPE when implemented
{ " start;\n", "(a,b) => a + b", "; more;",
- i::FUNCTION_SCOPE, i::SLOPPY },
+ i::ARROW_SCOPE, i::SLOPPY },
{ " start;\n", "(a,b) => { return a+b; }", "\nmore;",
- i::FUNCTION_SCOPE, i::SLOPPY },
+ i::ARROW_SCOPE, i::SLOPPY },
{ " start;\n"
" (function fun", "(a,b) { infunction; }", ")();",
i::FUNCTION_SCOPE, i::SLOPPY },
@@ -1137,7 +1275,7 @@
i::Parser parser(&info, &parse_info);
parser.set_allow_lazy(true);
parser.set_allow_harmony_scoping(true);
- parser.set_allow_arrow_functions(true);
+ parser.set_allow_harmony_arrow_functions(true);
info.MarkAsGlobal();
info.SetStrictMode(source_data[i].strict_mode);
parser.Parse();
@@ -1145,7 +1283,7 @@
// Check scope types and positions.
i::Scope* scope = info.function()->scope();
- CHECK(scope->is_global_scope());
+ CHECK(scope->is_script_scope());
CHECK_EQ(scope->start_position(), 0);
CHECK_EQ(scope->end_position(), kProgramSize);
CHECK_EQ(scope->inner_scopes()->length(), 1);
@@ -1211,13 +1349,16 @@
enum ParserFlag {
kAllowLazy,
- kAllowNativesSyntax,
+ kAllowNatives,
kAllowHarmonyScoping,
- kAllowModules,
+ kAllowHarmonyModules,
kAllowHarmonyNumericLiterals,
- kAllowArrowFunctions,
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyArrowFunctions,
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonyTemplates,
+ kAllowHarmonySloppy,
+ kAllowHarmonyUnicode
};
@@ -1231,15 +1372,19 @@
void SetParserFlags(i::ParserBase<Traits>* parser,
i::EnumSet<ParserFlag> flags) {
parser->set_allow_lazy(flags.Contains(kAllowLazy));
- parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
+ parser->set_allow_natives(flags.Contains(kAllowNatives));
parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
- parser->set_allow_modules(flags.Contains(kAllowModules));
+ parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
parser->set_allow_harmony_numeric_literals(
flags.Contains(kAllowHarmonyNumericLiterals));
parser->set_allow_harmony_object_literals(
flags.Contains(kAllowHarmonyObjectLiterals));
- parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions));
- parser->set_allow_classes(flags.Contains(kAllowClasses));
+ parser->set_allow_harmony_arrow_functions(
+ flags.Contains(kAllowHarmonyArrowFunctions));
+ parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
+ parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
+ parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
+ parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
}
@@ -1250,6 +1395,8 @@
i::Factory* factory = isolate->factory();
uintptr_t stack_limit = isolate->stack_guard()->real_climit();
+ int preparser_materialized_literals = -1;
+ int parser_materialized_literals = -2;
// Preparse the data.
i::CompleteParserRecorder log;
@@ -1259,7 +1406,8 @@
i::PreParser preparser(&scanner, &log, stack_limit);
SetParserFlags(&preparser, flags);
scanner.Initialize(&stream);
- i::PreParser::PreParseResult result = preparser.PreParseProgram();
+ i::PreParser::PreParseResult result = preparser.PreParseProgram(
+ &preparser_materialized_literals);
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
}
@@ -1278,6 +1426,9 @@
info.MarkAsGlobal();
parser.Parse();
function = info.function();
+ if (function) {
+ parser_materialized_literals = function->materialized_literal_count();
+ }
}
// Check that preparsing fails iff parsing fails.
@@ -1343,6 +1494,15 @@
"However, parser and preparser succeeded",
source->ToCString().get());
CHECK(false);
+ } else if (preparser_materialized_literals != parser_materialized_literals) {
+ v8::base::OS::Print(
+ "Preparser materialized literals (%d) differ from Parser materialized "
+ "literals (%d) on:\n"
+ "\t%s\n"
+ "However, parser and preparser succeeded",
+ preparser_materialized_literals, parser_materialized_literals,
+ source->ToCString().get());
+ CHECK(false);
}
}
@@ -1352,7 +1512,9 @@
size_t varying_flags_length,
ParserSyncTestResult result = kSuccessOrError,
const ParserFlag* always_true_flags = NULL,
- size_t always_true_flags_length = 0) {
+ size_t always_true_flags_length = 0,
+ const ParserFlag* always_false_flags = NULL,
+ size_t always_false_flags_length = 0) {
i::Handle<i::String> str =
CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
@@ -1365,6 +1527,10 @@
++flag_index) {
flags.Add(always_true_flags[flag_index]);
}
+ for (size_t flag_index = 0; flag_index < always_false_flags_length;
+ ++flag_index) {
+ flags.Remove(always_false_flags[flag_index]);
+ }
TestParserSyncWithFlags(str, flags, result);
}
}
@@ -1399,7 +1565,7 @@
"if (false) {} else ;",
"if (false) {} else {}",
"if (false) {} else 12",
- "if (false) ;"
+ "if (false) ;",
"if (false) {}",
"if (false) 12",
"do {} while (false)",
@@ -1419,8 +1585,8 @@
"with ({}) ;",
"with ({}) {}",
"with ({}) 12",
- "switch ({}) { default: }"
- "label3: "
+ "switch ({}) { default: }",
+ "label3: ",
"throw",
"throw 12",
"throw\n12",
@@ -1447,16 +1613,6 @@
CcTest::i_isolate()->stack_guard()->SetStackLimit(
i::GetCurrentStackPosition() - 128 * 1024);
- static const ParserFlag flags1[] = {
- kAllowArrowFunctions,
- kAllowClasses,
- kAllowHarmonyNumericLiterals,
- kAllowHarmonyObjectLiterals,
- kAllowHarmonyScoping,
- kAllowLazy,
- kAllowModules,
- };
-
for (int i = 0; context_data[i][0] != NULL; ++i) {
for (int j = 0; statement_data[j] != NULL; ++j) {
for (int k = 0; termination_data[k] != NULL; ++k) {
@@ -1476,7 +1632,7 @@
termination_data[k],
context_data[i][1]);
CHECK(length == kProgramSize);
- TestParserSync(program.start(), flags1, arraysize(flags1));
+ TestParserSync(program.start(), NULL, 0);
}
}
}
@@ -1488,7 +1644,7 @@
TestParserSync("0o1234", flags2, arraysize(flags2));
TestParserSync("0b1011", flags2, arraysize(flags2));
- static const ParserFlag flags3[] = { kAllowNativesSyntax };
+ static const ParserFlag flags3[] = { kAllowNatives };
TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
}
@@ -1522,7 +1678,9 @@
const ParserFlag* flags = NULL,
int flags_len = 0,
const ParserFlag* always_true_flags = NULL,
- int always_true_flags_len = 0) {
+ int always_true_len = 0,
+ const ParserFlag* always_false_flags = NULL,
+ int always_false_len = 0) {
v8::HandleScope handles(CcTest::isolate());
v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
@@ -1530,36 +1688,32 @@
CcTest::i_isolate()->stack_guard()->SetStackLimit(
i::GetCurrentStackPosition() - 128 * 1024);
+ // Experimental feature flags should not go here; pass the flags as
+ // always_true_flags if the test needs them.
static const ParserFlag default_flags[] = {
- kAllowArrowFunctions,
- kAllowClasses,
- kAllowHarmonyNumericLiterals,
- kAllowHarmonyObjectLiterals,
- kAllowHarmonyScoping,
kAllowLazy,
- kAllowModules,
- kAllowNativesSyntax,
+ kAllowNatives,
};
ParserFlag* generated_flags = NULL;
if (flags == NULL) {
flags = default_flags;
flags_len = arraysize(default_flags);
- if (always_true_flags != NULL) {
- // Remove always_true_flags from default_flags.
- CHECK(always_true_flags_len < flags_len);
- generated_flags = new ParserFlag[flags_len - always_true_flags_len];
+ if (always_true_flags != NULL || always_false_flags != NULL) {
+ // Remove always_true/false_flags from default_flags (if present).
+ CHECK((always_true_flags != NULL) == (always_true_len > 0));
+ CHECK((always_false_flags != NULL) == (always_false_len > 0));
+ generated_flags = new ParserFlag[flags_len + always_true_len];
int flag_index = 0;
for (int i = 0; i < flags_len; ++i) {
bool use_flag = true;
- for (int j = 0; j < always_true_flags_len; ++j) {
- if (flags[i] == always_true_flags[j]) {
- use_flag = false;
- break;
- }
+ for (int j = 0; use_flag && j < always_true_len; ++j) {
+ if (flags[i] == always_true_flags[j]) use_flag = false;
+ }
+ for (int j = 0; use_flag && j < always_false_len; ++j) {
+ if (flags[i] == always_false_flags[j]) use_flag = false;
}
if (use_flag) generated_flags[flag_index++] = flags[i];
}
- CHECK(flag_index == flags_len - always_true_flags_len);
flags_len = flag_index;
flags = generated_flags;
}
@@ -1584,7 +1738,9 @@
flags_len,
result,
always_true_flags,
- always_true_flags_len);
+ always_true_len,
+ always_false_flags,
+ always_false_len);
}
}
delete[] generated_flags;
@@ -1691,45 +1847,70 @@
NULL
};
- static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+ static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
+#define FUTURE_STRICT_RESERVED_WORDS(V) \
+ V(implements) \
+ V(interface) \
+ V(let) \
+ V(package) \
+ V(private) \
+ V(protected) \
+ V(public) \
+ V(static) \
+ V(yield)
+
+
+#define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
+ V(implements) \
+ V(let) \
+ V(static) \
+ V(yield)
+
+
+#define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
+ "var " #NAME ";", \
+ "var foo, " #NAME ";", \
+ "try { } catch (" #NAME ") { }", \
+ "function " #NAME "() { }", \
+ "(function " #NAME "() { })", \
+ "function foo(" #NAME ") { }", \
+ "function foo(bar, " #NAME ") { }", \
+ #NAME " = 1;", \
+ #NAME " += 1;", \
+ "var foo = " #NAME " = 1;", \
+ "++" #NAME ";", \
+ #NAME " ++;",
+
+
TEST(ErrorsFutureStrictReservedWords) {
// Tests that both preparsing and parsing produce the right kind of errors for
// using future strict reserved words as identifiers. Without the strict mode,
// it's ok to use future strict reserved words as identifiers. With the strict
// mode, it isn't.
const char* context_data[][2] = {
- { "\"use strict\";", "" },
{ "function test_func() {\"use strict\"; ", "}"},
{ "() => { \"use strict\"; ", "}" },
{ NULL, NULL }
};
- const char* statement_data[] = {
- "var interface;",
- "var foo, interface;",
- "try { } catch (interface) { }",
- "function interface() { }",
- "function foo(interface) { }",
- "function foo(bar, interface) { }",
- "interface = 1;",
- "var foo = interface = 1;",
- "++interface;",
- "interface++;",
- "var yield = 13;",
+ const char* statement_data[] {
+ LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
NULL
};
- static const ParserFlag always_flags[] = {kAllowArrowFunctions};
- RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
- arraysize(always_flags));
+ RunParserSyncTest(context_data, statement_data, kError);
+ RunParserSyncTest(context_data, statement_data, kError);
}
+#undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
+
+
TEST(NoErrorsFutureStrictReservedWords) {
const char* context_data[][2] = {
{ "", "" },
@@ -1739,23 +1920,18 @@
};
const char* statement_data[] = {
- "var interface;",
- "var foo, interface;",
- "try { } catch (interface) { }",
- "function interface() { }",
- "function foo(interface) { }",
- "function foo(bar, interface) { }",
- "interface = 1;",
- "var foo = interface = 1;",
- "++interface;",
- "interface++;",
- "var yield = 13;",
+ FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
NULL
};
- static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+ static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
+
+ static const ParserFlag classes_flags[] = {
+ kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
+ RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+ classes_flags, arraysize(classes_flags));
}
@@ -2135,12 +2311,13 @@
{ NULL, NULL }
};
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
const char* statement_data[] = {
"super: while(true) { break super; }",
- "interface: while(true) { break interface; }",
- "yield: while(true) { break yield; }",
+ FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
NULL
};
+#undef LABELLED_WHILE
RunParserSyncTest(context_data, statement_data, kError);
}
@@ -2165,7 +2342,28 @@
NULL
};
- static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+ static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
+ RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
+ const char* context_data[][2] = {
+ { "", ""},
+ { "function test_func() {", "}" },
+ { "() => {", "}" },
+ { NULL, NULL }
+ };
+
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
+ const char* statement_data[] {
+ FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
+ NULL
+ };
+#undef LABELLED_WHILE
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -2285,17 +2483,18 @@
i::ScriptData* sd = NULL;
info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
i::Parser::Parse(&info, true);
- i::ParseData pd(sd);
+ i::ParseData* pd = i::ParseData::FromCachedData(sd);
- if (pd.FunctionCount() != test_cases[i].functions) {
+ if (pd->FunctionCount() != test_cases[i].functions) {
v8::base::OS::Print(
"Expected preparse data for program:\n"
"\t%s\n"
"to contain %d functions, however, received %d functions.\n",
- program, test_cases[i].functions, pd.FunctionCount());
+ program, test_cases[i].functions, pd->FunctionCount());
CHECK(false);
}
delete sd;
+ delete pd;
}
}
@@ -2416,9 +2615,9 @@
NULL
};
- // This test requires kAllowNativesSyntax to succeed.
+ // This test requires kAllowNatives to succeed.
static const ParserFlag always_true_flags[] = {
- kAllowNativesSyntax
+ kAllowNatives
};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
@@ -2904,11 +3103,11 @@
const i::AstRawString* name = avf.GetOneByteString("result");
i::Handle<i::String> str = name->string();
CHECK(str->IsInternalizedString());
- i::Scope* global_scope =
- new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
- global_scope->Initialize();
- i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
- DCHECK(s != global_scope);
+ i::Scope* script_scope =
+ new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+ script_scope->Initialize();
+ i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+ DCHECK(s != script_scope);
DCHECK(name != NULL);
// Get result from h's function context (that is f's context)
@@ -2951,11 +3150,11 @@
i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
avf.Internalize(isolate);
- i::Scope* global_scope =
- new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
- global_scope->Initialize();
- i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
- DCHECK(s != global_scope);
+ i::Scope* script_scope =
+ new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+ script_scope->Initialize();
+ i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+ DCHECK(s != script_scope);
const i::AstRawString* name_x = avf.GetOneByteString("x");
// Get result from f's function context (that is g's outer context)
@@ -2998,11 +3197,11 @@
i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
avf.Internalize(isolate);
- i::Scope* global_scope =
- new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
- global_scope->Initialize();
- i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
- DCHECK(s != global_scope);
+ i::Scope* script_scope =
+ new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+ script_scope->Initialize();
+ i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+ DCHECK(s != script_scope);
const i::AstRawString* name_x = avf.GetOneByteString("x");
const i::AstRawString* name_f = avf.GetOneByteString("f");
const i::AstRawString* name_y = avf.GetOneByteString("y");
@@ -3156,8 +3355,7 @@
i::Parser parser(&info, &parse_info);
parser.set_allow_harmony_scoping(true);
CHECK(parser.Parse());
- CHECK(i::Rewriter::Rewrite(&info));
- CHECK(i::Scope::Analyze(&info));
+ CHECK(i::Compiler::Analyze(&info));
CHECK(info.function() != NULL);
i::Scope* scope = info.function()->scope();
@@ -3304,7 +3502,7 @@
// The test is quite slow, so run it with a reduced set of flags.
static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
- static const ParserFlag always_flags[] = { kAllowArrowFunctions };
+ static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
RunParserSyncTest(context_data, statement_data, kError, flags,
arraysize(flags), always_flags, arraysize(always_flags));
}
@@ -3358,7 +3556,7 @@
NULL
};
- static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+ static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -3383,7 +3581,7 @@
"z.super", // Ok, property lookup.
NULL};
- static const ParserFlag always_flags[] = {kAllowClasses};
+ static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -3402,7 +3600,7 @@
"f(super)",
NULL};
- static const ParserFlag always_flags[] = {kAllowClasses};
+ static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -3585,7 +3783,8 @@
"class name extends class base {} {}",
NULL};
- static const ParserFlag always_flags[] = {kAllowClasses};
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses, kAllowHarmonySloppy};
RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -3604,7 +3803,8 @@
"class name extends class base {} {}",
NULL};
- static const ParserFlag always_flags[] = {kAllowClasses};
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses, kAllowHarmonySloppy};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -3648,8 +3848,9 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3706,8 +3907,9 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3737,8 +3939,9 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3774,8 +3977,9 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyNumericLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyNumericLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3804,8 +4008,9 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_name, kError, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3837,8 +4042,9 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_name, kError, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3855,11 +4061,19 @@
"static get prototype() {}",
"static set prototype(_) {}",
"static *prototype() {}",
+ "static 'prototype'() {}",
+ "static *'prototype'() {}",
+ "static prot\\u006ftype() {}",
+ "static 'prot\\u006ftype'() {}",
+ "static get 'prot\\u006ftype'() {}",
+ "static set 'prot\\u006ftype'(_) {}",
+ "static *'prot\\u006ftype'() {}",
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3875,11 +4089,19 @@
"get constructor() {}",
"get constructor(_) {}",
"*constructor() {}",
+ "get 'constructor'() {}",
+ "*'constructor'() {}",
+ "get c\\u006fnstructor() {}",
+ "*c\\u006fnstructor() {}",
+ "get 'c\\u006fnstructor'() {}",
+ "get 'c\\u006fnstructor'(_) {}",
+ "*'c\\u006fnstructor'() {}",
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3900,8 +4122,9 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3909,9 +4132,6 @@
TEST(ClassMultipleConstructorErrors) {
- // We currently do not allow any duplicate properties in class bodies. This
- // test ensures that when we change that we still throw on duplicate
- // constructors.
const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"},
{NULL, NULL}};
@@ -3921,17 +4141,16 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
-// TODO(arv): We should allow duplicate property names.
-// https://code.google.com/p/v8/issues/detail?id=3570
-DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
+TEST(ClassMultiplePropertyNamesNoErrors) {
const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"},
{NULL, NULL}};
@@ -3940,11 +4159,14 @@
"constructor() {}; static constructor() {}",
"m() {}; static m() {}",
"m() {}; m() {}",
+ "static m() {}; static m() {}",
+ "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
@@ -3963,9 +4185,422 @@
NULL};
static const ParserFlag always_flags[] = {
- kAllowClasses,
- kAllowHarmonyObjectLiterals
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
+
+
+TEST(ObjectLiteralPropertyShorthandKeywordsError) {
+ const char* context_data[][2] = {{"({", "});"},
+ {"'use strict'; ({", "});"},
+ {NULL, NULL}};
+
+ const char* name_data[] = {
+ "break",
+ "case",
+ "catch",
+ "class",
+ "const",
+ "continue",
+ "debugger",
+ "default",
+ "delete",
+ "do",
+ "else",
+ "enum",
+ "export",
+ "extends",
+ "false",
+ "finally",
+ "for",
+ "function",
+ "if",
+ "import",
+ "in",
+ "instanceof",
+ "new",
+ "null",
+ "return",
+ "super",
+ "switch",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typeof",
+ "var",
+ "void",
+ "while",
+ "with",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+ RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
+ const char* context_data[][2] = {{"({", "});"},
+ {NULL, NULL}};
+
+ const char* name_data[] = {
+ "implements",
+ "interface",
+ "let",
+ "package",
+ "private",
+ "protected",
+ "public",
+ "static",
+ "yield",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+ RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+
+ const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
+ {NULL, NULL}};
+ RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandError) {
+ const char* context_data[][2] = {{"({", "});"},
+ {"'use strict'; ({", "});"},
+ {NULL, NULL}};
+
+ const char* name_data[] = {
+ "1",
+ "1.2",
+ "0",
+ "0.1",
+ "1.0",
+ "1e1",
+ "0x1",
+ "\"s\"",
+ "'s'",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+ RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
+ const char* context_data[][2] = {{"", ""},
+ {NULL, NULL}};
+
+ const char* name_data[] = {
+ "function* g() { ({yield}); }",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+ RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForIn) {
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function foo(){ 'use strict';", "}"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "for(const x = 1; ; ) {}",
+ "for(const x = 1, y = 2;;){}",
+ "for(const x in [1,2,3]) {}",
+ "for(const x of [1,2,3]) {}",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+ RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForInError) {
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function foo(){ 'use strict';", "}"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "for(const x,y = 1; ; ) {}",
+ "for(const x = 4 in [1,2,3]) {}",
+ "for(const x = 4, y in [1,2,3]) {}",
+ "for(const x = 4 of [1,2,3]) {}",
+ "for(const x = 4, y of [1,2,3]) {}",
+ "for(const x = 1, y = 2 in []) {}",
+ "for(const x,y in []) {}",
+ "for(const x = 1, y = 2 of []) {}",
+ "for(const x,y of []) {}",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+ RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(InvalidUnicodeEscapes) {
+ const char* context_data[][2] = {{"", ""},
+ {"'use strict';", ""},
+ {NULL, NULL}};
+ const char* data[] = {
+ "var foob\\u123r = 0;",
+ "var \\u123roo = 0;",
+ "\"foob\\u123rr\"",
+ // No escapes allowed in regexp flags
+ "/regex/\\u0069g",
+ "/regex/\\u006g",
+ // Braces gone wrong
+ "var foob\\u{c481r = 0;",
+ "var foob\\uc481}r = 0;",
+ "var \\u{0052oo = 0;",
+ "var \\u0052}oo = 0;",
+ "\"foob\\u{c481r\"",
+ "var foob\\u{}ar = 0;",
+ // Too high value for the unicode escape
+ "\"\\u{110000}\"",
+ // Not an unicode escape
+ "var foob\\v1234r = 0;",
+ "var foob\\U1234r = 0;",
+ "var foob\\v{1234}r = 0;",
+ "var foob\\U{1234}r = 0;",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+ RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(UnicodeEscapes) {
+ const char* context_data[][2] = {{"", ""},
+ {"'use strict';", ""},
+ {NULL, NULL}};
+ const char* data[] = {
+ // Identifier starting with escape
+ "var \\u0052oo = 0;",
+ "var \\u{0052}oo = 0;",
+ "var \\u{52}oo = 0;",
+ "var \\u{00000000052}oo = 0;",
+ // Identifier with an escape but not starting with an escape
+ "var foob\\uc481r = 0;",
+ "var foob\\u{c481}r = 0;",
+ // String with an escape
+ "\"foob\\uc481r\"",
+ "\"foob\\{uc481}r\"",
+ // This character is a valid unicode character, representable as a surrogate
+ // pair, not representable as 4 hex digits.
+ "\"foo\\u{10e6d}\"",
+ // Max value for the unicode escape
+ "\"\\u{10ffff}\"",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+ RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(ScanTemplateLiterals) {
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function foo(){ 'use strict';"
+ " var a, b, c; return ", "}"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "``",
+ "`no-subst-template`",
+ "`template-head${a}`",
+ "`${a}`",
+ "`${a}template-tail`",
+ "`template-head${a}template-tail`",
+ "`${a}${b}${c}`",
+ "`a${a}b${b}c${c}`",
+ "`${a}a${b}b${c}c`",
+ "`foo\n\nbar\r\nbaz`",
+ "`foo\n\n${ bar }\r\nbaz`",
+ "`foo${a /* comment */}`",
+ "`foo${a // comment\n}`",
+ "`foo${a \n}`",
+ "`foo${a \r\n}`",
+ "`foo${a \r}`",
+ "`foo${/* comment */ a}`",
+ "`foo${// comment\na}`",
+ "`foo${\n a}`",
+ "`foo${\r\n a}`",
+ "`foo${\r a}`",
+ "`foo${'a' in a}`",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+ RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(ScanTaggedTemplateLiterals) {
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function foo(){ 'use strict';"
+ " function tag() {}"
+ " var a, b, c; return ", "}"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "tag ``",
+ "tag `no-subst-template`",
+ "tag`template-head${a}`",
+ "tag `${a}`",
+ "tag `${a}template-tail`",
+ "tag `template-head${a}template-tail`",
+ "tag\n`${a}${b}${c}`",
+ "tag\r\n`a${a}b${b}c${c}`",
+ "tag `${a}a${b}b${c}c`",
+ "tag\t`foo\n\nbar\r\nbaz`",
+ "tag\r`foo\n\n${ bar }\r\nbaz`",
+ "tag`foo${a /* comment */}`",
+ "tag`foo${a // comment\n}`",
+ "tag`foo${a \n}`",
+ "tag`foo${a \r\n}`",
+ "tag`foo${a \r}`",
+ "tag`foo${/* comment */ a}`",
+ "tag`foo${// comment\na}`",
+ "tag`foo${\n a}`",
+ "tag`foo${\r\n a}`",
+ "tag`foo${\r a}`",
+ "tag`foo${'a' in a}`",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+ RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(TemplateMaterializedLiterals) {
+ const char* context_data[][2] = {
+ {
+ "'use strict';\n"
+ "function tag() {}\n"
+ "var a, b, c;\n"
+ "(", ")"
+ },
+ {NULL, NULL}
+ };
+
+ const char* data[] = {
+ "tag``",
+ "tag`a`",
+ "tag`a${1}b`",
+ "tag`a${1}b${2}c`",
+ "``",
+ "`a`",
+ "`a${1}b`",
+ "`a${1}b${2}c`",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+ RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(ScanUnterminatedTemplateLiterals) {
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function foo(){ 'use strict';"
+ " var a, b, c; return ", "}"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "`no-subst-template",
+ "`template-head${a}",
+ "`${a}template-tail",
+ "`template-head${a}template-tail",
+ "`${a}${b}${c}",
+ "`a${a}b${b}c${c}",
+ "`${a}a${b}b${c}c",
+ "`foo\n\nbar\r\nbaz",
+ "`foo\n\n${ bar }\r\nbaz",
+ "`foo${a /* comment } */`",
+ "`foo${a /* comment } `*/",
+ "`foo${a // comment}`",
+ "`foo${a \n`",
+ "`foo${a \r\n`",
+ "`foo${a \r`",
+ "`foo${/* comment */ a`",
+ "`foo${// commenta}`",
+ "`foo${\n a`",
+ "`foo${\r\n a`",
+ "`foo${\r a`",
+ "`foo${fn(}`",
+ "`foo${1 if}`",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+ RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(TemplateLiteralsIllegalTokens) {
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function foo(){ 'use strict';"
+ " var a, b, c; return ", "}"},
+ {NULL, NULL}};
+ const char* data[] = {
+ "`hello\\x`",
+ "`hello\\x${1}`",
+ "`hello${1}\\x`",
+ "`hello${1}\\x${2}`",
+ "`hello\\x\n`",
+ "`hello\\x\n${1}`",
+ "`hello${1}\\x\n`",
+ "`hello${1}\\x\n${2}`",
+ NULL};
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+ RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(LexicalScopingSloppyMode) {
+ const char* context_data[][2] = {
+ {"", ""},
+ {"function f() {", "}"},
+ {"{", "}"},
+ {NULL, NULL}};
+ const char* bad_data[] = {
+ "let x = 1;",
+ "for(let x = 1;;){}",
+ "for(let x of []){}",
+ "for(let x in []){}",
+ "class C {}",
+ "class C extends D {}",
+ "(class {})",
+ "(class extends D {})",
+ "(class C {})",
+ "(class C extends D {})",
+ NULL};
+ static const ParserFlag always_true_flags[] = {
+ kAllowHarmonyScoping, kAllowHarmonyClasses};
+ static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
+ RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
+ always_true_flags, arraysize(always_true_flags),
+ always_false_flags, arraysize(always_false_flags));
+
+ const char* good_data[] = {
+ "let = 1;",
+ "for(let = 1;;){}",
+ NULL};
+ RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0,
+ always_true_flags, arraysize(always_true_flags),
+ always_false_flags, arraysize(always_false_flags));
+}