summaryrefslogtreecommitdiff
path: root/deps/v8/test/cctest/test-parsing.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/test-parsing.cc')
-rw-r--r--deps/v8/test/cctest/test-parsing.cc1386
1 files changed, 1176 insertions, 210 deletions
diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc
index 08caeab55f..1a17475ada 100644
--- a/deps/v8/test/cctest/test-parsing.cc
+++ b/deps/v8/test/cctest/test-parsing.cc
@@ -157,7 +157,11 @@ TEST(ScanHTMLEndComments) {
i::CompleteParserRecorder log;
i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
scanner.Initialize(&stream);
- i::PreParser preparser(&scanner, &log, stack_limit);
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(
+ &zone, CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
+ stack_limit);
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
@@ -171,7 +175,11 @@ TEST(ScanHTMLEndComments) {
i::CompleteParserRecorder log;
i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
scanner.Initialize(&stream);
- i::PreParser preparser(&scanner, &log, stack_limit);
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(
+ &zone, CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
+ stack_limit);
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
// Even in the case of a syntax error, kPreParseSuccess is returned.
@@ -317,7 +325,11 @@ TEST(StandAlonePreParser) {
i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
scanner.Initialize(&stream);
- i::PreParser preparser(&scanner, &log, stack_limit);
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(
+ &zone, CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
+ stack_limit);
preparser.set_allow_lazy(true);
preparser.set_allow_natives(true);
preparser.set_allow_harmony_arrow_functions(true);
@@ -351,7 +363,11 @@ TEST(StandAlonePreParserNoNatives) {
scanner.Initialize(&stream);
// Preparser defaults to disallowing natives syntax.
- i::PreParser preparser(&scanner, &log, stack_limit);
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(
+ &zone, CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
+ stack_limit);
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
@@ -375,7 +391,7 @@ TEST(PreparsingObjectLiterals) {
v8::Local<v8::Value> result = ParserCacheCompileRun(source);
CHECK(result->IsString());
v8::String::Utf8Value utf8(result);
- CHECK_EQ("foo", *utf8);
+ CHECK_EQ(0, strcmp("foo", *utf8));
}
{
@@ -383,7 +399,7 @@ TEST(PreparsingObjectLiterals) {
v8::Local<v8::Value> result = ParserCacheCompileRun(source);
CHECK(result->IsString());
v8::String::Utf8Value utf8(result);
- CHECK_EQ("foo", *utf8);
+ CHECK_EQ(0, strcmp("foo", *utf8));
}
{
@@ -391,7 +407,7 @@ TEST(PreparsingObjectLiterals) {
v8::Local<v8::Value> result = ParserCacheCompileRun(source);
CHECK(result->IsString());
v8::String::Utf8Value utf8(result);
- CHECK_EQ("foo", *utf8);
+ CHECK_EQ(0, strcmp("foo", *utf8));
}
}
@@ -416,7 +432,10 @@ TEST(RegressChromium62639) {
i::CompleteParserRecorder log;
i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
scanner.Initialize(&stream);
- i::PreParser preparser(&scanner, &log,
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(&zone,
+ CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
CcTest::i_isolate()->stack_guard()->real_climit());
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
@@ -448,7 +467,10 @@ TEST(Regress928) {
i::CompleteParserRecorder log;
i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
scanner.Initialize(&stream);
- i::PreParser preparser(&scanner, &log,
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(&zone,
+ CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
CcTest::i_isolate()->stack_guard()->real_climit());
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
@@ -497,7 +519,11 @@ TEST(PreParseOverflow) {
i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
scanner.Initialize(&stream);
- i::PreParser preparser(&scanner, &log, stack_limit);
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(&zone,
+ CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
+ stack_limit);
preparser.set_allow_lazy(true);
preparser.set_allow_harmony_arrow_functions(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
@@ -696,7 +722,7 @@ TEST(Utf8CharacterStream) {
int i = 0;
while (stream.pos() < kMaxUC16CharU) {
CHECK_EQU(i, stream.pos());
- unsigned progress = stream.SeekForward(12);
+ int progress = static_cast<int>(stream.SeekForward(12));
i += progress;
int32_t c = stream.Advance();
if (i <= kMaxUC16Char) {
@@ -805,7 +831,7 @@ void TestScanRegExp(const char* re_source, const char* expected) {
CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
scanner.Next(); // Current token is now the regexp literal.
- i::Zone zone(CcTest::i_isolate());
+ i::Zone zone;
i::AstValueFactory ast_value_factory(&zone,
CcTest::i_isolate()->heap()->HashSeed());
ast_value_factory.Internalize(CcTest::i_isolate());
@@ -926,74 +952,70 @@ TEST(ScopeUsesArgumentsSuperThis) {
const char* suffix;
} surroundings[] = {
{ "function f() {", "}" },
- { "var f = () => {", "}" },
+ { "var f = () => {", "};" },
+ { "class C { constructor() {", "} }" },
};
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
+ SUPER_PROPERTY = 1 << 1,
+ THIS = 1 << 2,
+ INNER_ARGUMENTS = 1 << 3,
+ INNER_SUPER_PROPERTY = 1 << 4,
+ INNER_THIS = 1 << 5
};
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},
- };
+ {"", NONE},
+ {"return this", THIS},
+ {"return arguments", ARGUMENTS},
+ {"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.f() + x", INNER_SUPER_PROPERTY},
+ {"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.f() } }",
+ SUPER_PROPERTY},
+ {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
+ // 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 { m(x) { return super.m() + x } }", NONE},
+ {"var x = function () { this.foo = 42 };", NONE},
+ {"var x = { m() { super.foo = 42 } };", NONE},
+ {"if (1) { return function () { while (true) new this() } }", NONE},
+ {"if (1) { return { m() { while (true) super.m() } } }", NONE},
+ {"return function (x) { return () => this }", NONE},
+ {"return { m(x) { return () => super.m() } }", 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.f(), arguments; }",
+ INNER_ARGUMENTS | INNER_SUPER_PROPERTY | 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 { m() { return this + super.m() + arguments } }"
+ "}",
+ NONE},
+ };
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
@@ -1007,6 +1029,12 @@ TEST(ScopeUsesArgumentsSuperThis) {
for (unsigned j = 0; j < arraysize(surroundings); ++j) {
for (unsigned i = 0; i < arraysize(source_data); ++i) {
+ // Super property is only allowed in constructor and method.
+ if (((source_data[i].expected & SUPER_PROPERTY) ||
+ (source_data[i].expected & INNER_SUPER_PROPERTY) ||
+ (source_data[i].expected == NONE)) && j != 2) {
+ continue;
+ }
int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
i::StrLength(surroundings[j].suffix) +
i::StrLength(source_data[i].body);
@@ -1018,15 +1046,15 @@ TEST(ScopeUsesArgumentsSuperThis) {
.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);
+ i::Parser parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(), isolate->unicode_cache());
parser.set_allow_harmony_arrow_functions(true);
parser.set_allow_harmony_classes(true);
+ parser.set_allow_harmony_object_literals(true);
parser.set_allow_harmony_scoping(true);
+ parser.set_allow_harmony_sloppy(true);
info.MarkAsGlobal();
- parser.Parse();
+ CHECK(parser.Parse(&info));
CHECK(i::Rewriter::Rewrite(&info));
CHECK(i::Scope::Analyze(&info));
CHECK(info.function() != NULL);
@@ -1036,19 +1064,20 @@ TEST(ScopeUsesArgumentsSuperThis) {
CHECK_EQ(1, script_scope->inner_scopes()->length());
i::Scope* scope = script_scope->inner_scopes()->at(0);
+ // Adjust for constructor scope.
+ if (j == 2) {
+ CHECK_EQ(1, scope->inner_scopes()->length());
+ scope = 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());
}
@@ -1070,7 +1099,7 @@ TEST(ScopePositions) {
const char* inner_source;
const char* outer_suffix;
i::ScopeType scope_type;
- i::StrictMode strict_mode;
+ i::LanguageMode language_mode;
};
const SourceData source_data[] = {
@@ -1269,16 +1298,14 @@ TEST(ScopePositions) {
CHECK_EQ(source->length(), kProgramSize);
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);
+ i::Parser parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(), isolate->unicode_cache());
parser.set_allow_lazy(true);
parser.set_allow_harmony_scoping(true);
parser.set_allow_harmony_arrow_functions(true);
info.MarkAsGlobal();
- info.SetStrictMode(source_data[i].strict_mode);
- parser.Parse();
+ info.SetLanguageMode(source_data[i].language_mode);
+ parser.Parse(&info);
CHECK(info.function() != NULL);
// Check scope types and positions.
@@ -1356,9 +1383,12 @@ enum ParserFlag {
kAllowHarmonyArrowFunctions,
kAllowHarmonyClasses,
kAllowHarmonyObjectLiterals,
+ kAllowHarmonyRestParameters,
kAllowHarmonyTemplates,
kAllowHarmonySloppy,
- kAllowHarmonyUnicode
+ kAllowHarmonyUnicode,
+ kAllowHarmonyComputedPropertyNames,
+ kAllowStrongMode
};
@@ -1383,8 +1413,13 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
flags.Contains(kAllowHarmonyArrowFunctions));
parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
+ parser->set_allow_harmony_rest_params(
+ flags.Contains(kAllowHarmonyRestParameters));
parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
+ parser->set_allow_harmony_computed_property_names(
+ flags.Contains(kAllowHarmonyComputedPropertyNames));
+ parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode));
}
@@ -1403,7 +1438,11 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
{
i::Scanner scanner(isolate->unicode_cache());
i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
- i::PreParser preparser(&scanner, &log, stack_limit);
+ i::Zone zone;
+ i::AstValueFactory ast_value_factory(
+ &zone, CcTest::i_isolate()->heap()->HashSeed());
+ i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
+ stack_limit);
SetParserFlags(&preparser, flags);
scanner.Initialize(&stream);
i::PreParser::PreParseResult result = preparser.PreParseProgram(
@@ -1418,13 +1457,11 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
{
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);
+ i::Parser parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(), isolate->unicode_cache());
SetParserFlags(&parser, flags);
info.MarkAsGlobal();
- parser.Parse();
+ parser.Parse(&info);
function = info.function();
if (function) {
parser_materialized_literals = function->materialized_literal_count();
@@ -1667,8 +1704,9 @@ TEST(StrictOctal) {
v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
CHECK(try_catch.HasCaught());
v8::String::Utf8Value exception(try_catch.Exception());
- CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
- *exception);
+ CHECK_EQ(0,
+ strcmp("SyntaxError: Octal literals are not allowed in strict mode.",
+ *exception));
}
@@ -1753,10 +1791,11 @@ TEST(ErrorsEvalAndArguments) {
// ok to use "eval" or "arguments" as identifiers. With the strict mode, it
// isn't.
const char* context_data[][2] = {
- { "\"use strict\";", "" },
- { "var eval; function test_func() {\"use strict\"; ", "}"},
- { NULL, NULL }
- };
+ {"\"use strict\";", ""},
+ {"\"use strong\";", ""},
+ {"var eval; function test_func() {\"use strict\"; ", "}"},
+ {"var eval; function test_func() {\"use strong\"; ", "}"},
+ {NULL, NULL}};
const char* statement_data[] = {
"var eval;",
@@ -1786,7 +1825,9 @@ TEST(ErrorsEvalAndArguments) {
NULL
};
- RunParserSyncTest(context_data, statement_data, kError);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
}
@@ -1893,18 +1934,22 @@ TEST(ErrorsFutureStrictReservedWords) {
// it's ok to use future strict reserved words as identifiers. With the strict
// mode, it isn't.
const char* context_data[][2] = {
- { "function test_func() {\"use strict\"; ", "}"},
- { "() => { \"use strict\"; ", "}" },
- { NULL, NULL }
- };
+ {"function test_func() {\"use strict\"; ", "}"},
+ {"() => { \"use strict\"; ", "}"},
+ {"function test_func() {\"use strong\"; ", "}"},
+ {"() => { \"use strong\"; ", "}"},
+ {NULL, NULL}};
const char* statement_data[] {
LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
NULL
};
- RunParserSyncTest(context_data, statement_data, kError);
- RunParserSyncTest(context_data, statement_data, kError);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
}
@@ -2082,15 +2127,21 @@ TEST(NoErrorsYieldSloppyGeneratorsEnabled) {
TEST(ErrorsYieldStrict) {
const char* context_data[][2] = {
- { "\"use strict\";", "" },
- { "\"use strict\"; function not_gen() {", "}" },
- { "function test_func() {\"use strict\"; ", "}"},
- { "\"use strict\"; function * gen() { function not_gen() {", "} }" },
- { "\"use strict\"; (function not_gen() {", "})" },
- { "\"use strict\"; (function * gen() { (function not_gen() {", "}) })" },
- { "() => {\"use strict\"; ", "}" },
- { NULL, NULL }
- };
+ {"\"use strict\";", ""},
+ {"\"use strict\"; function not_gen() {", "}"},
+ {"function test_func() {\"use strict\"; ", "}"},
+ {"\"use strict\"; function * gen() { function not_gen() {", "} }"},
+ {"\"use strict\"; (function not_gen() {", "})"},
+ {"\"use strict\"; (function * gen() { (function not_gen() {", "}) })"},
+ {"() => {\"use strict\"; ", "}"},
+ {"\"use strong\";", ""},
+ {"\"use strong\"; function not_gen() {", "}"},
+ {"function test_func() {\"use strong\"; ", "}"},
+ {"\"use strong\"; function * gen() { function not_gen() {", "} }"},
+ {"\"use strong\"; (function not_gen() {", "})"},
+ {"\"use strong\"; (function * gen() { (function not_gen() {", "}) })"},
+ {"() => {\"use strong\"; ", "}"},
+ {NULL, NULL}};
const char* statement_data[] = {
"var yield;",
@@ -2110,7 +2161,9 @@ TEST(ErrorsYieldStrict) {
NULL
};
- RunParserSyncTest(context_data, statement_data, kError);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
}
@@ -2228,8 +2281,10 @@ TEST(ErrorsNameOfStrictFunction) {
const char* context_data[][2] = {
{ "function ", ""},
{ "\"use strict\"; function", ""},
+ { "\"use strong\"; function", ""},
{ "function * ", ""},
{ "\"use strict\"; function * ", ""},
+ { "\"use strong\"; function * ", ""},
{ NULL, NULL }
};
@@ -2239,12 +2294,14 @@ TEST(ErrorsNameOfStrictFunction) {
"interface() {\"use strict\";}",
"yield() {\"use strict\";}",
// Future reserved words are always illegal
- "function super() { }",
- "function super() {\"use strict\";}",
+ "super() { }",
+ "super() {\"use strict\";}",
NULL
};
- RunParserSyncTest(context_data, statement_data, kError);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
}
@@ -2305,11 +2362,13 @@ TEST(ErrorsIllegalWordsAsLabelsSloppy) {
TEST(ErrorsIllegalWordsAsLabelsStrict) {
// Tests that illegal tokens as labels produce the correct errors.
const char* context_data[][2] = {
- { "\"use strict\";", "" },
- { "function test_func() {\"use strict\"; ", "}"},
- { "() => {\"use strict\"; ", "}" },
- { NULL, NULL }
- };
+ {"\"use strict\";", ""},
+ {"function test_func() {\"use strict\"; ", "}"},
+ {"() => {\"use strict\"; ", "}"},
+ {"\"use strong\";", ""},
+ {"function test_func() {\"use strong\"; ", "}"},
+ {"() => {\"use strong\"; ", "}"},
+ {NULL, NULL}};
#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
const char* statement_data[] = {
@@ -2319,7 +2378,9 @@ TEST(ErrorsIllegalWordsAsLabelsStrict) {
};
#undef LABELLED_WHILE
- RunParserSyncTest(context_data, statement_data, kError);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
}
@@ -2396,10 +2457,13 @@ TEST(NoErrorsParenthesizedDirectivePrologue) {
const char* statement_data[] = {
"(\"use strict\"); var eval;",
+ "(\"use strong\"); var eval;",
NULL
};
- RunParserSyncTest(context_data, statement_data, kSuccess);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
}
@@ -2463,7 +2527,8 @@ TEST(DontRegressPreParserDataSizes) {
// No functions.
{"var x = 42;", 0},
// Functions.
- {"function foo() {}", 1}, {"function foo() {} function bar() {}", 2},
+ {"function foo() {}", 1},
+ {"function foo() {} function bar() {}", 2},
// Getter / setter functions are recorded as functions if they're on the top
// level.
{"var x = {get foo(){} };", 1},
@@ -2482,7 +2547,7 @@ TEST(DontRegressPreParserDataSizes) {
i::CompilationInfoWithZone info(script);
i::ScriptData* sd = NULL;
info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
- i::Parser::Parse(&info, true);
+ i::Parser::ParseStatic(&info, true);
i::ParseData* pd = i::ParseData::FromCachedData(sd);
if (pd->FunctionCount() != test_cases[i].functions) {
@@ -2523,6 +2588,7 @@ TEST(FunctionDeclaresItselfStrict) {
const char* strict_statement_data[] = {
"\"use strict\";",
+ "\"use strong\";",
NULL
};
@@ -2531,8 +2597,11 @@ TEST(FunctionDeclaresItselfStrict) {
NULL
};
- RunParserSyncTest(context_data, strict_statement_data, kError);
- RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(context_data, strict_statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(context_data, non_strict_statement_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
}
@@ -2684,12 +2753,9 @@ TEST(ErrorsNewExpression) {
TEST(StrictObjectLiteralChecking) {
- const char* strict_context_data[][2] = {
+ const char* context_data[][2] = {
{"\"use strict\"; var myobject = {", "};"},
{"\"use strict\"; var myobject = {", ",};"},
- { NULL, NULL }
- };
- const char* non_strict_context_data[][2] = {
{"var myobject = {", "};"},
{"var myobject = {", ",};"},
{ NULL, NULL }
@@ -2707,8 +2773,7 @@ TEST(StrictObjectLiteralChecking) {
NULL
};
- RunParserSyncTest(non_strict_context_data, statement_data, kSuccess);
- RunParserSyncTest(strict_context_data, statement_data, kError);
+ RunParserSyncTest(context_data, statement_data, kSuccess);
}
@@ -2720,36 +2785,17 @@ TEST(ErrorsObjectLiteralChecking) {
};
const char* statement_data[] = {
- ",",
- "foo: 1, get foo() {}",
- "foo: 1, set foo(v) {}",
- "\"foo\": 1, get \"foo\"() {}",
- "\"foo\": 1, set \"foo\"(v) {}",
- "1: 1, get 1() {}",
- "1: 1, set 1() {}",
- "get foo() {}, get foo() {}",
- "set foo(_) {}, set foo(_) {}",
- // It's counter-intuitive, but these collide too (even in classic
- // mode). Note that we can have "foo" and foo as properties in classic
- // mode,
- // but we cannot have "foo" and get foo, or foo and get "foo".
- "foo: 1, get \"foo\"() {}",
- "foo: 1, set \"foo\"(v) {}",
- "\"foo\": 1, get foo() {}",
- "\"foo\": 1, set foo(v) {}",
- "1: 1, get \"1\"() {}",
- "1: 1, set \"1\"() {}",
- "\"1\": 1, get 1() {}"
- "\"1\": 1, set 1(v) {}"
- // Wrong number of parameters
- "get bar(x) {}",
- "get bar(x, y) {}",
- "set bar() {}",
- "set bar(x, y) {}",
- // Parsing FunctionLiteral for getter or setter fails
- "get foo( +",
- "get foo() \"error\"",
- NULL};
+ ",",
+ // Wrong number of parameters
+ "get bar(x) {}",
+ "get bar(x, y) {}",
+ "set bar() {}",
+ "set bar(x, y) {}",
+ // Parsing FunctionLiteral for getter or setter fails
+ "get foo( +",
+ "get foo() \"error\"",
+ NULL
+ };
RunParserSyncTest(context_data, statement_data, kError);
}
@@ -2765,6 +2811,22 @@ TEST(NoErrorsObjectLiteralChecking) {
};
const char* statement_data[] = {
+ "foo: 1, get foo() {}",
+ "foo: 1, set foo(v) {}",
+ "\"foo\": 1, get \"foo\"() {}",
+ "\"foo\": 1, set \"foo\"(v) {}",
+ "1: 1, get 1() {}",
+ "1: 1, set 1(v) {}",
+ "get foo() {}, get foo() {}",
+ "set foo(_) {}, set foo(v) {}",
+ "foo: 1, get \"foo\"() {}",
+ "foo: 1, set \"foo\"(v) {}",
+ "\"foo\": 1, get foo() {}",
+ "\"foo\": 1, set foo(v) {}",
+ "1: 1, get \"1\"() {}",
+ "1: 1, set \"1\"(v) {}",
+ "\"1\": 1, get 1() {}",
+ "\"1\": 1, set 1(v) {}",
"foo: 1, bar: 2",
"\"foo\": 1, \"bar\": 2",
"1: 1, 2: 2",
@@ -2829,6 +2891,11 @@ TEST(TooManyArguments) {
TEST(StrictDelete) {
// "delete <Identifier>" is not allowed in strict mode.
+ const char* strong_context_data[][2] = {
+ {"\"use strong\"; ", ""},
+ { NULL, NULL }
+ };
+
const char* strict_context_data[][2] = {
{"\"use strict\"; ", ""},
{ NULL, NULL }
@@ -2870,14 +2937,27 @@ TEST(StrictDelete) {
NULL
};
- RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
- RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+ RunParserSyncTest(strong_context_data, sloppy_statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(strict_context_data, sloppy_statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess, NULL,
+ 0, always_flags, arraysize(always_flags));
- RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
- RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
+ RunParserSyncTest(strong_context_data, good_statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(strict_context_data, good_statement_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
- RunParserSyncTest(strict_context_data, bad_statement_data, kError);
- RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
+ RunParserSyncTest(strong_context_data, bad_statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(strict_context_data, bad_statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(sloppy_context_data, bad_statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
}
@@ -3093,7 +3173,7 @@ TEST(SerializationOfMaybeAssignmentFlag) {
i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
source->PrintOn(stdout);
printf("\n");
- i::Zone zone(isolate);
+ i::Zone zone;
v8::Local<v8::Value> v = CompileRun(src);
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
@@ -3104,9 +3184,10 @@ TEST(SerializationOfMaybeAssignmentFlag) {
i::Handle<i::String> str = name->string();
CHECK(str->IsInternalizedString());
i::Scope* script_scope =
- new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+ new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
script_scope->Initialize();
- i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+ i::Scope* s =
+ i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
DCHECK(s != script_scope);
DCHECK(name != NULL);
@@ -3142,7 +3223,7 @@ TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
source->PrintOn(stdout);
printf("\n");
- i::Zone zone(isolate);
+ i::Zone zone;
v8::Local<v8::Value> v = CompileRun(src);
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
@@ -3151,9 +3232,10 @@ TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
avf.Internalize(isolate);
i::Scope* script_scope =
- new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+ new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
script_scope->Initialize();
- i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+ i::Scope* s =
+ i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
DCHECK(s != script_scope);
const i::AstRawString* name_x = avf.GetOneByteString("x");
@@ -3189,7 +3271,7 @@ TEST(ExportsMaybeAssigned) {
i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
source->PrintOn(stdout);
printf("\n");
- i::Zone zone(isolate);
+ i::Zone zone;
v8::Local<v8::Value> v = CompileRun(src);
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
@@ -3198,9 +3280,10 @@ TEST(ExportsMaybeAssigned) {
avf.Internalize(isolate);
i::Scope* script_scope =
- new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+ new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
script_scope->Initialize();
- i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+ i::Scope* s =
+ i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
DCHECK(s != script_scope);
const i::AstRawString* name_x = avf.GetOneByteString("x");
const i::AstRawString* name_f = avf.GetOneByteString("f");
@@ -3349,12 +3432,11 @@ TEST(InnerAssignment) {
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);
+ i::Parser parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(),
+ isolate->unicode_cache());
parser.set_allow_harmony_scoping(true);
- CHECK(parser.Parse());
+ CHECK(parser.Parse(&info));
CHECK(i::Compiler::Analyze(&info));
CHECK(info.function() != NULL);
@@ -3562,45 +3644,224 @@ TEST(NoErrorsArrowFunctions) {
}
-TEST(NoErrorsSuper) {
+TEST(SuperNoErrors) {
// Tests that parser and preparser accept 'super' keyword in right places.
- const char* context_data[][2] = {{"", ";"},
- {"k = ", ";"},
- {"foo(", ");"},
- {NULL, NULL}};
+ const char* context_data[][2] = {
+ {"class C { m() { ", "; } }"},
+ {"class C { m() { k = ", "; } }"},
+ {"class C { m() { foo(", "); } }"},
+ {"class C { m() { () => ", "; } }"},
+ {NULL, NULL}
+ };
const char* statement_data[] = {
"super.x",
"super[27]",
+ "new super.x",
+ "new super.x()",
+ "new super[27]",
+ "new super[27]()",
+ "z.super", // Ok, property lookup.
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyArrowFunctions,
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
+ };
+ RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(SuperErrors) {
+ const char* context_data[][2] = {
+ {"class C { m() { ", "; } }"},
+ {"class C { m() { k = ", "; } }"},
+ {"class C { m() { foo(", "); } }"},
+ {"class C { m() { () => ", "; } }"},
+ {NULL, NULL}
+ };
+
+ const char* expression_data[] = {
+ "super",
+ "super = x",
+ "y = super",
+ "f(super)",
"new super",
"new super()",
"new super(12, 45)",
"new new super",
"new new super()",
"new new super()()",
- "z.super", // Ok, property lookup.
- NULL};
+ NULL
+ };
- static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
- RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
+ };
+ RunParserSyncTest(context_data, expression_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
-TEST(ErrorsSuper) {
- // Tests that parser and preparser generate same errors for 'super'.
- const char* context_data[][2] = {{"", ";"},
- {"k = ", ";"},
- {"foo(", ");"},
+TEST(SuperCall) {
+ const char* context_data[][2] = {{"", ""},
{NULL, NULL}};
+ const char* success_data[] = {
+ "class C extends B { constructor() { super(); } }",
+ "class C extends B { constructor() { () => super(); } }",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyArrowFunctions,
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
+ };
+ RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+
+ const char* error_data[] = {
+ "class C { constructor() { super(); } }",
+ "class C { method() { super(); } }",
+ "class C { method() { () => super(); } }",
+ "class C { *method() { super(); } }",
+ "class C { get x() { super(); } }",
+ "class C { set x(_) { super(); } }",
+ "({ method() { super(); } })",
+ "({ *method() { super(); } })",
+ "({ get x() { super(); } })",
+ "({ set x(_) { super(); } })",
+ "({ f: function() { super(); } })",
+ "(function() { super(); })",
+ "var f = function() { super(); }",
+ "({ f: function*() { super(); } })",
+ "(function*() { super(); })",
+ "var f = function*() { super(); }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(SuperNewNoErrors) {
+ const char* context_data[][2] = {
+ {"class C { constructor() { ", " } }"},
+ {"class C { *method() { ", " } }"},
+ {"class C { get x() { ", " } }"},
+ {"class C { set x(_) { ", " } }"},
+ {"({ method() { ", " } })"},
+ {"({ *method() { ", " } })"},
+ {"({ get x() { ", " } })"},
+ {"({ set x(_) { ", " } })"},
+ {NULL, NULL}
+ };
+
+ const char* expression_data[] = {
+ "new super.x;",
+ "new super.x();",
+ "() => new super.x;",
+ "() => new super.x();",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyArrowFunctions,
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
+ };
+ RunParserSyncTest(context_data, expression_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(SuperNewErrors) {
+ const char* context_data[][2] = {
+ {"class C { method() { ", " } }"},
+ {"class C { *method() { ", " } }"},
+ {"class C { get x() { ", " } }"},
+ {"class C { set x(_) { ", " } }"},
+ {"({ method() { ", " } })"},
+ {"({ *method() { ", " } })"},
+ {"({ get x() { ", " } })"},
+ {"({ set x(_) { ", " } })"},
+ {"({ f: function() { ", " } })"},
+ {"(function() { ", " })"},
+ {"var f = function() { ", " }"},
+ {"({ f: function*() { ", " } })"},
+ {"(function*() { ", " })"},
+ {"var f = function*() { ", " }"},
+ {NULL, NULL}
+ };
+
const char* statement_data[] = {
+ "new super;",
+ "new super();",
+ "() => new super;",
+ "() => new super();",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyArrowFunctions,
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
+ };
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(SuperErrorsNonMethods) {
+ // super is only allowed in methods, accessors and constructors.
+ const char* context_data[][2] = {
+ {"", ";"},
+ {"k = ", ";"},
+ {"foo(", ");"},
+ {"if (", ") {}"},
+ {"if (true) {", "}"},
+ {"if (false) {} else {", "}"},
+ {"while (true) {", "}"},
+ {"function f() {", "}"},
+ {"class C extends (", ") {}"},
+ {"class C { m() { function f() {", "} } }"},
+ {"({ m() { function f() {", "} } })"},
+ {NULL, NULL}
+ };
+
+ const char* statement_data[] = {
+ "super",
"super = x",
"y = super",
"f(super)",
- NULL};
+ "super.x",
+ "super[27]",
+ "super.x()",
+ "super[27]()",
+ "super()",
+ "new super.x",
+ "new super.x()",
+ "new super[27]",
+ "new super[27]()",
+ NULL
+ };
- static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy
+ };
RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -3714,8 +3975,6 @@ TEST(MethodDefinitionStrictFormalParamereters) {
const char* params_data[] = {
"x, x",
"x, y, x",
- "eval",
- "arguments",
"var",
"const",
NULL
@@ -3727,9 +3986,58 @@ TEST(MethodDefinitionStrictFormalParamereters) {
}
+TEST(MethodDefinitionEvalArguments) {
+ const char* strict_context_data[][2] =
+ {{"'use strict'; ({method(", "){}});"},
+ {"'use strict'; ({*method(", "){}});"},
+ {NULL, NULL}};
+ const char* sloppy_context_data[][2] =
+ {{"({method(", "){}});"},
+ {"({*method(", "){}});"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "eval",
+ "arguments",
+ NULL};
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+
+ // Fail in strict mode
+ RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+
+ // OK in sloppy mode
+ RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(MethodDefinitionDuplicateEvalArguments) {
+ const char* context_data[][2] =
+ {{"'use strict'; ({method(", "){}});"},
+ {"'use strict'; ({*method(", "){}});"},
+ {"({method(", "){}});"},
+ {"({*method(", "){}});"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "eval, eval",
+ "eval, a, eval",
+ "arguments, arguments",
+ "arguments, a, arguments",
+ NULL};
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+
+ // In strict mode, the error is using "eval" or "arguments" as parameter names
+ // In sloppy mode, the error is that eval / arguments are duplicated
+ RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
TEST(MethodDefinitionDuplicateProperty) {
- // Duplicate properties are allowed in ES6 but we haven't removed that check
- // yet.
const char* context_data[][2] = {{"'use strict'; ({", "});"},
{NULL, NULL}};
@@ -3760,7 +4068,7 @@ TEST(MethodDefinitionDuplicateProperty) {
};
static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
- RunParserSyncTest(context_data, params_data, kError, NULL, 0,
+ RunParserSyncTest(context_data, params_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -3791,9 +4099,9 @@ TEST(ClassExpressionNoErrors) {
TEST(ClassDeclarationNoErrors) {
- const char* context_data[][2] = {{"", ""},
- {"{", "}"},
- {"if (true) {", "}"},
+ const char* context_data[][2] = {{"'use strict'; ", ""},
+ {"'use strict'; {", "}"},
+ {"'use strict'; if (true) {", "}"},
{NULL, NULL}};
const char* statement_data[] = {
"class name {}",
@@ -3804,7 +4112,7 @@ TEST(ClassDeclarationNoErrors) {
NULL};
static const ParserFlag always_flags[] = {
- kAllowHarmonyClasses, kAllowHarmonySloppy};
+ kAllowHarmonyClasses, kAllowHarmonyScoping};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
@@ -4571,6 +4879,119 @@ TEST(TemplateLiteralsIllegalTokens) {
}
+TEST(ParseRestParameters) {
+ const char* context_data[][2] = {{"'use strict';(function(",
+ "){ return args;})(1, [], /regexp/, 'str',"
+ "function(){});"},
+ {"(function(", "){ return args;})(1, [],"
+ "/regexp/, 'str', function(){});"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "...args",
+ "a, ...args",
+ "... args",
+ "a, ... args",
+ "...\targs",
+ "a, ...\targs",
+ "...\r\nargs",
+ "a, ...\r\nargs",
+ "...\rargs",
+ "a, ...\rargs",
+ "...\t\n\t\t\n args",
+ "a, ... \n \n args",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
+ RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(ParseRestParametersErrors) {
+ const char* context_data[][2] = {{"'use strict';(function(",
+ "){ return args;}(1, [], /regexp/, 'str',"
+ "function(){});"},
+ {"(function(", "){ return args;}(1, [],"
+ "/regexp/, 'str', function(){});"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "...args, b",
+ "a, ...args, b",
+ "...args, b",
+ "a, ...args, b",
+ "...args,\tb",
+ "a,...args\t,b",
+ "...args\r\n, b",
+ "a, ... args,\r\nb",
+ "...args\r,b",
+ "a, ... args,\rb",
+ "...args\t\n\t\t\n, b",
+ "a, ... args, \n \n b",
+ "a, a, ...args",
+ "a,\ta, ...args",
+ "a,\ra, ...args",
+ "a,\na, ...args",
+ NULL};
+ static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
+ RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(RestParametersEvalArguments) {
+ const char* strict_context_data[][2] =
+ {{"'use strict';(function(",
+ "){ return;})(1, [], /regexp/, 'str',function(){});"},
+ {NULL, NULL}};
+ const char* sloppy_context_data[][2] =
+ {{"(function(",
+ "){ return;})(1, [],/regexp/, 'str', function(){});"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "...eval",
+ "eval, ...args",
+ "...arguments",
+ "arguments, ...args",
+ NULL};
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
+
+ // Fail in strict mode
+ RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+
+ // OK in sloppy mode
+ RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(RestParametersDuplicateEvalArguments) {
+ const char* context_data[][2] =
+ {{"'use strict';(function(",
+ "){ return;})(1, [], /regexp/, 'str',function(){});"},
+ {"(function(",
+ "){ return;})(1, [],/regexp/, 'str', function(){});"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "eval, ...eval",
+ "eval, eval, ...args",
+ "arguments, ...arguments",
+ "arguments, arguments, ...args",
+ NULL};
+
+ static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
+
+ // In strict mode, the error is using "eval" or "arguments" as parameter names
+ // In sloppy mode, the error is that eval / arguments are duplicated
+ RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
TEST(LexicalScopingSloppyMode) {
const char* context_data[][2] = {
{"", ""},
@@ -4604,3 +5025,548 @@ TEST(LexicalScopingSloppyMode) {
always_true_flags, arraysize(always_true_flags),
always_false_flags, arraysize(always_false_flags));
}
+
+
+TEST(ComputedPropertyName) {
+ const char* context_data[][2] = {{"({[", "]: 1});"},
+ {"({get [", "]() {}});"},
+ {"({set [", "](_) {}});"},
+ {"({[", "]() {}});"},
+ {"({*[", "]() {}});"},
+ {"(class {get [", "]() {}});"},
+ {"(class {set [", "](_) {}});"},
+ {"(class {[", "]() {}});"},
+ {"(class {*[", "]() {}});"},
+ {NULL, NULL}};
+ const char* error_data[] = {
+ "1, 2",
+ "var name",
+ NULL};
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses,
+ kAllowHarmonyComputedPropertyNames,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy,
+ };
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+
+ const char* name_data[] = {
+ "1",
+ "1 + 2",
+ "'name'",
+ "\"name\"",
+ "[]",
+ "{}",
+ NULL};
+
+ RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(ComputedPropertyNameShorthandError) {
+ const char* context_data[][2] = {{"({", "});"},
+ {NULL, NULL}};
+ const char* error_data[] = {
+ "a: 1, [2]",
+ "[1], a: 1",
+ NULL};
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses,
+ kAllowHarmonyComputedPropertyNames,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonySloppy,
+ };
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(BasicImportExportParsing) {
+ const char* kSources[] = {
+ "export let x = 0;",
+ "export var y = 0;",
+ "export const z = 0;",
+ "export function func() { };",
+ "export class C { };",
+ "export { };",
+ "function f() {}; f(); export { f };",
+ "var a, b, c; export { a, b as baz, c };",
+ "var d, e; export { d as dreary, e, };",
+ "export default function f() {}",
+ "export default class C {}",
+ "export default 42",
+ "var x; export default x = 7",
+ "export { Q } from 'somemodule.js';",
+ "export * from 'somemodule.js';",
+ "var foo; export { foo as for };",
+ "export { arguments } from 'm.js';",
+ "export { for } from 'm.js';",
+ "export { yield } from 'm.js'",
+ "export { static } from 'm.js'",
+ "export { let } from 'm.js'",
+
+ "import 'somemodule.js';",
+ "import { } from 'm.js';",
+ "import { a } from 'm.js';",
+ "import { a, b as d, c, } from 'm.js';",
+ "import * as thing from 'm.js';",
+ "import thing from 'm.js';",
+ "import thing, * as rest from 'm.js';",
+ "import thing, { a, b, c } from 'm.js';",
+ "import { arguments as a } from 'm.js';",
+ "import { for as f } from 'm.js';",
+ "import { yield as y } from 'm.js';",
+ "import { static as s } from 'm.js';",
+ "import { let as l } from 'm.js';",
+ };
+
+ 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 i = 0; i < arraysize(kSources); ++i) {
+ int kProgramByteSize = i::StrLength(kSources[i]);
+ i::ScopedVector<char> program(kProgramByteSize + 1);
+ i::SNPrintF(program, "%s", kSources[i]);
+ i::Handle<i::String> source =
+ factory->NewStringFromUtf8(i::CStrVector(program.start()))
+ .ToHandleChecked();
+
+ // Show that parsing as a module works
+ {
+ i::Handle<i::Script> script = factory->NewScript(source);
+ i::CompilationInfoWithZone info(script);
+ i::Parser parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(), isolate->unicode_cache());
+ parser.set_allow_harmony_classes(true);
+ parser.set_allow_harmony_modules(true);
+ parser.set_allow_harmony_scoping(true);
+ info.MarkAsModule();
+ if (!parser.Parse(&info)) {
+ i::Handle<i::JSObject> exception_handle(
+ i::JSObject::cast(isolate->pending_exception()));
+ i::Handle<i::String> message_string =
+ i::Handle<i::String>::cast(i::Object::GetProperty(
+ isolate, exception_handle, "message").ToHandleChecked());
+
+ v8::base::OS::Print(
+ "Parser failed on:\n"
+ "\t%s\n"
+ "with error:\n"
+ "\t%s\n"
+ "However, we expected no error.",
+ source->ToCString().get(), message_string->ToCString().get());
+ CHECK(false);
+ }
+ }
+
+ // And that parsing a script does not.
+ {
+ i::Handle<i::Script> script = factory->NewScript(source);
+ i::CompilationInfoWithZone info(script);
+ i::Parser parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(), isolate->unicode_cache());
+ parser.set_allow_harmony_classes(true);
+ parser.set_allow_harmony_modules(true);
+ parser.set_allow_harmony_scoping(true);
+ info.MarkAsGlobal();
+ CHECK(!parser.Parse(&info));
+ }
+ }
+}
+
+
+TEST(ImportExportParsingErrors) {
+ const char* kErrorSources[] = {
+ "export {",
+ "var a; export { a",
+ "var a; export { a,",
+ "var a; export { a, ;",
+ "var a; export { a as };",
+ "var a, b; export { a as , b};",
+ "export }",
+ "var foo, bar; export { foo bar };",
+ "export { foo };",
+ "export { , };",
+ "export default;",
+ "export default var x = 7;",
+ "export default let x = 7;",
+ "export default const x = 7;",
+ "export *;",
+ "export * from;",
+ "export { Q } from;",
+ "export default from 'module.js';",
+ "export { for }",
+ "export { for as foo }",
+ "export { arguments }",
+ "export { arguments as foo }",
+ "var a; export { a, a };",
+
+ "import from;",
+ "import from 'm.js';",
+ "import { };",
+ "import {;",
+ "import };",
+ "import { , };",
+ "import { , } from 'm.js';",
+ "import { a } from;",
+ "import { a } 'm.js';",
+ "import , from 'm.js';",
+ "import a , from 'm.js';",
+ "import a { b, c } from 'm.js';",
+ "import arguments from 'm.js';",
+ "import eval from 'm.js';",
+ "import { arguments } from 'm.js';",
+ "import { eval } from 'm.js';",
+ "import { a as arguments } from 'm.js';",
+ "import { for } from 'm.js';",
+ "import { y as yield } from 'm.js'",
+ "import { s as static } from 'm.js'",
+ "import { l as let } from 'm.js'",
+ "import { x }, def from 'm.js';",
+ "import def, def2 from 'm.js';",
+ "import * as x, def from 'm.js';",
+ "import * as x, * as y from 'm.js';",
+ "import {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 {};"
+ };
+
+ 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 i = 0; i < arraysize(kErrorSources); ++i) {
+ int kProgramByteSize = i::StrLength(kErrorSources[i]);
+ i::ScopedVector<char> program(kProgramByteSize + 1);
+ i::SNPrintF(program, "%s", kErrorSources[i]);
+ 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 parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(), isolate->unicode_cache());
+ parser.set_allow_harmony_classes(true);
+ parser.set_allow_harmony_modules(true);
+ parser.set_allow_harmony_scoping(true);
+ info.MarkAsModule();
+ CHECK(!parser.Parse(&info));
+ }
+}
+
+
+TEST(DuplicateProtoError) {
+ const char* context_data[][2] = {
+ {"({", "});"},
+ {"'use strict'; ({", "});"},
+ {NULL, NULL}
+ };
+ const char* error_data[] = {
+ "__proto__: {}, __proto__: {}",
+ "__proto__: {}, \"__proto__\": {}",
+ "__proto__: {}, \"__\x70roto__\": {}",
+ "__proto__: {}, a: 1, __proto__: {}",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, error_data, kError);
+}
+
+
+TEST(DuplicateProtoNoError) {
+ const char* context_data[][2] = {
+ {"({", "});"},
+ {"'use strict'; ({", "});"},
+ {NULL, NULL}
+ };
+ const char* error_data[] = {
+ "__proto__: {}, ['__proto__']: {}",
+ "__proto__: {}, __proto__() {}",
+ "__proto__: {}, get __proto__() {}",
+ "__proto__: {}, set __proto__(v) {}",
+ "__proto__: {}, __proto__",
+ NULL
+ };
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyComputedPropertyNames,
+ kAllowHarmonyObjectLiterals,
+ };
+ RunParserSyncTest(context_data, error_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(DeclarationsError) {
+ const char* context_data[][2] = {{"'use strict'; if (true)", ""},
+ {"'use strict'; if (false) {} else", ""},
+ {"'use strict'; while (false)", ""},
+ {"'use strict'; for (;;)", ""},
+ {"'use strict'; for (x in y)", ""},
+ {"'use strict'; do ", " while (false)"},
+ {"'use strong'; if (true)", ""},
+ {"'use strong'; if (false) {} else", ""},
+ {"'use strong'; while (false)", ""},
+ {"'use strong'; for (;;)", ""},
+ {"'use strong'; for (x in y)", ""},
+ {"'use strong'; do ", " while (false)"},
+ {NULL, NULL}};
+
+ const char* statement_data[] = {
+ "let x = 1;",
+ "const x = 1;",
+ "class C {}",
+ NULL};
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses, kAllowHarmonyScoping, kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+void TestLanguageMode(const char* source,
+ i::LanguageMode expected_language_mode) {
+ 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);
+
+ i::Handle<i::Script> script =
+ factory->NewScript(factory->NewStringFromAsciiChecked(source));
+ i::CompilationInfoWithZone info(script);
+ i::Parser parser(&info, isolate->stack_guard()->real_climit(),
+ isolate->heap()->HashSeed(), isolate->unicode_cache());
+ parser.set_allow_strong_mode(true);
+ info.MarkAsGlobal();
+ parser.Parse(&info);
+ CHECK(info.function() != NULL);
+ CHECK_EQ(expected_language_mode, info.function()->language_mode());
+}
+
+
+TEST(LanguageModeDirectives) {
+ TestLanguageMode("\"use nothing\"", i::SLOPPY);
+ TestLanguageMode("\"use strict\"", i::STRICT);
+ TestLanguageMode("\"use strong\"", i::STRONG);
+
+ TestLanguageMode("var x = 1; \"use strict\"", i::SLOPPY);
+ TestLanguageMode("var x = 1; \"use strong\"", i::SLOPPY);
+
+ // Test that multiple directives ("use strict" / "use strong") put the parser
+ // into the correct mode.
+ TestLanguageMode("\"use strict\"; \"use strong\";", i::STRONG);
+ TestLanguageMode("\"use strong\"; \"use strict\";", i::STRONG);
+
+ TestLanguageMode("\"use some future directive\"; \"use strict\";", i::STRICT);
+ TestLanguageMode("\"use some future directive\"; \"use strong\";", i::STRONG);
+}
+
+
+TEST(PropertyNameEvalArguments) {
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"'use strong';", ""},
+ {NULL, NULL}};
+
+ const char* statement_data[] = {
+ "({eval: 1})",
+ "({arguments: 1})",
+ "({eval() {}})",
+ "({arguments() {}})",
+ "({*eval() {}})",
+ "({*arguments() {}})",
+ "({get eval() {}})",
+ "({get arguments() {}})",
+ "({set eval(_) {}})",
+ "({set arguments(_) {}})",
+
+ "class C {eval() {}}",
+ "class C {arguments() {}}",
+ "class C {*eval() {}}",
+ "class C {*arguments() {}}",
+ "class C {get eval() {}}",
+ "class C {get arguments() {}}",
+ "class C {set eval(_) {}}",
+ "class C {set arguments(_) {}}",
+
+ "class C {static eval() {}}",
+ "class C {static arguments() {}}",
+ "class C {static *eval() {}}",
+ "class C {static *arguments() {}}",
+ "class C {static get eval() {}}",
+ "class C {static get arguments() {}}",
+ "class C {static set eval(_) {}}",
+ "class C {static set arguments(_) {}}",
+
+ NULL};
+
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowHarmonyScoping,
+ kAllowStrongMode};
+ RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(FunctionLiteralDuplicateParameters) {
+ const char* strict_context_data[][2] =
+ {{"'use strict';(function(", "){})();"},
+ {"(function(", ") { 'use strict'; })();"},
+ {"'use strict'; function fn(", ") {}; fn();"},
+ {"function fn(", ") { 'use strict'; }; fn();"},
+ {"'use strong';(function(", "){})();"},
+ {"(function(", ") { 'use strong'; })();"},
+ {"'use strong'; function fn(", ") {}; fn();"},
+ {"function fn(", ") { 'use strong'; }; fn();"},
+ {NULL, NULL}};
+
+ const char* sloppy_context_data[][2] =
+ {{"(function(", "){})();"},
+ {"(function(", ") {})();"},
+ {"function fn(", ") {}; fn();"},
+ {"function fn(", ") {}; fn();"},
+ {NULL, NULL}};
+
+ const char* data[] = {
+ "a, a",
+ "a, a, a",
+ "b, a, a",
+ "a, b, c, c",
+ "a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, w",
+ NULL};
+
+ static const ParserFlag always_flags[] = { kAllowStrongMode };
+ RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+ RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, NULL, 0);
+}
+
+
+TEST(VarForbiddenInStrongMode) {
+ const char* strong_context_data[][2] =
+ {{"'use strong'; ", ""},
+ {"function f() {'use strong'; ", "}"},
+ {"function f() {'use strong'; while (true) { ", "} }"},
+ {NULL, NULL}};
+
+ const char* strict_context_data[][2] =
+ {{"'use strict'; ", ""},
+ {"function f() {'use strict'; ", "}"},
+ {"function f() {'use strict'; while (true) { ", "} }"},
+ {NULL, NULL}};
+
+ const char* sloppy_context_data[][2] =
+ {{"", ""},
+ {"function f() { ", "}"},
+ {NULL, NULL}};
+
+ const char* var_declarations[] = {
+ "var x = 0;",
+ "for (var i = 0; i < 10; i++) { }",
+ NULL};
+
+ const char* let_declarations[] = {
+ "let x = 0;",
+ "for (let i = 0; i < 10; i++) { }",
+ NULL};
+
+ const char* const_declarations[] = {
+ "const x = 0;",
+ NULL};
+
+ static const ParserFlag always_flags[] = {kAllowStrongMode,
+ kAllowHarmonyScoping};
+ RunParserSyncTest(strong_context_data, var_declarations, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(strong_context_data, let_declarations, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(strong_context_data, const_declarations, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+
+ RunParserSyncTest(strict_context_data, var_declarations, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+ RunParserSyncTest(strict_context_data, let_declarations, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+
+ RunParserSyncTest(sloppy_context_data, var_declarations, kSuccess, NULL, 0,
+ always_flags, arraysize(always_flags));
+ // At the moment, let declarations are only available in strict mode.
+ RunParserSyncTest(sloppy_context_data, let_declarations, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
+TEST(StrongEmptySubStatements) {
+ const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
+ const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
+ const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
+
+ const char* data[] = {
+ "if (1);",
+ "if (1) {} else;",
+ "while (1);",
+ "do; while (1);",
+ "for (;;);",
+ "for (x in []);",
+ "for (x of []);",
+ "for (const x = 0;;);",
+ "for (const x in []);",
+ "for (const x of []);",
+ NULL};
+
+ static const ParserFlag always_flags[] = {
+ kAllowStrongMode, kAllowHarmonyScoping
+ };
+ RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+ RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+ RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(StrongForIn) {
+ const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
+ const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
+ const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
+
+ const char* data[] = {
+ "for (x in []) {}",
+ "for (const x in []) {}",
+ NULL};
+
+ static const ParserFlag always_flags[] = {
+ kAllowStrongMode, kAllowHarmonyScoping
+ };
+ RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+ RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+ RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}