Index: test/cctest/test-parsing.cc |
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc |
index ba2fa975fd7ad7728098686d2941e03fe279959f..a59566bd8003ac5175acbff69fccf0d867395204 100644 |
--- a/test/cctest/test-parsing.cc |
+++ b/test/cctest/test-parsing.cc |
@@ -954,74 +954,73 @@ 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, |
+ SUPER_CONSTRUCTOR_CALL = 1 << 2, |
+ THIS = 1 << 3, |
+ INNER_ARGUMENTS = 1 << 4, |
+ INNER_SUPER_PROPERTY = 1 << 5, |
+ INNER_SUPER_CONSTRUCTOR_CALL = 1 << 6, |
+ INNER_THIS = 1 << 7 |
}; |
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()", 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}, |
+ // 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(), 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 { m() { return this + super.m() + arguments } }" |
+ "}", |
+ NONE}, |
+ }; |
i::Isolate* isolate = CcTest::i_isolate(); |
i::Factory* factory = isolate->factory(); |
@@ -1035,6 +1034,15 @@ TEST(ScopeUsesArgumentsSuperThis) { |
for (unsigned j = 0; j < arraysize(surroundings); ++j) { |
for (unsigned i = 0; i < arraysize(source_data); ++i) { |
+ // Super constructor call is only allowed in constructor. |
+ // Super property is only allowed in constructor and method. |
+ if (((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) || |
+ (source_data[i].expected & SUPER_PROPERTY) || |
+ (source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) || |
+ (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); |
@@ -1052,9 +1060,11 @@ TEST(ScopeUsesArgumentsSuperThis) { |
i::Parser parser(&info, &parse_info); |
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()); |
CHECK(i::Rewriter::Rewrite(&info)); |
CHECK(i::Scope::Analyze(&info)); |
CHECK(info.function() != NULL); |
@@ -1064,6 +1074,11 @@ 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, |
@@ -3637,45 +3652,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 { constructor() { super(); } }", |
+ "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 { 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)); |
} |