diff options
Diffstat (limited to 'deps/v8/test/cctest/test-parsing.cc')
-rw-r--r-- | deps/v8/test/cctest/test-parsing.cc | 1386 |
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)); +} |