Chromium Code Reviews| Index: test/cctest/test-preparser.cc |
| diff --git a/test/cctest/test-preparser.cc b/test/cctest/test-preparser.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..07c270de27e2cfda040c2982228c0b7b8a22618a |
| --- /dev/null |
| +++ b/test/cctest/test-preparser.cc |
| @@ -0,0 +1,363 @@ |
| +// Copyright 2017 the V8 project authors. All rights reserved. |
|
vogelheim
2017/02/07 09:11:23
I'd be slightly happier if this file were in the p
marja
2017/02/07 13:38:14
Done.
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "src/ast/ast.h" |
| +#include "src/compiler.h" |
| +#include "src/objects-inl.h" |
| +#include "src/parsing/parse-info.h" |
| +#include "src/parsing/parsing.h" |
| + |
| +#include "test/cctest/cctest.h" |
| +#include "test/cctest/scope-test-helper.h" |
| +#include "test/cctest/unicode-helpers.h" |
| + |
| +TEST(PreParserScopeAnalysis) { |
| + i::FLAG_lazy_inner_functions = true; |
| + i::FLAG_preparser_scope_analysis = true; |
| + i::Isolate* isolate = CcTest::i_isolate(); |
| + i::Factory* factory = isolate->factory(); |
| + i::HandleScope scope(isolate); |
| + LocalContext env; |
| + |
| + const char* prefix = "(function outer() { "; |
| + const char* suffix = " })();"; |
| + int prefix_len = Utf8LengthHelper(prefix); |
| + int suffix_len = Utf8LengthHelper(suffix); |
|
vogelheim
2017/02/07 09:11:23
nitpick, and entirely unrelated to this CL: With t
marja
2017/02/07 13:38:14
Lol, this was some brainless copy paste...
Howeve
|
| + |
| + // The scope start positions must match; note the extra space in lazy_inner. |
| + const char* lazy_inner = " function inner(%s) { %s }"; |
| + const char* eager_inner = "(function inner(%s) { %s })()"; |
| + |
| + struct { |
| + const char* params; |
| + const char* source; |
| + } inners[] = { |
| + // Simple cases |
| + {"", "var1;"}, |
| + {"", "var1 = 5;"}, |
| + {"", "if (true) {}"}, |
| + {"", "function f1() {}"}, |
| + |
| + // Var declarations and assignments. |
| + {"", "var var1;"}, |
| + {"", "var var1; var1 = 5;"}, |
| + {"", "if (true) { var var1; }"}, |
| + {"", "if (true) { var var1; var1 = 5; }"}, |
| + {"", "var var1; function f() { var1; }"}, |
| + {"", "var var1; var1 = 5; function f() { var1; }"}, |
| + {"", "var var1; function f() { var1 = 5; }"}, |
| + |
| + // Let declarations and assignments. |
| + {"", "let var1;"}, |
| + {"", "let var1; var1 = 5;"}, |
| + {"", "if (true) { let var1; }"}, |
| + {"", "if (true) { let var1; var1 = 5; }"}, |
| + {"", "let var1; function f() { var1; }"}, |
| + {"", "let var1; var1 = 5; function f() { var1; }"}, |
| + {"", "let var1; function f() { var1 = 5; }"}, |
| + |
| + // Const declarations. |
| + {"", "const var1 = 5;"}, |
| + {"", "if (true) { const var1 = 5; }"}, |
| + {"", "const var1 = 5; function f() { var1; }"}, |
| + |
| + // Redeclarations. |
| + {"", "var var1; var var1;"}, |
| + {"", "var var1; var var1; var1 = 5;"}, |
| + {"", "var var1; if (true) { var var1; }"}, |
| + {"", "if (true) { var var1; var var1; }"}, |
| + {"", "var var1; if (true) { var var1; var1 = 5; }"}, |
| + {"", "if (true) { var var1; var var1; var1 = 5; }"}, |
| + {"", "var var1; var var1; function f() { var1; }"}, |
| + {"", "var var1; var var1; function f() { var1 = 5; }"}, |
| + |
| + // Shadowing declarations. |
| + {"", "var var1; if (true) { var var1; }"}, |
| + {"", "var var1; if (true) { let var1; }"}, |
| + {"", "let var1; if (true) { let var1; }"}, |
| + |
| + {"", "var var1; if (true) { const var1 = 0; }"}, |
| + {"", "const var1 = 0; if (true) { const var1 = 0; }"}, |
| + |
| + // Arguments and this. |
| + {"", "arguments;"}, |
| + {"", "arguments = 5;"}, |
| + {"", "if (true) { arguments; }"}, |
| + {"", "if (true) { arguments = 5; }"}, |
| + {"", "function f() { arguments; }"}, |
| + {"", "function f() { arguments = 5; }"}, |
| + |
| + {"", "this;"}, |
| + {"", "if (true) { this; }"}, |
| + {"", "function f() { this; }"}, |
| + |
| + // Variable called "arguments" |
| + {"", "var arguments;"}, |
| + {"", "var arguments; arguments = 5;"}, |
| + {"", "if (true) { var arguments; }"}, |
| + {"", "if (true) { var arguments; arguments = 5; }"}, |
| + {"", "var arguments; function f() { arguments; }"}, |
| + {"", "var arguments; arguments = 5; function f() { arguments; }"}, |
| + {"", "var arguments; function f() { arguments = 5; }"}, |
| + |
| + {"", "let arguments;"}, |
| + {"", "let arguments; arguments = 5;"}, |
| + {"", "if (true) { let arguments; }"}, |
| + {"", "if (true) { let arguments; arguments = 5; }"}, |
| + {"", "let arguments; function f() { arguments; }"}, |
| + {"", "let arguments; arguments = 5; function f() { arguments; }"}, |
| + {"", "let arguments; function f() { arguments = 5; }"}, |
| + |
| + {"", "const arguments = 5;"}, |
| + {"", "if (true) { const arguments = 5; }"}, |
| + {"", "const arguments = 5; function f() { arguments; }"}, |
| + |
| + // Destructuring declarations. |
| + {"", "var [var1, var2] = [1, 2];"}, |
| + {"", "var [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"}, |
| + {"", "var [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"}, |
| + {"", "var [var1, ...var2] = [1, 2, 3];"}, |
| + |
| + {"", "var {var1: var2, var3: var4} = {var1: 1, var3: 2};"}, |
| + {"", |
| + "var {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"}, |
| + {"", "var {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"}, |
| + |
| + {"", "let [var1, var2] = [1, 2];"}, |
| + {"", "let [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"}, |
| + {"", "let [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"}, |
| + {"", "let [var1, ...var2] = [1, 2, 3];"}, |
| + |
| + {"", "let {var1: var2, var3: var4} = {var1: 1, var3: 2};"}, |
| + {"", |
| + "let {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"}, |
| + {"", "let {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"}, |
| + |
| + {"", "const [var1, var2] = [1, 2];"}, |
| + {"", "const [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"}, |
| + {"", "const [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"}, |
| + {"", "const [var1, ...var2] = [1, 2, 3];"}, |
| + |
| + {"", "const {var1: var2, var3: var4} = {var1: 1, var3: 2};"}, |
| + {"", |
| + "const {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"}, |
| + {"", "const {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"}, |
| + |
| + // Referencing the function variable. |
| + {"", "inner;"}, |
| + {"", "function f1() { f1; }"}, |
| + {"", "function f1() { inner; }"}, |
| + {"", "function f1() { function f2() { f1; } }"}, |
| + {"", "function arguments() {}"}, |
| + {"", "function f1() {} function f1() {}"}, |
| + {"", "var f1; function f1() {}"}, |
| + |
| + // Assigning to the function variable. |
| + {"", "inner = 3;"}, |
| + {"", "function f1() { f1 = 3; }"}, |
| + {"", "function f1() { f1; } f1 = 3;"}, |
| + {"", "function arguments() {} arguments = 8"}, |
| + {"", "function f1() {} f1 = 3; function f1() {}"}, |
| + |
| + // Evals. |
| + {"", "var var1; eval('');"}, |
| + {"", "var var1; function f1() { eval(''); }"}, |
| + {"", "let var1; eval('');"}, |
| + {"", "let var1; function f1() { eval(''); }"}, |
| + {"", "const var1 = 10; eval('');"}, |
| + {"", "const var1 = 10; function f1() { eval(''); }"}, |
| + |
| + // Standard for loops. |
| + {"", "for (var var1 = 0; var1 < 10; ++var1) { }"}, |
| + {"", "for (let var1 = 0; var1 < 10; ++var1) { }"}, |
| + {"", "for (const var1 = 0; var1 < 10; ++var1) { }"}, |
| + |
| + {"", |
| + "for (var var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"}, |
| + {"", |
| + "for (let var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"}, |
| + {"", |
| + "for (const var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"}, |
| + {"", |
| + "'use strict'; for (var var1 = 0; var1 < 10; ++var1) { function foo() { " |
| + "var1; } }"}, |
| + {"", |
| + "'use strict'; for (let var1 = 0; var1 < 10; ++var1) { function foo() { " |
| + "var1; } }"}, |
| + {"", |
| + "'use strict'; for (const var1 = 0; var1 < 10; ++var1) { function foo() " |
| + "{ var1; } }"}, |
| + |
| + // For of loops |
| + {"", "for (var1 of [1, 2]) { }"}, |
| + {"", "for (var var1 of [1, 2]) { }"}, |
| + {"", "for (let var1 of [1, 2]) { }"}, |
| + {"", "for (const var1 of [1, 2]) { }"}, |
| + |
| + {"", "for (var1 of [1, 2]) { var1; }"}, |
| + {"", "for (var var1 of [1, 2]) { var1; }"}, |
| + {"", "for (let var1 of [1, 2]) { var1; }"}, |
| + {"", "for (const var1 of [1, 2]) { var1; }"}, |
| + |
| + {"", "for (var1 of [1, 2]) { var1 = 0; }"}, |
| + {"", "for (var var1 of [1, 2]) { var1 = 0; }"}, |
| + {"", "for (let var1 of [1, 2]) { var1 = 0; }"}, |
| + {"", "for (const var1 of [1, 2]) { var1 = 0; }"}, |
| + |
| + {"", "for (var1 of [1, 2]) { function foo() { var1; } }"}, |
| + {"", "for (var var1 of [1, 2]) { function foo() { var1; } }"}, |
| + {"", "for (let var1 of [1, 2]) { function foo() { var1; } }"}, |
| + {"", "for (const var1 of [1, 2]) { function foo() { var1; } }"}, |
| + |
| + {"", "for (var1 of [1, 2]) { function foo() { var1 = 0; } }"}, |
| + {"", "for (var var1 of [1, 2]) { function foo() { var1 = 0; } }"}, |
| + {"", "for (let var1 of [1, 2]) { function foo() { var1 = 0; } }"}, |
| + {"", "for (const var1 of [1, 2]) { function foo() { var1 = 0; } }"}, |
| + |
| + // For in loops |
| + {"", "for (var1 in {a: 6}) { }"}, |
| + {"", "for (var var1 in {a: 6}) { }"}, |
| + {"", "for (let var1 in {a: 6}) { }"}, |
| + {"", "for (const var1 in {a: 6}) { }"}, |
| + |
| + {"", "for (var1 in {a: 6}) { var1; }"}, |
| + {"", "for (var var1 in {a: 6}) { var1; }"}, |
| + {"", "for (let var1 in {a: 6}) { var1; }"}, |
| + {"", "for (const var1 in {a: 6}) { var1; }"}, |
| + |
| + {"", "for (var1 in {a: 6}) { var1 = 0; }"}, |
| + {"", "for (var var1 in {a: 6}) { var1 = 0; }"}, |
| + {"", "for (let var1 in {a: 6}) { var1 = 0; }"}, |
| + {"", "for (const var1 in {a: 6}) { var1 = 0; }"}, |
| + |
| + {"", "for (var1 in {a: 6}) { function foo() { var1; } }"}, |
| + {"", "for (var var1 in {a: 6}) { function foo() { var1; } }"}, |
| + {"", "for (let var1 in {a: 6}) { function foo() { var1; } }"}, |
| + {"", "for (const var1 in {a: 6}) { function foo() { var1; } }"}, |
| + |
| + {"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + {"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + {"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + {"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + |
| + {"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + {"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + {"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + {"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"}, |
| + |
| + // Loops without declarations |
| + {"", "var var1 = 0; for ( ; var1 < 2; ++var1) { }"}, |
| + {"", |
| + "var var1 = 0; for ( ; var1 < 2; ++var1) { function foo() { var1; } }"}, |
| + {"", "var var1 = 0; for ( ; var1 > 2; ) { }"}, |
| + {"", "var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1; } }"}, |
| + {"", |
| + "var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1 = 6; } }"}, |
| + |
| + {"", "var var1 = 0; for(var1; var1 < 2; ++var1) { }"}, |
| + {"", |
| + "var var1 = 0; for (var1; var1 < 2; ++var1) { function foo() { var1; } " |
| + "}"}, |
| + {"", "var var1 = 0; for (var1; var1 > 2; ) { }"}, |
| + {"", "var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1; } }"}, |
| + {"", |
| + "var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1 = 6; } }"}, |
| + |
| + // Sloppy block functions. |
| + {"", "if (true) { function f1() {} }"}, |
| + {"", "if (true) { function f1() {} function f1() {} }"}, |
| + {"", "if (true) { if (true) { function f1() {} } }"}, |
| + {"", "if (true) { if (true) { function f1() {} function f1() {} } }"}, |
| + {"", "if (true) { function f1() {} f1 = 3; }"}, |
| + |
| + {"", "if (true) { function f1() {} function foo() { f1; } }"}, |
| + {"", "if (true) { function f1() {} } function foo() { f1; }"}, |
| + {"", |
| + "if (true) { function f1() {} function f1() {} function foo() { f1; } " |
| + "}"}, |
| + {"", |
| + "if (true) { function f1() {} function f1() {} } function foo() { f1; " |
| + "}"}, |
| + {"", |
| + "if (true) { if (true) { function f1() {} } function foo() { f1; } }"}, |
| + {"", |
| + "if (true) { if (true) { function f1() {} function f1() {} } function " |
| + "foo() { f1; } }"}, |
| + {"", "if (true) { function f1() {} f1 = 3; function foo() { f1; } }"}, |
| + {"", "if (true) { function f1() {} f1 = 3; } function foo() { f1; }"}, |
| + |
| + {"", "function inner2() { if (true) { function f1() {} } }"}, |
| + {"", "function inner2() { if (true) { function f1() {} f1 = 3; } }"}, |
| + |
| + {"", "var f1 = 1; if (true) { function f1() {} }"}, |
| + {"", "var f1 = 1; if (true) { function f1() {} } function foo() { f1; }"}, |
| + }; |
| + |
| + for (unsigned i = 0; i < arraysize(inners); ++i) { |
| + // First compile with the lazy inner function and extract the scope data. |
| + const char* inner_function = lazy_inner; |
| + int inner_function_len = Utf8LengthHelper(inner_function) - 4; |
| + |
| + int params_len = Utf8LengthHelper(inners[i].params); |
| + int source_len = Utf8LengthHelper(inners[i].source); |
| + int len = |
| + prefix_len + inner_function_len + params_len + source_len + suffix_len; |
| + |
| + i::ScopedVector<char> lazy_program(len + 1); |
| + i::SNPrintF(lazy_program, "%s", prefix); |
| + i::SNPrintF(lazy_program + prefix_len, inner_function, inners[i].params, |
| + inners[i].source); |
| + i::SNPrintF(lazy_program + prefix_len + inner_function_len + params_len + |
| + source_len, |
| + "%s", suffix); |
| + |
| + i::Handle<i::String> source = |
| + factory->InternalizeUtf8String(lazy_program.start()); |
| + source->PrintOn(stdout); |
| + printf("\n"); |
| + |
| + i::Handle<i::Script> script = factory->NewScript(source); |
| + i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME); |
| + i::ParseInfo lazy_info(&zone, script); |
| + |
| + // No need to run scope analysis; preparser scope data is produced when |
| + // parsing. |
| + CHECK(i::parsing::ParseProgram(&lazy_info)); |
| + |
| + // Then parse eagerly and check against the scope data. |
| + inner_function = eager_inner; |
| + inner_function_len = Utf8LengthHelper(inner_function) - 4; |
| + len = |
| + prefix_len + inner_function_len + params_len + source_len + suffix_len; |
| + |
| + i::ScopedVector<char> eager_program(len + 1); |
| + i::SNPrintF(eager_program, "%s", prefix); |
| + i::SNPrintF(eager_program + prefix_len, inner_function, inners[i].params, |
| + inners[i].source); |
| + i::SNPrintF(eager_program + prefix_len + inner_function_len + params_len + |
| + source_len, |
| + "%s", suffix); |
| + |
| + source = factory->InternalizeUtf8String(eager_program.start()); |
| + source->PrintOn(stdout); |
| + printf("\n"); |
| + |
| + script = factory->NewScript(source); |
| + i::ParseInfo eager_info(&zone, script); |
| + eager_info.set_allow_lazy_parsing(false); |
| + |
| + CHECK(i::parsing::ParseProgram(&eager_info)); |
| + CHECK(i::Compiler::Analyze(&eager_info)); |
| + |
| + i::Scope* scope = |
| + eager_info.literal()->scope()->inner_scope()->inner_scope(); |
| + DCHECK_NOT_NULL(scope); |
| + DCHECK_NULL(scope->sibling()); |
| + DCHECK(scope->is_function_scope()); |
| + |
| + size_t index = 0; |
| + i::ScopeTestHelper::CompareScopeToData( |
| + scope, lazy_info.preparsed_scope_data(), index); |
| + } |
| +} |