1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include "execution.h"
40 #include "preparser.h"
41 #include "scanner-character-streams.h"
48 i::Token::Value token;
51 static const KeywordToken keywords[] = {
52 #define KEYWORD(t, s, d) { s, i::Token::t },
53 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
55 { NULL, i::Token::IDENTIFIER }
58 KeywordToken key_token;
59 i::UnicodeCache unicode_cache;
61 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
62 const i::byte* keyword =
63 reinterpret_cast<const i::byte*>(key_token.keyword);
64 int length = i::StrLength(key_token.keyword);
65 CHECK(static_cast<int>(sizeof(buffer)) >= length);
67 i::Utf8ToUtf16CharacterStream stream(keyword, length);
68 i::Scanner scanner(&unicode_cache);
69 // The scanner should parse Harmony keywords for this test.
70 scanner.SetHarmonyScoping(true);
71 scanner.SetHarmonyModules(true);
72 scanner.Initialize(&stream);
73 CHECK_EQ(key_token.token, scanner.Next());
74 CHECK_EQ(i::Token::EOS, scanner.Next());
76 // Removing characters will make keyword matching fail.
78 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
79 i::Scanner scanner(&unicode_cache);
80 scanner.Initialize(&stream);
81 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
82 CHECK_EQ(i::Token::EOS, scanner.Next());
84 // Adding characters will make keyword matching fail.
85 static const char chars_to_append[] = { 'z', '0', '_' };
86 for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) {
87 i::OS::MemMove(buffer, keyword, length);
88 buffer[length] = chars_to_append[j];
89 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
90 i::Scanner scanner(&unicode_cache);
91 scanner.Initialize(&stream);
92 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
93 CHECK_EQ(i::Token::EOS, scanner.Next());
95 // Replacing characters will make keyword matching fail.
97 i::OS::MemMove(buffer, keyword, length);
98 buffer[length - 1] = '_';
99 i::Utf8ToUtf16CharacterStream stream(buffer, length);
100 i::Scanner scanner(&unicode_cache);
101 scanner.Initialize(&stream);
102 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
103 CHECK_EQ(i::Token::EOS, scanner.Next());
109 TEST(ScanHTMLEndComments) {
110 v8::V8::Initialize();
111 v8::Isolate* isolate = CcTest::isolate();
112 v8::HandleScope handles(isolate);
114 // Regression test. See:
115 // http://code.google.com/p/chromium/issues/detail?id=53548
116 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
117 // is only whitespace before it on the line (with comments considered as
118 // whitespace, even a multiline-comment containing a newline).
119 // This was not the case if it occurred before the first real token
121 const char* tests[] = {
122 // Before first real token.
123 "--> is eol-comment\nvar y = 37;\n",
124 "\n --> is eol-comment\nvar y = 37;\n",
125 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
126 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
127 // After first real token.
128 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
129 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
133 const char* fail_tests[] = {
134 "x --> is eol-comment\nvar y = 37;\n",
135 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
136 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
137 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
138 "var x = 42; --> is eol-comment\nvar y = 37;\n",
139 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
143 // Parser/Scanner needs a stack limit.
145 CcTest::i_isolate()->stack_guard()->SetStackLimit(
146 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
148 for (int i = 0; tests[i]; i++) {
149 v8::Handle<v8::String> source = v8::String::NewFromUtf8(
150 isolate, tests[i], v8::String::kNormalString, i::StrLength(tests[i]));
151 v8::ScriptData* data = v8::ScriptData::PreCompile(source);
152 CHECK(data != NULL && !data->HasError());
156 for (int i = 0; fail_tests[i]; i++) {
157 v8::Handle<v8::String> source =
158 v8::String::NewFromUtf8(isolate,
160 v8::String::kNormalString,
161 i::StrLength(fail_tests[i]));
162 v8::ScriptData* data = v8::ScriptData::PreCompile(source);
163 CHECK(data == NULL || data->HasError());
169 class ScriptResource : public v8::String::ExternalAsciiStringResource {
171 ScriptResource(const char* data, size_t length)
172 : data_(data), length_(length) { }
174 const char* data() const { return data_; }
175 size_t length() const { return length_; }
184 v8::Isolate* isolate = CcTest::isolate();
185 v8::HandleScope handles(isolate);
186 v8::Local<v8::Context> context = v8::Context::New(isolate);
187 v8::Context::Scope context_scope(context);
189 CcTest::i_isolate()->stack_guard()->SetStackLimit(
190 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
192 // Source containing functions that might be lazily compiled and all types
193 // of symbols (string, propertyName, regexp).
196 "function foo(a) { return function nolazy(b) { return a + b; } }"
197 "function bar(a) { if (a) return function lazy(b) { return b; } }"
198 "var z = {'string': 'string literal', bareword: 'propertyName', "
199 " 42: 'number literal', for: 'keyword as propertyName', "
200 " f\\u006fr: 'keyword propertyname with escape'};"
201 "var v = /RegExp Literal/;"
202 "var w = /RegExp Literal\\u0020With Escape/gin;"
203 "var y = { get getter() { return 42; }, "
204 " set setter(v) { this.value = v; }};";
205 int source_length = i::StrLength(source);
206 const char* error_source = "var x = y z;";
207 int error_source_length = i::StrLength(error_source);
209 v8::ScriptData* preparse = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
210 isolate, source, v8::String::kNormalString, source_length));
211 CHECK(!preparse->HasError());
212 bool lazy_flag = i::FLAG_lazy;
215 ScriptResource* resource = new ScriptResource(source, source_length);
216 v8::ScriptCompiler::Source script_source(
217 v8::String::NewExternal(isolate, resource),
218 new v8::ScriptCompiler::CachedData(
219 reinterpret_cast<const uint8_t*>(preparse->Data()),
220 preparse->Length()));
221 v8::ScriptCompiler::Compile(isolate,
226 i::FLAG_lazy = false;
228 ScriptResource* resource = new ScriptResource(source, source_length);
229 v8::ScriptCompiler::Source script_source(
230 v8::String::NewExternal(isolate, resource),
231 new v8::ScriptCompiler::CachedData(
232 reinterpret_cast<const uint8_t*>(preparse->Data()),
233 preparse->Length()));
234 v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
237 i::FLAG_lazy = lazy_flag;
240 v8::ScriptData* error_preparse = v8::ScriptData::PreCompile(
241 v8::String::NewFromUtf8(isolate,
243 v8::String::kNormalString,
244 error_source_length));
245 CHECK(error_preparse->HasError());
246 i::ScriptDataImpl *pre_impl =
247 reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
248 i::Scanner::Location error_location =
249 pre_impl->MessageLocation();
250 // Error is at "z" in source, location 10..11.
251 CHECK_EQ(10, error_location.beg_pos);
252 CHECK_EQ(11, error_location.end_pos);
254 const char* message = pre_impl->BuildMessage();
255 i::Vector<const char*> args = pre_impl->BuildArgs();
256 CHECK_GT(strlen(message), 0);
258 i::DeleteArray(message);
259 delete error_preparse;
263 TEST(PreparseFunctionDataIsUsed) {
264 // This tests that we actually do use the function data generated by the
267 // Make preparsing work for short scripts.
268 i::FLAG_min_preparse_length = 0;
270 v8::Isolate* isolate = CcTest::isolate();
271 v8::HandleScope handles(isolate);
272 v8::Local<v8::Context> context = v8::Context::New(isolate);
273 v8::Context::Scope context_scope(context);
275 CcTest::i_isolate()->stack_guard()->SetStackLimit(
276 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
278 const char* good_code =
279 "function this_is_lazy() { var a; } function foo() { return 25; } foo();";
281 // Insert a syntax error inside the lazy function.
282 const char* bad_code =
283 "function this_is_lazy() { if ( } function foo() { return 25; } foo();";
285 v8::ScriptCompiler::Source good_source(v8_str(good_code));
286 v8::ScriptCompiler::Compile(isolate, &good_source,
287 v8::ScriptCompiler::kProduceDataToCache);
289 const v8::ScriptCompiler::CachedData* cached_data =
290 good_source.GetCachedData();
291 CHECK(cached_data->data != NULL);
292 CHECK_GT(cached_data->length, 0);
294 // Now compile the erroneous code with the good preparse data. If the preparse
295 // data is used, the lazy function is skipped and it should compile fine.
296 v8::ScriptCompiler::Source bad_source(
297 v8_str(bad_code), new v8::ScriptCompiler::CachedData(
298 cached_data->data, cached_data->length));
299 v8::Local<v8::Value> result =
300 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
301 CHECK(result->IsInt32());
302 CHECK_EQ(25, result->Int32Value());
306 TEST(PreparseSymbolDataIsUsed) {
307 // This tests that we actually do use the symbol data generated by the
310 // Only do one compilation pass in this test (otherwise we will parse the
311 // source code again without preparse data and it will fail).
312 i::FLAG_crankshaft = false;
314 // Make preparsing work for short scripts.
315 i::FLAG_min_preparse_length = 0;
317 v8::Isolate* isolate = CcTest::isolate();
318 v8::HandleScope handles(isolate);
319 v8::Local<v8::Context> context = v8::Context::New(isolate);
320 v8::Context::Scope context_scope(context);
322 CcTest::i_isolate()->stack_guard()->SetStackLimit(
323 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
325 // Note that the ( before function makes the function not lazily compiled.
326 const char* good_code =
327 "(function weird() { var foo = 26; return foo; })()";
329 // Insert an undefined identifier. If the preparser data is used, the symbol
330 // stream is used instead, and this identifier resolves to "foo".
331 const char* bad_code =
332 "(function weird() { var foo = 26; return wut; })()";
334 v8::ScriptCompiler::Source good_source(v8_str(good_code));
335 v8::ScriptCompiler::Compile(isolate, &good_source,
336 v8::ScriptCompiler::kProduceDataToCache);
338 const v8::ScriptCompiler::CachedData* cached_data =
339 good_source.GetCachedData();
340 CHECK(cached_data->data != NULL);
341 CHECK_GT(cached_data->length, 0);
343 // Now compile the erroneous code with the good preparse data. If the preparse
344 // data is used, we will see a second occurrence of "foo" instead of the
346 v8::ScriptCompiler::Source bad_source(
347 v8_str(bad_code), new v8::ScriptCompiler::CachedData(
348 cached_data->data, cached_data->length));
349 v8::Local<v8::Value> result =
350 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
351 CHECK(result->IsInt32());
352 CHECK_EQ(26, result->Int32Value());
356 TEST(StandAlonePreParser) {
357 v8::V8::Initialize();
360 CcTest::i_isolate()->stack_guard()->SetStackLimit(
361 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
363 const char* programs[] = {
366 "function foo(x, y) { return x + y; }",
367 "%ArgleBargle(glop);",
368 "var x = new new Function('this.x = 42');",
372 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
373 for (int i = 0; programs[i]; i++) {
374 const char* program = programs[i];
375 i::Utf8ToUtf16CharacterStream stream(
376 reinterpret_cast<const i::byte*>(program),
377 static_cast<unsigned>(strlen(program)));
378 i::CompleteParserRecorder log;
379 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
380 scanner.Initialize(&stream);
382 i::PreParser preparser(&scanner, &log, stack_limit);
383 preparser.set_allow_lazy(true);
384 preparser.set_allow_natives_syntax(true);
385 i::PreParser::PreParseResult result = preparser.PreParseProgram();
386 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
387 i::ScriptDataImpl data(log.ExtractData());
388 CHECK(!data.has_error());
393 TEST(StandAlonePreParserNoNatives) {
394 v8::V8::Initialize();
397 CcTest::i_isolate()->stack_guard()->SetStackLimit(
398 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
400 const char* programs[] = {
401 "%ArgleBargle(glop);",
402 "var x = %_IsSmi(42);",
406 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
407 for (int i = 0; programs[i]; i++) {
408 const char* program = programs[i];
409 i::Utf8ToUtf16CharacterStream stream(
410 reinterpret_cast<const i::byte*>(program),
411 static_cast<unsigned>(strlen(program)));
412 i::CompleteParserRecorder log;
413 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
414 scanner.Initialize(&stream);
416 // Preparser defaults to disallowing natives syntax.
417 i::PreParser preparser(&scanner, &log, stack_limit);
418 preparser.set_allow_lazy(true);
419 i::PreParser::PreParseResult result = preparser.PreParseProgram();
420 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
421 i::ScriptDataImpl data(log.ExtractData());
422 // Data contains syntax error.
423 CHECK(data.has_error());
428 TEST(PreparsingObjectLiterals) {
429 // Regression test for a bug where the symbol stream produced by PreParser
430 // didn't match what Parser wanted to consume.
431 v8::Isolate* isolate = CcTest::isolate();
432 v8::HandleScope handles(isolate);
433 v8::Local<v8::Context> context = v8::Context::New(isolate);
434 v8::Context::Scope context_scope(context);
436 CcTest::i_isolate()->stack_guard()->SetStackLimit(
437 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
440 const char* source = "var myo = {if: \"foo\"}; myo.if;";
441 v8::Local<v8::Value> result = PreCompileCompileRun(source);
442 CHECK(result->IsString());
443 v8::String::Utf8Value utf8(result);
444 CHECK_EQ("foo", *utf8);
448 const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
449 v8::Local<v8::Value> result = PreCompileCompileRun(source);
450 CHECK(result->IsString());
451 v8::String::Utf8Value utf8(result);
452 CHECK_EQ("foo", *utf8);
456 const char* source = "var myo = {1: \"foo\"}; myo[1];";
457 v8::Local<v8::Value> result = PreCompileCompileRun(source);
458 CHECK(result->IsString());
459 v8::String::Utf8Value utf8(result);
460 CHECK_EQ("foo", *utf8);
467 struct CompleteParserRecorderFriend {
468 static void FakeWritingSymbolIdInPreParseData(CompleteParserRecorder* log,
470 log->WriteNumber(number);
471 if (log->symbol_id_ < number + 1) {
472 log->symbol_id_ = number + 1;
475 static int symbol_position(CompleteParserRecorder* log) {
476 return log->symbol_store_.size();
478 static int symbol_ids(CompleteParserRecorder* log) {
479 return log->symbol_id_;
481 static int function_position(CompleteParserRecorder* log) {
482 return log->function_store_.size();
490 TEST(StoringNumbersInPreParseData) {
491 // Symbol IDs are split into chunks of 7 bits for storing. This is a
492 // regression test for a bug where a symbol id was incorrectly stored if some
493 // of the chunks in the middle were all zeros.
494 typedef i::CompleteParserRecorderFriend F;
495 i::CompleteParserRecorder log;
496 for (int i = 0; i < 18; ++i) {
497 F::FakeWritingSymbolIdInPreParseData(&log, 1 << i);
499 for (int i = 1; i < 18; ++i) {
500 F::FakeWritingSymbolIdInPreParseData(&log, (1 << i) + 1);
502 for (int i = 6; i < 18; ++i) {
503 F::FakeWritingSymbolIdInPreParseData(&log, (3 << i) + (5 << (i - 6)));
505 i::Vector<unsigned> store = log.ExtractData();
506 i::ScriptDataImpl script_data(store);
507 script_data.Initialize();
508 // Check that we get the same symbols back.
509 for (int i = 0; i < 18; ++i) {
510 CHECK_EQ(1 << i, script_data.GetSymbolIdentifier());
512 for (int i = 1; i < 18; ++i) {
513 CHECK_EQ((1 << i) + 1, script_data.GetSymbolIdentifier());
515 for (int i = 6; i < 18; ++i) {
516 CHECK_EQ((3 << i) + (5 << (i - 6)), script_data.GetSymbolIdentifier());
521 TEST(RegressChromium62639) {
522 v8::V8::Initialize();
523 i::Isolate* isolate = CcTest::i_isolate();
526 isolate->stack_guard()->SetStackLimit(
527 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
529 const char* program = "var x = 'something';\n"
530 "escape: function() {}";
531 // Fails parsing expecting an identifier after "function".
532 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
533 // and then used the invalid currently scanned literal. This always
534 // failed in debug mode, and sometimes crashed in release mode.
536 i::Utf8ToUtf16CharacterStream stream(
537 reinterpret_cast<const i::byte*>(program),
538 static_cast<unsigned>(strlen(program)));
539 i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
540 CHECK(data->HasError());
546 v8::V8::Initialize();
547 i::Isolate* isolate = CcTest::i_isolate();
548 i::Factory* factory = isolate->factory();
550 // Preparsing didn't consider the catch clause of a try statement
551 // as with-content, which made it assume that a function inside
552 // the block could be lazily compiled, and an extra, unexpected,
553 // entry was added to the data.
555 isolate->stack_guard()->SetStackLimit(
556 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
558 const char* program =
559 "try { } catch (e) { var foo = function () { /* first */ } }"
560 "var bar = function () { /* second */ }";
562 v8::HandleScope handles(CcTest::isolate());
563 i::Handle<i::String> source(
564 factory->NewStringFromAscii(i::CStrVector(program)));
565 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
566 i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
567 CHECK(!data->HasError());
572 static_cast<int>(strstr(program, "function") - program);
573 int first_lbrace = first_function + i::StrLength("function () ");
574 CHECK_EQ('{', program[first_lbrace]);
575 i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
576 CHECK(!entry1.is_valid());
578 int second_function =
579 static_cast<int>(strstr(program + first_lbrace, "function") - program);
581 second_function + i::StrLength("function () ");
582 CHECK_EQ('{', program[second_lbrace]);
583 i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
584 CHECK(entry2.is_valid());
585 CHECK_EQ('}', program[entry2.end_pos() - 1]);
590 TEST(PreParseOverflow) {
591 v8::V8::Initialize();
594 CcTest::i_isolate()->stack_guard()->SetStackLimit(
595 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
597 size_t kProgramSize = 1024 * 1024;
598 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
599 memset(program.get(), '(', kProgramSize);
600 program[kProgramSize] = '\0';
602 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
604 i::Utf8ToUtf16CharacterStream stream(
605 reinterpret_cast<const i::byte*>(program.get()),
606 static_cast<unsigned>(kProgramSize));
607 i::CompleteParserRecorder log;
608 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
609 scanner.Initialize(&stream);
611 i::PreParser preparser(&scanner, &log, stack_limit);
612 preparser.set_allow_lazy(true);
613 i::PreParser::PreParseResult result = preparser.PreParseProgram();
614 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
618 class TestExternalResource: public v8::String::ExternalStringResource {
620 explicit TestExternalResource(uint16_t* data, int length)
621 : data_(data), length_(static_cast<size_t>(length)) { }
623 ~TestExternalResource() { }
625 const uint16_t* data() const {
629 size_t length() const {
638 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
640 void TestCharacterStream(const char* ascii_source,
644 if (end == 0) end = length;
645 unsigned sub_length = end - start;
646 i::Isolate* isolate = CcTest::i_isolate();
647 i::Factory* factory = isolate->factory();
648 i::HandleScope test_scope(isolate);
649 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
650 for (unsigned i = 0; i < length; i++) {
651 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
653 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
654 i::Handle<i::String> ascii_string(
655 factory->NewStringFromAscii(ascii_vector));
656 TestExternalResource resource(uc16_buffer.get(), length);
657 i::Handle<i::String> uc16_string(
658 factory->NewExternalStringFromTwoByte(&resource));
660 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
661 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
662 i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
663 i::Utf8ToUtf16CharacterStream utf8_stream(
664 reinterpret_cast<const i::byte*>(ascii_source), end);
665 utf8_stream.SeekForward(start);
669 // Read streams one char at a time
670 CHECK_EQU(i, uc16_stream.pos());
671 CHECK_EQU(i, string_stream.pos());
672 CHECK_EQU(i, utf8_stream.pos());
673 int32_t c0 = ascii_source[i];
674 int32_t c1 = uc16_stream.Advance();
675 int32_t c2 = string_stream.Advance();
676 int32_t c3 = utf8_stream.Advance();
681 CHECK_EQU(i, uc16_stream.pos());
682 CHECK_EQU(i, string_stream.pos());
683 CHECK_EQU(i, utf8_stream.pos());
685 while (i > start + sub_length / 4) {
686 // Pushback, re-read, pushback again.
687 int32_t c0 = ascii_source[i - 1];
688 CHECK_EQU(i, uc16_stream.pos());
689 CHECK_EQU(i, string_stream.pos());
690 CHECK_EQU(i, utf8_stream.pos());
691 uc16_stream.PushBack(c0);
692 string_stream.PushBack(c0);
693 utf8_stream.PushBack(c0);
695 CHECK_EQU(i, uc16_stream.pos());
696 CHECK_EQU(i, string_stream.pos());
697 CHECK_EQU(i, utf8_stream.pos());
698 int32_t c1 = uc16_stream.Advance();
699 int32_t c2 = string_stream.Advance();
700 int32_t c3 = utf8_stream.Advance();
702 CHECK_EQU(i, uc16_stream.pos());
703 CHECK_EQU(i, string_stream.pos());
704 CHECK_EQU(i, utf8_stream.pos());
708 uc16_stream.PushBack(c0);
709 string_stream.PushBack(c0);
710 utf8_stream.PushBack(c0);
712 CHECK_EQU(i, uc16_stream.pos());
713 CHECK_EQU(i, string_stream.pos());
714 CHECK_EQU(i, utf8_stream.pos());
716 unsigned halfway = start + sub_length / 2;
717 uc16_stream.SeekForward(halfway - i);
718 string_stream.SeekForward(halfway - i);
719 utf8_stream.SeekForward(halfway - i);
721 CHECK_EQU(i, uc16_stream.pos());
722 CHECK_EQU(i, string_stream.pos());
723 CHECK_EQU(i, utf8_stream.pos());
726 // Read streams one char at a time
727 CHECK_EQU(i, uc16_stream.pos());
728 CHECK_EQU(i, string_stream.pos());
729 CHECK_EQU(i, utf8_stream.pos());
730 int32_t c0 = ascii_source[i];
731 int32_t c1 = uc16_stream.Advance();
732 int32_t c2 = string_stream.Advance();
733 int32_t c3 = utf8_stream.Advance();
738 CHECK_EQU(i, uc16_stream.pos());
739 CHECK_EQU(i, string_stream.pos());
740 CHECK_EQU(i, utf8_stream.pos());
743 int32_t c1 = uc16_stream.Advance();
744 int32_t c2 = string_stream.Advance();
745 int32_t c3 = utf8_stream.Advance();
752 TEST(CharacterStreams) {
753 v8::Isolate* isolate = CcTest::isolate();
754 v8::HandleScope handles(isolate);
755 v8::Local<v8::Context> context = v8::Context::New(isolate);
756 v8::Context::Scope context_scope(context);
758 TestCharacterStream("abc\0\n\r\x7f", 7);
759 static const unsigned kBigStringSize = 4096;
760 char buffer[kBigStringSize + 1];
761 for (unsigned i = 0; i < kBigStringSize; i++) {
762 buffer[i] = static_cast<char>(i & 0x7f);
764 TestCharacterStream(buffer, kBigStringSize);
766 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
768 TestCharacterStream("\0", 1);
769 TestCharacterStream("", 0);
773 TEST(Utf8CharacterStream) {
774 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
775 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
777 static const int kAllUtf8CharsSize =
778 (unibrow::Utf8::kMaxOneByteChar + 1) +
779 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
780 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
781 static const unsigned kAllUtf8CharsSizeU =
782 static_cast<unsigned>(kAllUtf8CharsSize);
784 char buffer[kAllUtf8CharsSizeU];
786 for (int i = 0; i <= kMaxUC16Char; i++) {
787 cursor += unibrow::Utf8::Encode(buffer + cursor,
789 unibrow::Utf16::kNoPreviousCharacter);
791 ASSERT(cursor == kAllUtf8CharsSizeU);
793 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
795 for (int i = 0; i <= kMaxUC16Char; i++) {
796 CHECK_EQU(i, stream.pos());
797 int32_t c = stream.Advance();
799 CHECK_EQU(i + 1, stream.pos());
801 for (int i = kMaxUC16Char; i >= 0; i--) {
802 CHECK_EQU(i + 1, stream.pos());
804 CHECK_EQU(i, stream.pos());
807 while (stream.pos() < kMaxUC16CharU) {
808 CHECK_EQU(i, stream.pos());
809 unsigned progress = stream.SeekForward(12);
811 int32_t c = stream.Advance();
812 if (i <= kMaxUC16Char) {
818 CHECK_EQU(i, stream.pos());
824 void TestStreamScanner(i::Utf16CharacterStream* stream,
825 i::Token::Value* expected_tokens,
826 int skip_pos = 0, // Zero means not skipping.
828 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
829 scanner.Initialize(stream);
833 i::Token::Value expected = expected_tokens[i];
834 i::Token::Value actual = scanner.Next();
835 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
836 if (scanner.location().end_pos == skip_pos) {
837 scanner.SeekForward(skip_to);
840 } while (expected_tokens[i] != i::Token::ILLEGAL);
844 TEST(StreamScanner) {
845 v8::V8::Initialize();
847 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
848 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
849 static_cast<unsigned>(strlen(str1)));
850 i::Token::Value expectations1[] = {
852 i::Token::IDENTIFIER,
853 i::Token::IDENTIFIER,
860 i::Token::IDENTIFIER,
864 TestStreamScanner(&stream1, expectations1, 0, 0);
866 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
867 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
868 static_cast<unsigned>(strlen(str2)));
869 i::Token::Value expectations2[] = {
880 ASSERT_EQ('{', str2[19]);
881 ASSERT_EQ('}', str2[37]);
882 TestStreamScanner(&stream2, expectations2, 20, 37);
884 const char* str3 = "{}}}}";
885 i::Token::Value expectations3[] = {
894 // Skip zero-four RBRACEs.
895 for (int i = 0; i <= 4; i++) {
896 expectations3[6 - i] = i::Token::ILLEGAL;
897 expectations3[5 - i] = i::Token::EOS;
898 i::Utf8ToUtf16CharacterStream stream3(
899 reinterpret_cast<const i::byte*>(str3),
900 static_cast<unsigned>(strlen(str3)));
901 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
906 void TestScanRegExp(const char* re_source, const char* expected) {
907 i::Utf8ToUtf16CharacterStream stream(
908 reinterpret_cast<const i::byte*>(re_source),
909 static_cast<unsigned>(strlen(re_source)));
910 i::HandleScope scope(CcTest::i_isolate());
911 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
912 scanner.Initialize(&stream);
914 i::Token::Value start = scanner.peek();
915 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
916 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
917 scanner.Next(); // Current token is now the regexp literal.
918 i::Handle<i::String> val =
919 scanner.AllocateInternalizedString(CcTest::i_isolate());
920 i::DisallowHeapAllocation no_alloc;
921 i::String::FlatContent content = val->GetFlatContent();
922 CHECK(content.IsAscii());
923 i::Vector<const uint8_t> actual = content.ToOneByteVector();
924 for (int i = 0; i < actual.length(); i++) {
925 CHECK_NE('\0', expected[i]);
926 CHECK_EQ(expected[i], actual[i]);
931 TEST(RegExpScanning) {
932 v8::V8::Initialize();
934 // RegExp token with added garbage at the end. The scanner should only
935 // scan the RegExp until the terminating slash just before "flipperwald".
936 TestScanRegExp("/b/flipperwald", "b");
937 // Incomplete escape sequences doesn't hide the terminating slash.
938 TestScanRegExp("/\\x/flipperwald", "\\x");
939 TestScanRegExp("/\\u/flipperwald", "\\u");
940 TestScanRegExp("/\\u1/flipperwald", "\\u1");
941 TestScanRegExp("/\\u12/flipperwald", "\\u12");
942 TestScanRegExp("/\\u123/flipperwald", "\\u123");
943 TestScanRegExp("/\\c/flipperwald", "\\c");
944 TestScanRegExp("/\\c//flipperwald", "\\c");
945 // Slashes inside character classes are not terminating.
946 TestScanRegExp("/[/]/flipperwald", "[/]");
947 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
948 // Incomplete escape sequences inside a character class doesn't hide
949 // the end of the character class.
950 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
951 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
952 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
953 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
954 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
955 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
956 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
957 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
958 // Escaped ']'s wont end the character class.
959 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
960 // Escaped slashes are not terminating.
961 TestScanRegExp("/\\//flipperwald", "\\/");
962 // Starting with '=' works too.
963 TestScanRegExp("/=/", "=");
964 TestScanRegExp("/=?/", "=?");
968 static int Utf8LengthHelper(const char* s) {
969 int len = i::StrLength(s);
970 int character_length = len;
971 for (int i = 0; i < len; i++) {
972 unsigned char c = s[i];
973 int input_offset = 0;
974 int output_adjust = 0;
976 if (c < 0xc0) continue;
979 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
981 continue; // Handle first UTF-8 byte.
983 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
984 // This 4 byte sequence could have been coded as a 3 byte sequence.
985 // Record a single kBadChar for the first byte and continue.
989 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
990 character_length -= 2;
991 } else if (c >= 0xe0) {
992 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
993 // This 3 byte sequence could have been coded as a 2 byte sequence.
994 // Record a single kBadChar for the first byte and continue.
998 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
1001 if ((c & 0x1e) == 0) {
1002 // This 2 byte sequence could have been coded as a 1 byte sequence.
1003 // Record a single kBadChar for the first byte and continue.
1007 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
1011 for (int j = 1; j <= input_offset; j++) {
1012 if ((s[i + j] & 0xc0) != 0x80) {
1013 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
1014 // which is a single UTF-16 code unit.
1021 character_length -= output_adjust;
1025 return character_length;
1029 TEST(ScopePositions) {
1030 v8::internal::FLAG_harmony_scoping = true;
1032 // Test the parser for correctly setting the start and end positions
1033 // of a scope. We check the scope positions of exactly one scope
1034 // nested in the global scope of a program. 'inner source' is the
1035 // source code that determines the part of the source belonging
1036 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
1037 // parts of the source that belong to the global scope.
1039 const char* outer_prefix;
1040 const char* inner_source;
1041 const char* outer_suffix;
1042 i::ScopeType scope_type;
1043 i::StrictMode strict_mode;
1046 const SourceData source_data[] = {
1047 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
1048 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
1049 { " with ({}) ", "{\n"
1052 " more;", i::WITH_SCOPE, i::SLOPPY },
1053 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
1054 { " with ({}) ", "statement", "\n"
1055 " more;", i::WITH_SCOPE, i::SLOPPY },
1057 " ", "statement;", "\n"
1058 " more;", i::WITH_SCOPE, i::SLOPPY },
1059 { " try {} catch ", "(e) { block; }", " more;",
1060 i::CATCH_SCOPE, i::SLOPPY },
1061 { " try {} catch ", "(e) { block; }", "; more;",
1062 i::CATCH_SCOPE, i::SLOPPY },
1063 { " try {} catch ", "(e) {\n"
1066 " more;", i::CATCH_SCOPE, i::SLOPPY },
1067 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
1068 i::CATCH_SCOPE, i::SLOPPY },
1070 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
1072 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
1077 " more;", i::BLOCK_SCOPE, i::STRICT },
1079 " function fun", "(a,b) { infunction; }", " more;",
1080 i::FUNCTION_SCOPE, i::SLOPPY },
1082 " function fun", "(a,b) {\n"
1085 " more;", i::FUNCTION_SCOPE, i::SLOPPY },
1086 { " (function fun", "(a,b) { infunction; }", ")();",
1087 i::FUNCTION_SCOPE, i::SLOPPY },
1088 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
1089 i::BLOCK_SCOPE, i::STRICT },
1090 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
1091 i::BLOCK_SCOPE, i::STRICT },
1092 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
1095 " more;", i::BLOCK_SCOPE, i::STRICT },
1096 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
1097 i::BLOCK_SCOPE, i::STRICT },
1098 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
1099 " more;", i::BLOCK_SCOPE, i::STRICT },
1100 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
1102 " more;", i::BLOCK_SCOPE, i::STRICT },
1103 { " for ", "(let x in {}) { block; }", " more;",
1104 i::BLOCK_SCOPE, i::STRICT },
1105 { " for ", "(let x in {}) { block; }", "; more;",
1106 i::BLOCK_SCOPE, i::STRICT },
1107 { " for ", "(let x in {}) {\n"
1110 " more;", i::BLOCK_SCOPE, i::STRICT },
1111 { " for ", "(let x in {}) statement;", " more;",
1112 i::BLOCK_SCOPE, i::STRICT },
1113 { " for ", "(let x in {}) statement", "\n"
1114 " more;", i::BLOCK_SCOPE, i::STRICT },
1115 { " for ", "(let x in {})\n"
1117 " more;", i::BLOCK_SCOPE, i::STRICT },
1118 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
1119 // the preparser off in terms of byte offsets.
1121 { " 'foo\355\240\201\355\260\211';\n"
1122 " (function fun", "(a,b) { infunction; }", ")();",
1123 i::FUNCTION_SCOPE, i::SLOPPY },
1125 { " 'foo\360\220\220\212';\n"
1126 " (function fun", "(a,b) { infunction; }", ")();",
1127 i::FUNCTION_SCOPE, i::SLOPPY },
1128 // 3 byte encoding of \u0fff.
1129 { " 'foo\340\277\277';\n"
1130 " (function fun", "(a,b) { infunction; }", ")();",
1131 i::FUNCTION_SCOPE, i::SLOPPY },
1132 // Broken 6 byte encoding with missing last byte.
1133 { " 'foo\355\240\201\355\211';\n"
1134 " (function fun", "(a,b) { infunction; }", ")();",
1135 i::FUNCTION_SCOPE, i::SLOPPY },
1136 // Broken 3 byte encoding of \u0fff with missing last byte.
1137 { " 'foo\340\277';\n"
1138 " (function fun", "(a,b) { infunction; }", ")();",
1139 i::FUNCTION_SCOPE, i::SLOPPY },
1140 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
1142 " (function fun", "(a,b) { infunction; }", ")();",
1143 i::FUNCTION_SCOPE, i::SLOPPY },
1144 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
1145 { " 'foo\340\203\277';\n"
1146 " (function fun", "(a,b) { infunction; }", ")();",
1147 i::FUNCTION_SCOPE, i::SLOPPY },
1148 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
1149 { " 'foo\340\201\277';\n"
1150 " (function fun", "(a,b) { infunction; }", ")();",
1151 i::FUNCTION_SCOPE, i::SLOPPY },
1152 // Unpaired lead surrogate.
1153 { " 'foo\355\240\201';\n"
1154 " (function fun", "(a,b) { infunction; }", ")();",
1155 i::FUNCTION_SCOPE, i::SLOPPY },
1156 // Unpaired lead surrogate where following code point is a 3 byte sequence.
1157 { " 'foo\355\240\201\340\277\277';\n"
1158 " (function fun", "(a,b) { infunction; }", ")();",
1159 i::FUNCTION_SCOPE, i::SLOPPY },
1160 // Unpaired lead surrogate where following code point is a 4 byte encoding
1161 // of a trail surrogate.
1162 { " 'foo\355\240\201\360\215\260\211';\n"
1163 " (function fun", "(a,b) { infunction; }", ")();",
1164 i::FUNCTION_SCOPE, i::SLOPPY },
1165 // Unpaired trail surrogate.
1166 { " 'foo\355\260\211';\n"
1167 " (function fun", "(a,b) { infunction; }", ")();",
1168 i::FUNCTION_SCOPE, i::SLOPPY },
1169 // 2 byte encoding of \u00ff.
1170 { " 'foo\303\277';\n"
1171 " (function fun", "(a,b) { infunction; }", ")();",
1172 i::FUNCTION_SCOPE, i::SLOPPY },
1173 // Broken 2 byte encoding of \u00ff with missing last byte.
1175 " (function fun", "(a,b) { infunction; }", ")();",
1176 i::FUNCTION_SCOPE, i::SLOPPY },
1177 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
1178 { " 'foo\301\277';\n"
1179 " (function fun", "(a,b) { infunction; }", ")();",
1180 i::FUNCTION_SCOPE, i::SLOPPY },
1181 // Illegal 5 byte encoding.
1182 { " 'foo\370\277\277\277\277';\n"
1183 " (function fun", "(a,b) { infunction; }", ")();",
1184 i::FUNCTION_SCOPE, i::SLOPPY },
1185 // Illegal 6 byte encoding.
1186 { " 'foo\374\277\277\277\277\277';\n"
1187 " (function fun", "(a,b) { infunction; }", ")();",
1188 i::FUNCTION_SCOPE, i::SLOPPY },
1189 // Illegal 0xfe byte
1190 { " 'foo\376\277\277\277\277\277\277';\n"
1191 " (function fun", "(a,b) { infunction; }", ")();",
1192 i::FUNCTION_SCOPE, i::SLOPPY },
1193 // Illegal 0xff byte
1194 { " 'foo\377\277\277\277\277\277\277\277';\n"
1195 " (function fun", "(a,b) { infunction; }", ")();",
1196 i::FUNCTION_SCOPE, i::SLOPPY },
1198 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
1199 i::FUNCTION_SCOPE, i::SLOPPY },
1201 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
1202 i::FUNCTION_SCOPE, i::SLOPPY },
1203 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
1206 i::Isolate* isolate = CcTest::i_isolate();
1207 i::Factory* factory = isolate->factory();
1209 v8::HandleScope handles(CcTest::isolate());
1210 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1211 v8::Context::Scope context_scope(context);
1214 isolate->stack_guard()->SetStackLimit(
1215 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1217 for (int i = 0; source_data[i].outer_prefix; i++) {
1218 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1219 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1220 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1221 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1222 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1223 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1224 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1225 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1226 i::ScopedVector<char> program(kProgramByteSize + 1);
1227 i::OS::SNPrintF(program, "%s%s%s",
1228 source_data[i].outer_prefix,
1229 source_data[i].inner_source,
1230 source_data[i].outer_suffix);
1232 // Parse program source.
1233 i::Handle<i::String> source(
1234 factory->NewStringFromUtf8(i::CStrVector(program.start())));
1235 CHECK_EQ(source->length(), kProgramSize);
1236 i::Handle<i::Script> script = factory->NewScript(source);
1237 i::CompilationInfoWithZone info(script);
1238 i::Parser parser(&info);
1239 parser.set_allow_lazy(true);
1240 parser.set_allow_harmony_scoping(true);
1241 info.MarkAsGlobal();
1242 info.SetStrictMode(source_data[i].strict_mode);
1244 CHECK(info.function() != NULL);
1246 // Check scope types and positions.
1247 i::Scope* scope = info.function()->scope();
1248 CHECK(scope->is_global_scope());
1249 CHECK_EQ(scope->start_position(), 0);
1250 CHECK_EQ(scope->end_position(), kProgramSize);
1251 CHECK_EQ(scope->inner_scopes()->length(), 1);
1253 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1254 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
1255 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1256 // The end position of a token is one position after the last
1257 // character belonging to that token.
1258 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1263 i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) {
1264 i::Isolate* isolate = CcTest::i_isolate();
1265 i::Factory* factory = isolate->factory();
1266 const char* message = data->BuildMessage();
1267 i::Handle<i::String> format = v8::Utils::OpenHandle(
1268 *v8::String::NewFromUtf8(CcTest::isolate(), message));
1269 i::Vector<const char*> args = data->BuildArgs();
1270 i::Handle<i::JSArray> args_array = factory->NewJSArray(args.length());
1271 for (int i = 0; i < args.length(); i++) {
1272 i::JSArray::SetElement(
1273 args_array, i, v8::Utils::OpenHandle(*v8::String::NewFromUtf8(
1274 CcTest::isolate(), args[i])),
1277 i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
1278 i::Handle<i::Object> format_fun =
1279 i::GetProperty(builtins, "FormatMessage");
1280 i::Handle<i::Object> arg_handles[] = { format, args_array };
1281 bool has_exception = false;
1282 i::Handle<i::Object> result = i::Execution::Call(
1283 isolate, format_fun, builtins, 2, arg_handles, &has_exception);
1284 CHECK(!has_exception);
1285 CHECK(result->IsString());
1286 for (int i = 0; i < args.length(); i++) {
1287 i::DeleteArray(args[i]);
1289 i::DeleteArray(args.start());
1290 i::DeleteArray(message);
1291 return i::Handle<i::String>::cast(result);
1297 kAllowNativesSyntax,
1298 kAllowHarmonyScoping,
1302 kAllowHarmonyNumericLiterals
1306 enum ParserSyncTestResult {
1312 template <typename Traits>
1313 void SetParserFlags(i::ParserBase<Traits>* parser,
1314 i::EnumSet<ParserFlag> flags) {
1315 parser->set_allow_lazy(flags.Contains(kAllowLazy));
1316 parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
1317 parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
1318 parser->set_allow_modules(flags.Contains(kAllowModules));
1319 parser->set_allow_generators(flags.Contains(kAllowGenerators));
1320 parser->set_allow_for_of(flags.Contains(kAllowForOf));
1321 parser->set_allow_harmony_numeric_literals(
1322 flags.Contains(kAllowHarmonyNumericLiterals));
1326 void TestParserSyncWithFlags(i::Handle<i::String> source,
1327 i::EnumSet<ParserFlag> flags,
1328 ParserSyncTestResult result) {
1329 i::Isolate* isolate = CcTest::i_isolate();
1330 i::Factory* factory = isolate->factory();
1332 uintptr_t stack_limit = isolate->stack_guard()->real_climit();
1334 // Preparse the data.
1335 i::CompleteParserRecorder log;
1337 i::Scanner scanner(isolate->unicode_cache());
1338 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1339 i::PreParser preparser(&scanner, &log, stack_limit);
1340 SetParserFlags(&preparser, flags);
1341 scanner.Initialize(&stream);
1342 i::PreParser::PreParseResult result = preparser.PreParseProgram();
1343 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1345 i::ScriptDataImpl data(log.ExtractData());
1348 i::FunctionLiteral* function;
1350 i::Handle<i::Script> script = factory->NewScript(source);
1351 i::CompilationInfoWithZone info(script);
1352 i::Parser parser(&info);
1353 SetParserFlags(&parser, flags);
1354 info.MarkAsGlobal();
1356 function = info.function();
1359 // Check that preparsing fails iff parsing fails.
1360 if (function == NULL) {
1361 // Extract exception from the parser.
1362 CHECK(isolate->has_pending_exception());
1363 i::MaybeObject* maybe_object = isolate->pending_exception();
1364 i::JSObject* exception = NULL;
1365 CHECK(maybe_object->To(&exception));
1366 i::Handle<i::JSObject> exception_handle(exception);
1367 i::Handle<i::String> message_string =
1368 i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
1370 if (result == kSuccess) {
1372 "Parser failed on:\n"
1376 "However, we expected no error.",
1377 source->ToCString().get(), message_string->ToCString().get());
1381 if (!data.has_error()) {
1383 "Parser failed on:\n"
1387 "However, the preparser succeeded",
1388 source->ToCString().get(), message_string->ToCString().get());
1391 // Check that preparser and parser produce the same error.
1392 i::Handle<i::String> preparser_message = FormatMessage(&data);
1393 if (!message_string->Equals(*preparser_message)) {
1395 "Expected parser and preparser to produce the same error on:\n"
1397 "However, found the following error messages\n"
1399 "\tpreparser: %s\n",
1400 source->ToCString().get(),
1401 message_string->ToCString().get(),
1402 preparser_message->ToCString().get());
1405 } else if (data.has_error()) {
1407 "Preparser failed on:\n"
1411 "However, the parser succeeded",
1412 source->ToCString().get(), FormatMessage(&data)->ToCString().get());
1414 } else if (result == kError) {
1416 "Expected error on:\n"
1418 "However, parser and preparser succeeded",
1419 source->ToCString().get());
1425 void TestParserSync(const char* source,
1426 const ParserFlag* flag_list,
1427 size_t flag_list_length,
1428 ParserSyncTestResult result = kSuccessOrError) {
1429 i::Handle<i::String> str =
1430 CcTest::i_isolate()->factory()->NewStringFromAscii(i::CStrVector(source));
1431 for (int bits = 0; bits < (1 << flag_list_length); bits++) {
1432 i::EnumSet<ParserFlag> flags;
1433 for (size_t flag_index = 0; flag_index < flag_list_length; flag_index++) {
1434 if ((bits & (1 << flag_index)) != 0) flags.Add(flag_list[flag_index]);
1436 TestParserSyncWithFlags(str, flags, result);
1442 const char* context_data[][2] = {
1445 { "if (true) ", " else {}" },
1446 { "if (true) {} else ", "" },
1447 { "if (true) ", "" },
1448 { "do ", " while (false)" },
1449 { "while (false) ", "" },
1450 { "for (;;) ", "" },
1451 { "with ({})", "" },
1452 { "switch (12) { case 12: ", "}" },
1453 { "switch (12) { default: ", "}" },
1454 { "switch (12) { ", "case 12: }" },
1459 const char* statement_data[] = {
1467 "if (false) {} else ;",
1468 "if (false) {} else {}",
1469 "if (false) {} else 12",
1473 "do {} while (false)",
1489 "switch ({}) { default: }"
1494 "try {} catch(e) {}",
1495 "try {} finally {}",
1496 "try {} catch(e) {} finally {}",
1501 const char* termination_data[] = {
1510 v8::HandleScope handles(CcTest::isolate());
1511 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1512 v8::Context::Scope context_scope(context);
1515 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1516 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1518 static const ParserFlag flags1[] = {
1519 kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
1522 for (int i = 0; context_data[i][0] != NULL; ++i) {
1523 for (int j = 0; statement_data[j] != NULL; ++j) {
1524 for (int k = 0; termination_data[k] != NULL; ++k) {
1525 int kPrefixLen = i::StrLength(context_data[i][0]);
1526 int kStatementLen = i::StrLength(statement_data[j]);
1527 int kTerminationLen = i::StrLength(termination_data[k]);
1528 int kSuffixLen = i::StrLength(context_data[i][1]);
1529 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1530 + kSuffixLen + i::StrLength("label: for (;;) { }");
1532 // Plug the source code pieces together.
1533 i::ScopedVector<char> program(kProgramSize + 1);
1534 int length = i::OS::SNPrintF(program,
1535 "label: for (;;) { %s%s%s%s }",
1538 termination_data[k],
1539 context_data[i][1]);
1540 CHECK(length == kProgramSize);
1541 TestParserSync(program.start(), flags1, ARRAY_SIZE(flags1));
1546 // Neither Harmony numeric literals nor our natives syntax have any
1547 // interaction with the flags above, so test these separately to reduce
1548 // the combinatorial explosion.
1549 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
1550 TestParserSync("0o1234", flags2, ARRAY_SIZE(flags2));
1551 TestParserSync("0b1011", flags2, ARRAY_SIZE(flags2));
1553 static const ParserFlag flags3[] = { kAllowNativesSyntax };
1554 TestParserSync("%DebugPrint(123)", flags3, ARRAY_SIZE(flags3));
1558 TEST(PreparserStrictOctal) {
1559 // Test that syntax error caused by octal literal is reported correctly as
1560 // such (issue 2220).
1561 v8::internal::FLAG_min_preparse_length = 1; // Force preparsing.
1562 v8::V8::Initialize();
1563 v8::HandleScope scope(CcTest::isolate());
1564 v8::Context::Scope context_scope(
1565 v8::Context::New(CcTest::isolate()));
1566 v8::TryCatch try_catch;
1567 const char* script =
1568 "\"use strict\"; \n"
1569 "a = function() { \n"
1570 " b = function() { \n"
1574 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
1575 CHECK(try_catch.HasCaught());
1576 v8::String::Utf8Value exception(try_catch.Exception());
1577 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
1582 void RunParserSyncTest(const char* context_data[][2],
1583 const char* statement_data[],
1584 ParserSyncTestResult result,
1585 const ParserFlag* flags = NULL,
1586 int flags_len = 0) {
1587 v8::HandleScope handles(CcTest::isolate());
1588 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1589 v8::Context::Scope context_scope(context);
1592 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1593 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1595 static const ParserFlag default_flags[] = {
1596 kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
1597 kAllowForOf, kAllowNativesSyntax
1600 flags = default_flags;
1601 flags_len = ARRAY_SIZE(default_flags);
1603 for (int i = 0; context_data[i][0] != NULL; ++i) {
1604 for (int j = 0; statement_data[j] != NULL; ++j) {
1605 int kPrefixLen = i::StrLength(context_data[i][0]);
1606 int kStatementLen = i::StrLength(statement_data[j]);
1607 int kSuffixLen = i::StrLength(context_data[i][1]);
1608 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
1610 // Plug the source code pieces together.
1611 i::ScopedVector<char> program(kProgramSize + 1);
1612 int length = i::OS::SNPrintF(program,
1616 context_data[i][1]);
1617 CHECK(length == kProgramSize);
1618 TestParserSync(program.start(),
1627 TEST(ErrorsEvalAndArguments) {
1628 // Tests that both preparsing and parsing produce the right kind of errors for
1629 // using "eval" and "arguments" as identifiers. Without the strict mode, it's
1630 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it
1632 const char* context_data[][2] = {
1633 { "\"use strict\";", "" },
1634 { "var eval; function test_func() {\"use strict\"; ", "}"},
1638 const char* statement_data[] = {
1642 "var foo, arguments;",
1643 "try { } catch (eval) { }",
1644 "try { } catch (arguments) { }",
1645 "function eval() { }",
1646 "function arguments() { }",
1647 "function foo(eval) { }",
1648 "function foo(arguments) { }",
1649 "function foo(bar, eval) { }",
1650 "function foo(bar, arguments) { }",
1653 "var foo = eval = 1;",
1654 "var foo = arguments = 1;",
1662 RunParserSyncTest(context_data, statement_data, kError);
1666 TEST(NoErrorsEvalAndArgumentsSloppy) {
1667 // Tests that both preparsing and parsing accept "eval" and "arguments" as
1668 // identifiers when needed.
1669 const char* context_data[][2] = {
1671 { "function test_func() {", "}"},
1675 const char* statement_data[] = {
1679 "var foo, arguments;",
1680 "try { } catch (eval) { }",
1681 "try { } catch (arguments) { }",
1682 "function eval() { }",
1683 "function arguments() { }",
1684 "function foo(eval) { }",
1685 "function foo(arguments) { }",
1686 "function foo(bar, eval) { }",
1687 "function foo(bar, arguments) { }",
1690 "var foo = eval = 1;",
1691 "var foo = arguments = 1;",
1699 RunParserSyncTest(context_data, statement_data, kSuccess);
1703 TEST(NoErrorsEvalAndArgumentsStrict) {
1704 const char* context_data[][2] = {
1705 { "\"use strict\";", "" },
1706 { "function test_func() { \"use strict\";", "}" },
1710 const char* statement_data[] = {
1714 "var foo = arguments;",
1715 "var foo = { eval: 1 };",
1716 "var foo = { arguments: 1 };",
1717 "var foo = { }; foo.eval = {};",
1718 "var foo = { }; foo.arguments = {};",
1722 RunParserSyncTest(context_data, statement_data, kSuccess);
1726 TEST(ErrorsFutureStrictReservedWords) {
1727 // Tests that both preparsing and parsing produce the right kind of errors for
1728 // using future strict reserved words as identifiers. Without the strict mode,
1729 // it's ok to use future strict reserved words as identifiers. With the strict
1731 const char* context_data[][2] = {
1732 { "\"use strict\";", "" },
1733 { "function test_func() {\"use strict\"; ", "}"},
1737 const char* statement_data[] = {
1739 "var foo, interface;",
1740 "try { } catch (interface) { }",
1741 "function interface() { }",
1742 "function foo(interface) { }",
1743 "function foo(bar, interface) { }",
1745 "var foo = interface = 1;",
1751 RunParserSyncTest(context_data, statement_data, kError);
1755 TEST(NoErrorsFutureStrictReservedWords) {
1756 const char* context_data[][2] = {
1758 { "function test_func() {", "}"},
1762 const char* statement_data[] = {
1764 "var foo, interface;",
1765 "try { } catch (interface) { }",
1766 "function interface() { }",
1767 "function foo(interface) { }",
1768 "function foo(bar, interface) { }",
1770 "var foo = interface = 1;",
1776 RunParserSyncTest(context_data, statement_data, kSuccess);
1780 TEST(ErrorsReservedWords) {
1781 // Tests that both preparsing and parsing produce the right kind of errors for
1782 // using future reserved words as identifiers. These tests don't depend on the
1784 const char* context_data[][2] = {
1786 { "\"use strict\";", "" },
1787 { "var eval; function test_func() {", "}"},
1788 { "var eval; function test_func() {\"use strict\"; ", "}"},
1792 const char* statement_data[] = {
1795 "try { } catch (super) { }",
1796 "function super() { }",
1797 "function foo(super) { }",
1798 "function foo(bar, super) { }",
1800 "var foo = super = 1;",
1803 "function foo super",
1807 RunParserSyncTest(context_data, statement_data, kError);
1811 TEST(NoErrorsYieldSloppy) {
1812 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
1813 // generator (see next test).
1814 const char* context_data[][2] = {
1816 { "function is_not_gen() {", "}" },
1820 const char* statement_data[] = {
1823 "try { } catch (yield) { }",
1824 "function yield() { }",
1825 "function foo(yield) { }",
1826 "function foo(bar, yield) { }",
1828 "var foo = yield = 1;",
1834 RunParserSyncTest(context_data, statement_data, kSuccess);
1838 TEST(ErrorsYieldSloppyGenerator) {
1839 const char* context_data[][2] = {
1840 { "function * is_gen() {", "}" },
1844 const char* statement_data[] = {
1847 "try { } catch (yield) { }",
1848 "function yield() { }",
1849 // BUG: These should not be allowed, but they are (if kAllowGenerators is
1851 // "function foo(yield) { }",
1852 // "function foo(bar, yield) { }",
1854 "var foo = yield = 1;",
1860 // If generators are not allowed, the error will be produced at the '*' token,
1861 // so this test works both with and without the kAllowGenerators flag.
1862 RunParserSyncTest(context_data, statement_data, kError);
1866 TEST(ErrorsYieldStrict) {
1867 const char* context_data[][2] = {
1868 { "\"use strict\";", "" },
1869 { "\"use strict\"; function is_not_gen() {", "}" },
1870 { "function test_func() {\"use strict\"; ", "}"},
1874 const char* statement_data[] = {
1877 "try { } catch (yield) { }",
1878 "function yield() { }",
1879 "function foo(yield) { }",
1880 "function foo(bar, yield) { }",
1882 "var foo = yield = 1;",
1888 RunParserSyncTest(context_data, statement_data, kError);
1893 const char* context_data[][2] = {
1894 { "function * is_gen() {", "}" },
1898 const char* statement_data[] = {
1899 "yield 2;", // this is legal inside generator
1900 "yield * 2;", // this is legal inside generator
1904 // Here we cannot assert that there is no error, since there will be without
1905 // the kAllowGenerators flag. However, we test that Parser and PreParser
1906 // produce the same errors.
1907 RunParserSyncTest(context_data, statement_data, kSuccessOrError);
1911 TEST(ErrorsNameOfStrictFunction) {
1912 // Tests that illegal tokens as names of a strict function produce the correct
1914 const char* context_data[][2] = {
1916 { "\"use strict\";", ""},
1920 const char* statement_data[] = {
1921 "function eval() {\"use strict\";}",
1922 "function arguments() {\"use strict\";}",
1923 "function interface() {\"use strict\";}",
1924 "function yield() {\"use strict\";}",
1925 // Future reserved words are always illegal
1926 "function super() { }",
1927 "function super() {\"use strict\";}",
1931 RunParserSyncTest(context_data, statement_data, kError);
1935 TEST(NoErrorsNameOfStrictFunction) {
1936 const char* context_data[][2] = {
1941 const char* statement_data[] = {
1942 "function eval() { }",
1943 "function arguments() { }",
1944 "function interface() { }",
1945 "function yield() { }",
1949 RunParserSyncTest(context_data, statement_data, kSuccess);
1954 TEST(ErrorsIllegalWordsAsLabelsSloppy) {
1955 // Using future reserved words as labels is always an error.
1956 const char* context_data[][2] = {
1958 { "function test_func() {", "}" },
1962 const char* statement_data[] = {
1963 "super: while(true) { break super; }",
1967 RunParserSyncTest(context_data, statement_data, kError);
1971 TEST(ErrorsIllegalWordsAsLabelsStrict) {
1972 // Tests that illegal tokens as labels produce the correct errors.
1973 const char* context_data[][2] = {
1974 { "\"use strict\";", "" },
1975 { "function test_func() {\"use strict\"; ", "}"},
1979 const char* statement_data[] = {
1980 "super: while(true) { break super; }",
1981 "interface: while(true) { break interface; }",
1982 "yield: while(true) { break yield; }",
1986 RunParserSyncTest(context_data, statement_data, kError);
1990 TEST(NoErrorsIllegalWordsAsLabels) {
1991 // Using eval and arguments as labels is legal even in strict mode.
1992 const char* context_data[][2] = {
1994 { "function test_func() {", "}" },
1995 { "\"use strict\";", "" },
1996 { "\"use strict\"; function test_func() {", "}" },
2000 const char* statement_data[] = {
2001 "mylabel: while(true) { break mylabel; }",
2002 "eval: while(true) { break eval; }",
2003 "arguments: while(true) { break arguments; }",
2007 RunParserSyncTest(context_data, statement_data, kSuccess);
2011 TEST(ErrorsParenthesizedLabels) {
2012 // Parenthesized identifiers shouldn't be recognized as labels.
2013 const char* context_data[][2] = {
2015 { "function test_func() {", "}" },
2019 const char* statement_data[] = {
2020 "(mylabel): while(true) { break mylabel; }",
2024 RunParserSyncTest(context_data, statement_data, kError);
2028 TEST(NoErrorsParenthesizedDirectivePrologue) {
2029 // Parenthesized directive prologue shouldn't be recognized.
2030 const char* context_data[][2] = {
2035 const char* statement_data[] = {
2036 "(\"use strict\"); var eval;",
2040 RunParserSyncTest(context_data, statement_data, kSuccess);
2044 TEST(ErrorsNotAnIdentifierName) {
2045 const char* context_data[][2] = {
2047 { "\"use strict\";", ""},
2051 const char* statement_data[] = {
2052 "var foo = {}; foo.{;",
2053 "var foo = {}; foo.};",
2054 "var foo = {}; foo.=;",
2055 "var foo = {}; foo.888;",
2056 "var foo = {}; foo.-;",
2057 "var foo = {}; foo.--;",
2061 RunParserSyncTest(context_data, statement_data, kError);
2065 TEST(NoErrorsIdentifierNames) {
2066 // Keywords etc. are valid as property names.
2067 const char* context_data[][2] = {
2069 { "\"use strict\";", ""},
2073 const char* statement_data[] = {
2074 "var foo = {}; foo.if;",
2075 "var foo = {}; foo.yield;",
2076 "var foo = {}; foo.super;",
2077 "var foo = {}; foo.interface;",
2078 "var foo = {}; foo.eval;",
2079 "var foo = {}; foo.arguments;",
2083 RunParserSyncTest(context_data, statement_data, kSuccess);
2087 TEST(DontRegressPreParserDataSizes) {
2088 // These tests make sure that PreParser doesn't start producing less data.
2090 v8::V8::Initialize();
2092 CcTest::i_isolate()->stack_guard()->SetStackLimit(
2093 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
2096 const char* program;
2100 // Labels and variables are recorded as symbols.
2101 {"{label: 42}", 1, 0}, {"{label: 42; label2: 43}", 2, 0},
2102 {"var x = 42;", 1, 0}, {"var x = 42, y = 43;", 2, 0},
2103 {"var x = {y: 1};", 2, 0},
2104 {"var x = {}; x.y = 1", 2, 0},
2105 // "get" is recorded as a symbol too.
2106 {"var x = {get foo(){} };", 3, 1},
2107 // When keywords are used as identifiers, they're logged as symbols, too:
2108 {"var x = {if: 1};", 2, 0},
2109 {"var x = {}; x.if = 1", 2, 0},
2110 {"var x = {get if(){} };", 3, 1},
2112 {"function foo() {}", 1, 1}, {"function foo() {} function bar() {}", 2, 2},
2113 // Labels, variables and functions insize lazy functions are not recorded.
2114 {"function lazy() { var a, b, c; }", 1, 1},
2115 {"function lazy() { a: 1; b: 2; c: 3; }", 1, 1},
2116 {"function lazy() { function a() {} function b() {} function c() {} }", 1,
2120 // Each function adds 5 elements to the preparse function data.
2121 const int kDataPerFunction = 5;
2123 typedef i::CompleteParserRecorderFriend F;
2124 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
2125 for (int i = 0; test_cases[i].program; i++) {
2126 const char* program = test_cases[i].program;
2127 i::Utf8ToUtf16CharacterStream stream(
2128 reinterpret_cast<const i::byte*>(program),
2129 static_cast<unsigned>(strlen(program)));
2130 i::CompleteParserRecorder log;
2131 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
2132 scanner.Initialize(&stream);
2134 i::PreParser preparser(&scanner, &log, stack_limit);
2135 preparser.set_allow_lazy(true);
2136 preparser.set_allow_natives_syntax(true);
2137 i::PreParser::PreParseResult result = preparser.PreParseProgram();
2138 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
2139 if (F::symbol_ids(&log) != test_cases[i].symbols) {
2141 "Expected preparse data for program:\n"
2143 "to contain %d symbols, however, received %d symbols.\n",
2144 program, test_cases[i].symbols, F::symbol_ids(&log));
2147 if (F::function_position(&log) !=
2148 test_cases[i].functions * kDataPerFunction) {
2150 "Expected preparse data for program:\n"
2152 "to contain %d functions, however, received %d functions.\n",
2153 program, test_cases[i].functions,
2154 F::function_position(&log) / kDataPerFunction);
2157 i::ScriptDataImpl data(log.ExtractData());
2158 CHECK(!data.has_error());
2163 TEST(FunctionDeclaresItselfStrict) {
2164 // Tests that we produce the right kinds of errors when a function declares
2165 // itself strict (we cannot produce there errors as soon as we see the
2166 // offending identifiers, because we don't know at that point whether the
2167 // function is strict or not).
2168 const char* context_data[][2] = {
2169 {"function eval() {", "}"},
2170 {"function arguments() {", "}"},
2171 {"function yield() {", "}"},
2172 {"function interface() {", "}"},
2173 {"function foo(eval) {", "}"},
2174 {"function foo(arguments) {", "}"},
2175 {"function foo(yield) {", "}"},
2176 {"function foo(interface) {", "}"},
2177 {"function foo(bar, eval) {", "}"},
2178 {"function foo(bar, arguments) {", "}"},
2179 {"function foo(bar, yield) {", "}"},
2180 {"function foo(bar, interface) {", "}"},
2181 {"function foo(bar, bar) {", "}"},
2185 const char* strict_statement_data[] = {
2190 const char* non_strict_statement_data[] = {
2195 RunParserSyncTest(context_data, strict_statement_data, kError);
2196 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
2200 TEST(ErrorsTryWithoutCatchOrFinally) {
2201 const char* context_data[][2] = {
2206 const char* statement_data[] = {
2209 "try { } catch (e) foo();",
2210 "try { } catch { }",
2211 "try { } finally foo();",
2215 RunParserSyncTest(context_data, statement_data, kError);
2219 TEST(NoErrorsTryCatchFinally) {
2220 const char* context_data[][2] = {
2225 const char* statement_data[] = {
2226 "try { } catch (e) { }",
2227 "try { } catch (e) { } finally { }",
2228 "try { } finally { }",
2232 RunParserSyncTest(context_data, statement_data, kSuccess);
2236 TEST(ErrorsRegexpLiteral) {
2237 const char* context_data[][2] = {
2242 const char* statement_data[] = {
2247 RunParserSyncTest(context_data, statement_data, kError);
2251 TEST(NoErrorsRegexpLiteral) {
2252 const char* context_data[][2] = {
2257 const char* statement_data[] = {
2260 "/foo/whatever", // This is an error but not detected by the parser.
2264 RunParserSyncTest(context_data, statement_data, kSuccess);
2269 const char* context_data[][2] = {
2274 const char* statement_data[] = {
2275 "%someintrinsic(arg)",
2279 // Parsing will fail or succeed depending on whether we allow natives syntax
2281 RunParserSyncTest(context_data, statement_data, kSuccessOrError);
2285 TEST(NoErrorsNewExpression) {
2286 const char* context_data[][2] = {
2292 const char* statement_data[] = {
2297 // The first () will be processed as a part of the NewExpression and the
2298 // second () will be processed as part of LeftHandSideExpression.
2300 // The first () will be processed as a part of the inner NewExpression and
2301 // the second () will be processed as a part of the outer NewExpression.
2306 "new foo.bar().baz;",
2309 "new foo[bar][baz];",
2310 "new foo[bar]()[baz];",
2311 "new foo[bar].baz(baz)()[bar].baz;",
2312 "new \"foo\"", // Runtime error
2313 "new 1", // Runtime error
2315 "(new new Function(\"this.x = 1\")).x;",
2316 "new new Test_Two(String, 2).v(0123).length;",
2320 RunParserSyncTest(context_data, statement_data, kSuccess);
2324 TEST(ErrorsNewExpression) {
2325 const char* context_data[][2] = {
2331 const char* statement_data[] = {
2339 RunParserSyncTest(context_data, statement_data, kError);
2343 TEST(StrictObjectLiteralChecking) {
2344 const char* strict_context_data[][2] = {
2345 {"\"use strict\"; var myobject = {", "};"},
2348 const char* non_strict_context_data[][2] = {
2349 {"var myobject = {", "};"},
2353 // These are only errors in strict mode.
2354 const char* statement_data[] = {
2356 "\"foo\": 1, \"foo\": 2",
2357 "foo: 1, \"foo\": 2",
2360 "get: 1, get: 2", // Not a getter for real, just a property called get.
2361 "set: 1, set: 2", // Not a setter for real, just a property called set.
2365 RunParserSyncTest(non_strict_context_data, statement_data, kSuccess);
2366 RunParserSyncTest(strict_context_data, statement_data, kError);
2370 TEST(ErrorsObjectLiteralChecking) {
2371 const char* context_data[][2] = {
2372 {"\"use strict\"; var myobject = {", "};"},
2373 {"var myobject = {", "};"},
2377 const char* statement_data[] = {
2378 "foo: 1, get foo() {}",
2379 "foo: 1, set foo() {}",
2380 "\"foo\": 1, get \"foo\"() {}",
2381 "\"foo\": 1, set \"foo\"() {}",
2384 // It's counter-intuitive, but these collide too (even in classic
2385 // mode). Note that we can have "foo" and foo as properties in classic mode,
2386 // but we cannot have "foo" and get foo, or foo and get "foo".
2387 "foo: 1, get \"foo\"() {}",
2388 "foo: 1, set \"foo\"() {}",
2389 "\"foo\": 1, get foo() {}",
2390 "\"foo\": 1, set foo() {}",
2391 "1: 1, get \"1\"() {}",
2392 "1: 1, set \"1\"() {}",
2393 "\"1\": 1, get 1() {}"
2394 "\"1\": 1, set 1() {}"
2395 // Parsing FunctionLiteral for getter or setter fails
2397 "get foo() \"error\"",
2401 RunParserSyncTest(context_data, statement_data, kError);
2405 TEST(NoErrorsObjectLiteralChecking) {
2406 const char* context_data[][2] = {
2407 {"var myobject = {", "};"},
2408 {"\"use strict\"; var myobject = {", "};"},
2412 const char* statement_data[] = {
2414 "\"foo\": 1, \"bar\": 2",
2416 // Syntax: IdentifierName ':' AssignmentExpression
2417 "foo: bar = 5 + baz",
2418 // Syntax: 'get' (IdentifierName | String | Number) FunctionLiteral
2422 // Syntax: 'set' (IdentifierName | String | Number) FunctionLiteral
2426 // Non-colliding getters and setters -> no errors
2427 "foo: 1, get bar() {}",
2428 "foo: 1, set bar(b) {}",
2429 "\"foo\": 1, get \"bar\"() {}",
2430 "\"foo\": 1, set \"bar\"() {}",
2433 // Weird number of parameters -> no errors
2434 "get bar() {}, set bar() {}",
2435 "get bar(x) {}, set bar(x) {}",
2436 "get bar(x, y) {}, set bar(x, y) {}",
2437 // Keywords, future reserved and strict future reserved are also allowed as
2447 RunParserSyncTest(context_data, statement_data, kSuccess);
2451 TEST(TooManyArguments) {
2452 const char* context_data[][2] = {
2457 using v8::internal::Code;
2458 char statement[Code::kMaxArguments * 2 + 1];
2459 for (int i = 0; i < Code::kMaxArguments; ++i) {
2460 statement[2 * i] = '0';
2461 statement[2 * i + 1] = ',';
2463 statement[Code::kMaxArguments * 2] = 0;
2465 const char* statement_data[] = {
2470 // The test is quite slow, so run it with a reduced set of flags.
2471 static const ParserFlag empty_flags[] = {kAllowLazy};
2472 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
2476 TEST(StrictDelete) {
2477 // "delete <Identifier>" is not allowed in strict mode.
2478 const char* strict_context_data[][2] = {
2479 {"\"use strict\"; ", ""},
2483 const char* sloppy_context_data[][2] = {
2488 // These are errors in the strict mode.
2489 const char* sloppy_statement_data[] = {
2494 "delete interface;",
2498 // These are always OK
2499 const char* good_statement_data[] = {
2508 "delete new foo();",
2509 "delete new foo(bar);",
2513 // These are always errors
2514 const char* bad_statement_data[] = {
2519 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
2520 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
2522 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
2523 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
2525 RunParserSyncTest(strict_context_data, bad_statement_data, kError);
2526 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
2530 TEST(InvalidLeftHandSide) {
2531 const char* assignment_context_data[][2] = {
2533 {"\"use strict\"; ", " = 1;"},
2537 const char* prefix_context_data[][2] = {
2539 {"\"use strict\"; ++", ";"},
2543 const char* postfix_context_data[][2] = {
2545 {"\"use strict\"; ", "++;"},
2549 // Good left hand sides for assigment or prefix / postfix operations.
2550 const char* good_statement_data[] = {
2563 // Bad left hand sides for assigment or prefix / postfix operations.
2564 const char* bad_statement_data_common[] = {
2568 "if", // Unexpected token
2569 "{x: 1}", // Unexpected token
2573 "new new foo()[bar]", // means: new (new foo()[bar])
2574 "new new foo().bar", // means: new (new foo()[bar])
2578 // These are not okay for assignment, but okay for prefix / postix.
2579 const char* bad_statement_data_for_assignment[] = {
2586 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
2587 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
2588 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
2591 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
2592 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
2594 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
2595 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);