summaryrefslogtreecommitdiff
path: root/deps/v8/test/cctest/test-parsing.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/test-parsing.cc')
-rw-r--r--deps/v8/test/cctest/test-parsing.cc737
1 files changed, 659 insertions, 78 deletions
diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc
index 22d5056f80..2746388bbd 100644
--- a/deps/v8/test/cctest/test-parsing.cc
+++ b/deps/v8/test/cctest/test-parsing.cc
@@ -35,6 +35,7 @@
#include "compiler.h"
#include "execution.h"
#include "isolate.h"
+#include "objects.h"
#include "parser.h"
#include "preparser.h"
#include "scanner-character-streams.h"
@@ -212,18 +213,25 @@ TEST(Preparsing) {
{
i::FLAG_lazy = true;
ScriptResource* resource = new ScriptResource(source, source_length);
- v8::Local<v8::String> script_source =
- v8::String::NewExternal(isolate, resource);
- v8::Script::Compile(script_source, NULL, preparse);
+ v8::ScriptCompiler::Source script_source(
+ v8::String::NewExternal(isolate, resource),
+ new v8::ScriptCompiler::CachedData(
+ reinterpret_cast<const uint8_t*>(preparse->Data()),
+ preparse->Length()));
+ v8::ScriptCompiler::Compile(isolate,
+ &script_source);
}
{
i::FLAG_lazy = false;
ScriptResource* resource = new ScriptResource(source, source_length);
- v8::Local<v8::String> script_source =
- v8::String::NewExternal(isolate, resource);
- v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
+ v8::ScriptCompiler::Source script_source(
+ v8::String::NewExternal(isolate, resource),
+ new v8::ScriptCompiler::CachedData(
+ reinterpret_cast<const uint8_t*>(preparse->Data()),
+ preparse->Length()));
+ v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
}
delete preparse;
i::FLAG_lazy = lazy_flag;
@@ -252,6 +260,99 @@ TEST(Preparsing) {
}
+TEST(PreparseFunctionDataIsUsed) {
+ // This tests that we actually do use the function data generated by the
+ // preparser.
+
+ // Make preparsing work for short scripts.
+ i::FLAG_min_preparse_length = 0;
+
+ 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* good_code =
+ "function this_is_lazy() { var a; } function foo() { return 25; } foo();";
+
+ // Insert a syntax error inside the lazy function.
+ const char* bad_code =
+ "function this_is_lazy() { if ( } function foo() { return 25; } foo();";
+
+ v8::ScriptCompiler::Source good_source(v8_str(good_code));
+ v8::ScriptCompiler::Compile(isolate, &good_source,
+ v8::ScriptCompiler::kProduceDataToCache);
+
+ const v8::ScriptCompiler::CachedData* cached_data =
+ good_source.GetCachedData();
+ CHECK(cached_data->data != NULL);
+ CHECK_GT(cached_data->length, 0);
+
+ // Now compile the erroneous code with the good preparse data. If the preparse
+ // data is used, the lazy function is skipped and it should compile fine.
+ v8::ScriptCompiler::Source bad_source(
+ v8_str(bad_code), new v8::ScriptCompiler::CachedData(
+ cached_data->data, cached_data->length));
+ v8::Local<v8::Value> result =
+ v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
+ CHECK(result->IsInt32());
+ CHECK_EQ(25, result->Int32Value());
+}
+
+
+TEST(PreparseSymbolDataIsUsed) {
+ // This tests that we actually do use the symbol data generated by the
+ // preparser.
+
+ // Only do one compilation pass in this test (otherwise we will parse the
+ // source code again without preparse data and it will fail).
+ i::FLAG_crankshaft = false;
+
+ // Make preparsing work for short scripts.
+ i::FLAG_min_preparse_length = 0;
+
+ 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);
+
+ // Note that the ( before function makes the function not lazily compiled.
+ const char* good_code =
+ "(function weird() { var foo = 26; return foo; })()";
+
+ // Insert an undefined identifier. If the preparser data is used, the symbol
+ // stream is used instead, and this identifier resolves to "foo".
+ const char* bad_code =
+ "(function weird() { var foo = 26; return wut; })()";
+
+ v8::ScriptCompiler::Source good_source(v8_str(good_code));
+ v8::ScriptCompiler::Compile(isolate, &good_source,
+ v8::ScriptCompiler::kProduceDataToCache);
+
+ const v8::ScriptCompiler::CachedData* cached_data =
+ good_source.GetCachedData();
+ CHECK(cached_data->data != NULL);
+ CHECK_GT(cached_data->length, 0);
+
+ // Now compile the erroneous code with the good preparse data. If the preparse
+ // data is used, we will see a second occurrence of "foo" instead of the
+ // unknown "wut".
+ v8::ScriptCompiler::Source bad_source(
+ v8_str(bad_code), new v8::ScriptCompiler::CachedData(
+ cached_data->data, cached_data->length));
+ v8::Local<v8::Value> result =
+ v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
+ CHECK(result->IsInt32());
+ CHECK_EQ(26, result->Int32Value());
+}
+
+
TEST(StandAlonePreParser) {
v8::V8::Initialize();
@@ -324,6 +425,99 @@ 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 {
+
+struct CompleteParserRecorderFriend {
+ static void FakeWritingSymbolIdInPreParseData(CompleteParserRecorder* log,
+ int number) {
+ log->WriteNumber(number);
+ if (log->symbol_id_ < number + 1) {
+ log->symbol_id_ = number + 1;
+ }
+ }
+ static int symbol_position(CompleteParserRecorder* log) {
+ return log->symbol_store_.size();
+ }
+ static int symbol_ids(CompleteParserRecorder* log) {
+ return log->symbol_id_;
+ }
+ static int function_position(CompleteParserRecorder* log) {
+ return log->function_store_.size();
+ }
+};
+
+}
+}
+
+
+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.
+ typedef i::CompleteParserRecorderFriend F;
+ i::CompleteParserRecorder log;
+ for (int i = 0; i < 18; ++i) {
+ F::FakeWritingSymbolIdInPreParseData(&log, 1 << i);
+ }
+ for (int i = 1; i < 18; ++i) {
+ F::FakeWritingSymbolIdInPreParseData(&log, (1 << i) + 1);
+ }
+ for (int i = 6; i < 18; ++i) {
+ F::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();
@@ -713,6 +907,7 @@ void TestScanRegExp(const char* re_source, const char* expected) {
i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const i::byte*>(re_source),
static_cast<unsigned>(strlen(re_source)));
+ i::HandleScope scope(CcTest::i_isolate());
i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
scanner.Initialize(&stream);
@@ -720,8 +915,12 @@ 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.
- CHECK(scanner.is_literal_ascii());
- i::Vector<const char> actual = scanner.literal_ascii_string();
+ i::Handle<i::String> val =
+ scanner.AllocateInternalizedString(CcTest::i_isolate());
+ i::DisallowHeapAllocation no_alloc;
+ i::String::FlatContent content = val->GetFlatContent();
+ CHECK(content.IsAscii());
+ i::Vector<const uint8_t> actual = content.ToOneByteVector();
for (int i = 0; i < actual.length(); i++) {
CHECK_NE('\0', expected[i]);
CHECK_EQ(expected[i], actual[i]);
@@ -828,6 +1027,8 @@ static int Utf8LengthHelper(const char* s) {
TEST(ScopePositions) {
+ v8::internal::FLAG_harmony_scoping = true;
+
// Test the parser for correctly setting the start and end positions
// of a scope. We check the scope positions of exactly one scope
// nested in the global scope of a program. 'inner source' is the
@@ -839,167 +1040,167 @@ TEST(ScopePositions) {
const char* inner_source;
const char* outer_suffix;
i::ScopeType scope_type;
- i::LanguageMode language_mode;
+ i::StrictMode strict_mode;
};
const SourceData source_data[] = {
- { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
- { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+ { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
+ { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
{ " with ({}) ", "{\n"
" block;\n"
" }", "\n"
- " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
- { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+ " more;", i::WITH_SCOPE, i::SLOPPY },
+ { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
{ " with ({}) ", "statement", "\n"
- " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+ " more;", i::WITH_SCOPE, i::SLOPPY },
{ " with ({})\n"
" ", "statement;", "\n"
- " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+ " more;", i::WITH_SCOPE, i::SLOPPY },
{ " try {} catch ", "(e) { block; }", " more;",
- i::CATCH_SCOPE, i::CLASSIC_MODE },
+ i::CATCH_SCOPE, i::SLOPPY },
{ " try {} catch ", "(e) { block; }", "; more;",
- i::CATCH_SCOPE, i::CLASSIC_MODE },
+ i::CATCH_SCOPE, i::SLOPPY },
{ " try {} catch ", "(e) {\n"
" block;\n"
" }", "\n"
- " more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
+ " more;", i::CATCH_SCOPE, i::SLOPPY },
{ " try {} catch ", "(e) { block; }", " finally { block; } more;",
- i::CATCH_SCOPE, i::CLASSIC_MODE },
+ i::CATCH_SCOPE, i::SLOPPY },
{ " start;\n"
- " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
{ " start;\n"
- " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
{ " start;\n"
" ", "{\n"
" let block;\n"
" }", "\n"
- " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " more;", i::BLOCK_SCOPE, i::STRICT },
{ " start;\n"
" function fun", "(a,b) { infunction; }", " more;",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
{ " start;\n"
" function fun", "(a,b) {\n"
" infunction;\n"
" }", "\n"
- " more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ " more;", i::FUNCTION_SCOPE, i::SLOPPY },
{ " (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
{ " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
- i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
- i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x = 1 ; x < 10; ++ x) {\n"
" block;\n"
" }", "\n"
- " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " more;", i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
- i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
- " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " more;", i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x = 1 ; x < 10; ++ x)\n"
" statement;", "\n"
- " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " more;", i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x in {}) { block; }", " more;",
- i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x in {}) { block; }", "; more;",
- i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x in {}) {\n"
" block;\n"
" }", "\n"
- " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " more;", i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x in {}) statement;", " more;",
- i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x in {}) statement", "\n"
- " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " more;", i::BLOCK_SCOPE, i::STRICT },
{ " for ", "(let x in {})\n"
" statement;", "\n"
- " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ " more;", i::BLOCK_SCOPE, i::STRICT },
// Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
// the preparser off in terms of byte offsets.
// 6 byte encoding.
{ " 'foo\355\240\201\355\260\211';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// 4 byte encoding.
{ " 'foo\360\220\220\212';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// 3 byte encoding of \u0fff.
{ " 'foo\340\277\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Broken 6 byte encoding with missing last byte.
{ " 'foo\355\240\201\355\211';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Broken 3 byte encoding of \u0fff with missing last byte.
{ " 'foo\340\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Broken 3 byte encoding of \u0fff with missing 2 last bytes.
{ " 'foo\340';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
{ " 'foo\340\203\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Broken 3 byte encoding of \u007f should be a 2 byte encoding.
{ " 'foo\340\201\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Unpaired lead surrogate.
{ " 'foo\355\240\201';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Unpaired lead surrogate where following code point is a 3 byte sequence.
{ " 'foo\355\240\201\340\277\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Unpaired lead surrogate where following code point is a 4 byte encoding
// of a trail surrogate.
{ " 'foo\355\240\201\360\215\260\211';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Unpaired trail surrogate.
{ " 'foo\355\260\211';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// 2 byte encoding of \u00ff.
{ " 'foo\303\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Broken 2 byte encoding of \u00ff with missing last byte.
{ " 'foo\303';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Broken 2 byte encoding of \u007f should be a 1 byte encoding.
{ " 'foo\301\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Illegal 5 byte encoding.
{ " 'foo\370\277\277\277\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Illegal 6 byte encoding.
{ " 'foo\374\277\277\277\277\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Illegal 0xfe byte
{ " 'foo\376\277\277\277\277\277\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
// Illegal 0xff byte
{ " 'foo\377\277\277\277\277\277\277\277';\n"
" (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
{ " 'foo';\n"
" (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ i::FUNCTION_SCOPE, i::SLOPPY },
{ " 'foo';\n"
" (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
- i::FUNCTION_SCOPE, i::CLASSIC_MODE },
- { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
+ i::FUNCTION_SCOPE, i::SLOPPY },
+ { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
};
i::Isolate* isolate = CcTest::i_isolate();
@@ -1038,7 +1239,7 @@ TEST(ScopePositions) {
parser.set_allow_lazy(true);
parser.set_allow_harmony_scoping(true);
info.MarkAsGlobal();
- info.SetLanguageMode(source_data[i].language_mode);
+ info.SetStrictMode(source_data[i].strict_mode);
parser.Parse();
CHECK(info.function() != NULL);
@@ -1071,7 +1272,7 @@ i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) {
i::JSArray::SetElement(
args_array, i, v8::Utils::OpenHandle(*v8::String::NewFromUtf8(
CcTest::isolate(), args[i])),
- NONE, i::kNonStrictMode);
+ NONE, i::SLOPPY);
}
i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
i::Handle<i::Object> format_fun =
@@ -1108,8 +1309,9 @@ enum ParserSyncTestResult {
kError
};
-
-void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
+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));
@@ -1379,7 +1581,9 @@ TEST(PreparserStrictOctal) {
void RunParserSyncTest(const char* context_data[][2],
const char* statement_data[],
- ParserSyncTestResult result) {
+ ParserSyncTestResult result,
+ const ParserFlag* flags = NULL,
+ int flags_len = 0) {
v8::HandleScope handles(CcTest::isolate());
v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
@@ -1388,10 +1592,14 @@ void RunParserSyncTest(const char* context_data[][2],
CcTest::i_isolate()->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
- static const ParserFlag flags[] = {
+ static const ParserFlag default_flags[] = {
kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
- kAllowForOf
+ kAllowForOf, kAllowNativesSyntax
};
+ if (!flags) {
+ flags = default_flags;
+ flags_len = ARRAY_SIZE(default_flags);
+ }
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]);
@@ -1409,7 +1617,7 @@ void RunParserSyncTest(const char* context_data[][2],
CHECK(length == kProgramSize);
TestParserSync(program.start(),
flags,
- ARRAY_SIZE(flags),
+ flags_len,
result);
}
}
@@ -1455,7 +1663,7 @@ TEST(ErrorsEvalAndArguments) {
}
-TEST(NoErrorsEvalAndArgumentsClassic) {
+TEST(NoErrorsEvalAndArgumentsSloppy) {
// Tests that both preparsing and parsing accept "eval" and "arguments" as
// identifiers when needed.
const char* context_data[][2] = {
@@ -1600,8 +1808,8 @@ TEST(ErrorsReservedWords) {
}
-TEST(NoErrorsYieldClassic) {
- // In classic mode, it's okay to use "yield" as identifier, *except* inside a
+TEST(NoErrorsYieldSloppy) {
+ // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
// generator (see next test).
const char* context_data[][2] = {
{ "", "" },
@@ -1627,7 +1835,7 @@ TEST(NoErrorsYieldClassic) {
}
-TEST(ErrorsYieldClassicGenerator) {
+TEST(ErrorsYieldSloppyGenerator) {
const char* context_data[][2] = {
{ "function * is_gen() {", "}" },
{ NULL, NULL }
@@ -1743,7 +1951,7 @@ TEST(NoErrorsNameOfStrictFunction) {
-TEST(ErrorsIllegalWordsAsLabelsClassic) {
+TEST(ErrorsIllegalWordsAsLabelsSloppy) {
// Using future reserved words as labels is always an error.
const char* context_data[][2] = {
{ "", ""},
@@ -1880,7 +2088,6 @@ 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);
@@ -1890,9 +2097,18 @@ TEST(DontRegressPreParserDataSizes) {
int symbols;
int functions;
} test_cases[] = {
- // Labels, variables and functions are recorded as symbols.
+ // Labels and variables 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},
+ {"var x = {y: 1};", 2, 0},
+ {"var x = {}; x.y = 1", 2, 0},
+ // "get" is recorded as a symbol too.
+ {"var x = {get foo(){} };", 3, 1},
+ // When keywords are used as identifiers, they're logged as symbols, too:
+ {"var x = {if: 1};", 2, 0},
+ {"var x = {}; x.if = 1", 2, 0},
+ {"var x = {get if(){} };", 3, 1},
+ // Functions
{"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},
@@ -1904,6 +2120,7 @@ TEST(DontRegressPreParserDataSizes) {
// Each function adds 5 elements to the preparse function data.
const int kDataPerFunction = 5;
+ typedef i::CompleteParserRecorderFriend F;
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;
@@ -1919,21 +2136,22 @@ TEST(DontRegressPreParserDataSizes) {
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) {
+ if (F::symbol_ids(&log) != 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());
+ program, test_cases[i].symbols, F::symbol_ids(&log));
CHECK(false);
}
- if (log.function_position() != test_cases[i].functions * kDataPerFunction) {
+ if (F::function_position(&log) !=
+ 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);
+ F::function_position(&log) / kDataPerFunction);
CHECK(false);
}
i::ScriptDataImpl data(log.ExtractData());
@@ -2013,3 +2231,366 @@ TEST(NoErrorsTryCatchFinally) {
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
+ // 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",
+ "new foo ++",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(StrictObjectLiteralChecking) {
+ const char* strict_context_data[][2] = {
+ {"\"use strict\"; var myobject = {", "};"},
+ { NULL, NULL }
+ };
+ const char* non_strict_context_data[][2] = {
+ {"var myobject = {", "};"},
+ { NULL, NULL }
+ };
+
+ // These are only errors in strict mode.
+ const char* statement_data[] = {
+ "foo: 1, foo: 2",
+ "\"foo\": 1, \"foo\": 2",
+ "foo: 1, \"foo\": 2",
+ "1: 1, 1: 2",
+ "1: 1, \"1\": 2",
+ "get: 1, get: 2", // Not a getter for real, just a property called get.
+ "set: 1, set: 2", // Not a setter for real, just a property called set.
+ NULL
+ };
+
+ RunParserSyncTest(non_strict_context_data, statement_data, kSuccess);
+ RunParserSyncTest(strict_context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsObjectLiteralChecking) {
+ const char* context_data[][2] = {
+ {"\"use strict\"; var myobject = {", "};"},
+ {"var myobject = {", "};"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "foo: 1, get foo() {}",
+ "foo: 1, set foo() {}",
+ "\"foo\": 1, get \"foo\"() {}",
+ "\"foo\": 1, set \"foo\"() {}",
+ "1: 1, get 1() {}",
+ "1: 1, set 1() {}",
+ // 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\"() {}",
+ "\"foo\": 1, get foo() {}",
+ "\"foo\": 1, set foo() {}",
+ "1: 1, get \"1\"() {}",
+ "1: 1, set \"1\"() {}",
+ "\"1\": 1, get 1() {}"
+ "\"1\": 1, set 1() {}"
+ // Parsing FunctionLiteral for getter or setter fails
+ "get foo( +",
+ "get foo() \"error\"",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsObjectLiteralChecking) {
+ const char* context_data[][2] = {
+ {"var myobject = {", "};"},
+ {"\"use strict\"; var myobject = {", "};"},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "foo: 1, bar: 2",
+ "\"foo\": 1, \"bar\": 2",
+ "1: 1, 2: 2",
+ // Syntax: IdentifierName ':' AssignmentExpression
+ "foo: bar = 5 + baz",
+ // Syntax: 'get' (IdentifierName | String | Number) FunctionLiteral
+ "get foo() {}",
+ "get \"foo\"() {}",
+ "get 1() {}",
+ // Syntax: 'set' (IdentifierName | String | Number) FunctionLiteral
+ "set foo() {}",
+ "set \"foo\"() {}",
+ "set 1() {}",
+ // Non-colliding getters and setters -> no errors
+ "foo: 1, get bar() {}",
+ "foo: 1, set bar(b) {}",
+ "\"foo\": 1, get \"bar\"() {}",
+ "\"foo\": 1, set \"bar\"() {}",
+ "1: 1, get 2() {}",
+ "1: 1, set 2() {}",
+ // Weird number of parameters -> no errors
+ "get bar() {}, set bar() {}",
+ "get bar(x) {}, set bar(x) {}",
+ "get bar(x, y) {}, set bar(x, y) {}",
+ // Keywords, future reserved and strict future reserved are also allowed as
+ // property names.
+ "if: 4",
+ "interface: 5",
+ "super: 6",
+ "eval: 7",
+ "arguments: 8",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(TooManyArguments) {
+ const char* context_data[][2] = {
+ {"foo(", "0)"},
+ { NULL, NULL }
+ };
+
+ using v8::internal::Code;
+ char statement[Code::kMaxArguments * 2 + 1];
+ for (int i = 0; i < Code::kMaxArguments; ++i) {
+ statement[2 * i] = '0';
+ statement[2 * i + 1] = ',';
+ }
+ statement[Code::kMaxArguments * 2] = 0;
+
+ const char* statement_data[] = {
+ statement,
+ NULL
+ };
+
+ // The test is quite slow, so run it with a reduced set of flags.
+ static const ParserFlag empty_flags[] = {kAllowLazy};
+ RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
+}
+
+
+TEST(StrictDelete) {
+ // "delete <Identifier>" is not allowed in strict mode.
+ const char* strict_context_data[][2] = {
+ {"\"use strict\"; ", ""},
+ { NULL, NULL }
+ };
+
+ const char* sloppy_context_data[][2] = {
+ {"", ""},
+ { NULL, NULL }
+ };
+
+ // These are errors in the strict mode.
+ const char* sloppy_statement_data[] = {
+ "delete foo;",
+ "delete foo + 1;",
+ "delete (foo);",
+ "delete eval;",
+ "delete interface;",
+ NULL
+ };
+
+ // These are always OK
+ const char* good_statement_data[] = {
+ "delete this;",
+ "delete 1;",
+ "delete 1 + 2;",
+ "delete foo();",
+ "delete foo.bar;",
+ "delete foo[bar];",
+ "delete foo--;",
+ "delete --foo;",
+ "delete new foo();",
+ "delete new foo(bar);",
+ NULL
+ };
+
+ // These are always errors
+ const char* bad_statement_data[] = {
+ "delete if;",
+ NULL
+ };
+
+ RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
+ RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
+
+ RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
+ RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
+
+ RunParserSyncTest(strict_context_data, bad_statement_data, kError);
+ RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
+}
+
+
+TEST(InvalidLeftHandSide) {
+ const char* assignment_context_data[][2] = {
+ {"", " = 1;"},
+ {"\"use strict\"; ", " = 1;"},
+ { NULL, NULL }
+ };
+
+ const char* prefix_context_data[][2] = {
+ {"++", ";"},
+ {"\"use strict\"; ++", ";"},
+ {NULL, NULL},
+ };
+
+ const char* postfix_context_data[][2] = {
+ {"", "++;"},
+ {"\"use strict\"; ", "++;"},
+ { NULL, NULL }
+ };
+
+ // Good left hand sides for assigment or prefix / postfix operations.
+ const char* good_statement_data[] = {
+ "foo",
+ "foo.bar",
+ "foo[bar]",
+ "foo()[bar]",
+ "foo().bar",
+ "this.foo",
+ "this[foo]",
+ "new foo()[bar]",
+ "new foo().bar",
+ NULL
+ };
+
+ // Bad left hand sides for assigment or prefix / postfix operations.
+ const char* bad_statement_data_common[] = {
+ "2",
+ "foo()",
+ "null",
+ "if", // Unexpected token
+ "{x: 1}", // Unexpected token
+ "this",
+ "\"bar\"",
+ "(foo + bar)",
+ "new new foo()[bar]", // means: new (new foo()[bar])
+ "new new foo().bar", // means: new (new foo()[bar])
+ NULL
+ };
+
+ // These are not okay for assignment, but okay for prefix / postix.
+ const char* bad_statement_data_for_assignment[] = {
+ "++foo",
+ "foo++",
+ "foo + bar",
+ NULL
+ };
+
+ RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
+ RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
+ RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
+ kError);
+
+ RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
+ RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
+
+ RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
+ RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);
+}