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 4// met: 5// 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. 15// 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. 27 28#include <stdlib.h> 29#include <stdio.h> 30#include <string.h> 31 32#include "src/v8.h" 33 34#include "src/compiler.h" 35#include "src/execution.h" 36#include "src/isolate.h" 37#include "src/objects.h" 38#include "src/parser.h" 39#include "src/preparser.h" 40#include "src/scanner-character-streams.h" 41#include "src/token.h" 42#include "src/utils.h" 43#include "test/cctest/cctest.h" 44 45TEST(ScanKeywords) { 46 struct KeywordToken { 47 const char* keyword; 48 i::Token::Value token; 49 }; 50 51 static const KeywordToken keywords[] = { 52#define KEYWORD(t, s, d) { s, i::Token::t }, 53 TOKEN_LIST(IGNORE_TOKEN, KEYWORD) 54#undef KEYWORD 55 { NULL, i::Token::IDENTIFIER } 56 }; 57 58 KeywordToken key_token; 59 i::UnicodeCache unicode_cache; 60 i::byte buffer[32]; 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); 66 { 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()); 75 } 76 // Removing characters will make keyword matching fail. 77 { 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()); 83 } 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::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()); 94 } 95 // Replacing characters will make keyword matching fail. 96 { 97 i::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()); 104 } 105 } 106} 107 108 109TEST(ScanHTMLEndComments) { 110 v8::V8::Initialize(); 111 v8::Isolate* isolate = CcTest::isolate(); 112 v8::HandleScope handles(isolate); 113 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 120 // in the input. 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", 130 NULL 131 }; 132 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", 140 NULL 141 }; 142 143 // Parser/Scanner needs a stack limit. 144 int marker; 145 CcTest::i_isolate()->stack_guard()->SetStackLimit( 146 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 147 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 148 for (int i = 0; tests[i]; i++) { 149 const i::byte* source = 150 reinterpret_cast<const i::byte*>(tests[i]); 151 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i])); 152 i::CompleteParserRecorder log; 153 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 154 scanner.Initialize(&stream); 155 i::PreParser preparser(&scanner, &log, stack_limit); 156 preparser.set_allow_lazy(true); 157 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 158 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 159 i::ScriptData data(log.ExtractData()); 160 CHECK(!data.has_error()); 161 } 162 163 for (int i = 0; fail_tests[i]; i++) { 164 const i::byte* source = 165 reinterpret_cast<const i::byte*>(fail_tests[i]); 166 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i])); 167 i::CompleteParserRecorder log; 168 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 169 scanner.Initialize(&stream); 170 i::PreParser preparser(&scanner, &log, stack_limit); 171 preparser.set_allow_lazy(true); 172 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 173 // Even in the case of a syntax error, kPreParseSuccess is returned. 174 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 175 i::ScriptData data(log.ExtractData()); 176 CHECK(data.has_error()); 177 } 178} 179 180 181class ScriptResource : public v8::String::ExternalAsciiStringResource { 182 public: 183 ScriptResource(const char* data, size_t length) 184 : data_(data), length_(length) { } 185 186 const char* data() const { return data_; } 187 size_t length() const { return length_; } 188 189 private: 190 const char* data_; 191 size_t length_; 192}; 193 194 195TEST(UsingCachedData) { 196 v8::Isolate* isolate = CcTest::isolate(); 197 v8::HandleScope handles(isolate); 198 v8::Local<v8::Context> context = v8::Context::New(isolate); 199 v8::Context::Scope context_scope(context); 200 int marker; 201 CcTest::i_isolate()->stack_guard()->SetStackLimit( 202 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 203 204 // Source containing functions that might be lazily compiled and all types 205 // of symbols (string, propertyName, regexp). 206 const char* source = 207 "var x = 42;" 208 "function foo(a) { return function nolazy(b) { return a + b; } }" 209 "function bar(a) { if (a) return function lazy(b) { return b; } }" 210 "var z = {'string': 'string literal', bareword: 'propertyName', " 211 " 42: 'number literal', for: 'keyword as propertyName', " 212 " f\\u006fr: 'keyword propertyname with escape'};" 213 "var v = /RegExp Literal/;" 214 "var w = /RegExp Literal\\u0020With Escape/gin;" 215 "var y = { get getter() { return 42; }, " 216 " set setter(v) { this.value = v; }};"; 217 int source_length = i::StrLength(source); 218 219 // ScriptResource will be deleted when the corresponding String is GCd. 220 v8::ScriptCompiler::Source script_source(v8::String::NewExternal( 221 isolate, new ScriptResource(source, source_length))); 222 i::FLAG_min_preparse_length = 0; 223 v8::ScriptCompiler::Compile(isolate, &script_source, 224 v8::ScriptCompiler::kProduceDataToCache); 225 CHECK(script_source.GetCachedData()); 226 227 // Compile the script again, using the cached data. 228 bool lazy_flag = i::FLAG_lazy; 229 i::FLAG_lazy = true; 230 v8::ScriptCompiler::Compile(isolate, &script_source); 231 i::FLAG_lazy = false; 232 v8::ScriptCompiler::CompileUnbound(isolate, &script_source); 233 i::FLAG_lazy = lazy_flag; 234} 235 236 237TEST(PreparseFunctionDataIsUsed) { 238 // This tests that we actually do use the function data generated by the 239 // preparser. 240 241 // Make preparsing work for short scripts. 242 i::FLAG_min_preparse_length = 0; 243 244 v8::Isolate* isolate = CcTest::isolate(); 245 v8::HandleScope handles(isolate); 246 v8::Local<v8::Context> context = v8::Context::New(isolate); 247 v8::Context::Scope context_scope(context); 248 int marker; 249 CcTest::i_isolate()->stack_guard()->SetStackLimit( 250 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 251 252 const char* good_code = 253 "function this_is_lazy() { var a; } function foo() { return 25; } foo();"; 254 255 // Insert a syntax error inside the lazy function. 256 const char* bad_code = 257 "function this_is_lazy() { if ( } function foo() { return 25; } foo();"; 258 259 v8::ScriptCompiler::Source good_source(v8_str(good_code)); 260 v8::ScriptCompiler::Compile(isolate, &good_source, 261 v8::ScriptCompiler::kProduceDataToCache); 262 263 const v8::ScriptCompiler::CachedData* cached_data = 264 good_source.GetCachedData(); 265 CHECK(cached_data->data != NULL); 266 CHECK_GT(cached_data->length, 0); 267 268 // Now compile the erroneous code with the good preparse data. If the preparse 269 // data is used, the lazy function is skipped and it should compile fine. 270 v8::ScriptCompiler::Source bad_source( 271 v8_str(bad_code), new v8::ScriptCompiler::CachedData( 272 cached_data->data, cached_data->length)); 273 v8::Local<v8::Value> result = 274 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run(); 275 CHECK(result->IsInt32()); 276 CHECK_EQ(25, result->Int32Value()); 277} 278 279 280TEST(StandAlonePreParser) { 281 v8::V8::Initialize(); 282 283 int marker; 284 CcTest::i_isolate()->stack_guard()->SetStackLimit( 285 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 286 287 const char* programs[] = { 288 "{label: 42}", 289 "var x = 42;", 290 "function foo(x, y) { return x + y; }", 291 "%ArgleBargle(glop);", 292 "var x = new new Function('this.x = 42');", 293 NULL 294 }; 295 296 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 297 for (int i = 0; programs[i]; i++) { 298 const char* program = programs[i]; 299 i::Utf8ToUtf16CharacterStream stream( 300 reinterpret_cast<const i::byte*>(program), 301 static_cast<unsigned>(strlen(program))); 302 i::CompleteParserRecorder log; 303 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 304 scanner.Initialize(&stream); 305 306 i::PreParser preparser(&scanner, &log, stack_limit); 307 preparser.set_allow_lazy(true); 308 preparser.set_allow_natives_syntax(true); 309 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 310 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 311 i::ScriptData data(log.ExtractData()); 312 CHECK(!data.has_error()); 313 } 314} 315 316 317TEST(StandAlonePreParserNoNatives) { 318 v8::V8::Initialize(); 319 320 int marker; 321 CcTest::i_isolate()->stack_guard()->SetStackLimit( 322 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 323 324 const char* programs[] = { 325 "%ArgleBargle(glop);", 326 "var x = %_IsSmi(42);", 327 NULL 328 }; 329 330 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 331 for (int i = 0; programs[i]; i++) { 332 const char* program = programs[i]; 333 i::Utf8ToUtf16CharacterStream stream( 334 reinterpret_cast<const i::byte*>(program), 335 static_cast<unsigned>(strlen(program))); 336 i::CompleteParserRecorder log; 337 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 338 scanner.Initialize(&stream); 339 340 // Preparser defaults to disallowing natives syntax. 341 i::PreParser preparser(&scanner, &log, stack_limit); 342 preparser.set_allow_lazy(true); 343 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 344 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 345 i::ScriptData data(log.ExtractData()); 346 // Data contains syntax error. 347 CHECK(data.has_error()); 348 } 349} 350 351 352TEST(PreparsingObjectLiterals) { 353 // Regression test for a bug where the symbol stream produced by PreParser 354 // didn't match what Parser wanted to consume. 355 v8::Isolate* isolate = CcTest::isolate(); 356 v8::HandleScope handles(isolate); 357 v8::Local<v8::Context> context = v8::Context::New(isolate); 358 v8::Context::Scope context_scope(context); 359 int marker; 360 CcTest::i_isolate()->stack_guard()->SetStackLimit( 361 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 362 363 { 364 const char* source = "var myo = {if: \"foo\"}; myo.if;"; 365 v8::Local<v8::Value> result = PreCompileCompileRun(source); 366 CHECK(result->IsString()); 367 v8::String::Utf8Value utf8(result); 368 CHECK_EQ("foo", *utf8); 369 } 370 371 { 372 const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];"; 373 v8::Local<v8::Value> result = PreCompileCompileRun(source); 374 CHECK(result->IsString()); 375 v8::String::Utf8Value utf8(result); 376 CHECK_EQ("foo", *utf8); 377 } 378 379 { 380 const char* source = "var myo = {1: \"foo\"}; myo[1];"; 381 v8::Local<v8::Value> result = PreCompileCompileRun(source); 382 CHECK(result->IsString()); 383 v8::String::Utf8Value utf8(result); 384 CHECK_EQ("foo", *utf8); 385 } 386} 387 388 389TEST(RegressChromium62639) { 390 v8::V8::Initialize(); 391 i::Isolate* isolate = CcTest::i_isolate(); 392 393 int marker; 394 isolate->stack_guard()->SetStackLimit( 395 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 396 397 const char* program = "var x = 'something';\n" 398 "escape: function() {}"; 399 // Fails parsing expecting an identifier after "function". 400 // Before fix, didn't check *ok after Expect(Token::Identifier, ok), 401 // and then used the invalid currently scanned literal. This always 402 // failed in debug mode, and sometimes crashed in release mode. 403 404 i::Utf8ToUtf16CharacterStream stream( 405 reinterpret_cast<const i::byte*>(program), 406 static_cast<unsigned>(strlen(program))); 407 i::CompleteParserRecorder log; 408 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 409 scanner.Initialize(&stream); 410 i::PreParser preparser(&scanner, &log, 411 CcTest::i_isolate()->stack_guard()->real_climit()); 412 preparser.set_allow_lazy(true); 413 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 414 // Even in the case of a syntax error, kPreParseSuccess is returned. 415 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 416 i::ScriptData data(log.ExtractData()); 417 CHECK(data.has_error()); 418} 419 420 421TEST(Regress928) { 422 v8::V8::Initialize(); 423 i::Isolate* isolate = CcTest::i_isolate(); 424 i::Factory* factory = isolate->factory(); 425 426 // Preparsing didn't consider the catch clause of a try statement 427 // as with-content, which made it assume that a function inside 428 // the block could be lazily compiled, and an extra, unexpected, 429 // entry was added to the data. 430 int marker; 431 isolate->stack_guard()->SetStackLimit( 432 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 433 434 const char* program = 435 "try { } catch (e) { var foo = function () { /* first */ } }" 436 "var bar = function () { /* second */ }"; 437 438 v8::HandleScope handles(CcTest::isolate()); 439 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program); 440 i::GenericStringUtf16CharacterStream stream(source, 0, source->length()); 441 i::CompleteParserRecorder log; 442 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 443 scanner.Initialize(&stream); 444 i::PreParser preparser(&scanner, &log, 445 CcTest::i_isolate()->stack_guard()->real_climit()); 446 preparser.set_allow_lazy(true); 447 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 448 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 449 i::ScriptData data(log.ExtractData()); 450 CHECK(!data.has_error()); 451 data.Initialize(); 452 453 int first_function = 454 static_cast<int>(strstr(program, "function") - program); 455 int first_lbrace = first_function + i::StrLength("function () "); 456 CHECK_EQ('{', program[first_lbrace]); 457 i::FunctionEntry entry1 = data.GetFunctionEntry(first_lbrace); 458 CHECK(!entry1.is_valid()); 459 460 int second_function = 461 static_cast<int>(strstr(program + first_lbrace, "function") - program); 462 int second_lbrace = 463 second_function + i::StrLength("function () "); 464 CHECK_EQ('{', program[second_lbrace]); 465 i::FunctionEntry entry2 = data.GetFunctionEntry(second_lbrace); 466 CHECK(entry2.is_valid()); 467 CHECK_EQ('}', program[entry2.end_pos() - 1]); 468} 469 470 471TEST(PreParseOverflow) { 472 v8::V8::Initialize(); 473 474 int marker; 475 CcTest::i_isolate()->stack_guard()->SetStackLimit( 476 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 477 478 size_t kProgramSize = 1024 * 1024; 479 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1)); 480 memset(program.get(), '(', kProgramSize); 481 program[kProgramSize] = '\0'; 482 483 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 484 485 i::Utf8ToUtf16CharacterStream stream( 486 reinterpret_cast<const i::byte*>(program.get()), 487 static_cast<unsigned>(kProgramSize)); 488 i::CompleteParserRecorder log; 489 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 490 scanner.Initialize(&stream); 491 492 i::PreParser preparser(&scanner, &log, stack_limit); 493 preparser.set_allow_lazy(true); 494 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 495 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result); 496} 497 498 499class TestExternalResource: public v8::String::ExternalStringResource { 500 public: 501 explicit TestExternalResource(uint16_t* data, int length) 502 : data_(data), length_(static_cast<size_t>(length)) { } 503 504 ~TestExternalResource() { } 505 506 const uint16_t* data() const { 507 return data_; 508 } 509 510 size_t length() const { 511 return length_; 512 } 513 private: 514 uint16_t* data_; 515 size_t length_; 516}; 517 518 519#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2)) 520 521void TestCharacterStream(const char* ascii_source, 522 unsigned length, 523 unsigned start = 0, 524 unsigned end = 0) { 525 if (end == 0) end = length; 526 unsigned sub_length = end - start; 527 i::Isolate* isolate = CcTest::i_isolate(); 528 i::Factory* factory = isolate->factory(); 529 i::HandleScope test_scope(isolate); 530 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]); 531 for (unsigned i = 0; i < length; i++) { 532 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]); 533 } 534 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length)); 535 i::Handle<i::String> ascii_string = 536 factory->NewStringFromAscii(ascii_vector).ToHandleChecked(); 537 TestExternalResource resource(uc16_buffer.get(), length); 538 i::Handle<i::String> uc16_string( 539 factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked()); 540 541 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream( 542 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end); 543 i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end); 544 i::Utf8ToUtf16CharacterStream utf8_stream( 545 reinterpret_cast<const i::byte*>(ascii_source), end); 546 utf8_stream.SeekForward(start); 547 548 unsigned i = start; 549 while (i < end) { 550 // Read streams one char at a time 551 CHECK_EQU(i, uc16_stream.pos()); 552 CHECK_EQU(i, string_stream.pos()); 553 CHECK_EQU(i, utf8_stream.pos()); 554 int32_t c0 = ascii_source[i]; 555 int32_t c1 = uc16_stream.Advance(); 556 int32_t c2 = string_stream.Advance(); 557 int32_t c3 = utf8_stream.Advance(); 558 i++; 559 CHECK_EQ(c0, c1); 560 CHECK_EQ(c0, c2); 561 CHECK_EQ(c0, c3); 562 CHECK_EQU(i, uc16_stream.pos()); 563 CHECK_EQU(i, string_stream.pos()); 564 CHECK_EQU(i, utf8_stream.pos()); 565 } 566 while (i > start + sub_length / 4) { 567 // Pushback, re-read, pushback again. 568 int32_t c0 = ascii_source[i - 1]; 569 CHECK_EQU(i, uc16_stream.pos()); 570 CHECK_EQU(i, string_stream.pos()); 571 CHECK_EQU(i, utf8_stream.pos()); 572 uc16_stream.PushBack(c0); 573 string_stream.PushBack(c0); 574 utf8_stream.PushBack(c0); 575 i--; 576 CHECK_EQU(i, uc16_stream.pos()); 577 CHECK_EQU(i, string_stream.pos()); 578 CHECK_EQU(i, utf8_stream.pos()); 579 int32_t c1 = uc16_stream.Advance(); 580 int32_t c2 = string_stream.Advance(); 581 int32_t c3 = utf8_stream.Advance(); 582 i++; 583 CHECK_EQU(i, uc16_stream.pos()); 584 CHECK_EQU(i, string_stream.pos()); 585 CHECK_EQU(i, utf8_stream.pos()); 586 CHECK_EQ(c0, c1); 587 CHECK_EQ(c0, c2); 588 CHECK_EQ(c0, c3); 589 uc16_stream.PushBack(c0); 590 string_stream.PushBack(c0); 591 utf8_stream.PushBack(c0); 592 i--; 593 CHECK_EQU(i, uc16_stream.pos()); 594 CHECK_EQU(i, string_stream.pos()); 595 CHECK_EQU(i, utf8_stream.pos()); 596 } 597 unsigned halfway = start + sub_length / 2; 598 uc16_stream.SeekForward(halfway - i); 599 string_stream.SeekForward(halfway - i); 600 utf8_stream.SeekForward(halfway - i); 601 i = halfway; 602 CHECK_EQU(i, uc16_stream.pos()); 603 CHECK_EQU(i, string_stream.pos()); 604 CHECK_EQU(i, utf8_stream.pos()); 605 606 while (i < end) { 607 // Read streams one char at a time 608 CHECK_EQU(i, uc16_stream.pos()); 609 CHECK_EQU(i, string_stream.pos()); 610 CHECK_EQU(i, utf8_stream.pos()); 611 int32_t c0 = ascii_source[i]; 612 int32_t c1 = uc16_stream.Advance(); 613 int32_t c2 = string_stream.Advance(); 614 int32_t c3 = utf8_stream.Advance(); 615 i++; 616 CHECK_EQ(c0, c1); 617 CHECK_EQ(c0, c2); 618 CHECK_EQ(c0, c3); 619 CHECK_EQU(i, uc16_stream.pos()); 620 CHECK_EQU(i, string_stream.pos()); 621 CHECK_EQU(i, utf8_stream.pos()); 622 } 623 624 int32_t c1 = uc16_stream.Advance(); 625 int32_t c2 = string_stream.Advance(); 626 int32_t c3 = utf8_stream.Advance(); 627 CHECK_LT(c1, 0); 628 CHECK_LT(c2, 0); 629 CHECK_LT(c3, 0); 630} 631 632 633TEST(CharacterStreams) { 634 v8::Isolate* isolate = CcTest::isolate(); 635 v8::HandleScope handles(isolate); 636 v8::Local<v8::Context> context = v8::Context::New(isolate); 637 v8::Context::Scope context_scope(context); 638 639 TestCharacterStream("abc\0\n\r\x7f", 7); 640 static const unsigned kBigStringSize = 4096; 641 char buffer[kBigStringSize + 1]; 642 for (unsigned i = 0; i < kBigStringSize; i++) { 643 buffer[i] = static_cast<char>(i & 0x7f); 644 } 645 TestCharacterStream(buffer, kBigStringSize); 646 647 TestCharacterStream(buffer, kBigStringSize, 576, 3298); 648 649 TestCharacterStream("\0", 1); 650 TestCharacterStream("", 0); 651} 652 653 654TEST(Utf8CharacterStream) { 655 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar; 656 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU); 657 658 static const int kAllUtf8CharsSize = 659 (unibrow::Utf8::kMaxOneByteChar + 1) + 660 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 + 661 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3; 662 static const unsigned kAllUtf8CharsSizeU = 663 static_cast<unsigned>(kAllUtf8CharsSize); 664 665 char buffer[kAllUtf8CharsSizeU]; 666 unsigned cursor = 0; 667 for (int i = 0; i <= kMaxUC16Char; i++) { 668 cursor += unibrow::Utf8::Encode(buffer + cursor, 669 i, 670 unibrow::Utf16::kNoPreviousCharacter); 671 } 672 ASSERT(cursor == kAllUtf8CharsSizeU); 673 674 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer), 675 kAllUtf8CharsSizeU); 676 for (int i = 0; i <= kMaxUC16Char; i++) { 677 CHECK_EQU(i, stream.pos()); 678 int32_t c = stream.Advance(); 679 CHECK_EQ(i, c); 680 CHECK_EQU(i + 1, stream.pos()); 681 } 682 for (int i = kMaxUC16Char; i >= 0; i--) { 683 CHECK_EQU(i + 1, stream.pos()); 684 stream.PushBack(i); 685 CHECK_EQU(i, stream.pos()); 686 } 687 int i = 0; 688 while (stream.pos() < kMaxUC16CharU) { 689 CHECK_EQU(i, stream.pos()); 690 unsigned progress = stream.SeekForward(12); 691 i += progress; 692 int32_t c = stream.Advance(); 693 if (i <= kMaxUC16Char) { 694 CHECK_EQ(i, c); 695 } else { 696 CHECK_EQ(-1, c); 697 } 698 i += 1; 699 CHECK_EQU(i, stream.pos()); 700 } 701} 702 703#undef CHECK_EQU 704 705void TestStreamScanner(i::Utf16CharacterStream* stream, 706 i::Token::Value* expected_tokens, 707 int skip_pos = 0, // Zero means not skipping. 708 int skip_to = 0) { 709 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 710 scanner.Initialize(stream); 711 712 int i = 0; 713 do { 714 i::Token::Value expected = expected_tokens[i]; 715 i::Token::Value actual = scanner.Next(); 716 CHECK_EQ(i::Token::String(expected), i::Token::String(actual)); 717 if (scanner.location().end_pos == skip_pos) { 718 scanner.SeekForward(skip_to); 719 } 720 i++; 721 } while (expected_tokens[i] != i::Token::ILLEGAL); 722} 723 724 725TEST(StreamScanner) { 726 v8::V8::Initialize(); 727 728 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib"; 729 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1), 730 static_cast<unsigned>(strlen(str1))); 731 i::Token::Value expectations1[] = { 732 i::Token::LBRACE, 733 i::Token::IDENTIFIER, 734 i::Token::IDENTIFIER, 735 i::Token::FOR, 736 i::Token::COLON, 737 i::Token::MUL, 738 i::Token::DIV, 739 i::Token::LT, 740 i::Token::SUB, 741 i::Token::IDENTIFIER, 742 i::Token::EOS, 743 i::Token::ILLEGAL 744 }; 745 TestStreamScanner(&stream1, expectations1, 0, 0); 746 747 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do"; 748 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2), 749 static_cast<unsigned>(strlen(str2))); 750 i::Token::Value expectations2[] = { 751 i::Token::CASE, 752 i::Token::DEFAULT, 753 i::Token::CONST, 754 i::Token::LBRACE, 755 // Skipped part here 756 i::Token::RBRACE, 757 i::Token::DO, 758 i::Token::EOS, 759 i::Token::ILLEGAL 760 }; 761 ASSERT_EQ('{', str2[19]); 762 ASSERT_EQ('}', str2[37]); 763 TestStreamScanner(&stream2, expectations2, 20, 37); 764 765 const char* str3 = "{}}}}"; 766 i::Token::Value expectations3[] = { 767 i::Token::LBRACE, 768 i::Token::RBRACE, 769 i::Token::RBRACE, 770 i::Token::RBRACE, 771 i::Token::RBRACE, 772 i::Token::EOS, 773 i::Token::ILLEGAL 774 }; 775 // Skip zero-four RBRACEs. 776 for (int i = 0; i <= 4; i++) { 777 expectations3[6 - i] = i::Token::ILLEGAL; 778 expectations3[5 - i] = i::Token::EOS; 779 i::Utf8ToUtf16CharacterStream stream3( 780 reinterpret_cast<const i::byte*>(str3), 781 static_cast<unsigned>(strlen(str3))); 782 TestStreamScanner(&stream3, expectations3, 1, 1 + i); 783 } 784} 785 786 787void TestScanRegExp(const char* re_source, const char* expected) { 788 i::Utf8ToUtf16CharacterStream stream( 789 reinterpret_cast<const i::byte*>(re_source), 790 static_cast<unsigned>(strlen(re_source))); 791 i::HandleScope scope(CcTest::i_isolate()); 792 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 793 scanner.Initialize(&stream); 794 795 i::Token::Value start = scanner.peek(); 796 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV); 797 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV)); 798 scanner.Next(); // Current token is now the regexp literal. 799 i::Handle<i::String> val = 800 scanner.AllocateInternalizedString(CcTest::i_isolate()); 801 i::DisallowHeapAllocation no_alloc; 802 i::String::FlatContent content = val->GetFlatContent(); 803 CHECK(content.IsAscii()); 804 i::Vector<const uint8_t> actual = content.ToOneByteVector(); 805 for (int i = 0; i < actual.length(); i++) { 806 CHECK_NE('\0', expected[i]); 807 CHECK_EQ(expected[i], actual[i]); 808 } 809} 810 811 812TEST(RegExpScanning) { 813 v8::V8::Initialize(); 814 815 // RegExp token with added garbage at the end. The scanner should only 816 // scan the RegExp until the terminating slash just before "flipperwald". 817 TestScanRegExp("/b/flipperwald", "b"); 818 // Incomplete escape sequences doesn't hide the terminating slash. 819 TestScanRegExp("/\\x/flipperwald", "\\x"); 820 TestScanRegExp("/\\u/flipperwald", "\\u"); 821 TestScanRegExp("/\\u1/flipperwald", "\\u1"); 822 TestScanRegExp("/\\u12/flipperwald", "\\u12"); 823 TestScanRegExp("/\\u123/flipperwald", "\\u123"); 824 TestScanRegExp("/\\c/flipperwald", "\\c"); 825 TestScanRegExp("/\\c//flipperwald", "\\c"); 826 // Slashes inside character classes are not terminating. 827 TestScanRegExp("/[/]/flipperwald", "[/]"); 828 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]"); 829 // Incomplete escape sequences inside a character class doesn't hide 830 // the end of the character class. 831 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]"); 832 TestScanRegExp("/[\\c]/flipperwald", "[\\c]"); 833 TestScanRegExp("/[\\x]/flipperwald", "[\\x]"); 834 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]"); 835 TestScanRegExp("/[\\u]/flipperwald", "[\\u]"); 836 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]"); 837 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]"); 838 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]"); 839 // Escaped ']'s wont end the character class. 840 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]"); 841 // Escaped slashes are not terminating. 842 TestScanRegExp("/\\//flipperwald", "\\/"); 843 // Starting with '=' works too. 844 TestScanRegExp("/=/", "="); 845 TestScanRegExp("/=?/", "=?"); 846} 847 848 849static int Utf8LengthHelper(const char* s) { 850 int len = i::StrLength(s); 851 int character_length = len; 852 for (int i = 0; i < len; i++) { 853 unsigned char c = s[i]; 854 int input_offset = 0; 855 int output_adjust = 0; 856 if (c > 0x7f) { 857 if (c < 0xc0) continue; 858 if (c >= 0xf0) { 859 if (c >= 0xf8) { 860 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8 861 // byte. 862 continue; // Handle first UTF-8 byte. 863 } 864 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) { 865 // This 4 byte sequence could have been coded as a 3 byte sequence. 866 // Record a single kBadChar for the first byte and continue. 867 continue; 868 } 869 input_offset = 3; 870 // 4 bytes of UTF-8 turn into 2 UTF-16 code units. 871 character_length -= 2; 872 } else if (c >= 0xe0) { 873 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) { 874 // This 3 byte sequence could have been coded as a 2 byte sequence. 875 // Record a single kBadChar for the first byte and continue. 876 continue; 877 } 878 input_offset = 2; 879 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit. 880 output_adjust = 2; 881 } else { 882 if ((c & 0x1e) == 0) { 883 // This 2 byte sequence could have been coded as a 1 byte sequence. 884 // Record a single kBadChar for the first byte and continue. 885 continue; 886 } 887 input_offset = 1; 888 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit. 889 output_adjust = 1; 890 } 891 bool bad = false; 892 for (int j = 1; j <= input_offset; j++) { 893 if ((s[i + j] & 0xc0) != 0x80) { 894 // Bad UTF-8 sequence turns the first in the sequence into kBadChar, 895 // which is a single UTF-16 code unit. 896 bad = true; 897 break; 898 } 899 } 900 if (!bad) { 901 i += input_offset; 902 character_length -= output_adjust; 903 } 904 } 905 } 906 return character_length; 907} 908 909 910TEST(ScopePositions) { 911 v8::internal::FLAG_harmony_scoping = true; 912 913 // Test the parser for correctly setting the start and end positions 914 // of a scope. We check the scope positions of exactly one scope 915 // nested in the global scope of a program. 'inner source' is the 916 // source code that determines the part of the source belonging 917 // to the nested scope. 'outer_prefix' and 'outer_suffix' are 918 // parts of the source that belong to the global scope. 919 struct SourceData { 920 const char* outer_prefix; 921 const char* inner_source; 922 const char* outer_suffix; 923 i::ScopeType scope_type; 924 i::StrictMode strict_mode; 925 }; 926 927 const SourceData source_data[] = { 928 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY }, 929 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY }, 930 { " with ({}) ", "{\n" 931 " block;\n" 932 " }", "\n" 933 " more;", i::WITH_SCOPE, i::SLOPPY }, 934 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY }, 935 { " with ({}) ", "statement", "\n" 936 " more;", i::WITH_SCOPE, i::SLOPPY }, 937 { " with ({})\n" 938 " ", "statement;", "\n" 939 " more;", i::WITH_SCOPE, i::SLOPPY }, 940 { " try {} catch ", "(e) { block; }", " more;", 941 i::CATCH_SCOPE, i::SLOPPY }, 942 { " try {} catch ", "(e) { block; }", "; more;", 943 i::CATCH_SCOPE, i::SLOPPY }, 944 { " try {} catch ", "(e) {\n" 945 " block;\n" 946 " }", "\n" 947 " more;", i::CATCH_SCOPE, i::SLOPPY }, 948 { " try {} catch ", "(e) { block; }", " finally { block; } more;", 949 i::CATCH_SCOPE, i::SLOPPY }, 950 { " start;\n" 951 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT }, 952 { " start;\n" 953 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT }, 954 { " start;\n" 955 " ", "{\n" 956 " let block;\n" 957 " }", "\n" 958 " more;", i::BLOCK_SCOPE, i::STRICT }, 959 { " start;\n" 960 " function fun", "(a,b) { infunction; }", " more;", 961 i::FUNCTION_SCOPE, i::SLOPPY }, 962 { " start;\n" 963 " function fun", "(a,b) {\n" 964 " infunction;\n" 965 " }", "\n" 966 " more;", i::FUNCTION_SCOPE, i::SLOPPY }, 967 { " (function fun", "(a,b) { infunction; }", ")();", 968 i::FUNCTION_SCOPE, i::SLOPPY }, 969 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;", 970 i::BLOCK_SCOPE, i::STRICT }, 971 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;", 972 i::BLOCK_SCOPE, i::STRICT }, 973 { " for ", "(let x = 1 ; x < 10; ++ x) {\n" 974 " block;\n" 975 " }", "\n" 976 " more;", i::BLOCK_SCOPE, i::STRICT }, 977 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;", 978 i::BLOCK_SCOPE, i::STRICT }, 979 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n" 980 " more;", i::BLOCK_SCOPE, i::STRICT }, 981 { " for ", "(let x = 1 ; x < 10; ++ x)\n" 982 " statement;", "\n" 983 " more;", i::BLOCK_SCOPE, i::STRICT }, 984 { " for ", "(let x in {}) { block; }", " more;", 985 i::BLOCK_SCOPE, i::STRICT }, 986 { " for ", "(let x in {}) { block; }", "; more;", 987 i::BLOCK_SCOPE, i::STRICT }, 988 { " for ", "(let x in {}) {\n" 989 " block;\n" 990 " }", "\n" 991 " more;", i::BLOCK_SCOPE, i::STRICT }, 992 { " for ", "(let x in {}) statement;", " more;", 993 i::BLOCK_SCOPE, i::STRICT }, 994 { " for ", "(let x in {}) statement", "\n" 995 " more;", i::BLOCK_SCOPE, i::STRICT }, 996 { " for ", "(let x in {})\n" 997 " statement;", "\n" 998 " more;", i::BLOCK_SCOPE, i::STRICT }, 999 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw 1000 // the preparser off in terms of byte offsets. 1001 // 6 byte encoding. 1002 { " 'foo\355\240\201\355\260\211';\n" 1003 " (function fun", "(a,b) { infunction; }", ")();", 1004 i::FUNCTION_SCOPE, i::SLOPPY }, 1005 // 4 byte encoding. 1006 { " 'foo\360\220\220\212';\n" 1007 " (function fun", "(a,b) { infunction; }", ")();", 1008 i::FUNCTION_SCOPE, i::SLOPPY }, 1009 // 3 byte encoding of \u0fff. 1010 { " 'foo\340\277\277';\n" 1011 " (function fun", "(a,b) { infunction; }", ")();", 1012 i::FUNCTION_SCOPE, i::SLOPPY }, 1013 // Broken 6 byte encoding with missing last byte. 1014 { " 'foo\355\240\201\355\211';\n" 1015 " (function fun", "(a,b) { infunction; }", ")();", 1016 i::FUNCTION_SCOPE, i::SLOPPY }, 1017 // Broken 3 byte encoding of \u0fff with missing last byte. 1018 { " 'foo\340\277';\n" 1019 " (function fun", "(a,b) { infunction; }", ")();", 1020 i::FUNCTION_SCOPE, i::SLOPPY }, 1021 // Broken 3 byte encoding of \u0fff with missing 2 last bytes. 1022 { " 'foo\340';\n" 1023 " (function fun", "(a,b) { infunction; }", ")();", 1024 i::FUNCTION_SCOPE, i::SLOPPY }, 1025 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding. 1026 { " 'foo\340\203\277';\n" 1027 " (function fun", "(a,b) { infunction; }", ")();", 1028 i::FUNCTION_SCOPE, i::SLOPPY }, 1029 // Broken 3 byte encoding of \u007f should be a 2 byte encoding. 1030 { " 'foo\340\201\277';\n" 1031 " (function fun", "(a,b) { infunction; }", ")();", 1032 i::FUNCTION_SCOPE, i::SLOPPY }, 1033 // Unpaired lead surrogate. 1034 { " 'foo\355\240\201';\n" 1035 " (function fun", "(a,b) { infunction; }", ")();", 1036 i::FUNCTION_SCOPE, i::SLOPPY }, 1037 // Unpaired lead surrogate where following code point is a 3 byte sequence. 1038 { " 'foo\355\240\201\340\277\277';\n" 1039 " (function fun", "(a,b) { infunction; }", ")();", 1040 i::FUNCTION_SCOPE, i::SLOPPY }, 1041 // Unpaired lead surrogate where following code point is a 4 byte encoding 1042 // of a trail surrogate. 1043 { " 'foo\355\240\201\360\215\260\211';\n" 1044 " (function fun", "(a,b) { infunction; }", ")();", 1045 i::FUNCTION_SCOPE, i::SLOPPY }, 1046 // Unpaired trail surrogate. 1047 { " 'foo\355\260\211';\n" 1048 " (function fun", "(a,b) { infunction; }", ")();", 1049 i::FUNCTION_SCOPE, i::SLOPPY }, 1050 // 2 byte encoding of \u00ff. 1051 { " 'foo\303\277';\n" 1052 " (function fun", "(a,b) { infunction; }", ")();", 1053 i::FUNCTION_SCOPE, i::SLOPPY }, 1054 // Broken 2 byte encoding of \u00ff with missing last byte. 1055 { " 'foo\303';\n" 1056 " (function fun", "(a,b) { infunction; }", ")();", 1057 i::FUNCTION_SCOPE, i::SLOPPY }, 1058 // Broken 2 byte encoding of \u007f should be a 1 byte encoding. 1059 { " 'foo\301\277';\n" 1060 " (function fun", "(a,b) { infunction; }", ")();", 1061 i::FUNCTION_SCOPE, i::SLOPPY }, 1062 // Illegal 5 byte encoding. 1063 { " 'foo\370\277\277\277\277';\n" 1064 " (function fun", "(a,b) { infunction; }", ")();", 1065 i::FUNCTION_SCOPE, i::SLOPPY }, 1066 // Illegal 6 byte encoding. 1067 { " 'foo\374\277\277\277\277\277';\n" 1068 " (function fun", "(a,b) { infunction; }", ")();", 1069 i::FUNCTION_SCOPE, i::SLOPPY }, 1070 // Illegal 0xfe byte 1071 { " 'foo\376\277\277\277\277\277\277';\n" 1072 " (function fun", "(a,b) { infunction; }", ")();", 1073 i::FUNCTION_SCOPE, i::SLOPPY }, 1074 // Illegal 0xff byte 1075 { " 'foo\377\277\277\277\277\277\277\277';\n" 1076 " (function fun", "(a,b) { infunction; }", ")();", 1077 i::FUNCTION_SCOPE, i::SLOPPY }, 1078 { " 'foo';\n" 1079 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();", 1080 i::FUNCTION_SCOPE, i::SLOPPY }, 1081 { " 'foo';\n" 1082 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();", 1083 i::FUNCTION_SCOPE, i::SLOPPY }, 1084 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY } 1085 }; 1086 1087 i::Isolate* isolate = CcTest::i_isolate(); 1088 i::Factory* factory = isolate->factory(); 1089 1090 v8::HandleScope handles(CcTest::isolate()); 1091 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); 1092 v8::Context::Scope context_scope(context); 1093 1094 int marker; 1095 isolate->stack_guard()->SetStackLimit( 1096 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 1097 1098 for (int i = 0; source_data[i].outer_prefix; i++) { 1099 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix); 1100 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source); 1101 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix); 1102 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix); 1103 int kInnerByteLen = i::StrLength(source_data[i].inner_source); 1104 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix); 1105 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen; 1106 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen; 1107 i::ScopedVector<char> program(kProgramByteSize + 1); 1108 i::SNPrintF(program, "%s%s%s", 1109 source_data[i].outer_prefix, 1110 source_data[i].inner_source, 1111 source_data[i].outer_suffix); 1112 1113 // Parse program source. 1114 i::Handle<i::String> source = factory->NewStringFromUtf8( 1115 i::CStrVector(program.start())).ToHandleChecked(); 1116 CHECK_EQ(source->length(), kProgramSize); 1117 i::Handle<i::Script> script = factory->NewScript(source); 1118 i::CompilationInfoWithZone info(script); 1119 i::Parser parser(&info); 1120 parser.set_allow_lazy(true); 1121 parser.set_allow_harmony_scoping(true); 1122 info.MarkAsGlobal(); 1123 info.SetStrictMode(source_data[i].strict_mode); 1124 parser.Parse(); 1125 CHECK(info.function() != NULL); 1126 1127 // Check scope types and positions. 1128 i::Scope* scope = info.function()->scope(); 1129 CHECK(scope->is_global_scope()); 1130 CHECK_EQ(scope->start_position(), 0); 1131 CHECK_EQ(scope->end_position(), kProgramSize); 1132 CHECK_EQ(scope->inner_scopes()->length(), 1); 1133 1134 i::Scope* inner_scope = scope->inner_scopes()->at(0); 1135 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type); 1136 CHECK_EQ(inner_scope->start_position(), kPrefixLen); 1137 // The end position of a token is one position after the last 1138 // character belonging to that token. 1139 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen); 1140 } 1141} 1142 1143 1144i::Handle<i::String> FormatMessage(i::ScriptData* data) { 1145 i::Isolate* isolate = CcTest::i_isolate(); 1146 i::Factory* factory = isolate->factory(); 1147 const char* message = data->BuildMessage(); 1148 i::Handle<i::String> format = v8::Utils::OpenHandle( 1149 *v8::String::NewFromUtf8(CcTest::isolate(), message)); 1150 const char* arg = data->BuildArg(); 1151 i::Handle<i::JSArray> args_array = factory->NewJSArray(arg == NULL ? 0 : 1); 1152 if (arg != NULL) { 1153 i::JSArray::SetElement( 1154 args_array, 0, v8::Utils::OpenHandle(*v8::String::NewFromUtf8( 1155 CcTest::isolate(), arg)), 1156 NONE, i::SLOPPY).Check(); 1157 } 1158 i::Handle<i::JSObject> builtins(isolate->js_builtins_object()); 1159 i::Handle<i::Object> format_fun = i::Object::GetProperty( 1160 isolate, builtins, "FormatMessage").ToHandleChecked(); 1161 i::Handle<i::Object> arg_handles[] = { format, args_array }; 1162 i::Handle<i::Object> result = i::Execution::Call( 1163 isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked(); 1164 CHECK(result->IsString()); 1165 i::DeleteArray(message); 1166 i::DeleteArray(arg); 1167 return i::Handle<i::String>::cast(result); 1168} 1169 1170 1171enum ParserFlag { 1172 kAllowLazy, 1173 kAllowNativesSyntax, 1174 kAllowHarmonyScoping, 1175 kAllowModules, 1176 kAllowGenerators, 1177 kAllowForOf, 1178 kAllowHarmonyNumericLiterals 1179}; 1180 1181 1182enum ParserSyncTestResult { 1183 kSuccessOrError, 1184 kSuccess, 1185 kError 1186}; 1187 1188template <typename Traits> 1189void SetParserFlags(i::ParserBase<Traits>* parser, 1190 i::EnumSet<ParserFlag> flags) { 1191 parser->set_allow_lazy(flags.Contains(kAllowLazy)); 1192 parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax)); 1193 parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping)); 1194 parser->set_allow_modules(flags.Contains(kAllowModules)); 1195 parser->set_allow_generators(flags.Contains(kAllowGenerators)); 1196 parser->set_allow_for_of(flags.Contains(kAllowForOf)); 1197 parser->set_allow_harmony_numeric_literals( 1198 flags.Contains(kAllowHarmonyNumericLiterals)); 1199} 1200 1201 1202void TestParserSyncWithFlags(i::Handle<i::String> source, 1203 i::EnumSet<ParserFlag> flags, 1204 ParserSyncTestResult result) { 1205 i::Isolate* isolate = CcTest::i_isolate(); 1206 i::Factory* factory = isolate->factory(); 1207 1208 uintptr_t stack_limit = isolate->stack_guard()->real_climit(); 1209 1210 // Preparse the data. 1211 i::CompleteParserRecorder log; 1212 { 1213 i::Scanner scanner(isolate->unicode_cache()); 1214 i::GenericStringUtf16CharacterStream stream(source, 0, source->length()); 1215 i::PreParser preparser(&scanner, &log, stack_limit); 1216 SetParserFlags(&preparser, flags); 1217 scanner.Initialize(&stream); 1218 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 1219 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 1220 } 1221 i::ScriptData data(log.ExtractData()); 1222 1223 // Parse the data 1224 i::FunctionLiteral* function; 1225 { 1226 i::Handle<i::Script> script = factory->NewScript(source); 1227 i::CompilationInfoWithZone info(script); 1228 i::Parser parser(&info); 1229 SetParserFlags(&parser, flags); 1230 info.MarkAsGlobal(); 1231 parser.Parse(); 1232 function = info.function(); 1233 } 1234 1235 // Check that preparsing fails iff parsing fails. 1236 if (function == NULL) { 1237 // Extract exception from the parser. 1238 CHECK(isolate->has_pending_exception()); 1239 i::Handle<i::JSObject> exception_handle( 1240 i::JSObject::cast(isolate->pending_exception())); 1241 i::Handle<i::String> message_string = 1242 i::Handle<i::String>::cast(i::Object::GetProperty( 1243 isolate, exception_handle, "message").ToHandleChecked()); 1244 1245 if (result == kSuccess) { 1246 i::OS::Print( 1247 "Parser failed on:\n" 1248 "\t%s\n" 1249 "with error:\n" 1250 "\t%s\n" 1251 "However, we expected no error.", 1252 source->ToCString().get(), message_string->ToCString().get()); 1253 CHECK(false); 1254 } 1255 1256 if (!data.has_error()) { 1257 i::OS::Print( 1258 "Parser failed on:\n" 1259 "\t%s\n" 1260 "with error:\n" 1261 "\t%s\n" 1262 "However, the preparser succeeded", 1263 source->ToCString().get(), message_string->ToCString().get()); 1264 CHECK(false); 1265 } 1266 // Check that preparser and parser produce the same error. 1267 i::Handle<i::String> preparser_message = FormatMessage(&data); 1268 if (!i::String::Equals(message_string, preparser_message)) { 1269 i::OS::Print( 1270 "Expected parser and preparser to produce the same error on:\n" 1271 "\t%s\n" 1272 "However, found the following error messages\n" 1273 "\tparser: %s\n" 1274 "\tpreparser: %s\n", 1275 source->ToCString().get(), 1276 message_string->ToCString().get(), 1277 preparser_message->ToCString().get()); 1278 CHECK(false); 1279 } 1280 } else if (data.has_error()) { 1281 i::OS::Print( 1282 "Preparser failed on:\n" 1283 "\t%s\n" 1284 "with error:\n" 1285 "\t%s\n" 1286 "However, the parser succeeded", 1287 source->ToCString().get(), FormatMessage(&data)->ToCString().get()); 1288 CHECK(false); 1289 } else if (result == kError) { 1290 i::OS::Print( 1291 "Expected error on:\n" 1292 "\t%s\n" 1293 "However, parser and preparser succeeded", 1294 source->ToCString().get()); 1295 CHECK(false); 1296 } 1297} 1298 1299 1300void TestParserSync(const char* source, 1301 const ParserFlag* flag_list, 1302 size_t flag_list_length, 1303 ParserSyncTestResult result = kSuccessOrError) { 1304 i::Handle<i::String> str = 1305 CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source); 1306 for (int bits = 0; bits < (1 << flag_list_length); bits++) { 1307 i::EnumSet<ParserFlag> flags; 1308 for (size_t flag_index = 0; flag_index < flag_list_length; flag_index++) { 1309 if ((bits & (1 << flag_index)) != 0) flags.Add(flag_list[flag_index]); 1310 } 1311 TestParserSyncWithFlags(str, flags, result); 1312 } 1313} 1314 1315 1316TEST(ParserSync) { 1317 const char* context_data[][2] = { 1318 { "", "" }, 1319 { "{", "}" }, 1320 { "if (true) ", " else {}" }, 1321 { "if (true) {} else ", "" }, 1322 { "if (true) ", "" }, 1323 { "do ", " while (false)" }, 1324 { "while (false) ", "" }, 1325 { "for (;;) ", "" }, 1326 { "with ({})", "" }, 1327 { "switch (12) { case 12: ", "}" }, 1328 { "switch (12) { default: ", "}" }, 1329 { "switch (12) { ", "case 12: }" }, 1330 { "label2: ", "" }, 1331 { NULL, NULL } 1332 }; 1333 1334 const char* statement_data[] = { 1335 "{}", 1336 "var x", 1337 "var x = 1", 1338 "const x", 1339 "const x = 1", 1340 ";", 1341 "12", 1342 "if (false) {} else ;", 1343 "if (false) {} else {}", 1344 "if (false) {} else 12", 1345 "if (false) ;" 1346 "if (false) {}", 1347 "if (false) 12", 1348 "do {} while (false)", 1349 "for (;;) ;", 1350 "for (;;) {}", 1351 "for (;;) 12", 1352 "continue", 1353 "continue label", 1354 "continue\nlabel", 1355 "break", 1356 "break label", 1357 "break\nlabel", 1358 // TODO(marja): activate once parsing 'return' is merged into ParserBase. 1359 // "return", 1360 // "return 12", 1361 // "return\n12", 1362 "with ({}) ;", 1363 "with ({}) {}", 1364 "with ({}) 12", 1365 "switch ({}) { default: }" 1366 "label3: " 1367 "throw", 1368 "throw 12", 1369 "throw\n12", 1370 "try {} catch(e) {}", 1371 "try {} finally {}", 1372 "try {} catch(e) {} finally {}", 1373 "debugger", 1374 NULL 1375 }; 1376 1377 const char* termination_data[] = { 1378 "", 1379 ";", 1380 "\n", 1381 ";\n", 1382 "\n;", 1383 NULL 1384 }; 1385 1386 v8::HandleScope handles(CcTest::isolate()); 1387 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); 1388 v8::Context::Scope context_scope(context); 1389 1390 int marker; 1391 CcTest::i_isolate()->stack_guard()->SetStackLimit( 1392 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 1393 1394 static const ParserFlag flags1[] = { 1395 kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators, 1396 kAllowForOf 1397 }; 1398 for (int i = 0; context_data[i][0] != NULL; ++i) { 1399 for (int j = 0; statement_data[j] != NULL; ++j) { 1400 for (int k = 0; termination_data[k] != NULL; ++k) { 1401 int kPrefixLen = i::StrLength(context_data[i][0]); 1402 int kStatementLen = i::StrLength(statement_data[j]); 1403 int kTerminationLen = i::StrLength(termination_data[k]); 1404 int kSuffixLen = i::StrLength(context_data[i][1]); 1405 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen 1406 + kSuffixLen + i::StrLength("label: for (;;) { }"); 1407 1408 // Plug the source code pieces together. 1409 i::ScopedVector<char> program(kProgramSize + 1); 1410 int length = i::SNPrintF(program, 1411 "label: for (;;) { %s%s%s%s }", 1412 context_data[i][0], 1413 statement_data[j], 1414 termination_data[k], 1415 context_data[i][1]); 1416 CHECK(length == kProgramSize); 1417 TestParserSync(program.start(), flags1, ARRAY_SIZE(flags1)); 1418 } 1419 } 1420 } 1421 1422 // Neither Harmony numeric literals nor our natives syntax have any 1423 // interaction with the flags above, so test these separately to reduce 1424 // the combinatorial explosion. 1425 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals }; 1426 TestParserSync("0o1234", flags2, ARRAY_SIZE(flags2)); 1427 TestParserSync("0b1011", flags2, ARRAY_SIZE(flags2)); 1428 1429 static const ParserFlag flags3[] = { kAllowNativesSyntax }; 1430 TestParserSync("%DebugPrint(123)", flags3, ARRAY_SIZE(flags3)); 1431} 1432 1433 1434TEST(StrictOctal) { 1435 // Test that syntax error caused by octal literal is reported correctly as 1436 // such (issue 2220). 1437 v8::V8::Initialize(); 1438 v8::HandleScope scope(CcTest::isolate()); 1439 v8::Context::Scope context_scope( 1440 v8::Context::New(CcTest::isolate())); 1441 v8::TryCatch try_catch; 1442 const char* script = 1443 "\"use strict\"; \n" 1444 "a = function() { \n" 1445 " b = function() { \n" 1446 " 01; \n" 1447 " }; \n" 1448 "}; \n"; 1449 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script)); 1450 CHECK(try_catch.HasCaught()); 1451 v8::String::Utf8Value exception(try_catch.Exception()); 1452 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.", 1453 *exception); 1454} 1455 1456 1457void RunParserSyncTest(const char* context_data[][2], 1458 const char* statement_data[], 1459 ParserSyncTestResult result, 1460 const ParserFlag* flags = NULL, 1461 int flags_len = 0) { 1462 v8::HandleScope handles(CcTest::isolate()); 1463 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); 1464 v8::Context::Scope context_scope(context); 1465 1466 int marker; 1467 CcTest::i_isolate()->stack_guard()->SetStackLimit( 1468 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 1469 1470 static const ParserFlag default_flags[] = { 1471 kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators, 1472 kAllowForOf, kAllowNativesSyntax 1473 }; 1474 if (!flags) { 1475 flags = default_flags; 1476 flags_len = ARRAY_SIZE(default_flags); 1477 } 1478 for (int i = 0; context_data[i][0] != NULL; ++i) { 1479 for (int j = 0; statement_data[j] != NULL; ++j) { 1480 int kPrefixLen = i::StrLength(context_data[i][0]); 1481 int kStatementLen = i::StrLength(statement_data[j]); 1482 int kSuffixLen = i::StrLength(context_data[i][1]); 1483 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen; 1484 1485 // Plug the source code pieces together. 1486 i::ScopedVector<char> program(kProgramSize + 1); 1487 int length = i::SNPrintF(program, 1488 "%s%s%s", 1489 context_data[i][0], 1490 statement_data[j], 1491 context_data[i][1]); 1492 CHECK(length == kProgramSize); 1493 TestParserSync(program.start(), 1494 flags, 1495 flags_len, 1496 result); 1497 } 1498 } 1499} 1500 1501 1502TEST(ErrorsEvalAndArguments) { 1503 // Tests that both preparsing and parsing produce the right kind of errors for 1504 // using "eval" and "arguments" as identifiers. Without the strict mode, it's 1505 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it 1506 // isn't. 1507 const char* context_data[][2] = { 1508 { "\"use strict\";", "" }, 1509 { "var eval; function test_func() {\"use strict\"; ", "}"}, 1510 { NULL, NULL } 1511 }; 1512 1513 const char* statement_data[] = { 1514 "var eval;", 1515 "var arguments", 1516 "var foo, eval;", 1517 "var foo, arguments;", 1518 "try { } catch (eval) { }", 1519 "try { } catch (arguments) { }", 1520 "function eval() { }", 1521 "function arguments() { }", 1522 "function foo(eval) { }", 1523 "function foo(arguments) { }", 1524 "function foo(bar, eval) { }", 1525 "function foo(bar, arguments) { }", 1526 "eval = 1;", 1527 "arguments = 1;", 1528 "var foo = eval = 1;", 1529 "var foo = arguments = 1;", 1530 "++eval;", 1531 "++arguments;", 1532 "eval++;", 1533 "arguments++;", 1534 NULL 1535 }; 1536 1537 RunParserSyncTest(context_data, statement_data, kError); 1538} 1539 1540 1541TEST(NoErrorsEvalAndArgumentsSloppy) { 1542 // Tests that both preparsing and parsing accept "eval" and "arguments" as 1543 // identifiers when needed. 1544 const char* context_data[][2] = { 1545 { "", "" }, 1546 { "function test_func() {", "}"}, 1547 { NULL, NULL } 1548 }; 1549 1550 const char* statement_data[] = { 1551 "var eval;", 1552 "var arguments", 1553 "var foo, eval;", 1554 "var foo, arguments;", 1555 "try { } catch (eval) { }", 1556 "try { } catch (arguments) { }", 1557 "function eval() { }", 1558 "function arguments() { }", 1559 "function foo(eval) { }", 1560 "function foo(arguments) { }", 1561 "function foo(bar, eval) { }", 1562 "function foo(bar, arguments) { }", 1563 "eval = 1;", 1564 "arguments = 1;", 1565 "var foo = eval = 1;", 1566 "var foo = arguments = 1;", 1567 "++eval;", 1568 "++arguments;", 1569 "eval++;", 1570 "arguments++;", 1571 NULL 1572 }; 1573 1574 RunParserSyncTest(context_data, statement_data, kSuccess); 1575} 1576 1577 1578TEST(NoErrorsEvalAndArgumentsStrict) { 1579 const char* context_data[][2] = { 1580 { "\"use strict\";", "" }, 1581 { "function test_func() { \"use strict\";", "}" }, 1582 { NULL, NULL } 1583 }; 1584 1585 const char* statement_data[] = { 1586 "eval;", 1587 "arguments;", 1588 "var foo = eval;", 1589 "var foo = arguments;", 1590 "var foo = { eval: 1 };", 1591 "var foo = { arguments: 1 };", 1592 "var foo = { }; foo.eval = {};", 1593 "var foo = { }; foo.arguments = {};", 1594 NULL 1595 }; 1596 1597 RunParserSyncTest(context_data, statement_data, kSuccess); 1598} 1599 1600 1601TEST(ErrorsFutureStrictReservedWords) { 1602 // Tests that both preparsing and parsing produce the right kind of errors for 1603 // using future strict reserved words as identifiers. Without the strict mode, 1604 // it's ok to use future strict reserved words as identifiers. With the strict 1605 // mode, it isn't. 1606 const char* context_data[][2] = { 1607 { "\"use strict\";", "" }, 1608 { "function test_func() {\"use strict\"; ", "}"}, 1609 { NULL, NULL } 1610 }; 1611 1612 const char* statement_data[] = { 1613 "var interface;", 1614 "var foo, interface;", 1615 "try { } catch (interface) { }", 1616 "function interface() { }", 1617 "function foo(interface) { }", 1618 "function foo(bar, interface) { }", 1619 "interface = 1;", 1620 "var foo = interface = 1;", 1621 "++interface;", 1622 "interface++;", 1623 NULL 1624 }; 1625 1626 RunParserSyncTest(context_data, statement_data, kError); 1627} 1628 1629 1630TEST(NoErrorsFutureStrictReservedWords) { 1631 const char* context_data[][2] = { 1632 { "", "" }, 1633 { "function test_func() {", "}"}, 1634 { NULL, NULL } 1635 }; 1636 1637 const char* statement_data[] = { 1638 "var interface;", 1639 "var foo, interface;", 1640 "try { } catch (interface) { }", 1641 "function interface() { }", 1642 "function foo(interface) { }", 1643 "function foo(bar, interface) { }", 1644 "interface = 1;", 1645 "var foo = interface = 1;", 1646 "++interface;", 1647 "interface++;", 1648 NULL 1649 }; 1650 1651 RunParserSyncTest(context_data, statement_data, kSuccess); 1652} 1653 1654 1655TEST(ErrorsReservedWords) { 1656 // Tests that both preparsing and parsing produce the right kind of errors for 1657 // using future reserved words as identifiers. These tests don't depend on the 1658 // strict mode. 1659 const char* context_data[][2] = { 1660 { "", "" }, 1661 { "\"use strict\";", "" }, 1662 { "var eval; function test_func() {", "}"}, 1663 { "var eval; function test_func() {\"use strict\"; ", "}"}, 1664 { NULL, NULL } 1665 }; 1666 1667 const char* statement_data[] = { 1668 "var super;", 1669 "var foo, super;", 1670 "try { } catch (super) { }", 1671 "function super() { }", 1672 "function foo(super) { }", 1673 "function foo(bar, super) { }", 1674 "super = 1;", 1675 "var foo = super = 1;", 1676 "++super;", 1677 "super++;", 1678 "function foo super", 1679 NULL 1680 }; 1681 1682 RunParserSyncTest(context_data, statement_data, kError); 1683} 1684 1685 1686TEST(NoErrorsYieldSloppy) { 1687 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a 1688 // generator (see next test). 1689 const char* context_data[][2] = { 1690 { "", "" }, 1691 { "function is_not_gen() {", "}" }, 1692 { NULL, NULL } 1693 }; 1694 1695 const char* statement_data[] = { 1696 "var yield;", 1697 "var foo, yield;", 1698 "try { } catch (yield) { }", 1699 "function yield() { }", 1700 "function foo(yield) { }", 1701 "function foo(bar, yield) { }", 1702 "yield = 1;", 1703 "var foo = yield = 1;", 1704 "++yield;", 1705 "yield++;", 1706 NULL 1707 }; 1708 1709 RunParserSyncTest(context_data, statement_data, kSuccess); 1710} 1711 1712 1713TEST(ErrorsYieldSloppyGenerator) { 1714 const char* context_data[][2] = { 1715 { "function * is_gen() {", "}" }, 1716 { NULL, NULL } 1717 }; 1718 1719 const char* statement_data[] = { 1720 "var yield;", 1721 "var foo, yield;", 1722 "try { } catch (yield) { }", 1723 "function yield() { }", 1724 // BUG: These should not be allowed, but they are (if kAllowGenerators is 1725 // set) 1726 // "function foo(yield) { }", 1727 // "function foo(bar, yield) { }", 1728 "yield = 1;", 1729 "var foo = yield = 1;", 1730 "++yield;", 1731 "yield++;", 1732 NULL 1733 }; 1734 1735 // If generators are not allowed, the error will be produced at the '*' token, 1736 // so this test works both with and without the kAllowGenerators flag. 1737 RunParserSyncTest(context_data, statement_data, kError); 1738} 1739 1740 1741TEST(ErrorsYieldStrict) { 1742 const char* context_data[][2] = { 1743 { "\"use strict\";", "" }, 1744 { "\"use strict\"; function is_not_gen() {", "}" }, 1745 { "function test_func() {\"use strict\"; ", "}"}, 1746 { NULL, NULL } 1747 }; 1748 1749 const char* statement_data[] = { 1750 "var yield;", 1751 "var foo, yield;", 1752 "try { } catch (yield) { }", 1753 "function yield() { }", 1754 "function foo(yield) { }", 1755 "function foo(bar, yield) { }", 1756 "yield = 1;", 1757 "var foo = yield = 1;", 1758 "++yield;", 1759 "yield++;", 1760 NULL 1761 }; 1762 1763 RunParserSyncTest(context_data, statement_data, kError); 1764} 1765 1766 1767TEST(ErrorsYield) { 1768 const char* context_data[][2] = { 1769 { "function * is_gen() {", "}" }, 1770 { NULL, NULL } 1771 }; 1772 1773 const char* statement_data[] = { 1774 "yield 2;", // this is legal inside generator 1775 "yield * 2;", // this is legal inside generator 1776 NULL 1777 }; 1778 1779 // Here we cannot assert that there is no error, since there will be without 1780 // the kAllowGenerators flag. However, we test that Parser and PreParser 1781 // produce the same errors. 1782 RunParserSyncTest(context_data, statement_data, kSuccessOrError); 1783} 1784 1785 1786TEST(ErrorsNameOfStrictFunction) { 1787 // Tests that illegal tokens as names of a strict function produce the correct 1788 // errors. 1789 const char* context_data[][2] = { 1790 { "", ""}, 1791 { "\"use strict\";", ""}, 1792 { NULL, NULL } 1793 }; 1794 1795 const char* statement_data[] = { 1796 "function eval() {\"use strict\";}", 1797 "function arguments() {\"use strict\";}", 1798 "function interface() {\"use strict\";}", 1799 "function yield() {\"use strict\";}", 1800 // Future reserved words are always illegal 1801 "function super() { }", 1802 "function super() {\"use strict\";}", 1803 NULL 1804 }; 1805 1806 RunParserSyncTest(context_data, statement_data, kError); 1807} 1808 1809 1810TEST(NoErrorsNameOfStrictFunction) { 1811 const char* context_data[][2] = { 1812 { "", ""}, 1813 { NULL, NULL } 1814 }; 1815 1816 const char* statement_data[] = { 1817 "function eval() { }", 1818 "function arguments() { }", 1819 "function interface() { }", 1820 "function yield() { }", 1821 NULL 1822 }; 1823 1824 RunParserSyncTest(context_data, statement_data, kSuccess); 1825} 1826 1827 1828 1829TEST(ErrorsIllegalWordsAsLabelsSloppy) { 1830 // Using future reserved words as labels is always an error. 1831 const char* context_data[][2] = { 1832 { "", ""}, 1833 { "function test_func() {", "}" }, 1834 { NULL, NULL } 1835 }; 1836 1837 const char* statement_data[] = { 1838 "super: while(true) { break super; }", 1839 NULL 1840 }; 1841 1842 RunParserSyncTest(context_data, statement_data, kError); 1843} 1844 1845 1846TEST(ErrorsIllegalWordsAsLabelsStrict) { 1847 // Tests that illegal tokens as labels produce the correct errors. 1848 const char* context_data[][2] = { 1849 { "\"use strict\";", "" }, 1850 { "function test_func() {\"use strict\"; ", "}"}, 1851 { NULL, NULL } 1852 }; 1853 1854 const char* statement_data[] = { 1855 "super: while(true) { break super; }", 1856 "interface: while(true) { break interface; }", 1857 "yield: while(true) { break yield; }", 1858 NULL 1859 }; 1860 1861 RunParserSyncTest(context_data, statement_data, kError); 1862} 1863 1864 1865TEST(NoErrorsIllegalWordsAsLabels) { 1866 // Using eval and arguments as labels is legal even in strict mode. 1867 const char* context_data[][2] = { 1868 { "", ""}, 1869 { "function test_func() {", "}" }, 1870 { "\"use strict\";", "" }, 1871 { "\"use strict\"; function test_func() {", "}" }, 1872 { NULL, NULL } 1873 }; 1874 1875 const char* statement_data[] = { 1876 "mylabel: while(true) { break mylabel; }", 1877 "eval: while(true) { break eval; }", 1878 "arguments: while(true) { break arguments; }", 1879 NULL 1880 }; 1881 1882 RunParserSyncTest(context_data, statement_data, kSuccess); 1883} 1884 1885 1886TEST(ErrorsParenthesizedLabels) { 1887 // Parenthesized identifiers shouldn't be recognized as labels. 1888 const char* context_data[][2] = { 1889 { "", ""}, 1890 { "function test_func() {", "}" }, 1891 { NULL, NULL } 1892 }; 1893 1894 const char* statement_data[] = { 1895 "(mylabel): while(true) { break mylabel; }", 1896 NULL 1897 }; 1898 1899 RunParserSyncTest(context_data, statement_data, kError); 1900} 1901 1902 1903TEST(NoErrorsParenthesizedDirectivePrologue) { 1904 // Parenthesized directive prologue shouldn't be recognized. 1905 const char* context_data[][2] = { 1906 { "", ""}, 1907 { NULL, NULL } 1908 }; 1909 1910 const char* statement_data[] = { 1911 "(\"use strict\"); var eval;", 1912 NULL 1913 }; 1914 1915 RunParserSyncTest(context_data, statement_data, kSuccess); 1916} 1917 1918 1919TEST(ErrorsNotAnIdentifierName) { 1920 const char* context_data[][2] = { 1921 { "", ""}, 1922 { "\"use strict\";", ""}, 1923 { NULL, NULL } 1924 }; 1925 1926 const char* statement_data[] = { 1927 "var foo = {}; foo.{;", 1928 "var foo = {}; foo.};", 1929 "var foo = {}; foo.=;", 1930 "var foo = {}; foo.888;", 1931 "var foo = {}; foo.-;", 1932 "var foo = {}; foo.--;", 1933 NULL 1934 }; 1935 1936 RunParserSyncTest(context_data, statement_data, kError); 1937} 1938 1939 1940TEST(NoErrorsIdentifierNames) { 1941 // Keywords etc. are valid as property names. 1942 const char* context_data[][2] = { 1943 { "", ""}, 1944 { "\"use strict\";", ""}, 1945 { NULL, NULL } 1946 }; 1947 1948 const char* statement_data[] = { 1949 "var foo = {}; foo.if;", 1950 "var foo = {}; foo.yield;", 1951 "var foo = {}; foo.super;", 1952 "var foo = {}; foo.interface;", 1953 "var foo = {}; foo.eval;", 1954 "var foo = {}; foo.arguments;", 1955 NULL 1956 }; 1957 1958 RunParserSyncTest(context_data, statement_data, kSuccess); 1959} 1960 1961 1962TEST(DontRegressPreParserDataSizes) { 1963 // These tests make sure that Parser doesn't start producing less "preparse 1964 // data" (data which the embedder can cache). 1965 v8::V8::Initialize(); 1966 v8::Isolate* isolate = CcTest::isolate(); 1967 v8::HandleScope handles(isolate); 1968 1969 int marker; 1970 CcTest::i_isolate()->stack_guard()->SetStackLimit( 1971 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 1972 1973 struct TestCase { 1974 const char* program; 1975 int functions; 1976 } test_cases[] = { 1977 // No functions. 1978 {"var x = 42;", 0}, 1979 // Functions. 1980 {"function foo() {}", 1}, {"function foo() {} function bar() {}", 2}, 1981 // Getter / setter functions are recorded as functions if they're on the top 1982 // level. 1983 {"var x = {get foo(){} };", 1}, 1984 // Functions insize lazy functions are not recorded. 1985 {"function lazy() { function a() {} function b() {} function c() {} }", 1}, 1986 {"function lazy() { var x = {get foo(){} } }", 1}, 1987 {NULL, 0} 1988 }; 1989 1990 for (int i = 0; test_cases[i].program; i++) { 1991 const char* program = test_cases[i].program; 1992 i::Factory* factory = CcTest::i_isolate()->factory(); 1993 i::Handle<i::String> source = 1994 factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked(); 1995 i::Handle<i::Script> script = factory->NewScript(source); 1996 i::CompilationInfoWithZone info(script); 1997 i::ScriptData* data = NULL; 1998 info.SetCachedData(&data, i::PRODUCE_CACHED_DATA); 1999 i::Parser::Parse(&info, true); 2000 CHECK(data); 2001 CHECK(!data->HasError()); 2002 2003 if (data->function_count() != test_cases[i].functions) { 2004 i::OS::Print( 2005 "Expected preparse data for program:\n" 2006 "\t%s\n" 2007 "to contain %d functions, however, received %d functions.\n", 2008 program, test_cases[i].functions, 2009 data->function_count()); 2010 CHECK(false); 2011 } 2012 delete data; 2013 } 2014} 2015 2016 2017TEST(FunctionDeclaresItselfStrict) { 2018 // Tests that we produce the right kinds of errors when a function declares 2019 // itself strict (we cannot produce there errors as soon as we see the 2020 // offending identifiers, because we don't know at that point whether the 2021 // function is strict or not). 2022 const char* context_data[][2] = { 2023 {"function eval() {", "}"}, 2024 {"function arguments() {", "}"}, 2025 {"function yield() {", "}"}, 2026 {"function interface() {", "}"}, 2027 {"function foo(eval) {", "}"}, 2028 {"function foo(arguments) {", "}"}, 2029 {"function foo(yield) {", "}"}, 2030 {"function foo(interface) {", "}"}, 2031 {"function foo(bar, eval) {", "}"}, 2032 {"function foo(bar, arguments) {", "}"}, 2033 {"function foo(bar, yield) {", "}"}, 2034 {"function foo(bar, interface) {", "}"}, 2035 {"function foo(bar, bar) {", "}"}, 2036 { NULL, NULL } 2037 }; 2038 2039 const char* strict_statement_data[] = { 2040 "\"use strict\";", 2041 NULL 2042 }; 2043 2044 const char* non_strict_statement_data[] = { 2045 ";", 2046 NULL 2047 }; 2048 2049 RunParserSyncTest(context_data, strict_statement_data, kError); 2050 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess); 2051} 2052 2053 2054TEST(ErrorsTryWithoutCatchOrFinally) { 2055 const char* context_data[][2] = { 2056 {"", ""}, 2057 { NULL, NULL } 2058 }; 2059 2060 const char* statement_data[] = { 2061 "try { }", 2062 "try { } foo();", 2063 "try { } catch (e) foo();", 2064 "try { } catch { }", 2065 "try { } finally foo();", 2066 NULL 2067 }; 2068 2069 RunParserSyncTest(context_data, statement_data, kError); 2070} 2071 2072 2073TEST(NoErrorsTryCatchFinally) { 2074 const char* context_data[][2] = { 2075 {"", ""}, 2076 { NULL, NULL } 2077 }; 2078 2079 const char* statement_data[] = { 2080 "try { } catch (e) { }", 2081 "try { } catch (e) { } finally { }", 2082 "try { } finally { }", 2083 NULL 2084 }; 2085 2086 RunParserSyncTest(context_data, statement_data, kSuccess); 2087} 2088 2089 2090TEST(ErrorsRegexpLiteral) { 2091 const char* context_data[][2] = { 2092 {"var r = ", ""}, 2093 { NULL, NULL } 2094 }; 2095 2096 const char* statement_data[] = { 2097 "/unterminated", 2098 NULL 2099 }; 2100 2101 RunParserSyncTest(context_data, statement_data, kError); 2102} 2103 2104 2105TEST(NoErrorsRegexpLiteral) { 2106 const char* context_data[][2] = { 2107 {"var r = ", ""}, 2108 { NULL, NULL } 2109 }; 2110 2111 const char* statement_data[] = { 2112 "/foo/", 2113 "/foo/g", 2114 "/foo/whatever", // This is an error but not detected by the parser. 2115 NULL 2116 }; 2117 2118 RunParserSyncTest(context_data, statement_data, kSuccess); 2119} 2120 2121 2122TEST(Intrinsics) { 2123 const char* context_data[][2] = { 2124 {"", ""}, 2125 { NULL, NULL } 2126 }; 2127 2128 const char* statement_data[] = { 2129 "%someintrinsic(arg)", 2130 NULL 2131 }; 2132 2133 // Parsing will fail or succeed depending on whether we allow natives syntax 2134 // or not. 2135 RunParserSyncTest(context_data, statement_data, kSuccessOrError); 2136} 2137 2138 2139TEST(NoErrorsNewExpression) { 2140 const char* context_data[][2] = { 2141 {"", ""}, 2142 {"var f =", ""}, 2143 { NULL, NULL } 2144 }; 2145 2146 const char* statement_data[] = { 2147 "new foo", 2148 "new foo();", 2149 "new foo(1);", 2150 "new foo(1, 2);", 2151 // The first () will be processed as a part of the NewExpression and the 2152 // second () will be processed as part of LeftHandSideExpression. 2153 "new foo()();", 2154 // The first () will be processed as a part of the inner NewExpression and 2155 // the second () will be processed as a part of the outer NewExpression. 2156 "new new foo()();", 2157 "new foo.bar;", 2158 "new foo.bar();", 2159 "new foo.bar.baz;", 2160 "new foo.bar().baz;", 2161 "new foo[bar];", 2162 "new foo[bar]();", 2163 "new foo[bar][baz];", 2164 "new foo[bar]()[baz];", 2165 "new foo[bar].baz(baz)()[bar].baz;", 2166 "new \"foo\"", // Runtime error 2167 "new 1", // Runtime error 2168 // This even runs: 2169 "(new new Function(\"this.x = 1\")).x;", 2170 "new new Test_Two(String, 2).v(0123).length;", 2171 NULL 2172 }; 2173 2174 RunParserSyncTest(context_data, statement_data, kSuccess); 2175} 2176 2177 2178TEST(ErrorsNewExpression) { 2179 const char* context_data[][2] = { 2180 {"", ""}, 2181 {"var f =", ""}, 2182 { NULL, NULL } 2183 }; 2184 2185 const char* statement_data[] = { 2186 "new foo bar", 2187 "new ) foo", 2188 "new ++foo", 2189 "new foo ++", 2190 NULL 2191 }; 2192 2193 RunParserSyncTest(context_data, statement_data, kError); 2194} 2195 2196 2197TEST(StrictObjectLiteralChecking) { 2198 const char* strict_context_data[][2] = { 2199 {"\"use strict\"; var myobject = {", "};"}, 2200 { NULL, NULL } 2201 }; 2202 const char* non_strict_context_data[][2] = { 2203 {"var myobject = {", "};"}, 2204 { NULL, NULL } 2205 }; 2206 2207 // These are only errors in strict mode. 2208 const char* statement_data[] = { 2209 "foo: 1, foo: 2", 2210 "\"foo\": 1, \"foo\": 2", 2211 "foo: 1, \"foo\": 2", 2212 "1: 1, 1: 2", 2213 "1: 1, \"1\": 2", 2214 "get: 1, get: 2", // Not a getter for real, just a property called get. 2215 "set: 1, set: 2", // Not a setter for real, just a property called set. 2216 NULL 2217 }; 2218 2219 RunParserSyncTest(non_strict_context_data, statement_data, kSuccess); 2220 RunParserSyncTest(strict_context_data, statement_data, kError); 2221} 2222 2223 2224TEST(ErrorsObjectLiteralChecking) { 2225 const char* context_data[][2] = { 2226 {"\"use strict\"; var myobject = {", "};"}, 2227 {"var myobject = {", "};"}, 2228 { NULL, NULL } 2229 }; 2230 2231 const char* statement_data[] = { 2232 "foo: 1, get foo() {}", 2233 "foo: 1, set foo(v) {}", 2234 "\"foo\": 1, get \"foo\"() {}", 2235 "\"foo\": 1, set \"foo\"(v) {}", 2236 "1: 1, get 1() {}", 2237 "1: 1, set 1() {}", 2238 // It's counter-intuitive, but these collide too (even in classic 2239 // mode). Note that we can have "foo" and foo as properties in classic mode, 2240 // but we cannot have "foo" and get foo, or foo and get "foo". 2241 "foo: 1, get \"foo\"() {}", 2242 "foo: 1, set \"foo\"(v) {}", 2243 "\"foo\": 1, get foo() {}", 2244 "\"foo\": 1, set foo(v) {}", 2245 "1: 1, get \"1\"() {}", 2246 "1: 1, set \"1\"() {}", 2247 "\"1\": 1, get 1() {}" 2248 "\"1\": 1, set 1(v) {}" 2249 // Wrong number of parameters 2250 "get bar(x) {}", 2251 "get bar(x, y) {}", 2252 "set bar() {}", 2253 "set bar(x, y) {}", 2254 // Parsing FunctionLiteral for getter or setter fails 2255 "get foo( +", 2256 "get foo() \"error\"", 2257 NULL 2258 }; 2259 2260 RunParserSyncTest(context_data, statement_data, kError); 2261} 2262 2263 2264TEST(NoErrorsObjectLiteralChecking) { 2265 const char* context_data[][2] = { 2266 {"var myobject = {", "};"}, 2267 {"\"use strict\"; var myobject = {", "};"}, 2268 { NULL, NULL } 2269 }; 2270 2271 const char* statement_data[] = { 2272 "foo: 1, bar: 2", 2273 "\"foo\": 1, \"bar\": 2", 2274 "1: 1, 2: 2", 2275 // Syntax: IdentifierName ':' AssignmentExpression 2276 "foo: bar = 5 + baz", 2277 // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}' 2278 "get foo() {}", 2279 "get \"foo\"() {}", 2280 "get 1() {}", 2281 // Syntax: 'set' PropertyName '(' PropertySetParameterList ')' 2282 // '{' FunctionBody '}' 2283 "set foo(v) {}", 2284 "set \"foo\"(v) {}", 2285 "set 1(v) {}", 2286 // Non-colliding getters and setters -> no errors 2287 "foo: 1, get bar() {}", 2288 "foo: 1, set bar(v) {}", 2289 "\"foo\": 1, get \"bar\"() {}", 2290 "\"foo\": 1, set \"bar\"(v) {}", 2291 "1: 1, get 2() {}", 2292 "1: 1, set 2(v) {}", 2293 // Keywords, future reserved and strict future reserved are also allowed as 2294 // property names. 2295 "if: 4", 2296 "interface: 5", 2297 "super: 6", 2298 "eval: 7", 2299 "arguments: 8", 2300 NULL 2301 }; 2302 2303 RunParserSyncTest(context_data, statement_data, kSuccess); 2304} 2305 2306 2307TEST(TooManyArguments) { 2308 const char* context_data[][2] = { 2309 {"foo(", "0)"}, 2310 { NULL, NULL } 2311 }; 2312 2313 using v8::internal::Code; 2314 char statement[Code::kMaxArguments * 2 + 1]; 2315 for (int i = 0; i < Code::kMaxArguments; ++i) { 2316 statement[2 * i] = '0'; 2317 statement[2 * i + 1] = ','; 2318 } 2319 statement[Code::kMaxArguments * 2] = 0; 2320 2321 const char* statement_data[] = { 2322 statement, 2323 NULL 2324 }; 2325 2326 // The test is quite slow, so run it with a reduced set of flags. 2327 static const ParserFlag empty_flags[] = {kAllowLazy}; 2328 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1); 2329} 2330 2331 2332TEST(StrictDelete) { 2333 // "delete <Identifier>" is not allowed in strict mode. 2334 const char* strict_context_data[][2] = { 2335 {"\"use strict\"; ", ""}, 2336 { NULL, NULL } 2337 }; 2338 2339 const char* sloppy_context_data[][2] = { 2340 {"", ""}, 2341 { NULL, NULL } 2342 }; 2343 2344 // These are errors in the strict mode. 2345 const char* sloppy_statement_data[] = { 2346 "delete foo;", 2347 "delete foo + 1;", 2348 "delete (foo);", 2349 "delete eval;", 2350 "delete interface;", 2351 NULL 2352 }; 2353 2354 // These are always OK 2355 const char* good_statement_data[] = { 2356 "delete this;", 2357 "delete 1;", 2358 "delete 1 + 2;", 2359 "delete foo();", 2360 "delete foo.bar;", 2361 "delete foo[bar];", 2362 "delete foo--;", 2363 "delete --foo;", 2364 "delete new foo();", 2365 "delete new foo(bar);", 2366 NULL 2367 }; 2368 2369 // These are always errors 2370 const char* bad_statement_data[] = { 2371 "delete if;", 2372 NULL 2373 }; 2374 2375 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError); 2376 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess); 2377 2378 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess); 2379 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess); 2380 2381 RunParserSyncTest(strict_context_data, bad_statement_data, kError); 2382 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError); 2383} 2384 2385 2386TEST(InvalidLeftHandSide) { 2387 const char* assignment_context_data[][2] = { 2388 {"", " = 1;"}, 2389 {"\"use strict\"; ", " = 1;"}, 2390 { NULL, NULL } 2391 }; 2392 2393 const char* prefix_context_data[][2] = { 2394 {"++", ";"}, 2395 {"\"use strict\"; ++", ";"}, 2396 {NULL, NULL}, 2397 }; 2398 2399 const char* postfix_context_data[][2] = { 2400 {"", "++;"}, 2401 {"\"use strict\"; ", "++;"}, 2402 { NULL, NULL } 2403 }; 2404 2405 // Good left hand sides for assigment or prefix / postfix operations. 2406 const char* good_statement_data[] = { 2407 "foo", 2408 "foo.bar", 2409 "foo[bar]", 2410 "foo()[bar]", 2411 "foo().bar", 2412 "this.foo", 2413 "this[foo]", 2414 "new foo()[bar]", 2415 "new foo().bar", 2416 "foo()", 2417 "foo(bar)", 2418 "foo[bar]()", 2419 "foo.bar()", 2420 "this()", 2421 "this.foo()", 2422 "this[foo].bar()", 2423 "this.foo[foo].bar(this)(bar)[foo]()", 2424 NULL 2425 }; 2426 2427 // Bad left hand sides for assigment or prefix / postfix operations. 2428 const char* bad_statement_data_common[] = { 2429 "2", 2430 "new foo", 2431 "new foo()", 2432 "null", 2433 "if", // Unexpected token 2434 "{x: 1}", // Unexpected token 2435 "this", 2436 "\"bar\"", 2437 "(foo + bar)", 2438 "new new foo()[bar]", // means: new (new foo()[bar]) 2439 "new new foo().bar", // means: new (new foo()[bar]) 2440 NULL 2441 }; 2442 2443 // These are not okay for assignment, but okay for prefix / postix. 2444 const char* bad_statement_data_for_assignment[] = { 2445 "++foo", 2446 "foo++", 2447 "foo + bar", 2448 NULL 2449 }; 2450 2451 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess); 2452 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError); 2453 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment, 2454 kError); 2455 2456 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess); 2457 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError); 2458 2459 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess); 2460 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError); 2461} 2462 2463 2464TEST(FuncNameInferrerBasic) { 2465 // Tests that function names are inferred properly. 2466 i::FLAG_allow_natives_syntax = true; 2467 v8::Isolate* isolate = CcTest::isolate(); 2468 v8::HandleScope scope(isolate); 2469 LocalContext env; 2470 CompileRun("var foo1 = function() {}; " 2471 "var foo2 = function foo3() {}; " 2472 "function not_ctor() { " 2473 " var foo4 = function() {}; " 2474 " return %FunctionGetInferredName(foo4); " 2475 "} " 2476 "function Ctor() { " 2477 " var foo5 = function() {}; " 2478 " return %FunctionGetInferredName(foo5); " 2479 "} " 2480 "var obj1 = { foo6: function() {} }; " 2481 "var obj2 = { 'foo7': function() {} }; " 2482 "var obj3 = {}; " 2483 "obj3[1] = function() {}; " 2484 "var obj4 = {}; " 2485 "obj4[1] = function foo8() {}; " 2486 "var obj5 = {}; " 2487 "obj5['foo9'] = function() {}; " 2488 "var obj6 = { obj7 : { foo10: function() {} } };"); 2489 ExpectString("%FunctionGetInferredName(foo1)", "foo1"); 2490 // foo2 is not unnamed -> its name is not inferred. 2491 ExpectString("%FunctionGetInferredName(foo2)", ""); 2492 ExpectString("not_ctor()", "foo4"); 2493 ExpectString("Ctor()", "Ctor.foo5"); 2494 ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6"); 2495 ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7"); 2496 ExpectString("%FunctionGetInferredName(obj3[1])", 2497 "obj3.(anonymous function)"); 2498 ExpectString("%FunctionGetInferredName(obj4[1])", ""); 2499 ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9"); 2500 ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10"); 2501} 2502 2503 2504TEST(FuncNameInferrerTwoByte) { 2505 // Tests function name inferring in cases where some parts of the inferred 2506 // function name are two-byte strings. 2507 i::FLAG_allow_natives_syntax = true; 2508 v8::Isolate* isolate = CcTest::isolate(); 2509 v8::HandleScope scope(isolate); 2510 LocalContext env; 2511 uint16_t* two_byte_source = AsciiToTwoByteString( 2512 "var obj1 = { oXj2 : { foo1: function() {} } }; " 2513 "%FunctionGetInferredName(obj1.oXj2.foo1)"); 2514 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1"); 2515 // Make it really non-ASCII (replace the Xs with a non-ASCII character). 2516 two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d; 2517 v8::Local<v8::String> source = 2518 v8::String::NewFromTwoByte(isolate, two_byte_source); 2519 v8::Local<v8::Value> result = CompileRun(source); 2520 CHECK(result->IsString()); 2521 v8::Local<v8::String> expected_name = 2522 v8::String::NewFromTwoByte(isolate, two_byte_name); 2523 CHECK(result->Equals(expected_name)); 2524 i::DeleteArray(two_byte_source); 2525 i::DeleteArray(two_byte_name); 2526} 2527 2528 2529TEST(FuncNameInferrerEscaped) { 2530 // The same as FuncNameInferrerTwoByte, except that we express the two-byte 2531 // character as a unicode escape. 2532 i::FLAG_allow_natives_syntax = true; 2533 v8::Isolate* isolate = CcTest::isolate(); 2534 v8::HandleScope scope(isolate); 2535 LocalContext env; 2536 uint16_t* two_byte_source = AsciiToTwoByteString( 2537 "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; " 2538 "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)"); 2539 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1"); 2540 // Fix to correspond to the non-ASCII name in two_byte_source. 2541 two_byte_name[6] = 0x010d; 2542 v8::Local<v8::String> source = 2543 v8::String::NewFromTwoByte(isolate, two_byte_source); 2544 v8::Local<v8::Value> result = CompileRun(source); 2545 CHECK(result->IsString()); 2546 v8::Local<v8::String> expected_name = 2547 v8::String::NewFromTwoByte(isolate, two_byte_name); 2548 CHECK(result->Equals(expected_name)); 2549 i::DeleteArray(two_byte_source); 2550 i::DeleteArray(two_byte_name); 2551} 2552