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"
39 #include "preparser.h"
40 #include "scanner-character-streams.h"
47 i::Token::Value token;
50 static const KeywordToken keywords[] = {
51 #define KEYWORD(t, s, d) { s, i::Token::t },
52 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
54 { NULL, i::Token::IDENTIFIER }
57 KeywordToken key_token;
58 i::UnicodeCache unicode_cache;
60 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
61 const i::byte* keyword =
62 reinterpret_cast<const i::byte*>(key_token.keyword);
63 int length = i::StrLength(key_token.keyword);
64 CHECK(static_cast<int>(sizeof(buffer)) >= length);
66 i::Utf8ToUtf16CharacterStream stream(keyword, length);
67 i::Scanner scanner(&unicode_cache);
68 // The scanner should parse Harmony keywords for this test.
69 scanner.SetHarmonyScoping(true);
70 scanner.SetHarmonyModules(true);
71 scanner.Initialize(&stream);
72 CHECK_EQ(key_token.token, scanner.Next());
73 CHECK_EQ(i::Token::EOS, scanner.Next());
75 // Removing characters will make keyword matching fail.
77 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
78 i::Scanner scanner(&unicode_cache);
79 scanner.Initialize(&stream);
80 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
81 CHECK_EQ(i::Token::EOS, scanner.Next());
83 // Adding characters will make keyword matching fail.
84 static const char chars_to_append[] = { 'z', '0', '_' };
85 for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) {
86 i::OS::MemMove(buffer, keyword, length);
87 buffer[length] = chars_to_append[j];
88 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
89 i::Scanner scanner(&unicode_cache);
90 scanner.Initialize(&stream);
91 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
92 CHECK_EQ(i::Token::EOS, scanner.Next());
94 // Replacing characters will make keyword matching fail.
96 i::OS::MemMove(buffer, keyword, length);
97 buffer[length - 1] = '_';
98 i::Utf8ToUtf16CharacterStream stream(buffer, length);
99 i::Scanner scanner(&unicode_cache);
100 scanner.Initialize(&stream);
101 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
102 CHECK_EQ(i::Token::EOS, scanner.Next());
108 TEST(ScanHTMLEndComments) {
109 v8::V8::Initialize();
110 v8::Isolate* isolate = CcTest::isolate();
111 v8::HandleScope handles(isolate);
113 // Regression test. See:
114 // http://code.google.com/p/chromium/issues/detail?id=53548
115 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
116 // is only whitespace before it on the line (with comments considered as
117 // whitespace, even a multiline-comment containing a newline).
118 // This was not the case if it occurred before the first real token
120 const char* tests[] = {
121 // Before first real token.
122 "--> is eol-comment\nvar y = 37;\n",
123 "\n --> is eol-comment\nvar y = 37;\n",
124 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
125 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
126 // After first real token.
127 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
128 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
132 const char* fail_tests[] = {
133 "x --> is eol-comment\nvar y = 37;\n",
134 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
135 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
136 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
137 "var x = 42; --> is eol-comment\nvar y = 37;\n",
138 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
142 // Parser/Scanner needs a stack limit.
144 CcTest::i_isolate()->stack_guard()->SetStackLimit(
145 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
147 for (int i = 0; tests[i]; i++) {
148 v8::Handle<v8::String> source = v8::String::NewFromUtf8(
149 isolate, tests[i], v8::String::kNormalString, i::StrLength(tests[i]));
150 v8::ScriptData* data = v8::ScriptData::PreCompile(source);
151 CHECK(data != NULL && !data->HasError());
155 for (int i = 0; fail_tests[i]; i++) {
156 v8::Handle<v8::String> source =
157 v8::String::NewFromUtf8(isolate,
159 v8::String::kNormalString,
160 i::StrLength(fail_tests[i]));
161 v8::ScriptData* data = v8::ScriptData::PreCompile(source);
162 CHECK(data == NULL || data->HasError());
168 class ScriptResource : public v8::String::ExternalAsciiStringResource {
170 ScriptResource(const char* data, size_t length)
171 : data_(data), length_(length) { }
173 const char* data() const { return data_; }
174 size_t length() const { return length_; }
183 v8::Isolate* isolate = CcTest::isolate();
184 v8::HandleScope handles(isolate);
185 v8::Local<v8::Context> context = v8::Context::New(isolate);
186 v8::Context::Scope context_scope(context);
188 CcTest::i_isolate()->stack_guard()->SetStackLimit(
189 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
191 // Source containing functions that might be lazily compiled and all types
192 // of symbols (string, propertyName, regexp).
195 "function foo(a) { return function nolazy(b) { return a + b; } }"
196 "function bar(a) { if (a) return function lazy(b) { return b; } }"
197 "var z = {'string': 'string literal', bareword: 'propertyName', "
198 " 42: 'number literal', for: 'keyword as propertyName', "
199 " f\\u006fr: 'keyword propertyname with escape'};"
200 "var v = /RegExp Literal/;"
201 "var w = /RegExp Literal\\u0020With Escape/gin;"
202 "var y = { get getter() { return 42; }, "
203 " set setter(v) { this.value = v; }};";
204 int source_length = i::StrLength(source);
205 const char* error_source = "var x = y z;";
206 int error_source_length = i::StrLength(error_source);
208 v8::ScriptData* preparse = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
209 isolate, source, v8::String::kNormalString, source_length));
210 CHECK(!preparse->HasError());
211 bool lazy_flag = i::FLAG_lazy;
214 ScriptResource* resource = new ScriptResource(source, source_length);
215 v8::Local<v8::String> script_source =
216 v8::String::NewExternal(isolate, resource);
217 v8::Script::Compile(script_source, NULL, preparse);
221 i::FLAG_lazy = false;
223 ScriptResource* resource = new ScriptResource(source, source_length);
224 v8::Local<v8::String> script_source =
225 v8::String::NewExternal(isolate, resource);
226 v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
229 i::FLAG_lazy = lazy_flag;
232 v8::ScriptData* error_preparse = v8::ScriptData::PreCompile(
233 v8::String::NewFromUtf8(isolate,
235 v8::String::kNormalString,
236 error_source_length));
237 CHECK(error_preparse->HasError());
238 i::ScriptDataImpl *pre_impl =
239 reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
240 i::Scanner::Location error_location =
241 pre_impl->MessageLocation();
242 // Error is at "z" in source, location 10..11.
243 CHECK_EQ(10, error_location.beg_pos);
244 CHECK_EQ(11, error_location.end_pos);
246 const char* message = pre_impl->BuildMessage();
247 pre_impl->BuildArgs();
248 CHECK_GT(strlen(message), 0);
252 TEST(StandAlonePreParser) {
253 v8::V8::Initialize();
256 CcTest::i_isolate()->stack_guard()->SetStackLimit(
257 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
259 const char* programs[] = {
262 "function foo(x, y) { return x + y; }",
263 "%ArgleBargle(glop);",
264 "var x = new new Function('this.x = 42');",
268 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
269 for (int i = 0; programs[i]; i++) {
270 const char* program = programs[i];
271 i::Utf8ToUtf16CharacterStream stream(
272 reinterpret_cast<const i::byte*>(program),
273 static_cast<unsigned>(strlen(program)));
274 i::CompleteParserRecorder log;
275 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
276 scanner.Initialize(&stream);
278 i::PreParser preparser(&scanner, &log, stack_limit);
279 preparser.set_allow_lazy(true);
280 preparser.set_allow_natives_syntax(true);
281 i::PreParser::PreParseResult result = preparser.PreParseProgram();
282 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
283 i::ScriptDataImpl data(log.ExtractData());
284 CHECK(!data.has_error());
289 TEST(StandAlonePreParserNoNatives) {
290 v8::V8::Initialize();
293 CcTest::i_isolate()->stack_guard()->SetStackLimit(
294 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
296 const char* programs[] = {
297 "%ArgleBargle(glop);",
298 "var x = %_IsSmi(42);",
302 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
303 for (int i = 0; programs[i]; i++) {
304 const char* program = programs[i];
305 i::Utf8ToUtf16CharacterStream stream(
306 reinterpret_cast<const i::byte*>(program),
307 static_cast<unsigned>(strlen(program)));
308 i::CompleteParserRecorder log;
309 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
310 scanner.Initialize(&stream);
312 // Preparser defaults to disallowing natives syntax.
313 i::PreParser preparser(&scanner, &log, stack_limit);
314 preparser.set_allow_lazy(true);
315 i::PreParser::PreParseResult result = preparser.PreParseProgram();
316 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
317 i::ScriptDataImpl data(log.ExtractData());
318 // Data contains syntax error.
319 CHECK(data.has_error());
324 TEST(RegressChromium62639) {
325 v8::V8::Initialize();
326 i::Isolate* isolate = CcTest::i_isolate();
329 isolate->stack_guard()->SetStackLimit(
330 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
332 const char* program = "var x = 'something';\n"
333 "escape: function() {}";
334 // Fails parsing expecting an identifier after "function".
335 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
336 // and then used the invalid currently scanned literal. This always
337 // failed in debug mode, and sometimes crashed in release mode.
339 i::Utf8ToUtf16CharacterStream stream(
340 reinterpret_cast<const i::byte*>(program),
341 static_cast<unsigned>(strlen(program)));
342 i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
343 CHECK(data->HasError());
349 v8::V8::Initialize();
350 i::Isolate* isolate = CcTest::i_isolate();
351 i::Factory* factory = isolate->factory();
353 // Preparsing didn't consider the catch clause of a try statement
354 // as with-content, which made it assume that a function inside
355 // the block could be lazily compiled, and an extra, unexpected,
356 // entry was added to the data.
358 isolate->stack_guard()->SetStackLimit(
359 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
361 const char* program =
362 "try { } catch (e) { var foo = function () { /* first */ } }"
363 "var bar = function () { /* second */ }";
365 v8::HandleScope handles(CcTest::isolate());
366 i::Handle<i::String> source(
367 factory->NewStringFromAscii(i::CStrVector(program)));
368 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
369 i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
370 CHECK(!data->HasError());
375 static_cast<int>(strstr(program, "function") - program);
376 int first_lbrace = first_function + i::StrLength("function () ");
377 CHECK_EQ('{', program[first_lbrace]);
378 i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
379 CHECK(!entry1.is_valid());
381 int second_function =
382 static_cast<int>(strstr(program + first_lbrace, "function") - program);
384 second_function + i::StrLength("function () ");
385 CHECK_EQ('{', program[second_lbrace]);
386 i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
387 CHECK(entry2.is_valid());
388 CHECK_EQ('}', program[entry2.end_pos() - 1]);
393 TEST(PreParseOverflow) {
394 v8::V8::Initialize();
397 CcTest::i_isolate()->stack_guard()->SetStackLimit(
398 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
400 size_t kProgramSize = 1024 * 1024;
401 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
402 memset(program.get(), '(', kProgramSize);
403 program[kProgramSize] = '\0';
405 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
407 i::Utf8ToUtf16CharacterStream stream(
408 reinterpret_cast<const i::byte*>(program.get()),
409 static_cast<unsigned>(kProgramSize));
410 i::CompleteParserRecorder log;
411 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
412 scanner.Initialize(&stream);
414 i::PreParser preparser(&scanner, &log, stack_limit);
415 preparser.set_allow_lazy(true);
416 i::PreParser::PreParseResult result = preparser.PreParseProgram();
417 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
421 class TestExternalResource: public v8::String::ExternalStringResource {
423 explicit TestExternalResource(uint16_t* data, int length)
424 : data_(data), length_(static_cast<size_t>(length)) { }
426 ~TestExternalResource() { }
428 const uint16_t* data() const {
432 size_t length() const {
441 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
443 void TestCharacterStream(const char* ascii_source,
447 if (end == 0) end = length;
448 unsigned sub_length = end - start;
449 i::Isolate* isolate = CcTest::i_isolate();
450 i::Factory* factory = isolate->factory();
451 i::HandleScope test_scope(isolate);
452 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
453 for (unsigned i = 0; i < length; i++) {
454 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
456 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
457 i::Handle<i::String> ascii_string(
458 factory->NewStringFromAscii(ascii_vector));
459 TestExternalResource resource(uc16_buffer.get(), length);
460 i::Handle<i::String> uc16_string(
461 factory->NewExternalStringFromTwoByte(&resource));
463 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
464 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
465 i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
466 i::Utf8ToUtf16CharacterStream utf8_stream(
467 reinterpret_cast<const i::byte*>(ascii_source), end);
468 utf8_stream.SeekForward(start);
472 // Read streams one char at a time
473 CHECK_EQU(i, uc16_stream.pos());
474 CHECK_EQU(i, string_stream.pos());
475 CHECK_EQU(i, utf8_stream.pos());
476 int32_t c0 = ascii_source[i];
477 int32_t c1 = uc16_stream.Advance();
478 int32_t c2 = string_stream.Advance();
479 int32_t c3 = utf8_stream.Advance();
484 CHECK_EQU(i, uc16_stream.pos());
485 CHECK_EQU(i, string_stream.pos());
486 CHECK_EQU(i, utf8_stream.pos());
488 while (i > start + sub_length / 4) {
489 // Pushback, re-read, pushback again.
490 int32_t c0 = ascii_source[i - 1];
491 CHECK_EQU(i, uc16_stream.pos());
492 CHECK_EQU(i, string_stream.pos());
493 CHECK_EQU(i, utf8_stream.pos());
494 uc16_stream.PushBack(c0);
495 string_stream.PushBack(c0);
496 utf8_stream.PushBack(c0);
498 CHECK_EQU(i, uc16_stream.pos());
499 CHECK_EQU(i, string_stream.pos());
500 CHECK_EQU(i, utf8_stream.pos());
501 int32_t c1 = uc16_stream.Advance();
502 int32_t c2 = string_stream.Advance();
503 int32_t c3 = utf8_stream.Advance();
505 CHECK_EQU(i, uc16_stream.pos());
506 CHECK_EQU(i, string_stream.pos());
507 CHECK_EQU(i, utf8_stream.pos());
511 uc16_stream.PushBack(c0);
512 string_stream.PushBack(c0);
513 utf8_stream.PushBack(c0);
515 CHECK_EQU(i, uc16_stream.pos());
516 CHECK_EQU(i, string_stream.pos());
517 CHECK_EQU(i, utf8_stream.pos());
519 unsigned halfway = start + sub_length / 2;
520 uc16_stream.SeekForward(halfway - i);
521 string_stream.SeekForward(halfway - i);
522 utf8_stream.SeekForward(halfway - i);
524 CHECK_EQU(i, uc16_stream.pos());
525 CHECK_EQU(i, string_stream.pos());
526 CHECK_EQU(i, utf8_stream.pos());
529 // Read streams one char at a time
530 CHECK_EQU(i, uc16_stream.pos());
531 CHECK_EQU(i, string_stream.pos());
532 CHECK_EQU(i, utf8_stream.pos());
533 int32_t c0 = ascii_source[i];
534 int32_t c1 = uc16_stream.Advance();
535 int32_t c2 = string_stream.Advance();
536 int32_t c3 = utf8_stream.Advance();
541 CHECK_EQU(i, uc16_stream.pos());
542 CHECK_EQU(i, string_stream.pos());
543 CHECK_EQU(i, utf8_stream.pos());
546 int32_t c1 = uc16_stream.Advance();
547 int32_t c2 = string_stream.Advance();
548 int32_t c3 = utf8_stream.Advance();
555 TEST(CharacterStreams) {
556 v8::Isolate* isolate = CcTest::isolate();
557 v8::HandleScope handles(isolate);
558 v8::Local<v8::Context> context = v8::Context::New(isolate);
559 v8::Context::Scope context_scope(context);
561 TestCharacterStream("abc\0\n\r\x7f", 7);
562 static const unsigned kBigStringSize = 4096;
563 char buffer[kBigStringSize + 1];
564 for (unsigned i = 0; i < kBigStringSize; i++) {
565 buffer[i] = static_cast<char>(i & 0x7f);
567 TestCharacterStream(buffer, kBigStringSize);
569 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
571 TestCharacterStream("\0", 1);
572 TestCharacterStream("", 0);
576 TEST(Utf8CharacterStream) {
577 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
578 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
580 static const int kAllUtf8CharsSize =
581 (unibrow::Utf8::kMaxOneByteChar + 1) +
582 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
583 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
584 static const unsigned kAllUtf8CharsSizeU =
585 static_cast<unsigned>(kAllUtf8CharsSize);
587 char buffer[kAllUtf8CharsSizeU];
589 for (int i = 0; i <= kMaxUC16Char; i++) {
590 cursor += unibrow::Utf8::Encode(buffer + cursor,
592 unibrow::Utf16::kNoPreviousCharacter);
594 ASSERT(cursor == kAllUtf8CharsSizeU);
596 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
598 for (int i = 0; i <= kMaxUC16Char; i++) {
599 CHECK_EQU(i, stream.pos());
600 int32_t c = stream.Advance();
602 CHECK_EQU(i + 1, stream.pos());
604 for (int i = kMaxUC16Char; i >= 0; i--) {
605 CHECK_EQU(i + 1, stream.pos());
607 CHECK_EQU(i, stream.pos());
610 while (stream.pos() < kMaxUC16CharU) {
611 CHECK_EQU(i, stream.pos());
612 unsigned progress = stream.SeekForward(12);
614 int32_t c = stream.Advance();
615 if (i <= kMaxUC16Char) {
621 CHECK_EQU(i, stream.pos());
627 void TestStreamScanner(i::Utf16CharacterStream* stream,
628 i::Token::Value* expected_tokens,
629 int skip_pos = 0, // Zero means not skipping.
631 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
632 scanner.Initialize(stream);
636 i::Token::Value expected = expected_tokens[i];
637 i::Token::Value actual = scanner.Next();
638 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
639 if (scanner.location().end_pos == skip_pos) {
640 scanner.SeekForward(skip_to);
643 } while (expected_tokens[i] != i::Token::ILLEGAL);
647 TEST(StreamScanner) {
648 v8::V8::Initialize();
650 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
651 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
652 static_cast<unsigned>(strlen(str1)));
653 i::Token::Value expectations1[] = {
655 i::Token::IDENTIFIER,
656 i::Token::IDENTIFIER,
663 i::Token::IDENTIFIER,
667 TestStreamScanner(&stream1, expectations1, 0, 0);
669 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
670 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
671 static_cast<unsigned>(strlen(str2)));
672 i::Token::Value expectations2[] = {
683 ASSERT_EQ('{', str2[19]);
684 ASSERT_EQ('}', str2[37]);
685 TestStreamScanner(&stream2, expectations2, 20, 37);
687 const char* str3 = "{}}}}";
688 i::Token::Value expectations3[] = {
697 // Skip zero-four RBRACEs.
698 for (int i = 0; i <= 4; i++) {
699 expectations3[6 - i] = i::Token::ILLEGAL;
700 expectations3[5 - i] = i::Token::EOS;
701 i::Utf8ToUtf16CharacterStream stream3(
702 reinterpret_cast<const i::byte*>(str3),
703 static_cast<unsigned>(strlen(str3)));
704 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
709 void TestScanRegExp(const char* re_source, const char* expected) {
710 i::Utf8ToUtf16CharacterStream stream(
711 reinterpret_cast<const i::byte*>(re_source),
712 static_cast<unsigned>(strlen(re_source)));
713 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
714 scanner.Initialize(&stream);
716 i::Token::Value start = scanner.peek();
717 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
718 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
719 scanner.Next(); // Current token is now the regexp literal.
720 CHECK(scanner.is_literal_ascii());
721 i::Vector<const char> actual = scanner.literal_ascii_string();
722 for (int i = 0; i < actual.length(); i++) {
723 CHECK_NE('\0', expected[i]);
724 CHECK_EQ(expected[i], actual[i]);
729 TEST(RegExpScanning) {
730 v8::V8::Initialize();
732 // RegExp token with added garbage at the end. The scanner should only
733 // scan the RegExp until the terminating slash just before "flipperwald".
734 TestScanRegExp("/b/flipperwald", "b");
735 // Incomplete escape sequences doesn't hide the terminating slash.
736 TestScanRegExp("/\\x/flipperwald", "\\x");
737 TestScanRegExp("/\\u/flipperwald", "\\u");
738 TestScanRegExp("/\\u1/flipperwald", "\\u1");
739 TestScanRegExp("/\\u12/flipperwald", "\\u12");
740 TestScanRegExp("/\\u123/flipperwald", "\\u123");
741 TestScanRegExp("/\\c/flipperwald", "\\c");
742 TestScanRegExp("/\\c//flipperwald", "\\c");
743 // Slashes inside character classes are not terminating.
744 TestScanRegExp("/[/]/flipperwald", "[/]");
745 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
746 // Incomplete escape sequences inside a character class doesn't hide
747 // the end of the character class.
748 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
749 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
750 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
751 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
752 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
753 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
754 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
755 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
756 // Escaped ']'s wont end the character class.
757 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
758 // Escaped slashes are not terminating.
759 TestScanRegExp("/\\//flipperwald", "\\/");
760 // Starting with '=' works too.
761 TestScanRegExp("/=/", "=");
762 TestScanRegExp("/=?/", "=?");
766 static int Utf8LengthHelper(const char* s) {
767 int len = i::StrLength(s);
768 int character_length = len;
769 for (int i = 0; i < len; i++) {
770 unsigned char c = s[i];
771 int input_offset = 0;
772 int output_adjust = 0;
774 if (c < 0xc0) continue;
777 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
779 continue; // Handle first UTF-8 byte.
781 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
782 // This 4 byte sequence could have been coded as a 3 byte sequence.
783 // Record a single kBadChar for the first byte and continue.
787 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
788 character_length -= 2;
789 } else if (c >= 0xe0) {
790 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
791 // This 3 byte sequence could have been coded as a 2 byte sequence.
792 // Record a single kBadChar for the first byte and continue.
796 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
799 if ((c & 0x1e) == 0) {
800 // This 2 byte sequence could have been coded as a 1 byte sequence.
801 // Record a single kBadChar for the first byte and continue.
805 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
809 for (int j = 1; j <= input_offset; j++) {
810 if ((s[i + j] & 0xc0) != 0x80) {
811 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
812 // which is a single UTF-16 code unit.
819 character_length -= output_adjust;
823 return character_length;
827 TEST(ScopePositions) {
828 // Test the parser for correctly setting the start and end positions
829 // of a scope. We check the scope positions of exactly one scope
830 // nested in the global scope of a program. 'inner source' is the
831 // source code that determines the part of the source belonging
832 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
833 // parts of the source that belong to the global scope.
835 const char* outer_prefix;
836 const char* inner_source;
837 const char* outer_suffix;
838 i::ScopeType scope_type;
839 i::LanguageMode language_mode;
842 const SourceData source_data[] = {
843 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
844 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
845 { " with ({}) ", "{\n"
848 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
849 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
850 { " with ({}) ", "statement", "\n"
851 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
853 " ", "statement;", "\n"
854 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
855 { " try {} catch ", "(e) { block; }", " more;",
856 i::CATCH_SCOPE, i::CLASSIC_MODE },
857 { " try {} catch ", "(e) { block; }", "; more;",
858 i::CATCH_SCOPE, i::CLASSIC_MODE },
859 { " try {} catch ", "(e) {\n"
862 " more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
863 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
864 i::CATCH_SCOPE, i::CLASSIC_MODE },
866 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
868 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
873 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
875 " function fun", "(a,b) { infunction; }", " more;",
876 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
878 " function fun", "(a,b) {\n"
881 " more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
882 { " (function fun", "(a,b) { infunction; }", ")();",
883 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
884 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
885 i::BLOCK_SCOPE, i::EXTENDED_MODE },
886 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
887 i::BLOCK_SCOPE, i::EXTENDED_MODE },
888 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
891 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
892 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
893 i::BLOCK_SCOPE, i::EXTENDED_MODE },
894 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
895 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
896 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
898 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
899 { " for ", "(let x in {}) { block; }", " more;",
900 i::BLOCK_SCOPE, i::EXTENDED_MODE },
901 { " for ", "(let x in {}) { block; }", "; more;",
902 i::BLOCK_SCOPE, i::EXTENDED_MODE },
903 { " for ", "(let x in {}) {\n"
906 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
907 { " for ", "(let x in {}) statement;", " more;",
908 i::BLOCK_SCOPE, i::EXTENDED_MODE },
909 { " for ", "(let x in {}) statement", "\n"
910 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
911 { " for ", "(let x in {})\n"
913 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
914 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
915 // the preparser off in terms of byte offsets.
917 { " 'foo\355\240\201\355\260\211';\n"
918 " (function fun", "(a,b) { infunction; }", ")();",
919 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
921 { " 'foo\360\220\220\212';\n"
922 " (function fun", "(a,b) { infunction; }", ")();",
923 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
924 // 3 byte encoding of \u0fff.
925 { " 'foo\340\277\277';\n"
926 " (function fun", "(a,b) { infunction; }", ")();",
927 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
928 // Broken 6 byte encoding with missing last byte.
929 { " 'foo\355\240\201\355\211';\n"
930 " (function fun", "(a,b) { infunction; }", ")();",
931 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
932 // Broken 3 byte encoding of \u0fff with missing last byte.
933 { " 'foo\340\277';\n"
934 " (function fun", "(a,b) { infunction; }", ")();",
935 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
936 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
938 " (function fun", "(a,b) { infunction; }", ")();",
939 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
940 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
941 { " 'foo\340\203\277';\n"
942 " (function fun", "(a,b) { infunction; }", ")();",
943 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
944 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
945 { " 'foo\340\201\277';\n"
946 " (function fun", "(a,b) { infunction; }", ")();",
947 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
948 // Unpaired lead surrogate.
949 { " 'foo\355\240\201';\n"
950 " (function fun", "(a,b) { infunction; }", ")();",
951 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
952 // Unpaired lead surrogate where following code point is a 3 byte sequence.
953 { " 'foo\355\240\201\340\277\277';\n"
954 " (function fun", "(a,b) { infunction; }", ")();",
955 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
956 // Unpaired lead surrogate where following code point is a 4 byte encoding
957 // of a trail surrogate.
958 { " 'foo\355\240\201\360\215\260\211';\n"
959 " (function fun", "(a,b) { infunction; }", ")();",
960 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
961 // Unpaired trail surrogate.
962 { " 'foo\355\260\211';\n"
963 " (function fun", "(a,b) { infunction; }", ")();",
964 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
965 // 2 byte encoding of \u00ff.
966 { " 'foo\303\277';\n"
967 " (function fun", "(a,b) { infunction; }", ")();",
968 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
969 // Broken 2 byte encoding of \u00ff with missing last byte.
971 " (function fun", "(a,b) { infunction; }", ")();",
972 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
973 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
974 { " 'foo\301\277';\n"
975 " (function fun", "(a,b) { infunction; }", ")();",
976 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
977 // Illegal 5 byte encoding.
978 { " 'foo\370\277\277\277\277';\n"
979 " (function fun", "(a,b) { infunction; }", ")();",
980 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
981 // Illegal 6 byte encoding.
982 { " 'foo\374\277\277\277\277\277';\n"
983 " (function fun", "(a,b) { infunction; }", ")();",
984 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
986 { " 'foo\376\277\277\277\277\277\277';\n"
987 " (function fun", "(a,b) { infunction; }", ")();",
988 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
990 { " 'foo\377\277\277\277\277\277\277\277';\n"
991 " (function fun", "(a,b) { infunction; }", ")();",
992 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
994 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
995 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
997 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
998 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
999 { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
1002 i::Isolate* isolate = CcTest::i_isolate();
1003 i::Factory* factory = isolate->factory();
1005 v8::HandleScope handles(CcTest::isolate());
1006 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1007 v8::Context::Scope context_scope(context);
1010 isolate->stack_guard()->SetStackLimit(
1011 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1013 for (int i = 0; source_data[i].outer_prefix; i++) {
1014 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1015 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1016 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1017 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1018 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1019 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1020 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1021 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1022 i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
1023 i::OS::SNPrintF(program, "%s%s%s",
1024 source_data[i].outer_prefix,
1025 source_data[i].inner_source,
1026 source_data[i].outer_suffix);
1028 // Parse program source.
1029 i::Handle<i::String> source(
1030 factory->NewStringFromUtf8(i::CStrVector(program.start())));
1031 CHECK_EQ(source->length(), kProgramSize);
1032 i::Handle<i::Script> script = factory->NewScript(source);
1033 i::CompilationInfoWithZone info(script);
1034 i::Parser parser(&info);
1035 parser.set_allow_lazy(true);
1036 parser.set_allow_harmony_scoping(true);
1037 info.MarkAsGlobal();
1038 info.SetLanguageMode(source_data[i].language_mode);
1040 CHECK(info.function() != NULL);
1042 // Check scope types and positions.
1043 i::Scope* scope = info.function()->scope();
1044 CHECK(scope->is_global_scope());
1045 CHECK_EQ(scope->start_position(), 0);
1046 CHECK_EQ(scope->end_position(), kProgramSize);
1047 CHECK_EQ(scope->inner_scopes()->length(), 1);
1049 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1050 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
1051 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1052 // The end position of a token is one position after the last
1053 // character belonging to that token.
1054 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1059 i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) {
1060 i::Isolate* isolate = CcTest::i_isolate();
1061 i::Factory* factory = isolate->factory();
1062 const char* message = data->BuildMessage();
1063 i::Handle<i::String> format = v8::Utils::OpenHandle(
1064 *v8::String::NewFromUtf8(CcTest::isolate(), message));
1065 i::Vector<const char*> args = data->BuildArgs();
1066 i::Handle<i::JSArray> args_array = factory->NewJSArray(args.length());
1067 for (int i = 0; i < args.length(); i++) {
1068 i::JSArray::SetElement(
1069 args_array, i, v8::Utils::OpenHandle(*v8::String::NewFromUtf8(
1070 CcTest::isolate(), args[i])),
1071 NONE, i::kNonStrictMode);
1073 i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
1074 i::Handle<i::Object> format_fun =
1075 i::GetProperty(builtins, "FormatMessage");
1076 i::Handle<i::Object> arg_handles[] = { format, args_array };
1077 bool has_exception = false;
1078 i::Handle<i::Object> result = i::Execution::Call(
1079 isolate, format_fun, builtins, 2, arg_handles, &has_exception);
1080 CHECK(!has_exception);
1081 CHECK(result->IsString());
1082 for (int i = 0; i < args.length(); i++) {
1083 i::DeleteArray(args[i]);
1085 i::DeleteArray(args.start());
1086 i::DeleteArray(message);
1087 return i::Handle<i::String>::cast(result);
1093 kAllowNativesSyntax,
1094 kAllowHarmonyScoping,
1098 kAllowHarmonyNumericLiterals
1102 void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
1103 parser->set_allow_lazy(flags.Contains(kAllowLazy));
1104 parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
1105 parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
1106 parser->set_allow_modules(flags.Contains(kAllowModules));
1107 parser->set_allow_generators(flags.Contains(kAllowGenerators));
1108 parser->set_allow_for_of(flags.Contains(kAllowForOf));
1109 parser->set_allow_harmony_numeric_literals(
1110 flags.Contains(kAllowHarmonyNumericLiterals));
1114 void TestParserSyncWithFlags(i::Handle<i::String> source,
1115 i::EnumSet<ParserFlag> flags) {
1116 i::Isolate* isolate = CcTest::i_isolate();
1117 i::Factory* factory = isolate->factory();
1119 uintptr_t stack_limit = isolate->stack_guard()->real_climit();
1121 // Preparse the data.
1122 i::CompleteParserRecorder log;
1124 i::Scanner scanner(isolate->unicode_cache());
1125 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1126 i::PreParser preparser(&scanner, &log, stack_limit);
1127 SetParserFlags(&preparser, flags);
1128 scanner.Initialize(&stream);
1129 i::PreParser::PreParseResult result = preparser.PreParseProgram();
1130 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1132 i::ScriptDataImpl data(log.ExtractData());
1135 i::FunctionLiteral* function;
1137 i::Handle<i::Script> script = factory->NewScript(source);
1138 i::CompilationInfoWithZone info(script);
1139 i::Parser parser(&info);
1140 SetParserFlags(&parser, flags);
1141 info.MarkAsGlobal();
1143 function = info.function();
1146 // Check that preparsing fails iff parsing fails.
1147 if (function == NULL) {
1148 // Extract exception from the parser.
1149 CHECK(isolate->has_pending_exception());
1150 i::MaybeObject* maybe_object = isolate->pending_exception();
1151 i::JSObject* exception = NULL;
1152 CHECK(maybe_object->To(&exception));
1153 i::Handle<i::JSObject> exception_handle(exception);
1154 i::Handle<i::String> message_string =
1155 i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
1157 if (!data.has_error()) {
1159 "Parser failed on:\n"
1163 "However, the preparser succeeded",
1164 source->ToCString().get(), message_string->ToCString().get());
1167 // Check that preparser and parser produce the same error.
1168 i::Handle<i::String> preparser_message = FormatMessage(&data);
1169 if (!message_string->Equals(*preparser_message)) {
1171 "Expected parser and preparser to produce the same error on:\n"
1173 "However, found the following error messages\n"
1175 "\tpreparser: %s\n",
1176 source->ToCString().get(),
1177 message_string->ToCString().get(),
1178 preparser_message->ToCString().get());
1181 } else if (data.has_error()) {
1183 "Preparser failed on:\n"
1187 "However, the parser succeeded",
1188 source->ToCString().get(), FormatMessage(&data)->ToCString().get());
1194 void TestParserSync(const char* source,
1195 const ParserFlag* flag_list,
1196 size_t flag_list_length) {
1197 i::Handle<i::String> str =
1198 CcTest::i_isolate()->factory()->NewStringFromAscii(i::CStrVector(source));
1199 for (int bits = 0; bits < (1 << flag_list_length); bits++) {
1200 i::EnumSet<ParserFlag> flags;
1201 for (size_t flag_index = 0; flag_index < flag_list_length; flag_index++) {
1202 if ((bits & (1 << flag_index)) != 0) flags.Add(flag_list[flag_index]);
1204 TestParserSyncWithFlags(str, flags);
1210 const char* context_data[][2] = {
1213 { "if (true) ", " else {}" },
1214 { "if (true) {} else ", "" },
1215 { "if (true) ", "" },
1216 { "do ", " while (false)" },
1217 { "while (false) ", "" },
1218 { "for (;;) ", "" },
1219 { "with ({})", "" },
1220 { "switch (12) { case 12: ", "}" },
1221 { "switch (12) { default: ", "}" },
1222 { "switch (12) { ", "case 12: }" },
1227 const char* statement_data[] = {
1235 "if (false) {} else ;",
1236 "if (false) {} else {}",
1237 "if (false) {} else 12",
1241 "do {} while (false)",
1257 "switch ({}) { default: }"
1262 "try {} catch(e) {}",
1263 "try {} finally {}",
1264 "try {} catch(e) {} finally {}",
1269 const char* termination_data[] = {
1278 v8::HandleScope handles(CcTest::isolate());
1279 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1280 v8::Context::Scope context_scope(context);
1283 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1284 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1286 static const ParserFlag flags1[] = {
1287 kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
1290 for (int i = 0; context_data[i][0] != NULL; ++i) {
1291 for (int j = 0; statement_data[j] != NULL; ++j) {
1292 for (int k = 0; termination_data[k] != NULL; ++k) {
1293 int kPrefixLen = i::StrLength(context_data[i][0]);
1294 int kStatementLen = i::StrLength(statement_data[j]);
1295 int kTerminationLen = i::StrLength(termination_data[k]);
1296 int kSuffixLen = i::StrLength(context_data[i][1]);
1297 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1298 + kSuffixLen + i::StrLength("label: for (;;) { }");
1300 // Plug the source code pieces together.
1301 i::ScopedVector<char> program(kProgramSize + 1);
1302 int length = i::OS::SNPrintF(program,
1303 "label: for (;;) { %s%s%s%s }",
1306 termination_data[k],
1307 context_data[i][1]);
1308 CHECK(length == kProgramSize);
1309 TestParserSync(program.start(), flags1, ARRAY_SIZE(flags1));
1314 // Neither Harmony numeric literals nor our natives syntax have any
1315 // interaction with the flags above, so test these separately to reduce
1316 // the combinatorial explosion.
1317 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
1318 TestParserSync("0o1234", flags2, ARRAY_SIZE(flags2));
1319 TestParserSync("0b1011", flags2, ARRAY_SIZE(flags2));
1321 static const ParserFlag flags3[] = { kAllowNativesSyntax };
1322 TestParserSync("%DebugPrint(123)", flags3, ARRAY_SIZE(flags3));
1326 TEST(PreparserStrictOctal) {
1327 // Test that syntax error caused by octal literal is reported correctly as
1328 // such (issue 2220).
1329 v8::internal::FLAG_min_preparse_length = 1; // Force preparsing.
1330 v8::V8::Initialize();
1331 v8::HandleScope scope(CcTest::isolate());
1332 v8::Context::Scope context_scope(
1333 v8::Context::New(CcTest::isolate()));
1334 v8::TryCatch try_catch;
1335 const char* script =
1336 "\"use strict\"; \n"
1337 "a = function() { \n"
1338 " b = function() { \n"
1342 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
1343 CHECK(try_catch.HasCaught());
1344 v8::String::Utf8Value exception(try_catch.Exception());
1345 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",