Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(375)

Unified Diff: test/cctest/test-parsing.cc

Issue 185653004: Experimental parser: merge to r19637 (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/cctest/test-microtask-delivery.cc ('k') | test/cctest/test-platform.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-parsing.cc
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index eb04c0424813d412ff6bd69bdd444f9d469f2d59..345db049e5e0bacf771e4acb0894053678f92d0e 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -237,15 +237,18 @@ TEST(Preparsing) {
CHECK(error_preparse->HasError());
i::ScriptDataImpl *pre_impl =
reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
- i::ScannerBase::Location error_location =
+ i::Scanner::Location error_location =
pre_impl->MessageLocation();
// Error is at "z" in source, location 10..11.
CHECK_EQ(10, error_location.beg_pos);
CHECK_EQ(11, error_location.end_pos);
// Should not crash.
const char* message = pre_impl->BuildMessage();
- pre_impl->BuildArgs();
+ i::Vector<const char*> args = pre_impl->BuildArgs();
CHECK_GT(strlen(message), 0);
+ args.Dispose();
+ i::DeleteArray(message);
+ delete error_preparse;
}
@@ -267,13 +270,13 @@ TEST(StandAlonePreParser) {
uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
for (int i = 0; programs[i]; i++) {
- i::HandleScope handle_scope(CcTest::i_isolate());
- i::Handle<i::String> source =
- CcTest::i_isolate()->factory()->NewStringFromAscii(
- i::Vector<const char>(programs[i], strlen(programs[i])));
+ const char* program = programs[i];
+ i::Utf8ToUtf16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
i::CompleteParserRecorder log;
- i::ExperimentalScanner<uint8_t> scanner(source, CcTest::i_isolate());
- scanner.Init();
+ i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+ scanner.Initialize(&stream);
i::PreParser preparser(&scanner, &log, stack_limit);
preparser.set_allow_lazy(true);
@@ -301,13 +304,14 @@ TEST(StandAlonePreParserNoNatives) {
uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
for (int i = 0; programs[i]; i++) {
- i::HandleScope handle_scope(CcTest::i_isolate());
- i::Handle<i::String> source =
- CcTest::i_isolate()->factory()->NewStringFromAscii(
- i::Vector<const char>(programs[i], strlen(programs[i])));
+ const char* program = programs[i];
+ i::Utf8ToUtf16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
i::CompleteParserRecorder log;
- i::ExperimentalScanner<uint8_t> scanner(source, CcTest::i_isolate());
- scanner.Init();
+ i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+ scanner.Initialize(&stream);
+
// Preparser defaults to disallowing natives syntax.
i::PreParser preparser(&scanner, &log, stack_limit);
preparser.set_allow_lazy(true);
@@ -320,6 +324,87 @@ TEST(StandAlonePreParserNoNatives) {
}
+TEST(PreparsingObjectLiterals) {
+ // Regression test for a bug where the symbol stream produced by PreParser
+ // didn't match what Parser wanted to consume.
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope handles(isolate);
+ v8::Local<v8::Context> context = v8::Context::New(isolate);
+ v8::Context::Scope context_scope(context);
+ int marker;
+ CcTest::i_isolate()->stack_guard()->SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ {
+ const char* source = "var myo = {if: \"foo\"}; myo.if;";
+ v8::Local<v8::Value> result = PreCompileCompileRun(source);
+ CHECK(result->IsString());
+ v8::String::Utf8Value utf8(result);
+ CHECK_EQ("foo", *utf8);
+ }
+
+ {
+ const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
+ v8::Local<v8::Value> result = PreCompileCompileRun(source);
+ CHECK(result->IsString());
+ v8::String::Utf8Value utf8(result);
+ CHECK_EQ("foo", *utf8);
+ }
+
+ {
+ const char* source = "var myo = {1: \"foo\"}; myo[1];";
+ v8::Local<v8::Value> result = PreCompileCompileRun(source);
+ CHECK(result->IsString());
+ v8::String::Utf8Value utf8(result);
+ CHECK_EQ("foo", *utf8);
+ }
+}
+
+namespace v8 {
+namespace internal {
+
+void FakeWritingSymbolIdInPreParseData(i::CompleteParserRecorder* log,
+ int number) {
+ log->WriteNumber(number);
+ if (log->symbol_id_ < number + 1) {
+ log->symbol_id_ = number + 1;
+ }
+}
+
+}
+}
+
+
+TEST(StoringNumbersInPreParseData) {
+ // Symbol IDs are split into chunks of 7 bits for storing. This is a
+ // regression test for a bug where a symbol id was incorrectly stored if some
+ // of the chunks in the middle were all zeros.
+ i::CompleteParserRecorder log;
+ for (int i = 0; i < 18; ++i) {
+ FakeWritingSymbolIdInPreParseData(&log, 1 << i);
+ }
+ for (int i = 1; i < 18; ++i) {
+ FakeWritingSymbolIdInPreParseData(&log, (1 << i) + 1);
+ }
+ for (int i = 6; i < 18; ++i) {
+ FakeWritingSymbolIdInPreParseData(&log, (3 << i) + (5 << (i - 6)));
+ }
+ i::Vector<unsigned> store = log.ExtractData();
+ i::ScriptDataImpl script_data(store);
+ script_data.Initialize();
+ // Check that we get the same symbols back.
+ for (int i = 0; i < 18; ++i) {
+ CHECK_EQ(1 << i, script_data.GetSymbolIdentifier());
+ }
+ for (int i = 1; i < 18; ++i) {
+ CHECK_EQ((1 << i) + 1, script_data.GetSymbolIdentifier());
+ }
+ for (int i = 6; i < 18; ++i) {
+ CHECK_EQ((3 << i) + (5 << (i - 6)), script_data.GetSymbolIdentifier());
+ }
+}
+
+
TEST(RegressChromium62639) {
v8::V8::Initialize();
i::Isolate* isolate = CcTest::i_isolate();
@@ -335,11 +420,10 @@ TEST(RegressChromium62639) {
// and then used the invalid currently scanned literal. This always
// failed in debug mode, and sometimes crashed in release mode.
- v8::HandleScope handles(CcTest::isolate());
- i::Handle<i::String> source = isolate->factory()->NewStringFromAscii(
- i::Vector<const char>(reinterpret_cast<const char*>(program),
- strlen(program)));
- i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, source);
+ i::Utf8ToUtf16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
+ i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
CHECK(data->HasError());
delete data;
}
@@ -365,7 +449,8 @@ TEST(Regress928) {
v8::HandleScope handles(CcTest::isolate());
i::Handle<i::String> source(
factory->NewStringFromAscii(i::CStrVector(program)));
- i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, source);
+ i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
+ i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
CHECK(!data->HasError());
data->Initialize();
@@ -403,13 +488,12 @@ TEST(PreParseOverflow) {
uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
- i::HandleScope handle_scope(CcTest::i_isolate());
- i::Handle<i::String> source =
- CcTest::i_isolate()->factory()->NewStringFromAscii(
- i::Vector<const char>(program.get(), kProgramSize));
+ i::Utf8ToUtf16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program.get()),
+ static_cast<unsigned>(kProgramSize));
i::CompleteParserRecorder log;
- i::ExperimentalScanner<uint8_t> scanner(source, CcTest::i_isolate());
- scanner.Init();
+ i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+ scanner.Initialize(&stream);
i::PreParser preparser(&scanner, &log, stack_limit);
preparser.set_allow_lazy(true);
@@ -438,8 +522,12 @@ class TestExternalResource: public v8::String::ExternalStringResource {
};
+#ifndef V8_USE_GENERATED_LEXER
+
+
#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
+
void TestCharacterStream(const char* ascii_source,
unsigned length,
unsigned start = 0,
@@ -624,6 +712,10 @@ TEST(Utf8CharacterStream) {
#undef CHECK_EQU
+
+#endif
+
+
void TestStreamScanner(i::Utf16CharacterStream* stream,
i::Token::Value* expected_tokens,
int skip_pos = 0, // Zero means not skipping.
@@ -1019,7 +1111,7 @@ TEST(ScopePositions) {
int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
- i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
+ i::ScopedVector<char> program(kProgramByteSize + 1);
i::OS::SNPrintF(program, "%s%s%s",
source_data[i].outer_prefix,
source_data[i].inner_source,
@@ -1099,7 +1191,15 @@ enum ParserFlag {
};
-void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
+enum ParserSyncTestResult {
+ kSuccessOrError,
+ kSuccess,
+ kError
+};
+
+template <typename Traits>
+void SetParserFlags(i::ParserBase<Traits>* parser,
+ i::EnumSet<ParserFlag> flags) {
parser->set_allow_lazy(flags.Contains(kAllowLazy));
parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
@@ -1112,7 +1212,8 @@ void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
void TestParserSyncWithFlags(i::Handle<i::String> source,
- i::EnumSet<ParserFlag> flags) {
+ i::EnumSet<ParserFlag> flags,
+ ParserSyncTestResult result) {
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
@@ -1121,10 +1222,11 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
// Preparse the data.
i::CompleteParserRecorder log;
{
- i::ExperimentalScanner<uint8_t> scanner(source, CcTest::i_isolate());
+ i::Scanner scanner(isolate->unicode_cache());
+ i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
i::PreParser preparser(&scanner, &log, stack_limit);
SetParserFlags(&preparser, flags);
- scanner.Init();
+ scanner.Initialize(&stream);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
}
@@ -1151,7 +1253,18 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
CHECK(maybe_object->To(&exception));
i::Handle<i::JSObject> exception_handle(exception);
i::Handle<i::String> message_string =
- i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
+ i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
+
+ if (result == kSuccess) {
+ i::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);
+ }
if (!data.has_error()) {
i::OS::Print(
@@ -1186,13 +1299,21 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
"However, the parser succeeded",
source->ToCString().get(), FormatMessage(&data)->ToCString().get());
CHECK(false);
+ } else if (result == kError) {
+ i::OS::Print(
+ "Expected error on:\n"
+ "\t%s\n"
+ "However, parser and preparser succeeded",
+ source->ToCString().get());
+ CHECK(false);
}
}
void TestParserSync(const char* source,
const ParserFlag* flag_list,
- size_t flag_list_length) {
+ size_t flag_list_length,
+ ParserSyncTestResult result = kSuccessOrError) {
i::Handle<i::String> str =
CcTest::i_isolate()->factory()->NewStringFromAscii(i::CStrVector(source));
for (int bits = 0; bits < (1 << flag_list_length); bits++) {
@@ -1200,7 +1321,7 @@ void TestParserSync(const char* source,
for (size_t flag_index = 0; flag_index < flag_list_length; flag_index++) {
if ((bits & (1 << flag_index)) != 0) flags.Add(flag_list[flag_index]);
}
- TestParserSyncWithFlags(str, flags);
+ TestParserSyncWithFlags(str, flags, result);
}
}
@@ -1344,3 +1465,748 @@ TEST(PreparserStrictOctal) {
CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
*exception);
}
+
+
+void RunParserSyncTest(const char* context_data[][2],
+ const char* statement_data[],
+ ParserSyncTestResult result) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ int marker;
+ CcTest::i_isolate()->stack_guard()->SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ static const ParserFlag flags[] = {
+ kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
+ kAllowForOf, kAllowNativesSyntax
+ };
+ for (int i = 0; context_data[i][0] != NULL; ++i) {
+ for (int j = 0; statement_data[j] != NULL; ++j) {
+ int kPrefixLen = i::StrLength(context_data[i][0]);
+ int kStatementLen = i::StrLength(statement_data[j]);
+ int kSuffixLen = i::StrLength(context_data[i][1]);
+ int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
+
+ // Plug the source code pieces together.
+ i::ScopedVector<char> program(kProgramSize + 1);
+ int length = i::OS::SNPrintF(program,
+ "%s%s%s",
+ context_data[i][0],
+ statement_data[j],
+ context_data[i][1]);
+ CHECK(length == kProgramSize);
+ TestParserSync(program.start(),
+ flags,
+ ARRAY_SIZE(flags),
+ result);
+ }
+ }
+}
+
+
+TEST(ErrorsEvalAndArguments) {
+ // Tests that both preparsing and parsing produce the right kind of errors for
+ // using "eval" and "arguments" as identifiers. Without the strict mode, it's
+ // 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 }
+ };
+
+ const char* statement_data[] = {
+ "var eval;",
+ "var arguments",
+ "var foo, eval;",
+ "var foo, arguments;",
+ "try { } catch (eval) { }",
+ "try { } catch (arguments) { }",
+ "function eval() { }",
+ "function arguments() { }",
+ "function foo(eval) { }",
+ "function foo(arguments) { }",
+ "function foo(bar, eval) { }",
+ "function foo(bar, arguments) { }",
+ "eval = 1;",
+ "arguments = 1;",
+ "var foo = eval = 1;",
+ "var foo = arguments = 1;",
+ "++eval;",
+ "++arguments;",
+ "eval++;",
+ "arguments++;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsEvalAndArgumentsClassic) {
+ // Tests that both preparsing and parsing accept "eval" and "arguments" as
+ // identifiers when needed.
+ const char* context_data[][2] = {
+ { "", "" },
+ { "function test_func() {", "}"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var eval;",
+ "var arguments",
+ "var foo, eval;",
+ "var foo, arguments;",
+ "try { } catch (eval) { }",
+ "try { } catch (arguments) { }",
+ "function eval() { }",
+ "function arguments() { }",
+ "function foo(eval) { }",
+ "function foo(arguments) { }",
+ "function foo(bar, eval) { }",
+ "function foo(bar, arguments) { }",
+ "eval = 1;",
+ "arguments = 1;",
+ "var foo = eval = 1;",
+ "var foo = arguments = 1;",
+ "++eval;",
+ "++arguments;",
+ "eval++;",
+ "arguments++;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(NoErrorsEvalAndArgumentsStrict) {
+ const char* context_data[][2] = {
+ { "\"use strict\";", "" },
+ { "function test_func() { \"use strict\";", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "eval;",
+ "arguments;",
+ "var foo = eval;",
+ "var foo = arguments;",
+ "var foo = { eval: 1 };",
+ "var foo = { arguments: 1 };",
+ "var foo = { }; foo.eval = {};",
+ "var foo = { }; foo.arguments = {};",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsFutureStrictReservedWords) {
+ // Tests that both preparsing and parsing produce the right kind of errors for
+ // using future strict reserved words as identifiers. Without the strict mode,
+ // it's ok to use future strict reserved words as identifiers. With the strict
+ // mode, it isn't.
+ const char* context_data[][2] = {
+ { "\"use strict\";", "" },
+ { "function test_func() {\"use strict\"; ", "}"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var interface;",
+ "var foo, interface;",
+ "try { } catch (interface) { }",
+ "function interface() { }",
+ "function foo(interface) { }",
+ "function foo(bar, interface) { }",
+ "interface = 1;",
+ "var foo = interface = 1;",
+ "++interface;",
+ "interface++;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsFutureStrictReservedWords) {
+ const char* context_data[][2] = {
+ { "", "" },
+ { "function test_func() {", "}"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var interface;",
+ "var foo, interface;",
+ "try { } catch (interface) { }",
+ "function interface() { }",
+ "function foo(interface) { }",
+ "function foo(bar, interface) { }",
+ "interface = 1;",
+ "var foo = interface = 1;",
+ "++interface;",
+ "interface++;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsReservedWords) {
+ // Tests that both preparsing and parsing produce the right kind of errors for
+ // using future reserved words as identifiers. These tests don't depend on the
+ // strict mode.
+ const char* context_data[][2] = {
+ { "", "" },
+ { "\"use strict\";", "" },
+ { "var eval; function test_func() {", "}"},
+ { "var eval; function test_func() {\"use strict\"; ", "}"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var super;",
+ "var foo, super;",
+ "try { } catch (super) { }",
+ "function super() { }",
+ "function foo(super) { }",
+ "function foo(bar, super) { }",
+ "super = 1;",
+ "var foo = super = 1;",
+ "++super;",
+ "super++;",
+ "function foo super",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsYieldClassic) {
+ // In classic mode, it's okay to use "yield" as identifier, *except* inside a
+ // generator (see next test).
+ const char* context_data[][2] = {
+ { "", "" },
+ { "function is_not_gen() {", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var yield;",
+ "var foo, yield;",
+ "try { } catch (yield) { }",
+ "function yield() { }",
+ "function foo(yield) { }",
+ "function foo(bar, yield) { }",
+ "yield = 1;",
+ "var foo = yield = 1;",
+ "++yield;",
+ "yield++;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsYieldClassicGenerator) {
+ const char* context_data[][2] = {
+ { "function * is_gen() {", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var yield;",
+ "var foo, yield;",
+ "try { } catch (yield) { }",
+ "function yield() { }",
+ // BUG: These should not be allowed, but they are (if kAllowGenerators is
+ // set)
+ // "function foo(yield) { }",
+ // "function foo(bar, yield) { }",
+ "yield = 1;",
+ "var foo = yield = 1;",
+ "++yield;",
+ "yield++;",
+ NULL
+ };
+
+ // If generators are not allowed, the error will be produced at the '*' token,
+ // so this test works both with and without the kAllowGenerators flag.
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsYieldStrict) {
+ const char* context_data[][2] = {
+ { "\"use strict\";", "" },
+ { "\"use strict\"; function is_not_gen() {", "}" },
+ { "function test_func() {\"use strict\"; ", "}"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var yield;",
+ "var foo, yield;",
+ "try { } catch (yield) { }",
+ "function yield() { }",
+ "function foo(yield) { }",
+ "function foo(bar, yield) { }",
+ "yield = 1;",
+ "var foo = yield = 1;",
+ "++yield;",
+ "yield++;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsYield) {
+ const char* context_data[][2] = {
+ { "function * is_gen() {", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "yield 2;", // this is legal inside generator
+ "yield * 2;", // this is legal inside generator
+ NULL
+ };
+
+ // Here we cannot assert that there is no error, since there will be without
+ // the kAllowGenerators flag. However, we test that Parser and PreParser
+ // produce the same errors.
+ RunParserSyncTest(context_data, statement_data, kSuccessOrError);
+}
+
+
+TEST(ErrorsNameOfStrictFunction) {
+ // Tests that illegal tokens as names of a strict function produce the correct
+ // errors.
+ const char* context_data[][2] = {
+ { "", ""},
+ { "\"use strict\";", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "function eval() {\"use strict\";}",
+ "function arguments() {\"use strict\";}",
+ "function interface() {\"use strict\";}",
+ "function yield() {\"use strict\";}",
+ // Future reserved words are always illegal
+ "function super() { }",
+ "function super() {\"use strict\";}",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsNameOfStrictFunction) {
+ const char* context_data[][2] = {
+ { "", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "function eval() { }",
+ "function arguments() { }",
+ "function interface() { }",
+ "function yield() { }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+
+TEST(ErrorsIllegalWordsAsLabelsClassic) {
+ // Using future reserved words as labels is always an error.
+ const char* context_data[][2] = {
+ { "", ""},
+ { "function test_func() {", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "super: while(true) { break super; }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsIllegalWordsAsLabelsStrict) {
+ // Tests that illegal tokens as labels produce the correct errors.
+ const char* context_data[][2] = {
+ { "\"use strict\";", "" },
+ { "function test_func() {\"use strict\"; ", "}"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "super: while(true) { break super; }",
+ "interface: while(true) { break interface; }",
+ "yield: while(true) { break yield; }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsIllegalWordsAsLabels) {
+ // Using eval and arguments as labels is legal even in strict mode.
+ const char* context_data[][2] = {
+ { "", ""},
+ { "function test_func() {", "}" },
+ { "\"use strict\";", "" },
+ { "\"use strict\"; function test_func() {", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "mylabel: while(true) { break mylabel; }",
+ "eval: while(true) { break eval; }",
+ "arguments: while(true) { break arguments; }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsParenthesizedLabels) {
+ // Parenthesized identifiers shouldn't be recognized as labels.
+ const char* context_data[][2] = {
+ { "", ""},
+ { "function test_func() {", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "(mylabel): while(true) { break mylabel; }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsParenthesizedDirectivePrologue) {
+ // Parenthesized directive prologue shouldn't be recognized.
+ const char* context_data[][2] = {
+ { "", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "(\"use strict\"); var eval;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsNotAnIdentifierName) {
+ const char* context_data[][2] = {
+ { "", ""},
+ { "\"use strict\";", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var foo = {}; foo.{;",
+ "var foo = {}; foo.};",
+ "var foo = {}; foo.=;",
+ "var foo = {}; foo.888;",
+ "var foo = {}; foo.-;",
+ "var foo = {}; foo.--;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsIdentifierNames) {
+ // Keywords etc. are valid as property names.
+ const char* context_data[][2] = {
+ { "", ""},
+ { "\"use strict\";", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "var foo = {}; foo.if;",
+ "var foo = {}; foo.yield;",
+ "var foo = {}; foo.super;",
+ "var foo = {}; foo.interface;",
+ "var foo = {}; foo.eval;",
+ "var foo = {}; foo.arguments;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(DontRegressPreParserDataSizes) {
+ // These tests make sure that PreParser doesn't start producing less data.
+
+ v8::V8::Initialize();
+
+ int marker;
+ CcTest::i_isolate()->stack_guard()->SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ struct TestCase {
+ const char* program;
+ int symbols;
+ int functions;
+ } test_cases[] = {
+ // Labels, variables and functions are recorded as symbols.
+ {"{label: 42}", 1, 0}, {"{label: 42; label2: 43}", 2, 0},
+ {"var x = 42;", 1, 0}, {"var x = 42, y = 43;", 2, 0},
+ {"function foo() {}", 1, 1}, {"function foo() {} function bar() {}", 2, 2},
+ // Labels, variables and functions insize lazy functions are not recorded.
+ {"function lazy() { var a, b, c; }", 1, 1},
+ {"function lazy() { a: 1; b: 2; c: 3; }", 1, 1},
+ {"function lazy() { function a() {} function b() {} function c() {} }", 1,
+ 1},
+ {NULL, 0, 0}
+ };
+ // Each function adds 5 elements to the preparse function data.
+ const int kDataPerFunction = 5;
+
+ uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
+ for (int i = 0; test_cases[i].program; i++) {
+ const char* program = test_cases[i].program;
+ i::Utf8ToUtf16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
+ i::CompleteParserRecorder log;
+ i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+ scanner.Initialize(&stream);
+
+ i::PreParser preparser(&scanner, &log, stack_limit);
+ preparser.set_allow_lazy(true);
+ preparser.set_allow_natives_syntax(true);
+ i::PreParser::PreParseResult result = preparser.PreParseProgram();
+ CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+ if (log.symbol_ids() != test_cases[i].symbols) {
+ i::OS::Print(
+ "Expected preparse data for program:\n"
+ "\t%s\n"
+ "to contain %d symbols, however, received %d symbols.\n",
+ program, test_cases[i].symbols, log.symbol_ids());
+ CHECK(false);
+ }
+ if (log.function_position() != test_cases[i].functions * kDataPerFunction) {
+ i::OS::Print(
+ "Expected preparse data for program:\n"
+ "\t%s\n"
+ "to contain %d functions, however, received %d functions.\n",
+ program, test_cases[i].functions,
+ log.function_position() / kDataPerFunction);
+ CHECK(false);
+ }
+ i::ScriptDataImpl data(log.ExtractData());
+ CHECK(!data.has_error());
+ }
+}
+
+
+TEST(FunctionDeclaresItselfStrict) {
+ // Tests that we produce the right kinds of errors when a function declares
+ // itself strict (we cannot produce there errors as soon as we see the
+ // offending identifiers, because we don't know at that point whether the
+ // function is strict or not).
+ const char* context_data[][2] = {
+ {"function eval() {", "}"},
+ {"function arguments() {", "}"},
+ {"function yield() {", "}"},
+ {"function interface() {", "}"},
+ {"function foo(eval) {", "}"},
+ {"function foo(arguments) {", "}"},
+ {"function foo(yield) {", "}"},
+ {"function foo(interface) {", "}"},
+ {"function foo(bar, eval) {", "}"},
+ {"function foo(bar, arguments) {", "}"},
+ {"function foo(bar, yield) {", "}"},
+ {"function foo(bar, interface) {", "}"},
+ {"function foo(bar, bar) {", "}"},
+ { NULL, NULL }
+ };
+
+ const char* strict_statement_data[] = {
+ "\"use strict\";",
+ NULL
+ };
+
+ const char* non_strict_statement_data[] = {
+ ";",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, strict_statement_data, kError);
+ RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
+}
+
+
+TEST(ErrorsTryWithoutCatchOrFinally) {
+ const char* context_data[][2] = {
+ {"", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "try { }",
+ "try { } foo();",
+ "try { } catch (e) foo();",
+ "try { } catch { }",
+ "try { } finally foo();",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsTryCatchFinally) {
+ const char* context_data[][2] = {
+ {"", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "try { } catch (e) { }",
+ "try { } catch (e) { } finally { }",
+ "try { } finally { }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsRegexpLiteral) {
+ const char* context_data[][2] = {
+ {"var r = ", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "/unterminated",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsRegexpLiteral) {
+ const char* context_data[][2] = {
+ {"var r = ", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "/foo/",
+ "/foo/g",
+ "/foo/whatever", // This is an error but not detected by the parser.
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(Intrinsics) {
+ const char* context_data[][2] = {
+ {"", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "%someintrinsic(arg)",
+ NULL
+ };
+
+ // Parsing will fail or succeed depending on whether we allow natives syntax
+ // or not.
+ RunParserSyncTest(context_data, statement_data, kSuccessOrError);
+}
+
+
+TEST(NoErrorsNewExpression) {
+ const char* context_data[][2] = {
+ {"", ""},
+ {"var f =", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "new foo",
+ "new foo();",
+ "new foo(1);",
+ "new foo(1, 2);",
+ // The first () will be processed as a part of the NewExpression and the
+ // second () will be processed as part of LeftHandSideExpression.
+ "new foo()();",
+ // The first () will be processed as a part of the inner NewExpression and
+ // the second () will be processed as a part of the outer NewExpression.
+ "new new foo()();",
+ "new foo.bar;",
+ "new foo.bar();",
+ "new foo.bar.baz;",
+ "new foo.bar().baz;",
+ "new foo[bar];",
+ "new foo[bar]();",
+ "new foo[bar][baz];",
+ "new foo[bar]()[baz];",
+ "new foo[bar].baz(baz)()[bar].baz;",
+ "new \"foo\"", // Runtime error
+ "new 1", // Runtime error
+ "new foo++",
+ // This even runs:
+ "(new new Function(\"this.x = 1\")).x;",
+ "new new Test_Two(String, 2).v(0123).length;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsNewExpression) {
+ const char* context_data[][2] = {
+ {"", ""},
+ {"var f =", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "new foo bar",
+ "new ) foo",
+ "new ++foo",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
« no previous file with comments | « test/cctest/test-microtask-delivery.cc ('k') | test/cctest/test-platform.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698