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 <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 #include "src/v8.h" 33 34 #include "src/ast-value-factory.h" 35 #include "src/compiler.h" 36 #include "src/execution.h" 37 #include "src/isolate.h" 38 #include "src/objects.h" 39 #include "src/parser.h" 40 #include "src/preparser.h" 41 #include "src/rewriter.h" 42 #include "src/scanner-character-streams.h" 43 #include "src/token.h" 44 #include "src/utils.h" 45 46 #include "test/cctest/cctest.h" 47 48 TEST(ScanKeywords) { 49 struct KeywordToken { 50 const char* keyword; 51 i::Token::Value token; 52 }; 53 54 static const KeywordToken keywords[] = { 55 #define KEYWORD(t, s, d) { s, i::Token::t }, 56 TOKEN_LIST(IGNORE_TOKEN, KEYWORD) 57 #undef KEYWORD 58 { NULL, i::Token::IDENTIFIER } 59 }; 60 61 KeywordToken key_token; 62 i::UnicodeCache unicode_cache; 63 i::byte buffer[32]; 64 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) { 65 const i::byte* keyword = 66 reinterpret_cast<const i::byte*>(key_token.keyword); 67 int length = i::StrLength(key_token.keyword); 68 CHECK(static_cast<int>(sizeof(buffer)) >= length); 69 { 70 i::Utf8ToUtf16CharacterStream stream(keyword, length); 71 i::Scanner scanner(&unicode_cache); 72 // The scanner should parse Harmony keywords for this test. 73 scanner.SetHarmonyScoping(true); 74 scanner.SetHarmonyModules(true); 75 scanner.SetHarmonyClasses(true); 76 scanner.Initialize(&stream); 77 CHECK_EQ(key_token.token, scanner.Next()); 78 CHECK_EQ(i::Token::EOS, scanner.Next()); 79 } 80 // Removing characters will make keyword matching fail. 81 { 82 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1); 83 i::Scanner scanner(&unicode_cache); 84 scanner.Initialize(&stream); 85 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next()); 86 CHECK_EQ(i::Token::EOS, scanner.Next()); 87 } 88 // Adding characters will make keyword matching fail. 89 static const char chars_to_append[] = { 'z', '0', '_' }; 90 for (int j = 0; j < static_cast<int>(arraysize(chars_to_append)); ++j) { 91 i::MemMove(buffer, keyword, length); 92 buffer[length] = chars_to_append[j]; 93 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1); 94 i::Scanner scanner(&unicode_cache); 95 scanner.Initialize(&stream); 96 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next()); 97 CHECK_EQ(i::Token::EOS, scanner.Next()); 98 } 99 // Replacing characters will make keyword matching fail. 100 { 101 i::MemMove(buffer, keyword, length); 102 buffer[length - 1] = '_'; 103 i::Utf8ToUtf16CharacterStream stream(buffer, length); 104 i::Scanner scanner(&unicode_cache); 105 scanner.Initialize(&stream); 106 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next()); 107 CHECK_EQ(i::Token::EOS, scanner.Next()); 108 } 109 } 110 } 111 112 113 TEST(ScanHTMLEndComments) { 114 v8::V8::Initialize(); 115 v8::Isolate* isolate = CcTest::isolate(); 116 v8::HandleScope handles(isolate); 117 118 // Regression test. See: 119 // http://code.google.com/p/chromium/issues/detail?id=53548 120 // Tests that --> is correctly interpreted as comment-to-end-of-line if there 121 // is only whitespace before it on the line (with comments considered as 122 // whitespace, even a multiline-comment containing a newline). 123 // This was not the case if it occurred before the first real token 124 // in the input. 125 const char* tests[] = { 126 // Before first real token. 127 "--> is eol-comment\nvar y = 37;\n", 128 "\n --> is eol-comment\nvar y = 37;\n", 129 "/* precomment */ --> is eol-comment\nvar y = 37;\n", 130 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n", 131 // After first real token. 132 "var x = 42;\n--> is eol-comment\nvar y = 37;\n", 133 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n", 134 NULL 135 }; 136 137 const char* fail_tests[] = { 138 "x --> is eol-comment\nvar y = 37;\n", 139 "\"\\n\" --> is eol-comment\nvar y = 37;\n", 140 "x/* precomment */ --> is eol-comment\nvar y = 37;\n", 141 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n", 142 "var x = 42; --> is eol-comment\nvar y = 37;\n", 143 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n", 144 NULL 145 }; 146 147 // Parser/Scanner needs a stack limit. 148 CcTest::i_isolate()->stack_guard()->SetStackLimit( 149 i::GetCurrentStackPosition() - 128 * 1024); 150 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 151 for (int i = 0; tests[i]; i++) { 152 const i::byte* source = 153 reinterpret_cast<const i::byte*>(tests[i]); 154 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i])); 155 i::CompleteParserRecorder log; 156 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 157 scanner.Initialize(&stream); 158 i::PreParser preparser(&scanner, &log, stack_limit); 159 preparser.set_allow_lazy(true); 160 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 161 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 162 CHECK(!log.HasError()); 163 } 164 165 for (int i = 0; fail_tests[i]; i++) { 166 const i::byte* source = 167 reinterpret_cast<const i::byte*>(fail_tests[i]); 168 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i])); 169 i::CompleteParserRecorder log; 170 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 171 scanner.Initialize(&stream); 172 i::PreParser preparser(&scanner, &log, stack_limit); 173 preparser.set_allow_lazy(true); 174 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 175 // Even in the case of a syntax error, kPreParseSuccess is returned. 176 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 177 CHECK(log.HasError()); 178 } 179 } 180 181 182 class ScriptResource : public v8::String::ExternalOneByteStringResource { 183 public: 184 ScriptResource(const char* data, size_t length) 185 : data_(data), length_(length) { } 186 187 const char* data() const { return data_; } 188 size_t length() const { return length_; } 189 190 private: 191 const char* data_; 192 size_t length_; 193 }; 194 195 196 TEST(UsingCachedData) { 197 v8::Isolate* isolate = CcTest::isolate(); 198 v8::HandleScope handles(isolate); 199 v8::Local<v8::Context> context = v8::Context::New(isolate); 200 v8::Context::Scope context_scope(context); 201 CcTest::i_isolate()->stack_guard()->SetStackLimit( 202 i::GetCurrentStackPosition() - 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 "var f = a => function (b) { return a + b; };" 218 "var g = a => b => a + b;"; 219 int source_length = i::StrLength(source); 220 221 // ScriptResource will be deleted when the corresponding String is GCd. 222 v8::ScriptCompiler::Source script_source(v8::String::NewExternal( 223 isolate, new ScriptResource(source, source_length))); 224 i::FLAG_harmony_arrow_functions = true; 225 i::FLAG_min_preparse_length = 0; 226 v8::ScriptCompiler::Compile(isolate, &script_source, 227 v8::ScriptCompiler::kProduceParserCache); 228 CHECK(script_source.GetCachedData()); 229 230 // Compile the script again, using the cached data. 231 bool lazy_flag = i::FLAG_lazy; 232 i::FLAG_lazy = true; 233 v8::ScriptCompiler::Compile(isolate, &script_source, 234 v8::ScriptCompiler::kConsumeParserCache); 235 i::FLAG_lazy = false; 236 v8::ScriptCompiler::CompileUnbound(isolate, &script_source, 237 v8::ScriptCompiler::kConsumeParserCache); 238 i::FLAG_lazy = lazy_flag; 239 } 240 241 242 TEST(PreparseFunctionDataIsUsed) { 243 // This tests that we actually do use the function data generated by the 244 // preparser. 245 246 // Make preparsing work for short scripts. 247 i::FLAG_min_preparse_length = 0; 248 i::FLAG_harmony_arrow_functions = true; 249 250 v8::Isolate* isolate = CcTest::isolate(); 251 v8::HandleScope handles(isolate); 252 v8::Local<v8::Context> context = v8::Context::New(isolate); 253 v8::Context::Scope context_scope(context); 254 CcTest::i_isolate()->stack_guard()->SetStackLimit( 255 i::GetCurrentStackPosition() - 128 * 1024); 256 257 const char* good_code[] = { 258 "function this_is_lazy() { var a; } function foo() { return 25; } foo();", 259 "var this_is_lazy = () => { var a; }; var foo = () => 25; foo();", 260 }; 261 262 // Insert a syntax error inside the lazy function. 263 const char* bad_code[] = { 264 "function this_is_lazy() { if ( } function foo() { return 25; } foo();", 265 "var this_is_lazy = () => { if ( }; var foo = () => 25; foo();", 266 }; 267 268 for (unsigned i = 0; i < arraysize(good_code); i++) { 269 v8::ScriptCompiler::Source good_source(v8_str(good_code[i])); 270 v8::ScriptCompiler::Compile(isolate, &good_source, 271 v8::ScriptCompiler::kProduceDataToCache); 272 273 const v8::ScriptCompiler::CachedData* cached_data = 274 good_source.GetCachedData(); 275 CHECK(cached_data->data != NULL); 276 CHECK_GT(cached_data->length, 0); 277 278 // Now compile the erroneous code with the good preparse data. If the 279 // preparse data is used, the lazy function is skipped and it should 280 // compile fine. 281 v8::ScriptCompiler::Source bad_source( 282 v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData( 283 cached_data->data, cached_data->length)); 284 v8::Local<v8::Value> result = 285 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run(); 286 CHECK(result->IsInt32()); 287 CHECK_EQ(25, result->Int32Value()); 288 } 289 } 290 291 292 TEST(StandAlonePreParser) { 293 v8::V8::Initialize(); 294 295 CcTest::i_isolate()->stack_guard()->SetStackLimit( 296 i::GetCurrentStackPosition() - 128 * 1024); 297 298 const char* programs[] = { 299 "{label: 42}", 300 "var x = 42;", 301 "function foo(x, y) { return x + y; }", 302 "%ArgleBargle(glop);", 303 "var x = new new Function('this.x = 42');", 304 "var f = (x, y) => x + y;", 305 NULL 306 }; 307 308 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 309 for (int i = 0; programs[i]; i++) { 310 const char* program = programs[i]; 311 i::Utf8ToUtf16CharacterStream stream( 312 reinterpret_cast<const i::byte*>(program), 313 static_cast<unsigned>(strlen(program))); 314 i::CompleteParserRecorder log; 315 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 316 scanner.Initialize(&stream); 317 318 i::PreParser preparser(&scanner, &log, stack_limit); 319 preparser.set_allow_lazy(true); 320 preparser.set_allow_natives_syntax(true); 321 preparser.set_allow_arrow_functions(true); 322 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 323 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 324 CHECK(!log.HasError()); 325 } 326 } 327 328 329 TEST(StandAlonePreParserNoNatives) { 330 v8::V8::Initialize(); 331 332 CcTest::i_isolate()->stack_guard()->SetStackLimit( 333 i::GetCurrentStackPosition() - 128 * 1024); 334 335 const char* programs[] = { 336 "%ArgleBargle(glop);", 337 "var x = %_IsSmi(42);", 338 NULL 339 }; 340 341 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 342 for (int i = 0; programs[i]; i++) { 343 const char* program = programs[i]; 344 i::Utf8ToUtf16CharacterStream stream( 345 reinterpret_cast<const i::byte*>(program), 346 static_cast<unsigned>(strlen(program))); 347 i::CompleteParserRecorder log; 348 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 349 scanner.Initialize(&stream); 350 351 // Preparser defaults to disallowing natives syntax. 352 i::PreParser preparser(&scanner, &log, stack_limit); 353 preparser.set_allow_lazy(true); 354 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 355 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 356 CHECK(log.HasError()); 357 } 358 } 359 360 361 TEST(PreparsingObjectLiterals) { 362 // Regression test for a bug where the symbol stream produced by PreParser 363 // didn't match what Parser wanted to consume. 364 v8::Isolate* isolate = CcTest::isolate(); 365 v8::HandleScope handles(isolate); 366 v8::Local<v8::Context> context = v8::Context::New(isolate); 367 v8::Context::Scope context_scope(context); 368 CcTest::i_isolate()->stack_guard()->SetStackLimit( 369 i::GetCurrentStackPosition() - 128 * 1024); 370 371 { 372 const char* source = "var myo = {if: \"foo\"}; myo.if;"; 373 v8::Local<v8::Value> result = ParserCacheCompileRun(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 = {\"bar\": \"foo\"}; myo[\"bar\"];"; 381 v8::Local<v8::Value> result = ParserCacheCompileRun(source); 382 CHECK(result->IsString()); 383 v8::String::Utf8Value utf8(result); 384 CHECK_EQ("foo", *utf8); 385 } 386 387 { 388 const char* source = "var myo = {1: \"foo\"}; myo[1];"; 389 v8::Local<v8::Value> result = ParserCacheCompileRun(source); 390 CHECK(result->IsString()); 391 v8::String::Utf8Value utf8(result); 392 CHECK_EQ("foo", *utf8); 393 } 394 } 395 396 397 TEST(RegressChromium62639) { 398 v8::V8::Initialize(); 399 i::Isolate* isolate = CcTest::i_isolate(); 400 401 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() - 402 128 * 1024); 403 404 const char* program = "var x = 'something';\n" 405 "escape: function() {}"; 406 // Fails parsing expecting an identifier after "function". 407 // Before fix, didn't check *ok after Expect(Token::Identifier, ok), 408 // and then used the invalid currently scanned literal. This always 409 // failed in debug mode, and sometimes crashed in release mode. 410 411 i::Utf8ToUtf16CharacterStream stream( 412 reinterpret_cast<const i::byte*>(program), 413 static_cast<unsigned>(strlen(program))); 414 i::CompleteParserRecorder log; 415 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 416 scanner.Initialize(&stream); 417 i::PreParser preparser(&scanner, &log, 418 CcTest::i_isolate()->stack_guard()->real_climit()); 419 preparser.set_allow_lazy(true); 420 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 421 // Even in the case of a syntax error, kPreParseSuccess is returned. 422 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 423 CHECK(log.HasError()); 424 } 425 426 427 TEST(Regress928) { 428 v8::V8::Initialize(); 429 i::Isolate* isolate = CcTest::i_isolate(); 430 i::Factory* factory = isolate->factory(); 431 432 // Preparsing didn't consider the catch clause of a try statement 433 // as with-content, which made it assume that a function inside 434 // the block could be lazily compiled, and an extra, unexpected, 435 // entry was added to the data. 436 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() - 437 128 * 1024); 438 439 const char* program = 440 "try { } catch (e) { var foo = function () { /* first */ } }" 441 "var bar = function () { /* second */ }"; 442 443 v8::HandleScope handles(CcTest::isolate()); 444 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program); 445 i::GenericStringUtf16CharacterStream stream(source, 0, source->length()); 446 i::CompleteParserRecorder log; 447 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 448 scanner.Initialize(&stream); 449 i::PreParser preparser(&scanner, &log, 450 CcTest::i_isolate()->stack_guard()->real_climit()); 451 preparser.set_allow_lazy(true); 452 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 453 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 454 i::ScriptData* sd = log.GetScriptData(); 455 i::ParseData pd(sd); 456 pd.Initialize(); 457 458 int first_function = 459 static_cast<int>(strstr(program, "function") - program); 460 int first_lbrace = first_function + i::StrLength("function () "); 461 CHECK_EQ('{', program[first_lbrace]); 462 i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace); 463 CHECK(!entry1.is_valid()); 464 465 int second_function = 466 static_cast<int>(strstr(program + first_lbrace, "function") - program); 467 int second_lbrace = 468 second_function + i::StrLength("function () "); 469 CHECK_EQ('{', program[second_lbrace]); 470 i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace); 471 CHECK(entry2.is_valid()); 472 CHECK_EQ('}', program[entry2.end_pos() - 1]); 473 delete sd; 474 } 475 476 477 TEST(PreParseOverflow) { 478 v8::V8::Initialize(); 479 480 CcTest::i_isolate()->stack_guard()->SetStackLimit( 481 i::GetCurrentStackPosition() - 128 * 1024); 482 483 size_t kProgramSize = 1024 * 1024; 484 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1)); 485 memset(program.get(), '(', kProgramSize); 486 program[kProgramSize] = '\0'; 487 488 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); 489 490 i::Utf8ToUtf16CharacterStream stream( 491 reinterpret_cast<const i::byte*>(program.get()), 492 static_cast<unsigned>(kProgramSize)); 493 i::CompleteParserRecorder log; 494 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 495 scanner.Initialize(&stream); 496 497 i::PreParser preparser(&scanner, &log, stack_limit); 498 preparser.set_allow_lazy(true); 499 preparser.set_allow_arrow_functions(true); 500 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 501 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result); 502 } 503 504 505 class TestExternalResource: public v8::String::ExternalStringResource { 506 public: 507 explicit TestExternalResource(uint16_t* data, int length) 508 : data_(data), length_(static_cast<size_t>(length)) { } 509 510 ~TestExternalResource() { } 511 512 const uint16_t* data() const { 513 return data_; 514 } 515 516 size_t length() const { 517 return length_; 518 } 519 private: 520 uint16_t* data_; 521 size_t length_; 522 }; 523 524 525 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2)) 526 527 void TestCharacterStream(const char* one_byte_source, unsigned length, 528 unsigned start = 0, unsigned end = 0) { 529 if (end == 0) end = length; 530 unsigned sub_length = end - start; 531 i::Isolate* isolate = CcTest::i_isolate(); 532 i::Factory* factory = isolate->factory(); 533 i::HandleScope test_scope(isolate); 534 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]); 535 for (unsigned i = 0; i < length; i++) { 536 uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]); 537 } 538 i::Vector<const char> one_byte_vector(one_byte_source, 539 static_cast<int>(length)); 540 i::Handle<i::String> one_byte_string = 541 factory->NewStringFromAscii(one_byte_vector).ToHandleChecked(); 542 TestExternalResource resource(uc16_buffer.get(), length); 543 i::Handle<i::String> uc16_string( 544 factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked()); 545 546 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream( 547 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end); 548 i::GenericStringUtf16CharacterStream string_stream(one_byte_string, start, 549 end); 550 i::Utf8ToUtf16CharacterStream utf8_stream( 551 reinterpret_cast<const i::byte*>(one_byte_source), end); 552 utf8_stream.SeekForward(start); 553 554 unsigned i = start; 555 while (i < end) { 556 // Read streams one char at a time 557 CHECK_EQU(i, uc16_stream.pos()); 558 CHECK_EQU(i, string_stream.pos()); 559 CHECK_EQU(i, utf8_stream.pos()); 560 int32_t c0 = one_byte_source[i]; 561 int32_t c1 = uc16_stream.Advance(); 562 int32_t c2 = string_stream.Advance(); 563 int32_t c3 = utf8_stream.Advance(); 564 i++; 565 CHECK_EQ(c0, c1); 566 CHECK_EQ(c0, c2); 567 CHECK_EQ(c0, c3); 568 CHECK_EQU(i, uc16_stream.pos()); 569 CHECK_EQU(i, string_stream.pos()); 570 CHECK_EQU(i, utf8_stream.pos()); 571 } 572 while (i > start + sub_length / 4) { 573 // Pushback, re-read, pushback again. 574 int32_t c0 = one_byte_source[i - 1]; 575 CHECK_EQU(i, uc16_stream.pos()); 576 CHECK_EQU(i, string_stream.pos()); 577 CHECK_EQU(i, utf8_stream.pos()); 578 uc16_stream.PushBack(c0); 579 string_stream.PushBack(c0); 580 utf8_stream.PushBack(c0); 581 i--; 582 CHECK_EQU(i, uc16_stream.pos()); 583 CHECK_EQU(i, string_stream.pos()); 584 CHECK_EQU(i, utf8_stream.pos()); 585 int32_t c1 = uc16_stream.Advance(); 586 int32_t c2 = string_stream.Advance(); 587 int32_t c3 = utf8_stream.Advance(); 588 i++; 589 CHECK_EQU(i, uc16_stream.pos()); 590 CHECK_EQU(i, string_stream.pos()); 591 CHECK_EQU(i, utf8_stream.pos()); 592 CHECK_EQ(c0, c1); 593 CHECK_EQ(c0, c2); 594 CHECK_EQ(c0, c3); 595 uc16_stream.PushBack(c0); 596 string_stream.PushBack(c0); 597 utf8_stream.PushBack(c0); 598 i--; 599 CHECK_EQU(i, uc16_stream.pos()); 600 CHECK_EQU(i, string_stream.pos()); 601 CHECK_EQU(i, utf8_stream.pos()); 602 } 603 unsigned halfway = start + sub_length / 2; 604 uc16_stream.SeekForward(halfway - i); 605 string_stream.SeekForward(halfway - i); 606 utf8_stream.SeekForward(halfway - i); 607 i = halfway; 608 CHECK_EQU(i, uc16_stream.pos()); 609 CHECK_EQU(i, string_stream.pos()); 610 CHECK_EQU(i, utf8_stream.pos()); 611 612 while (i < end) { 613 // Read streams one char at a time 614 CHECK_EQU(i, uc16_stream.pos()); 615 CHECK_EQU(i, string_stream.pos()); 616 CHECK_EQU(i, utf8_stream.pos()); 617 int32_t c0 = one_byte_source[i]; 618 int32_t c1 = uc16_stream.Advance(); 619 int32_t c2 = string_stream.Advance(); 620 int32_t c3 = utf8_stream.Advance(); 621 i++; 622 CHECK_EQ(c0, c1); 623 CHECK_EQ(c0, c2); 624 CHECK_EQ(c0, c3); 625 CHECK_EQU(i, uc16_stream.pos()); 626 CHECK_EQU(i, string_stream.pos()); 627 CHECK_EQU(i, utf8_stream.pos()); 628 } 629 630 int32_t c1 = uc16_stream.Advance(); 631 int32_t c2 = string_stream.Advance(); 632 int32_t c3 = utf8_stream.Advance(); 633 CHECK_LT(c1, 0); 634 CHECK_LT(c2, 0); 635 CHECK_LT(c3, 0); 636 } 637 638 639 TEST(CharacterStreams) { 640 v8::Isolate* isolate = CcTest::isolate(); 641 v8::HandleScope handles(isolate); 642 v8::Local<v8::Context> context = v8::Context::New(isolate); 643 v8::Context::Scope context_scope(context); 644 645 TestCharacterStream("abc\0\n\r\x7f", 7); 646 static const unsigned kBigStringSize = 4096; 647 char buffer[kBigStringSize + 1]; 648 for (unsigned i = 0; i < kBigStringSize; i++) { 649 buffer[i] = static_cast<char>(i & 0x7f); 650 } 651 TestCharacterStream(buffer, kBigStringSize); 652 653 TestCharacterStream(buffer, kBigStringSize, 576, 3298); 654 655 TestCharacterStream("\0", 1); 656 TestCharacterStream("", 0); 657 } 658 659 660 TEST(Utf8CharacterStream) { 661 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar; 662 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU); 663 664 static const int kAllUtf8CharsSize = 665 (unibrow::Utf8::kMaxOneByteChar + 1) + 666 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 + 667 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3; 668 static const unsigned kAllUtf8CharsSizeU = 669 static_cast<unsigned>(kAllUtf8CharsSize); 670 671 char buffer[kAllUtf8CharsSizeU]; 672 unsigned cursor = 0; 673 for (int i = 0; i <= kMaxUC16Char; i++) { 674 cursor += unibrow::Utf8::Encode(buffer + cursor, 675 i, 676 unibrow::Utf16::kNoPreviousCharacter); 677 } 678 DCHECK(cursor == kAllUtf8CharsSizeU); 679 680 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer), 681 kAllUtf8CharsSizeU); 682 for (int i = 0; i <= kMaxUC16Char; i++) { 683 CHECK_EQU(i, stream.pos()); 684 int32_t c = stream.Advance(); 685 CHECK_EQ(i, c); 686 CHECK_EQU(i + 1, stream.pos()); 687 } 688 for (int i = kMaxUC16Char; i >= 0; i--) { 689 CHECK_EQU(i + 1, stream.pos()); 690 stream.PushBack(i); 691 CHECK_EQU(i, stream.pos()); 692 } 693 int i = 0; 694 while (stream.pos() < kMaxUC16CharU) { 695 CHECK_EQU(i, stream.pos()); 696 unsigned progress = stream.SeekForward(12); 697 i += progress; 698 int32_t c = stream.Advance(); 699 if (i <= kMaxUC16Char) { 700 CHECK_EQ(i, c); 701 } else { 702 CHECK_EQ(-1, c); 703 } 704 i += 1; 705 CHECK_EQU(i, stream.pos()); 706 } 707 } 708 709 #undef CHECK_EQU 710 711 void TestStreamScanner(i::Utf16CharacterStream* stream, 712 i::Token::Value* expected_tokens, 713 int skip_pos = 0, // Zero means not skipping. 714 int skip_to = 0) { 715 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 716 scanner.Initialize(stream); 717 718 int i = 0; 719 do { 720 i::Token::Value expected = expected_tokens[i]; 721 i::Token::Value actual = scanner.Next(); 722 CHECK_EQ(i::Token::String(expected), i::Token::String(actual)); 723 if (scanner.location().end_pos == skip_pos) { 724 scanner.SeekForward(skip_to); 725 } 726 i++; 727 } while (expected_tokens[i] != i::Token::ILLEGAL); 728 } 729 730 731 TEST(StreamScanner) { 732 v8::V8::Initialize(); 733 734 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib"; 735 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1), 736 static_cast<unsigned>(strlen(str1))); 737 i::Token::Value expectations1[] = { 738 i::Token::LBRACE, 739 i::Token::IDENTIFIER, 740 i::Token::IDENTIFIER, 741 i::Token::FOR, 742 i::Token::COLON, 743 i::Token::MUL, 744 i::Token::DIV, 745 i::Token::LT, 746 i::Token::SUB, 747 i::Token::IDENTIFIER, 748 i::Token::EOS, 749 i::Token::ILLEGAL 750 }; 751 TestStreamScanner(&stream1, expectations1, 0, 0); 752 753 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do"; 754 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2), 755 static_cast<unsigned>(strlen(str2))); 756 i::Token::Value expectations2[] = { 757 i::Token::CASE, 758 i::Token::DEFAULT, 759 i::Token::CONST, 760 i::Token::LBRACE, 761 // Skipped part here 762 i::Token::RBRACE, 763 i::Token::DO, 764 i::Token::EOS, 765 i::Token::ILLEGAL 766 }; 767 DCHECK_EQ('{', str2[19]); 768 DCHECK_EQ('}', str2[37]); 769 TestStreamScanner(&stream2, expectations2, 20, 37); 770 771 const char* str3 = "{}}}}"; 772 i::Token::Value expectations3[] = { 773 i::Token::LBRACE, 774 i::Token::RBRACE, 775 i::Token::RBRACE, 776 i::Token::RBRACE, 777 i::Token::RBRACE, 778 i::Token::EOS, 779 i::Token::ILLEGAL 780 }; 781 // Skip zero-four RBRACEs. 782 for (int i = 0; i <= 4; i++) { 783 expectations3[6 - i] = i::Token::ILLEGAL; 784 expectations3[5 - i] = i::Token::EOS; 785 i::Utf8ToUtf16CharacterStream stream3( 786 reinterpret_cast<const i::byte*>(str3), 787 static_cast<unsigned>(strlen(str3))); 788 TestStreamScanner(&stream3, expectations3, 1, 1 + i); 789 } 790 } 791 792 793 void TestScanRegExp(const char* re_source, const char* expected) { 794 i::Utf8ToUtf16CharacterStream stream( 795 reinterpret_cast<const i::byte*>(re_source), 796 static_cast<unsigned>(strlen(re_source))); 797 i::HandleScope scope(CcTest::i_isolate()); 798 i::Scanner scanner(CcTest::i_isolate()->unicode_cache()); 799 scanner.Initialize(&stream); 800 801 i::Token::Value start = scanner.peek(); 802 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV); 803 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV)); 804 scanner.Next(); // Current token is now the regexp literal. 805 i::Zone zone(CcTest::i_isolate()); 806 i::AstValueFactory ast_value_factory(&zone, 807 CcTest::i_isolate()->heap()->HashSeed()); 808 ast_value_factory.Internalize(CcTest::i_isolate()); 809 i::Handle<i::String> val = 810 scanner.CurrentSymbol(&ast_value_factory)->string(); 811 i::DisallowHeapAllocation no_alloc; 812 i::String::FlatContent content = val->GetFlatContent(); 813 CHECK(content.IsOneByte()); 814 i::Vector<const uint8_t> actual = content.ToOneByteVector(); 815 for (int i = 0; i < actual.length(); i++) { 816 CHECK_NE('\0', expected[i]); 817 CHECK_EQ(expected[i], actual[i]); 818 } 819 } 820 821 822 TEST(RegExpScanning) { 823 v8::V8::Initialize(); 824 825 // RegExp token with added garbage at the end. The scanner should only 826 // scan the RegExp until the terminating slash just before "flipperwald". 827 TestScanRegExp("/b/flipperwald", "b"); 828 // Incomplete escape sequences doesn't hide the terminating slash. 829 TestScanRegExp("/\\x/flipperwald", "\\x"); 830 TestScanRegExp("/\\u/flipperwald", "\\u"); 831 TestScanRegExp("/\\u1/flipperwald", "\\u1"); 832 TestScanRegExp("/\\u12/flipperwald", "\\u12"); 833 TestScanRegExp("/\\u123/flipperwald", "\\u123"); 834 TestScanRegExp("/\\c/flipperwald", "\\c"); 835 TestScanRegExp("/\\c//flipperwald", "\\c"); 836 // Slashes inside character classes are not terminating. 837 TestScanRegExp("/[/]/flipperwald", "[/]"); 838 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]"); 839 // Incomplete escape sequences inside a character class doesn't hide 840 // the end of the character class. 841 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]"); 842 TestScanRegExp("/[\\c]/flipperwald", "[\\c]"); 843 TestScanRegExp("/[\\x]/flipperwald", "[\\x]"); 844 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]"); 845 TestScanRegExp("/[\\u]/flipperwald", "[\\u]"); 846 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]"); 847 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]"); 848 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]"); 849 // Escaped ']'s wont end the character class. 850 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]"); 851 // Escaped slashes are not terminating. 852 TestScanRegExp("/\\//flipperwald", "\\/"); 853 // Starting with '=' works too. 854 TestScanRegExp("/=/", "="); 855 TestScanRegExp("/=?/", "=?"); 856 } 857 858 859 static int Utf8LengthHelper(const char* s) { 860 int len = i::StrLength(s); 861 int character_length = len; 862 for (int i = 0; i < len; i++) { 863 unsigned char c = s[i]; 864 int input_offset = 0; 865 int output_adjust = 0; 866 if (c > 0x7f) { 867 if (c < 0xc0) continue; 868 if (c >= 0xf0) { 869 if (c >= 0xf8) { 870 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8 871 // byte. 872 continue; // Handle first UTF-8 byte. 873 } 874 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) { 875 // This 4 byte sequence could have been coded as a 3 byte sequence. 876 // Record a single kBadChar for the first byte and continue. 877 continue; 878 } 879 input_offset = 3; 880 // 4 bytes of UTF-8 turn into 2 UTF-16 code units. 881 character_length -= 2; 882 } else if (c >= 0xe0) { 883 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) { 884 // This 3 byte sequence could have been coded as a 2 byte sequence. 885 // Record a single kBadChar for the first byte and continue. 886 continue; 887 } 888 input_offset = 2; 889 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit. 890 output_adjust = 2; 891 } else { 892 if ((c & 0x1e) == 0) { 893 // This 2 byte sequence could have been coded as a 1 byte sequence. 894 // Record a single kBadChar for the first byte and continue. 895 continue; 896 } 897 input_offset = 1; 898 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit. 899 output_adjust = 1; 900 } 901 bool bad = false; 902 for (int j = 1; j <= input_offset; j++) { 903 if ((s[i + j] & 0xc0) != 0x80) { 904 // Bad UTF-8 sequence turns the first in the sequence into kBadChar, 905 // which is a single UTF-16 code unit. 906 bad = true; 907 break; 908 } 909 } 910 if (!bad) { 911 i += input_offset; 912 character_length -= output_adjust; 913 } 914 } 915 } 916 return character_length; 917 } 918 919 920 TEST(ScopePositions) { 921 v8::internal::FLAG_harmony_scoping = true; 922 923 // Test the parser for correctly setting the start and end positions 924 // of a scope. We check the scope positions of exactly one scope 925 // nested in the global scope of a program. 'inner source' is the 926 // source code that determines the part of the source belonging 927 // to the nested scope. 'outer_prefix' and 'outer_suffix' are 928 // parts of the source that belong to the global scope. 929 struct SourceData { 930 const char* outer_prefix; 931 const char* inner_source; 932 const char* outer_suffix; 933 i::ScopeType scope_type; 934 i::StrictMode strict_mode; 935 }; 936 937 const SourceData source_data[] = { 938 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY }, 939 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY }, 940 { " with ({}) ", "{\n" 941 " block;\n" 942 " }", "\n" 943 " more;", i::WITH_SCOPE, i::SLOPPY }, 944 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY }, 945 { " with ({}) ", "statement", "\n" 946 " more;", i::WITH_SCOPE, i::SLOPPY }, 947 { " with ({})\n" 948 " ", "statement;", "\n" 949 " more;", i::WITH_SCOPE, i::SLOPPY }, 950 { " try {} catch ", "(e) { block; }", " more;", 951 i::CATCH_SCOPE, i::SLOPPY }, 952 { " try {} catch ", "(e) { block; }", "; more;", 953 i::CATCH_SCOPE, i::SLOPPY }, 954 { " try {} catch ", "(e) {\n" 955 " block;\n" 956 " }", "\n" 957 " more;", i::CATCH_SCOPE, i::SLOPPY }, 958 { " try {} catch ", "(e) { block; }", " finally { block; } more;", 959 i::CATCH_SCOPE, i::SLOPPY }, 960 { " start;\n" 961 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT }, 962 { " start;\n" 963 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT }, 964 { " start;\n" 965 " ", "{\n" 966 " let block;\n" 967 " }", "\n" 968 " more;", i::BLOCK_SCOPE, i::STRICT }, 969 { " start;\n" 970 " function fun", "(a,b) { infunction; }", " more;", 971 i::FUNCTION_SCOPE, i::SLOPPY }, 972 { " start;\n" 973 " function fun", "(a,b) {\n" 974 " infunction;\n" 975 " }", "\n" 976 " more;", i::FUNCTION_SCOPE, i::SLOPPY }, 977 // TODO(aperez): Change to use i::ARROW_SCOPE when implemented 978 { " start;\n", "(a,b) => a + b", "; more;", 979 i::FUNCTION_SCOPE, i::SLOPPY }, 980 { " start;\n", "(a,b) => { return a+b; }", "\nmore;", 981 i::FUNCTION_SCOPE, i::SLOPPY }, 982 { " start;\n" 983 " (function fun", "(a,b) { infunction; }", ")();", 984 i::FUNCTION_SCOPE, i::SLOPPY }, 985 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;", 986 i::BLOCK_SCOPE, i::STRICT }, 987 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;", 988 i::BLOCK_SCOPE, i::STRICT }, 989 { " for ", "(let x = 1 ; x < 10; ++ x) {\n" 990 " block;\n" 991 " }", "\n" 992 " more;", i::BLOCK_SCOPE, i::STRICT }, 993 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;", 994 i::BLOCK_SCOPE, i::STRICT }, 995 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n" 996 " more;", i::BLOCK_SCOPE, i::STRICT }, 997 { " for ", "(let x = 1 ; x < 10; ++ x)\n" 998 " statement;", "\n" 999 " more;", i::BLOCK_SCOPE, i::STRICT }, 1000 { " for ", "(let x in {}) { block; }", " more;", 1001 i::BLOCK_SCOPE, i::STRICT }, 1002 { " for ", "(let x in {}) { block; }", "; more;", 1003 i::BLOCK_SCOPE, i::STRICT }, 1004 { " for ", "(let x in {}) {\n" 1005 " block;\n" 1006 " }", "\n" 1007 " more;", i::BLOCK_SCOPE, i::STRICT }, 1008 { " for ", "(let x in {}) statement;", " more;", 1009 i::BLOCK_SCOPE, i::STRICT }, 1010 { " for ", "(let x in {}) statement", "\n" 1011 " more;", i::BLOCK_SCOPE, i::STRICT }, 1012 { " for ", "(let x in {})\n" 1013 " statement;", "\n" 1014 " more;", i::BLOCK_SCOPE, i::STRICT }, 1015 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw 1016 // the preparser off in terms of byte offsets. 1017 // 6 byte encoding. 1018 { " 'foo\355\240\201\355\260\211';\n" 1019 " (function fun", "(a,b) { infunction; }", ")();", 1020 i::FUNCTION_SCOPE, i::SLOPPY }, 1021 // 4 byte encoding. 1022 { " 'foo\360\220\220\212';\n" 1023 " (function fun", "(a,b) { infunction; }", ")();", 1024 i::FUNCTION_SCOPE, i::SLOPPY }, 1025 // 3 byte encoding of \u0fff. 1026 { " 'foo\340\277\277';\n" 1027 " (function fun", "(a,b) { infunction; }", ")();", 1028 i::FUNCTION_SCOPE, i::SLOPPY }, 1029 // Broken 6 byte encoding with missing last byte. 1030 { " 'foo\355\240\201\355\211';\n" 1031 " (function fun", "(a,b) { infunction; }", ")();", 1032 i::FUNCTION_SCOPE, i::SLOPPY }, 1033 // Broken 3 byte encoding of \u0fff with missing last byte. 1034 { " 'foo\340\277';\n" 1035 " (function fun", "(a,b) { infunction; }", ")();", 1036 i::FUNCTION_SCOPE, i::SLOPPY }, 1037 // Broken 3 byte encoding of \u0fff with missing 2 last bytes. 1038 { " 'foo\340';\n" 1039 " (function fun", "(a,b) { infunction; }", ")();", 1040 i::FUNCTION_SCOPE, i::SLOPPY }, 1041 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding. 1042 { " 'foo\340\203\277';\n" 1043 " (function fun", "(a,b) { infunction; }", ")();", 1044 i::FUNCTION_SCOPE, i::SLOPPY }, 1045 // Broken 3 byte encoding of \u007f should be a 2 byte encoding. 1046 { " 'foo\340\201\277';\n" 1047 " (function fun", "(a,b) { infunction; }", ")();", 1048 i::FUNCTION_SCOPE, i::SLOPPY }, 1049 // Unpaired lead surrogate. 1050 { " 'foo\355\240\201';\n" 1051 " (function fun", "(a,b) { infunction; }", ")();", 1052 i::FUNCTION_SCOPE, i::SLOPPY }, 1053 // Unpaired lead surrogate where following code point is a 3 byte sequence. 1054 { " 'foo\355\240\201\340\277\277';\n" 1055 " (function fun", "(a,b) { infunction; }", ")();", 1056 i::FUNCTION_SCOPE, i::SLOPPY }, 1057 // Unpaired lead surrogate where following code point is a 4 byte encoding 1058 // of a trail surrogate. 1059 { " 'foo\355\240\201\360\215\260\211';\n" 1060 " (function fun", "(a,b) { infunction; }", ")();", 1061 i::FUNCTION_SCOPE, i::SLOPPY }, 1062 // Unpaired trail surrogate. 1063 { " 'foo\355\260\211';\n" 1064 " (function fun", "(a,b) { infunction; }", ")();", 1065 i::FUNCTION_SCOPE, i::SLOPPY }, 1066 // 2 byte encoding of \u00ff. 1067 { " 'foo\303\277';\n" 1068 " (function fun", "(a,b) { infunction; }", ")();", 1069 i::FUNCTION_SCOPE, i::SLOPPY }, 1070 // Broken 2 byte encoding of \u00ff with missing last byte. 1071 { " 'foo\303';\n" 1072 " (function fun", "(a,b) { infunction; }", ")();", 1073 i::FUNCTION_SCOPE, i::SLOPPY }, 1074 // Broken 2 byte encoding of \u007f should be a 1 byte encoding. 1075 { " 'foo\301\277';\n" 1076 " (function fun", "(a,b) { infunction; }", ")();", 1077 i::FUNCTION_SCOPE, i::SLOPPY }, 1078 // Illegal 5 byte encoding. 1079 { " 'foo\370\277\277\277\277';\n" 1080 " (function fun", "(a,b) { infunction; }", ")();", 1081 i::FUNCTION_SCOPE, i::SLOPPY }, 1082 // Illegal 6 byte encoding. 1083 { " 'foo\374\277\277\277\277\277';\n" 1084 " (function fun", "(a,b) { infunction; }", ")();", 1085 i::FUNCTION_SCOPE, i::SLOPPY }, 1086 // Illegal 0xfe byte 1087 { " 'foo\376\277\277\277\277\277\277';\n" 1088 " (function fun", "(a,b) { infunction; }", ")();", 1089 i::FUNCTION_SCOPE, i::SLOPPY }, 1090 // Illegal 0xff byte 1091 { " 'foo\377\277\277\277\277\277\277\277';\n" 1092 " (function fun", "(a,b) { infunction; }", ")();", 1093 i::FUNCTION_SCOPE, i::SLOPPY }, 1094 { " 'foo';\n" 1095 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();", 1096 i::FUNCTION_SCOPE, i::SLOPPY }, 1097 { " 'foo';\n" 1098 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();", 1099 i::FUNCTION_SCOPE, i::SLOPPY }, 1100 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY } 1101 }; 1102 1103 i::Isolate* isolate = CcTest::i_isolate(); 1104 i::Factory* factory = isolate->factory(); 1105 1106 v8::HandleScope handles(CcTest::isolate()); 1107 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); 1108 v8::Context::Scope context_scope(context); 1109 1110 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() - 1111 128 * 1024); 1112 1113 for (int i = 0; source_data[i].outer_prefix; i++) { 1114 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix); 1115 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source); 1116 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix); 1117 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix); 1118 int kInnerByteLen = i::StrLength(source_data[i].inner_source); 1119 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix); 1120 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen; 1121 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen; 1122 i::ScopedVector<char> program(kProgramByteSize + 1); 1123 i::SNPrintF(program, "%s%s%s", 1124 source_data[i].outer_prefix, 1125 source_data[i].inner_source, 1126 source_data[i].outer_suffix); 1127 1128 // Parse program source. 1129 i::Handle<i::String> source = factory->NewStringFromUtf8( 1130 i::CStrVector(program.start())).ToHandleChecked(); 1131 CHECK_EQ(source->length(), kProgramSize); 1132 i::Handle<i::Script> script = factory->NewScript(source); 1133 i::CompilationInfoWithZone info(script); 1134 i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(), 1135 isolate->heap()->HashSeed(), 1136 isolate->unicode_cache()}; 1137 i::Parser parser(&info, &parse_info); 1138 parser.set_allow_lazy(true); 1139 parser.set_allow_harmony_scoping(true); 1140 parser.set_allow_arrow_functions(true); 1141 info.MarkAsGlobal(); 1142 info.SetStrictMode(source_data[i].strict_mode); 1143 parser.Parse(); 1144 CHECK(info.function() != NULL); 1145 1146 // Check scope types and positions. 1147 i::Scope* scope = info.function()->scope(); 1148 CHECK(scope->is_global_scope()); 1149 CHECK_EQ(scope->start_position(), 0); 1150 CHECK_EQ(scope->end_position(), kProgramSize); 1151 CHECK_EQ(scope->inner_scopes()->length(), 1); 1152 1153 i::Scope* inner_scope = scope->inner_scopes()->at(0); 1154 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type); 1155 CHECK_EQ(inner_scope->start_position(), kPrefixLen); 1156 // The end position of a token is one position after the last 1157 // character belonging to that token. 1158 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen); 1159 } 1160 } 1161 1162 1163 const char* ReadString(unsigned* start) { 1164 int length = start[0]; 1165 char* result = i::NewArray<char>(length + 1); 1166 for (int i = 0; i < length; i++) { 1167 result[i] = start[i + 1]; 1168 } 1169 result[length] = '\0'; 1170 return result; 1171 } 1172 1173 1174 i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) { 1175 i::Isolate* isolate = CcTest::i_isolate(); 1176 i::Factory* factory = isolate->factory(); 1177 const char* message = 1178 ReadString(&data[i::PreparseDataConstants::kMessageTextPos]); 1179 i::Handle<i::String> format = v8::Utils::OpenHandle( 1180 *v8::String::NewFromUtf8(CcTest::isolate(), message)); 1181 int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos]; 1182 const char* arg = NULL; 1183 i::Handle<i::JSArray> args_array; 1184 if (arg_count == 1) { 1185 // Position after text found by skipping past length field and 1186 // length field content words. 1187 int pos = i::PreparseDataConstants::kMessageTextPos + 1 + 1188 data[i::PreparseDataConstants::kMessageTextPos]; 1189 arg = ReadString(&data[pos]); 1190 args_array = factory->NewJSArray(1); 1191 i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)), 1192 NONE, i::SLOPPY).Check(); 1193 } else { 1194 CHECK_EQ(0, arg_count); 1195 args_array = factory->NewJSArray(0); 1196 } 1197 1198 i::Handle<i::JSObject> builtins(isolate->js_builtins_object()); 1199 i::Handle<i::Object> format_fun = i::Object::GetProperty( 1200 isolate, builtins, "FormatMessage").ToHandleChecked(); 1201 i::Handle<i::Object> arg_handles[] = { format, args_array }; 1202 i::Handle<i::Object> result = i::Execution::Call( 1203 isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked(); 1204 CHECK(result->IsString()); 1205 i::DeleteArray(message); 1206 i::DeleteArray(arg); 1207 data.Dispose(); 1208 return i::Handle<i::String>::cast(result); 1209 } 1210 1211 1212 enum ParserFlag { 1213 kAllowLazy, 1214 kAllowNativesSyntax, 1215 kAllowHarmonyScoping, 1216 kAllowModules, 1217 kAllowHarmonyNumericLiterals, 1218 kAllowArrowFunctions, 1219 kAllowClasses, 1220 kAllowHarmonyObjectLiterals 1221 }; 1222 1223 1224 enum ParserSyncTestResult { 1225 kSuccessOrError, 1226 kSuccess, 1227 kError 1228 }; 1229 1230 template <typename Traits> 1231 void SetParserFlags(i::ParserBase<Traits>* parser, 1232 i::EnumSet<ParserFlag> flags) { 1233 parser->set_allow_lazy(flags.Contains(kAllowLazy)); 1234 parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax)); 1235 parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping)); 1236 parser->set_allow_modules(flags.Contains(kAllowModules)); 1237 parser->set_allow_harmony_numeric_literals( 1238 flags.Contains(kAllowHarmonyNumericLiterals)); 1239 parser->set_allow_harmony_object_literals( 1240 flags.Contains(kAllowHarmonyObjectLiterals)); 1241 parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions)); 1242 parser->set_allow_classes(flags.Contains(kAllowClasses)); 1243 } 1244 1245 1246 void TestParserSyncWithFlags(i::Handle<i::String> source, 1247 i::EnumSet<ParserFlag> flags, 1248 ParserSyncTestResult result) { 1249 i::Isolate* isolate = CcTest::i_isolate(); 1250 i::Factory* factory = isolate->factory(); 1251 1252 uintptr_t stack_limit = isolate->stack_guard()->real_climit(); 1253 1254 // Preparse the data. 1255 i::CompleteParserRecorder log; 1256 { 1257 i::Scanner scanner(isolate->unicode_cache()); 1258 i::GenericStringUtf16CharacterStream stream(source, 0, source->length()); 1259 i::PreParser preparser(&scanner, &log, stack_limit); 1260 SetParserFlags(&preparser, flags); 1261 scanner.Initialize(&stream); 1262 i::PreParser::PreParseResult result = preparser.PreParseProgram(); 1263 CHECK_EQ(i::PreParser::kPreParseSuccess, result); 1264 } 1265 1266 bool preparse_error = log.HasError(); 1267 1268 // Parse the data 1269 i::FunctionLiteral* function; 1270 { 1271 i::Handle<i::Script> script = factory->NewScript(source); 1272 i::CompilationInfoWithZone info(script); 1273 i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(), 1274 isolate->heap()->HashSeed(), 1275 isolate->unicode_cache()}; 1276 i::Parser parser(&info, &parse_info); 1277 SetParserFlags(&parser, flags); 1278 info.MarkAsGlobal(); 1279 parser.Parse(); 1280 function = info.function(); 1281 } 1282 1283 // Check that preparsing fails iff parsing fails. 1284 if (function == NULL) { 1285 // Extract exception from the parser. 1286 CHECK(isolate->has_pending_exception()); 1287 i::Handle<i::JSObject> exception_handle( 1288 i::JSObject::cast(isolate->pending_exception())); 1289 i::Handle<i::String> message_string = 1290 i::Handle<i::String>::cast(i::Object::GetProperty( 1291 isolate, exception_handle, "message").ToHandleChecked()); 1292 1293 if (result == kSuccess) { 1294 v8::base::OS::Print( 1295 "Parser failed on:\n" 1296 "\t%s\n" 1297 "with error:\n" 1298 "\t%s\n" 1299 "However, we expected no error.", 1300 source->ToCString().get(), message_string->ToCString().get()); 1301 CHECK(false); 1302 } 1303 1304 if (!preparse_error) { 1305 v8::base::OS::Print( 1306 "Parser failed on:\n" 1307 "\t%s\n" 1308 "with error:\n" 1309 "\t%s\n" 1310 "However, the preparser succeeded", 1311 source->ToCString().get(), message_string->ToCString().get()); 1312 CHECK(false); 1313 } 1314 // Check that preparser and parser produce the same error. 1315 i::Handle<i::String> preparser_message = 1316 FormatMessage(log.ErrorMessageData()); 1317 if (!i::String::Equals(message_string, preparser_message)) { 1318 v8::base::OS::Print( 1319 "Expected parser and preparser to produce the same error on:\n" 1320 "\t%s\n" 1321 "However, found the following error messages\n" 1322 "\tparser: %s\n" 1323 "\tpreparser: %s\n", 1324 source->ToCString().get(), 1325 message_string->ToCString().get(), 1326 preparser_message->ToCString().get()); 1327 CHECK(false); 1328 } 1329 } else if (preparse_error) { 1330 v8::base::OS::Print( 1331 "Preparser failed on:\n" 1332 "\t%s\n" 1333 "with error:\n" 1334 "\t%s\n" 1335 "However, the parser succeeded", 1336 source->ToCString().get(), 1337 FormatMessage(log.ErrorMessageData())->ToCString().get()); 1338 CHECK(false); 1339 } else if (result == kError) { 1340 v8::base::OS::Print( 1341 "Expected error on:\n" 1342 "\t%s\n" 1343 "However, parser and preparser succeeded", 1344 source->ToCString().get()); 1345 CHECK(false); 1346 } 1347 } 1348 1349 1350 void TestParserSync(const char* source, 1351 const ParserFlag* varying_flags, 1352 size_t varying_flags_length, 1353 ParserSyncTestResult result = kSuccessOrError, 1354 const ParserFlag* always_true_flags = NULL, 1355 size_t always_true_flags_length = 0) { 1356 i::Handle<i::String> str = 1357 CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source); 1358 for (int bits = 0; bits < (1 << varying_flags_length); bits++) { 1359 i::EnumSet<ParserFlag> flags; 1360 for (size_t flag_index = 0; flag_index < varying_flags_length; 1361 ++flag_index) { 1362 if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]); 1363 } 1364 for (size_t flag_index = 0; flag_index < always_true_flags_length; 1365 ++flag_index) { 1366 flags.Add(always_true_flags[flag_index]); 1367 } 1368 TestParserSyncWithFlags(str, flags, result); 1369 } 1370 } 1371 1372 1373 TEST(ParserSync) { 1374 const char* context_data[][2] = { 1375 { "", "" }, 1376 { "{", "}" }, 1377 { "if (true) ", " else {}" }, 1378 { "if (true) {} else ", "" }, 1379 { "if (true) ", "" }, 1380 { "do ", " while (false)" }, 1381 { "while (false) ", "" }, 1382 { "for (;;) ", "" }, 1383 { "with ({})", "" }, 1384 { "switch (12) { case 12: ", "}" }, 1385 { "switch (12) { default: ", "}" }, 1386 { "switch (12) { ", "case 12: }" }, 1387 { "label2: ", "" }, 1388 { NULL, NULL } 1389 }; 1390 1391 const char* statement_data[] = { 1392 "{}", 1393 "var x", 1394 "var x = 1", 1395 "const x", 1396 "const x = 1", 1397 ";", 1398 "12", 1399 "if (false) {} else ;", 1400 "if (false) {} else {}", 1401 "if (false) {} else 12", 1402 "if (false) ;" 1403 "if (false) {}", 1404 "if (false) 12", 1405 "do {} while (false)", 1406 "for (;;) ;", 1407 "for (;;) {}", 1408 "for (;;) 12", 1409 "continue", 1410 "continue label", 1411 "continue\nlabel", 1412 "break", 1413 "break label", 1414 "break\nlabel", 1415 // TODO(marja): activate once parsing 'return' is merged into ParserBase. 1416 // "return", 1417 // "return 12", 1418 // "return\n12", 1419 "with ({}) ;", 1420 "with ({}) {}", 1421 "with ({}) 12", 1422 "switch ({}) { default: }" 1423 "label3: " 1424 "throw", 1425 "throw 12", 1426 "throw\n12", 1427 "try {} catch(e) {}", 1428 "try {} finally {}", 1429 "try {} catch(e) {} finally {}", 1430 "debugger", 1431 NULL 1432 }; 1433 1434 const char* termination_data[] = { 1435 "", 1436 ";", 1437 "\n", 1438 ";\n", 1439 "\n;", 1440 NULL 1441 }; 1442 1443 v8::HandleScope handles(CcTest::isolate()); 1444 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); 1445 v8::Context::Scope context_scope(context); 1446 1447 CcTest::i_isolate()->stack_guard()->SetStackLimit( 1448 i::GetCurrentStackPosition() - 128 * 1024); 1449 1450 static const ParserFlag flags1[] = { 1451 kAllowArrowFunctions, 1452 kAllowClasses, 1453 kAllowHarmonyNumericLiterals, 1454 kAllowHarmonyObjectLiterals, 1455 kAllowHarmonyScoping, 1456 kAllowLazy, 1457 kAllowModules, 1458 }; 1459 1460 for (int i = 0; context_data[i][0] != NULL; ++i) { 1461 for (int j = 0; statement_data[j] != NULL; ++j) { 1462 for (int k = 0; termination_data[k] != NULL; ++k) { 1463 int kPrefixLen = i::StrLength(context_data[i][0]); 1464 int kStatementLen = i::StrLength(statement_data[j]); 1465 int kTerminationLen = i::StrLength(termination_data[k]); 1466 int kSuffixLen = i::StrLength(context_data[i][1]); 1467 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen 1468 + kSuffixLen + i::StrLength("label: for (;;) { }"); 1469 1470 // Plug the source code pieces together. 1471 i::ScopedVector<char> program(kProgramSize + 1); 1472 int length = i::SNPrintF(program, 1473 "label: for (;;) { %s%s%s%s }", 1474 context_data[i][0], 1475 statement_data[j], 1476 termination_data[k], 1477 context_data[i][1]); 1478 CHECK(length == kProgramSize); 1479 TestParserSync(program.start(), flags1, arraysize(flags1)); 1480 } 1481 } 1482 } 1483 1484 // Neither Harmony numeric literals nor our natives syntax have any 1485 // interaction with the flags above, so test these separately to reduce 1486 // the combinatorial explosion. 1487 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals }; 1488 TestParserSync("0o1234", flags2, arraysize(flags2)); 1489 TestParserSync("0b1011", flags2, arraysize(flags2)); 1490 1491 static const ParserFlag flags3[] = { kAllowNativesSyntax }; 1492 TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3)); 1493 } 1494 1495 1496 TEST(StrictOctal) { 1497 // Test that syntax error caused by octal literal is reported correctly as 1498 // such (issue 2220). 1499 v8::V8::Initialize(); 1500 v8::HandleScope scope(CcTest::isolate()); 1501 v8::Context::Scope context_scope( 1502 v8::Context::New(CcTest::isolate())); 1503 v8::TryCatch try_catch; 1504 const char* script = 1505 "\"use strict\"; \n" 1506 "a = function() { \n" 1507 " b = function() { \n" 1508 " 01; \n" 1509 " }; \n" 1510 "}; \n"; 1511 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script)); 1512 CHECK(try_catch.HasCaught()); 1513 v8::String::Utf8Value exception(try_catch.Exception()); 1514 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.", 1515 *exception); 1516 } 1517 1518 1519 void RunParserSyncTest(const char* context_data[][2], 1520 const char* statement_data[], 1521 ParserSyncTestResult result, 1522 const ParserFlag* flags = NULL, 1523 int flags_len = 0, 1524 const ParserFlag* always_true_flags = NULL, 1525 int always_true_flags_len = 0) { 1526 v8::HandleScope handles(CcTest::isolate()); 1527 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); 1528 v8::Context::Scope context_scope(context); 1529 1530 CcTest::i_isolate()->stack_guard()->SetStackLimit( 1531 i::GetCurrentStackPosition() - 128 * 1024); 1532 1533 static const ParserFlag default_flags[] = { 1534 kAllowArrowFunctions, 1535 kAllowClasses, 1536 kAllowHarmonyNumericLiterals, 1537 kAllowHarmonyObjectLiterals, 1538 kAllowHarmonyScoping, 1539 kAllowLazy, 1540 kAllowModules, 1541 kAllowNativesSyntax, 1542 }; 1543 ParserFlag* generated_flags = NULL; 1544 if (flags == NULL) { 1545 flags = default_flags; 1546 flags_len = arraysize(default_flags); 1547 if (always_true_flags != NULL) { 1548 // Remove always_true_flags from default_flags. 1549 CHECK(always_true_flags_len < flags_len); 1550 generated_flags = new ParserFlag[flags_len - always_true_flags_len]; 1551 int flag_index = 0; 1552 for (int i = 0; i < flags_len; ++i) { 1553 bool use_flag = true; 1554 for (int j = 0; j < always_true_flags_len; ++j) { 1555 if (flags[i] == always_true_flags[j]) { 1556 use_flag = false; 1557 break; 1558 } 1559 } 1560 if (use_flag) generated_flags[flag_index++] = flags[i]; 1561 } 1562 CHECK(flag_index == flags_len - always_true_flags_len); 1563 flags_len = flag_index; 1564 flags = generated_flags; 1565 } 1566 } 1567 for (int i = 0; context_data[i][0] != NULL; ++i) { 1568 for (int j = 0; statement_data[j] != NULL; ++j) { 1569 int kPrefixLen = i::StrLength(context_data[i][0]); 1570 int kStatementLen = i::StrLength(statement_data[j]); 1571 int kSuffixLen = i::StrLength(context_data[i][1]); 1572 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen; 1573 1574 // Plug the source code pieces together. 1575 i::ScopedVector<char> program(kProgramSize + 1); 1576 int length = i::SNPrintF(program, 1577 "%s%s%s", 1578 context_data[i][0], 1579 statement_data[j], 1580 context_data[i][1]); 1581 CHECK(length == kProgramSize); 1582 TestParserSync(program.start(), 1583 flags, 1584 flags_len, 1585 result, 1586 always_true_flags, 1587 always_true_flags_len); 1588 } 1589 } 1590 delete[] generated_flags; 1591 } 1592 1593 1594 TEST(ErrorsEvalAndArguments) { 1595 // Tests that both preparsing and parsing produce the right kind of errors for 1596 // using "eval" and "arguments" as identifiers. Without the strict mode, it's 1597 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it 1598 // isn't. 1599 const char* context_data[][2] = { 1600 { "\"use strict\";", "" }, 1601 { "var eval; function test_func() {\"use strict\"; ", "}"}, 1602 { NULL, NULL } 1603 }; 1604 1605 const char* statement_data[] = { 1606 "var eval;", 1607 "var arguments", 1608 "var foo, eval;", 1609 "var foo, arguments;", 1610 "try { } catch (eval) { }", 1611 "try { } catch (arguments) { }", 1612 "function eval() { }", 1613 "function arguments() { }", 1614 "function foo(eval) { }", 1615 "function foo(arguments) { }", 1616 "function foo(bar, eval) { }", 1617 "function foo(bar, arguments) { }", 1618 "(eval) => { }", 1619 "(arguments) => { }", 1620 "(foo, eval) => { }", 1621 "(foo, arguments) => { }", 1622 "eval = 1;", 1623 "arguments = 1;", 1624 "var foo = eval = 1;", 1625 "var foo = arguments = 1;", 1626 "++eval;", 1627 "++arguments;", 1628 "eval++;", 1629 "arguments++;", 1630 NULL 1631 }; 1632 1633 RunParserSyncTest(context_data, statement_data, kError); 1634 } 1635 1636 1637 TEST(NoErrorsEvalAndArgumentsSloppy) { 1638 // Tests that both preparsing and parsing accept "eval" and "arguments" as 1639 // identifiers when needed. 1640 const char* context_data[][2] = { 1641 { "", "" }, 1642 { "function test_func() {", "}"}, 1643 { NULL, NULL } 1644 }; 1645 1646 const char* statement_data[] = { 1647 "var eval;", 1648 "var arguments", 1649 "var foo, eval;", 1650 "var foo, arguments;", 1651 "try { } catch (eval) { }", 1652 "try { } catch (arguments) { }", 1653 "function eval() { }", 1654 "function arguments() { }", 1655 "function foo(eval) { }", 1656 "function foo(arguments) { }", 1657 "function foo(bar, eval) { }", 1658 "function foo(bar, arguments) { }", 1659 "eval = 1;", 1660 "arguments = 1;", 1661 "var foo = eval = 1;", 1662 "var foo = arguments = 1;", 1663 "++eval;", 1664 "++arguments;", 1665 "eval++;", 1666 "arguments++;", 1667 NULL 1668 }; 1669 1670 RunParserSyncTest(context_data, statement_data, kSuccess); 1671 } 1672 1673 1674 TEST(NoErrorsEvalAndArgumentsStrict) { 1675 const char* context_data[][2] = { 1676 { "\"use strict\";", "" }, 1677 { "function test_func() { \"use strict\";", "}" }, 1678 { "() => { \"use strict\"; ", "}" }, 1679 { NULL, NULL } 1680 }; 1681 1682 const char* statement_data[] = { 1683 "eval;", 1684 "arguments;", 1685 "var foo = eval;", 1686 "var foo = arguments;", 1687 "var foo = { eval: 1 };", 1688 "var foo = { arguments: 1 };", 1689 "var foo = { }; foo.eval = {};", 1690 "var foo = { }; foo.arguments = {};", 1691 NULL 1692 }; 1693 1694 static const ParserFlag always_flags[] = {kAllowArrowFunctions}; 1695 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, 1696 always_flags, arraysize(always_flags)); 1697 } 1698 1699 1700 TEST(ErrorsFutureStrictReservedWords) { 1701 // Tests that both preparsing and parsing produce the right kind of errors for 1702 // using future strict reserved words as identifiers. Without the strict mode, 1703 // it's ok to use future strict reserved words as identifiers. With the strict 1704 // mode, it isn't. 1705 const char* context_data[][2] = { 1706 { "\"use strict\";", "" }, 1707 { "function test_func() {\"use strict\"; ", "}"}, 1708 { "() => { \"use strict\"; ", "}" }, 1709 { NULL, NULL } 1710 }; 1711 1712 const char* statement_data[] = { 1713 "var interface;", 1714 "var foo, interface;", 1715 "try { } catch (interface) { }", 1716 "function interface() { }", 1717 "function foo(interface) { }", 1718 "function foo(bar, interface) { }", 1719 "interface = 1;", 1720 "var foo = interface = 1;", 1721 "++interface;", 1722 "interface++;", 1723 "var yield = 13;", 1724 NULL 1725 }; 1726 1727 static const ParserFlag always_flags[] = {kAllowArrowFunctions}; 1728 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, 1729 arraysize(always_flags)); 1730 } 1731 1732 1733 TEST(NoErrorsFutureStrictReservedWords) { 1734 const char* context_data[][2] = { 1735 { "", "" }, 1736 { "function test_func() {", "}"}, 1737 { "() => {", "}" }, 1738 { NULL, NULL } 1739 }; 1740 1741 const char* statement_data[] = { 1742 "var interface;", 1743 "var foo, interface;", 1744 "try { } catch (interface) { }", 1745 "function interface() { }", 1746 "function foo(interface) { }", 1747 "function foo(bar, interface) { }", 1748 "interface = 1;", 1749 "var foo = interface = 1;", 1750 "++interface;", 1751 "interface++;", 1752 "var yield = 13;", 1753 NULL 1754 }; 1755 1756 static const ParserFlag always_flags[] = {kAllowArrowFunctions}; 1757 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, 1758 always_flags, arraysize(always_flags)); 1759 } 1760 1761 1762 TEST(ErrorsReservedWords) { 1763 // Tests that both preparsing and parsing produce the right kind of errors for 1764 // using future reserved words as identifiers. These tests don't depend on the 1765 // strict mode. 1766 const char* context_data[][2] = { 1767 { "", "" }, 1768 { "\"use strict\";", "" }, 1769 { "var eval; function test_func() {", "}"}, 1770 { "var eval; function test_func() {\"use strict\"; ", "}"}, 1771 { "var eval; () => {", "}"}, 1772 { "var eval; () => {\"use strict\"; ", "}"}, 1773 { NULL, NULL } 1774 }; 1775 1776 const char* statement_data[] = { 1777 "var super;", 1778 "var foo, super;", 1779 "try { } catch (super) { }", 1780 "function super() { }", 1781 "function foo(super) { }", 1782 "function foo(bar, super) { }", 1783 "(super) => { }", 1784 "(bar, super) => { }", 1785 "super = 1;", 1786 "var foo = super = 1;", 1787 "++super;", 1788 "super++;", 1789 "function foo super", 1790 NULL 1791 }; 1792 1793 RunParserSyncTest(context_data, statement_data, kError); 1794 } 1795 1796 1797 TEST(NoErrorsLetSloppyAllModes) { 1798 // In sloppy mode, it's okay to use "let" as identifier. 1799 const char* context_data[][2] = { 1800 { "", "" }, 1801 { "function f() {", "}" }, 1802 { "(function f() {", "})" }, 1803 { NULL, NULL } 1804 }; 1805 1806 const char* statement_data[] = { 1807 "var let;", 1808 "var foo, let;", 1809 "try { } catch (let) { }", 1810 "function let() { }", 1811 "(function let() { })", 1812 "function foo(let) { }", 1813 "function foo(bar, let) { }", 1814 "let = 1;", 1815 "var foo = let = 1;", 1816 "let * 2;", 1817 "++let;", 1818 "let++;", 1819 "let: 34", 1820 "function let(let) { let: let(let + let(0)); }", 1821 "({ let: 1 })", 1822 "({ get let() { 1 } })", 1823 "let(100)", 1824 NULL 1825 }; 1826 1827 RunParserSyncTest(context_data, statement_data, kSuccess); 1828 } 1829 1830 1831 TEST(NoErrorsYieldSloppyAllModes) { 1832 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a 1833 // generator (see other test). 1834 const char* context_data[][2] = { 1835 { "", "" }, 1836 { "function not_gen() {", "}" }, 1837 { "(function not_gen() {", "})" }, 1838 { NULL, NULL } 1839 }; 1840 1841 const char* statement_data[] = { 1842 "var yield;", 1843 "var foo, yield;", 1844 "try { } catch (yield) { }", 1845 "function yield() { }", 1846 "(function yield() { })", 1847 "function foo(yield) { }", 1848 "function foo(bar, yield) { }", 1849 "yield = 1;", 1850 "var foo = yield = 1;", 1851 "yield * 2;", 1852 "++yield;", 1853 "yield++;", 1854 "yield: 34", 1855 "function yield(yield) { yield: yield (yield + yield(0)); }", 1856 "({ yield: 1 })", 1857 "({ get yield() { 1 } })", 1858 "yield(100)", 1859 "yield[100]", 1860 NULL 1861 }; 1862 1863 RunParserSyncTest(context_data, statement_data, kSuccess); 1864 } 1865 1866 1867 TEST(NoErrorsYieldSloppyGeneratorsEnabled) { 1868 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a 1869 // generator (see next test). 1870 const char* context_data[][2] = { 1871 { "", "" }, 1872 { "function not_gen() {", "}" }, 1873 { "function * gen() { function not_gen() {", "} }" }, 1874 { "(function not_gen() {", "})" }, 1875 { "(function * gen() { (function not_gen() {", "}) })" }, 1876 { NULL, NULL } 1877 }; 1878 1879 const char* statement_data[] = { 1880 "var yield;", 1881 "var foo, yield;", 1882 "try { } catch (yield) { }", 1883 "function yield() { }", 1884 "(function yield() { })", 1885 "function foo(yield) { }", 1886 "function foo(bar, yield) { }", 1887 "function * yield() { }", 1888 "(function * yield() { })", 1889 "yield = 1;", 1890 "var foo = yield = 1;", 1891 "yield * 2;", 1892 "++yield;", 1893 "yield++;", 1894 "yield: 34", 1895 "function yield(yield) { yield: yield (yield + yield(0)); }", 1896 "({ yield: 1 })", 1897 "({ get yield() { 1 } })", 1898 "yield(100)", 1899 "yield[100]", 1900 NULL 1901 }; 1902 1903 RunParserSyncTest(context_data, statement_data, kSuccess); 1904 } 1905 1906 1907 TEST(ErrorsYieldStrict) { 1908 const char* context_data[][2] = { 1909 { "\"use strict\";", "" }, 1910 { "\"use strict\"; function not_gen() {", "}" }, 1911 { "function test_func() {\"use strict\"; ", "}"}, 1912 { "\"use strict\"; function * gen() { function not_gen() {", "} }" }, 1913 { "\"use strict\"; (function not_gen() {", "})" }, 1914 { "\"use strict\"; (function * gen() { (function not_gen() {", "}) })" }, 1915 { "() => {\"use strict\"; ", "}" }, 1916 { NULL, NULL } 1917 }; 1918 1919 const char* statement_data[] = { 1920 "var yield;", 1921 "var foo, yield;", 1922 "try { } catch (yield) { }", 1923 "function yield() { }", 1924 "(function yield() { })", 1925 "function foo(yield) { }", 1926 "function foo(bar, yield) { }", 1927 "function * yield() { }", 1928 "(function * yield() { })", 1929 "yield = 1;", 1930 "var foo = yield = 1;", 1931 "++yield;", 1932 "yield++;", 1933 "yield: 34;", 1934 NULL 1935 }; 1936 1937 RunParserSyncTest(context_data, statement_data, kError); 1938 } 1939 1940 1941 TEST(NoErrorsGenerator) { 1942 const char* context_data[][2] = { 1943 { "function * gen() {", "}" }, 1944 { "(function * gen() {", "})" }, 1945 { "(function * () {", "})" }, 1946 { NULL, NULL } 1947 }; 1948 1949 const char* statement_data[] = { 1950 // A generator without a body is valid. 1951 "" 1952 // Valid yield expressions inside generators. 1953 "yield 2;", 1954 "yield * 2;", 1955 "yield * \n 2;", 1956 "yield yield 1;", 1957 "yield * yield * 1;", 1958 "yield 3 + (yield 4);", 1959 "yield * 3 + (yield * 4);", 1960 "(yield * 3) + (yield * 4);", 1961 "yield 3; yield 4;", 1962 "yield * 3; yield * 4;", 1963 "(function (yield) { })", 1964 "yield { yield: 12 }", 1965 "yield /* comment */ { yield: 12 }", 1966 "yield * \n { yield: 12 }", 1967 "yield /* comment */ * \n { yield: 12 }", 1968 // You can return in a generator. 1969 "yield 1; return", 1970 "yield * 1; return", 1971 "yield 1; return 37", 1972 "yield * 1; return 37", 1973 "yield 1; return 37; yield 'dead';", 1974 "yield * 1; return 37; yield * 'dead';", 1975 // Yield is still a valid key in object literals. 1976 "({ yield: 1 })", 1977 "({ get yield() { } })", 1978 // Yield without RHS. 1979 "yield;", 1980 "yield", 1981 "yield\n", 1982 "yield /* comment */" 1983 "yield // comment\n" 1984 "(yield)", 1985 "[yield]", 1986 "{yield}", 1987 "yield, yield", 1988 "yield; yield", 1989 "(yield) ? yield : yield", 1990 "(yield) \n ? yield : yield", 1991 // If there is a newline before the next token, we don't look for RHS. 1992 "yield\nfor (;;) {}", 1993 NULL 1994 }; 1995 1996 RunParserSyncTest(context_data, statement_data, kSuccess); 1997 } 1998 1999 2000 TEST(ErrorsYieldGenerator) { 2001 const char* context_data[][2] = { 2002 { "function * gen() {", "}" }, 2003 { "\"use strict\"; function * gen() {", "}" }, 2004 { NULL, NULL } 2005 }; 2006 2007 const char* statement_data[] = { 2008 // Invalid yield expressions inside generators. 2009 "var yield;", 2010 "var foo, yield;", 2011 "try { } catch (yield) { }", 2012 "function yield() { }", 2013 // The name of the NFE is let-bound in the generator, which does not permit 2014 // yield to be an identifier. 2015 "(function yield() { })", 2016 "(function * yield() { })", 2017 // Yield isn't valid as a formal parameter for generators. 2018 "function * foo(yield) { }", 2019 "(function * foo(yield) { })", 2020 "yield = 1;", 2021 "var foo = yield = 1;", 2022 "++yield;", 2023 "yield++;", 2024 "yield *", 2025 "(yield *)", 2026 // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which 2027 // is invalid. 2028 "yield 3 + yield 4;", 2029 "yield: 34", 2030 "yield ? 1 : 2", 2031 // Parses as yield (/ yield): invalid. 2032 "yield / yield", 2033 "+ yield", 2034 "+ yield 3", 2035 // Invalid (no newline allowed between yield and *). 2036 "yield\n*3", 2037 // Invalid (we see a newline, so we parse {yield:42} as a statement, not an 2038 // object literal, and yield is not a valid label). 2039 "yield\n{yield: 42}", 2040 "yield /* comment */\n {yield: 42}", 2041 "yield //comment\n {yield: 42}", 2042 NULL 2043 }; 2044 2045 RunParserSyncTest(context_data, statement_data, kError); 2046 } 2047 2048 2049 TEST(ErrorsNameOfStrictFunction) { 2050 // Tests that illegal tokens as names of a strict function produce the correct 2051 // errors. 2052 const char* context_data[][2] = { 2053 { "function ", ""}, 2054 { "\"use strict\"; function", ""}, 2055 { "function * ", ""}, 2056 { "\"use strict\"; function * ", ""}, 2057 { NULL, NULL } 2058 }; 2059 2060 const char* statement_data[] = { 2061 "eval() {\"use strict\";}", 2062 "arguments() {\"use strict\";}", 2063 "interface() {\"use strict\";}", 2064 "yield() {\"use strict\";}", 2065 // Future reserved words are always illegal 2066 "function super() { }", 2067 "function super() {\"use strict\";}", 2068 NULL 2069 }; 2070 2071 RunParserSyncTest(context_data, statement_data, kError); 2072 } 2073 2074 2075 TEST(NoErrorsNameOfStrictFunction) { 2076 const char* context_data[][2] = { 2077 { "function ", ""}, 2078 { NULL, NULL } 2079 }; 2080 2081 const char* statement_data[] = { 2082 "eval() { }", 2083 "arguments() { }", 2084 "interface() { }", 2085 "yield() { }", 2086 NULL 2087 }; 2088 2089 RunParserSyncTest(context_data, statement_data, kSuccess); 2090 } 2091 2092 2093 TEST(NoErrorsNameOfStrictGenerator) { 2094 const char* context_data[][2] = { 2095 { "function * ", ""}, 2096 { NULL, NULL } 2097 }; 2098 2099 const char* statement_data[] = { 2100 "eval() { }", 2101 "arguments() { }", 2102 "interface() { }", 2103 "yield() { }", 2104 NULL 2105 }; 2106 2107 RunParserSyncTest(context_data, statement_data, kSuccess); 2108 } 2109 2110 2111 TEST(ErrorsIllegalWordsAsLabelsSloppy) { 2112 // Using future reserved words as labels is always an error. 2113 const char* context_data[][2] = { 2114 { "", ""}, 2115 { "function test_func() {", "}" }, 2116 { "() => {", "}" }, 2117 { NULL, NULL } 2118 }; 2119 2120 const char* statement_data[] = { 2121 "super: while(true) { break super; }", 2122 NULL 2123 }; 2124 2125 RunParserSyncTest(context_data, statement_data, kError); 2126 } 2127 2128 2129 TEST(ErrorsIllegalWordsAsLabelsStrict) { 2130 // Tests that illegal tokens as labels produce the correct errors. 2131 const char* context_data[][2] = { 2132 { "\"use strict\";", "" }, 2133 { "function test_func() {\"use strict\"; ", "}"}, 2134 { "() => {\"use strict\"; ", "}" }, 2135 { NULL, NULL } 2136 }; 2137 2138 const char* statement_data[] = { 2139 "super: while(true) { break super; }", 2140 "interface: while(true) { break interface; }", 2141 "yield: while(true) { break yield; }", 2142 NULL 2143 }; 2144 2145 RunParserSyncTest(context_data, statement_data, kError); 2146 } 2147 2148 2149 TEST(NoErrorsIllegalWordsAsLabels) { 2150 // Using eval and arguments as labels is legal even in strict mode. 2151 const char* context_data[][2] = { 2152 { "", ""}, 2153 { "function test_func() {", "}" }, 2154 { "() => {", "}" }, 2155 { "\"use strict\";", "" }, 2156 { "\"use strict\"; function test_func() {", "}" }, 2157 { "\"use strict\"; () => {", "}" }, 2158 { NULL, NULL } 2159 }; 2160 2161 const char* statement_data[] = { 2162 "mylabel: while(true) { break mylabel; }", 2163 "eval: while(true) { break eval; }", 2164 "arguments: while(true) { break arguments; }", 2165 NULL 2166 }; 2167 2168 static const ParserFlag always_flags[] = {kAllowArrowFunctions}; 2169 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, 2170 always_flags, arraysize(always_flags)); 2171 } 2172 2173 2174 TEST(ErrorsParenthesizedLabels) { 2175 // Parenthesized identifiers shouldn't be recognized as labels. 2176 const char* context_data[][2] = { 2177 { "", ""}, 2178 { "function test_func() {", "}" }, 2179 { "() => {", "}" }, 2180 { NULL, NULL } 2181 }; 2182 2183 const char* statement_data[] = { 2184 "(mylabel): while(true) { break mylabel; }", 2185 NULL 2186 }; 2187 2188 RunParserSyncTest(context_data, statement_data, kError); 2189 } 2190 2191 2192 TEST(NoErrorsParenthesizedDirectivePrologue) { 2193 // Parenthesized directive prologue shouldn't be recognized. 2194 const char* context_data[][2] = { 2195 { "", ""}, 2196 { NULL, NULL } 2197 }; 2198 2199 const char* statement_data[] = { 2200 "(\"use strict\"); var eval;", 2201 NULL 2202 }; 2203 2204 RunParserSyncTest(context_data, statement_data, kSuccess); 2205 } 2206 2207 2208 TEST(ErrorsNotAnIdentifierName) { 2209 const char* context_data[][2] = { 2210 { "", ""}, 2211 { "\"use strict\";", ""}, 2212 { NULL, NULL } 2213 }; 2214 2215 const char* statement_data[] = { 2216 "var foo = {}; foo.{;", 2217 "var foo = {}; foo.};", 2218 "var foo = {}; foo.=;", 2219 "var foo = {}; foo.888;", 2220 "var foo = {}; foo.-;", 2221 "var foo = {}; foo.--;", 2222 NULL 2223 }; 2224 2225 RunParserSyncTest(context_data, statement_data, kError); 2226 } 2227 2228 2229 TEST(NoErrorsIdentifierNames) { 2230 // Keywords etc. are valid as property names. 2231 const char* context_data[][2] = { 2232 { "", ""}, 2233 { "\"use strict\";", ""}, 2234 { NULL, NULL } 2235 }; 2236 2237 const char* statement_data[] = { 2238 "var foo = {}; foo.if;", 2239 "var foo = {}; foo.yield;", 2240 "var foo = {}; foo.super;", 2241 "var foo = {}; foo.interface;", 2242 "var foo = {}; foo.eval;", 2243 "var foo = {}; foo.arguments;", 2244 NULL 2245 }; 2246 2247 RunParserSyncTest(context_data, statement_data, kSuccess); 2248 } 2249 2250 2251 TEST(DontRegressPreParserDataSizes) { 2252 // These tests make sure that Parser doesn't start producing less "preparse 2253 // data" (data which the embedder can cache). 2254 v8::V8::Initialize(); 2255 v8::Isolate* isolate = CcTest::isolate(); 2256 v8::HandleScope handles(isolate); 2257 2258 CcTest::i_isolate()->stack_guard()->SetStackLimit( 2259 i::GetCurrentStackPosition() - 128 * 1024); 2260 2261 struct TestCase { 2262 const char* program; 2263 int functions; 2264 } test_cases[] = { 2265 // No functions. 2266 {"var x = 42;", 0}, 2267 // Functions. 2268 {"function foo() {}", 1}, {"function foo() {} function bar() {}", 2}, 2269 // Getter / setter functions are recorded as functions if they're on the top 2270 // level. 2271 {"var x = {get foo(){} };", 1}, 2272 // Functions insize lazy functions are not recorded. 2273 {"function lazy() { function a() {} function b() {} function c() {} }", 1}, 2274 {"function lazy() { var x = {get foo(){} } }", 1}, 2275 {NULL, 0} 2276 }; 2277 2278 for (int i = 0; test_cases[i].program; i++) { 2279 const char* program = test_cases[i].program; 2280 i::Factory* factory = CcTest::i_isolate()->factory(); 2281 i::Handle<i::String> source = 2282 factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked(); 2283 i::Handle<i::Script> script = factory->NewScript(source); 2284 i::CompilationInfoWithZone info(script); 2285 i::ScriptData* sd = NULL; 2286 info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache); 2287 i::Parser::Parse(&info, true); 2288 i::ParseData pd(sd); 2289 2290 if (pd.FunctionCount() != test_cases[i].functions) { 2291 v8::base::OS::Print( 2292 "Expected preparse data for program:\n" 2293 "\t%s\n" 2294 "to contain %d functions, however, received %d functions.\n", 2295 program, test_cases[i].functions, pd.FunctionCount()); 2296 CHECK(false); 2297 } 2298 delete sd; 2299 } 2300 } 2301 2302 2303 TEST(FunctionDeclaresItselfStrict) { 2304 // Tests that we produce the right kinds of errors when a function declares 2305 // itself strict (we cannot produce there errors as soon as we see the 2306 // offending identifiers, because we don't know at that point whether the 2307 // function is strict or not). 2308 const char* context_data[][2] = { 2309 {"function eval() {", "}"}, 2310 {"function arguments() {", "}"}, 2311 {"function yield() {", "}"}, 2312 {"function interface() {", "}"}, 2313 {"function foo(eval) {", "}"}, 2314 {"function foo(arguments) {", "}"}, 2315 {"function foo(yield) {", "}"}, 2316 {"function foo(interface) {", "}"}, 2317 {"function foo(bar, eval) {", "}"}, 2318 {"function foo(bar, arguments) {", "}"}, 2319 {"function foo(bar, yield) {", "}"}, 2320 {"function foo(bar, interface) {", "}"}, 2321 {"function foo(bar, bar) {", "}"}, 2322 { NULL, NULL } 2323 }; 2324 2325 const char* strict_statement_data[] = { 2326 "\"use strict\";", 2327 NULL 2328 }; 2329 2330 const char* non_strict_statement_data[] = { 2331 ";", 2332 NULL 2333 }; 2334 2335 RunParserSyncTest(context_data, strict_statement_data, kError); 2336 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess); 2337 } 2338 2339 2340 TEST(ErrorsTryWithoutCatchOrFinally) { 2341 const char* context_data[][2] = { 2342 {"", ""}, 2343 { NULL, NULL } 2344 }; 2345 2346 const char* statement_data[] = { 2347 "try { }", 2348 "try { } foo();", 2349 "try { } catch (e) foo();", 2350 "try { } catch { }", 2351 "try { } finally foo();", 2352 NULL 2353 }; 2354 2355 RunParserSyncTest(context_data, statement_data, kError); 2356 } 2357 2358 2359 TEST(NoErrorsTryCatchFinally) { 2360 const char* context_data[][2] = { 2361 {"", ""}, 2362 { NULL, NULL } 2363 }; 2364 2365 const char* statement_data[] = { 2366 "try { } catch (e) { }", 2367 "try { } catch (e) { } finally { }", 2368 "try { } finally { }", 2369 NULL 2370 }; 2371 2372 RunParserSyncTest(context_data, statement_data, kSuccess); 2373 } 2374 2375 2376 TEST(ErrorsRegexpLiteral) { 2377 const char* context_data[][2] = { 2378 {"var r = ", ""}, 2379 { NULL, NULL } 2380 }; 2381 2382 const char* statement_data[] = { 2383 "/unterminated", 2384 NULL 2385 }; 2386 2387 RunParserSyncTest(context_data, statement_data, kError); 2388 } 2389 2390 2391 TEST(NoErrorsRegexpLiteral) { 2392 const char* context_data[][2] = { 2393 {"var r = ", ""}, 2394 { NULL, NULL } 2395 }; 2396 2397 const char* statement_data[] = { 2398 "/foo/", 2399 "/foo/g", 2400 "/foo/whatever", // This is an error but not detected by the parser. 2401 NULL 2402 }; 2403 2404 RunParserSyncTest(context_data, statement_data, kSuccess); 2405 } 2406 2407 2408 TEST(Intrinsics) { 2409 const char* context_data[][2] = { 2410 {"", ""}, 2411 { NULL, NULL } 2412 }; 2413 2414 const char* statement_data[] = { 2415 "%someintrinsic(arg)", 2416 NULL 2417 }; 2418 2419 // This test requires kAllowNativesSyntax to succeed. 2420 static const ParserFlag always_true_flags[] = { 2421 kAllowNativesSyntax 2422 }; 2423 2424 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, 2425 always_true_flags, 1); 2426 } 2427 2428 2429 TEST(NoErrorsNewExpression) { 2430 const char* context_data[][2] = { 2431 {"", ""}, 2432 {"var f =", ""}, 2433 { NULL, NULL } 2434 }; 2435 2436 const char* statement_data[] = { 2437 "new foo", 2438 "new foo();", 2439 "new foo(1);", 2440 "new foo(1, 2);", 2441 // The first () will be processed as a part of the NewExpression and the 2442 // second () will be processed as part of LeftHandSideExpression. 2443 "new foo()();", 2444 // The first () will be processed as a part of the inner NewExpression and 2445 // the second () will be processed as a part of the outer NewExpression. 2446 "new new foo()();", 2447 "new foo.bar;", 2448 "new foo.bar();", 2449 "new foo.bar.baz;", 2450 "new foo.bar().baz;", 2451 "new foo[bar];", 2452 "new foo[bar]();", 2453 "new foo[bar][baz];", 2454 "new foo[bar]()[baz];", 2455 "new foo[bar].baz(baz)()[bar].baz;", 2456 "new \"foo\"", // Runtime error 2457 "new 1", // Runtime error 2458 // This even runs: 2459 "(new new Function(\"this.x = 1\")).x;", 2460 "new new Test_Two(String, 2).v(0123).length;", 2461 NULL 2462 }; 2463 2464 RunParserSyncTest(context_data, statement_data, kSuccess); 2465 } 2466 2467 2468 TEST(ErrorsNewExpression) { 2469 const char* context_data[][2] = { 2470 {"", ""}, 2471 {"var f =", ""}, 2472 { NULL, NULL } 2473 }; 2474 2475 const char* statement_data[] = { 2476 "new foo bar", 2477 "new ) foo", 2478 "new ++foo", 2479 "new foo ++", 2480 NULL 2481 }; 2482 2483 RunParserSyncTest(context_data, statement_data, kError); 2484 } 2485 2486 2487 TEST(StrictObjectLiteralChecking) { 2488 const char* strict_context_data[][2] = { 2489 {"\"use strict\"; var myobject = {", "};"}, 2490 {"\"use strict\"; var myobject = {", ",};"}, 2491 { NULL, NULL } 2492 }; 2493 const char* non_strict_context_data[][2] = { 2494 {"var myobject = {", "};"}, 2495 {"var myobject = {", ",};"}, 2496 { NULL, NULL } 2497 }; 2498 2499 // These are only errors in strict mode. 2500 const char* statement_data[] = { 2501 "foo: 1, foo: 2", 2502 "\"foo\": 1, \"foo\": 2", 2503 "foo: 1, \"foo\": 2", 2504 "1: 1, 1: 2", 2505 "1: 1, \"1\": 2", 2506 "get: 1, get: 2", // Not a getter for real, just a property called get. 2507 "set: 1, set: 2", // Not a setter for real, just a property called set. 2508 NULL 2509 }; 2510 2511 RunParserSyncTest(non_strict_context_data, statement_data, kSuccess); 2512 RunParserSyncTest(strict_context_data, statement_data, kError); 2513 } 2514 2515 2516 TEST(ErrorsObjectLiteralChecking) { 2517 const char* context_data[][2] = { 2518 {"\"use strict\"; var myobject = {", "};"}, 2519 {"var myobject = {", "};"}, 2520 { NULL, NULL } 2521 }; 2522 2523 const char* statement_data[] = { 2524 ",", 2525 "foo: 1, get foo() {}", 2526 "foo: 1, set foo(v) {}", 2527 "\"foo\": 1, get \"foo\"() {}", 2528 "\"foo\": 1, set \"foo\"(v) {}", 2529 "1: 1, get 1() {}", 2530 "1: 1, set 1() {}", 2531 "get foo() {}, get foo() {}", 2532 "set foo(_) {}, set foo(_) {}", 2533 // It's counter-intuitive, but these collide too (even in classic 2534 // mode). Note that we can have "foo" and foo as properties in classic 2535 // mode, 2536 // but we cannot have "foo" and get foo, or foo and get "foo". 2537 "foo: 1, get \"foo\"() {}", 2538 "foo: 1, set \"foo\"(v) {}", 2539 "\"foo\": 1, get foo() {}", 2540 "\"foo\": 1, set foo(v) {}", 2541 "1: 1, get \"1\"() {}", 2542 "1: 1, set \"1\"() {}", 2543 "\"1\": 1, get 1() {}" 2544 "\"1\": 1, set 1(v) {}" 2545 // Wrong number of parameters 2546 "get bar(x) {}", 2547 "get bar(x, y) {}", 2548 "set bar() {}", 2549 "set bar(x, y) {}", 2550 // Parsing FunctionLiteral for getter or setter fails 2551 "get foo( +", 2552 "get foo() \"error\"", 2553 NULL}; 2554 2555 RunParserSyncTest(context_data, statement_data, kError); 2556 } 2557 2558 2559 TEST(NoErrorsObjectLiteralChecking) { 2560 const char* context_data[][2] = { 2561 {"var myobject = {", "};"}, 2562 {"var myobject = {", ",};"}, 2563 {"\"use strict\"; var myobject = {", "};"}, 2564 {"\"use strict\"; var myobject = {", ",};"}, 2565 { NULL, NULL } 2566 }; 2567 2568 const char* statement_data[] = { 2569 "foo: 1, bar: 2", 2570 "\"foo\": 1, \"bar\": 2", 2571 "1: 1, 2: 2", 2572 // Syntax: IdentifierName ':' AssignmentExpression 2573 "foo: bar = 5 + baz", 2574 // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}' 2575 "get foo() {}", 2576 "get \"foo\"() {}", 2577 "get 1() {}", 2578 // Syntax: 'set' PropertyName '(' PropertySetParameterList ')' 2579 // '{' FunctionBody '}' 2580 "set foo(v) {}", 2581 "set \"foo\"(v) {}", 2582 "set 1(v) {}", 2583 // Non-colliding getters and setters -> no errors 2584 "foo: 1, get bar() {}", 2585 "foo: 1, set bar(v) {}", 2586 "\"foo\": 1, get \"bar\"() {}", 2587 "\"foo\": 1, set \"bar\"(v) {}", 2588 "1: 1, get 2() {}", 2589 "1: 1, set 2(v) {}", 2590 "get: 1, get foo() {}", 2591 "set: 1, set foo(_) {}", 2592 // Keywords, future reserved and strict future reserved are also allowed as 2593 // property names. 2594 "if: 4", 2595 "interface: 5", 2596 "super: 6", 2597 "eval: 7", 2598 "arguments: 8", 2599 NULL 2600 }; 2601 2602 RunParserSyncTest(context_data, statement_data, kSuccess); 2603 } 2604 2605 2606 TEST(TooManyArguments) { 2607 const char* context_data[][2] = { 2608 {"foo(", "0)"}, 2609 { NULL, NULL } 2610 }; 2611 2612 using v8::internal::Code; 2613 char statement[Code::kMaxArguments * 2 + 1]; 2614 for (int i = 0; i < Code::kMaxArguments; ++i) { 2615 statement[2 * i] = '0'; 2616 statement[2 * i + 1] = ','; 2617 } 2618 statement[Code::kMaxArguments * 2] = 0; 2619 2620 const char* statement_data[] = { 2621 statement, 2622 NULL 2623 }; 2624 2625 // The test is quite slow, so run it with a reduced set of flags. 2626 static const ParserFlag empty_flags[] = {kAllowLazy}; 2627 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1); 2628 } 2629 2630 2631 TEST(StrictDelete) { 2632 // "delete <Identifier>" is not allowed in strict mode. 2633 const char* strict_context_data[][2] = { 2634 {"\"use strict\"; ", ""}, 2635 { NULL, NULL } 2636 }; 2637 2638 const char* sloppy_context_data[][2] = { 2639 {"", ""}, 2640 { NULL, NULL } 2641 }; 2642 2643 // These are errors in the strict mode. 2644 const char* sloppy_statement_data[] = { 2645 "delete foo;", 2646 "delete foo + 1;", 2647 "delete (foo);", 2648 "delete eval;", 2649 "delete interface;", 2650 NULL 2651 }; 2652 2653 // These are always OK 2654 const char* good_statement_data[] = { 2655 "delete this;", 2656 "delete 1;", 2657 "delete 1 + 2;", 2658 "delete foo();", 2659 "delete foo.bar;", 2660 "delete foo[bar];", 2661 "delete foo--;", 2662 "delete --foo;", 2663 "delete new foo();", 2664 "delete new foo(bar);", 2665 NULL 2666 }; 2667 2668 // These are always errors 2669 const char* bad_statement_data[] = { 2670 "delete if;", 2671 NULL 2672 }; 2673 2674 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError); 2675 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess); 2676 2677 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess); 2678 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess); 2679 2680 RunParserSyncTest(strict_context_data, bad_statement_data, kError); 2681 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError); 2682 } 2683 2684 2685 TEST(InvalidLeftHandSide) { 2686 const char* assignment_context_data[][2] = { 2687 {"", " = 1;"}, 2688 {"\"use strict\"; ", " = 1;"}, 2689 { NULL, NULL } 2690 }; 2691 2692 const char* prefix_context_data[][2] = { 2693 {"++", ";"}, 2694 {"\"use strict\"; ++", ";"}, 2695 {NULL, NULL}, 2696 }; 2697 2698 const char* postfix_context_data[][2] = { 2699 {"", "++;"}, 2700 {"\"use strict\"; ", "++;"}, 2701 { NULL, NULL } 2702 }; 2703 2704 // Good left hand sides for assigment or prefix / postfix operations. 2705 const char* good_statement_data[] = { 2706 "foo", 2707 "foo.bar", 2708 "foo[bar]", 2709 "foo()[bar]", 2710 "foo().bar", 2711 "this.foo", 2712 "this[foo]", 2713 "new foo()[bar]", 2714 "new foo().bar", 2715 "foo()", 2716 "foo(bar)", 2717 "foo[bar]()", 2718 "foo.bar()", 2719 "this()", 2720 "this.foo()", 2721 "this[foo].bar()", 2722 "this.foo[foo].bar(this)(bar)[foo]()", 2723 NULL 2724 }; 2725 2726 // Bad left hand sides for assigment or prefix / postfix operations. 2727 const char* bad_statement_data_common[] = { 2728 "2", 2729 "new foo", 2730 "new foo()", 2731 "null", 2732 "if", // Unexpected token 2733 "{x: 1}", // Unexpected token 2734 "this", 2735 "\"bar\"", 2736 "(foo + bar)", 2737 "new new foo()[bar]", // means: new (new foo()[bar]) 2738 "new new foo().bar", // means: new (new foo()[bar]) 2739 NULL 2740 }; 2741 2742 // These are not okay for assignment, but okay for prefix / postix. 2743 const char* bad_statement_data_for_assignment[] = { 2744 "++foo", 2745 "foo++", 2746 "foo + bar", 2747 NULL 2748 }; 2749 2750 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess); 2751 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError); 2752 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment, 2753 kError); 2754 2755 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess); 2756 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError); 2757 2758 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess); 2759 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError); 2760 } 2761 2762 2763 TEST(FuncNameInferrerBasic) { 2764 // Tests that function names are inferred properly. 2765 i::FLAG_allow_natives_syntax = true; 2766 v8::Isolate* isolate = CcTest::isolate(); 2767 v8::HandleScope scope(isolate); 2768 LocalContext env; 2769 CompileRun("var foo1 = function() {}; " 2770 "var foo2 = function foo3() {}; " 2771 "function not_ctor() { " 2772 " var foo4 = function() {}; " 2773 " return %FunctionGetInferredName(foo4); " 2774 "} " 2775 "function Ctor() { " 2776 " var foo5 = function() {}; " 2777 " return %FunctionGetInferredName(foo5); " 2778 "} " 2779 "var obj1 = { foo6: function() {} }; " 2780 "var obj2 = { 'foo7': function() {} }; " 2781 "var obj3 = {}; " 2782 "obj3[1] = function() {}; " 2783 "var obj4 = {}; " 2784 "obj4[1] = function foo8() {}; " 2785 "var obj5 = {}; " 2786 "obj5['foo9'] = function() {}; " 2787 "var obj6 = { obj7 : { foo10: function() {} } };"); 2788 ExpectString("%FunctionGetInferredName(foo1)", "foo1"); 2789 // foo2 is not unnamed -> its name is not inferred. 2790 ExpectString("%FunctionGetInferredName(foo2)", ""); 2791 ExpectString("not_ctor()", "foo4"); 2792 ExpectString("Ctor()", "Ctor.foo5"); 2793 ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6"); 2794 ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7"); 2795 ExpectString("%FunctionGetInferredName(obj3[1])", 2796 "obj3.(anonymous function)"); 2797 ExpectString("%FunctionGetInferredName(obj4[1])", ""); 2798 ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9"); 2799 ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10"); 2800 } 2801 2802 2803 TEST(FuncNameInferrerTwoByte) { 2804 // Tests function name inferring in cases where some parts of the inferred 2805 // function name are two-byte strings. 2806 i::FLAG_allow_natives_syntax = true; 2807 v8::Isolate* isolate = CcTest::isolate(); 2808 v8::HandleScope scope(isolate); 2809 LocalContext env; 2810 uint16_t* two_byte_source = AsciiToTwoByteString( 2811 "var obj1 = { oXj2 : { foo1: function() {} } }; " 2812 "%FunctionGetInferredName(obj1.oXj2.foo1)"); 2813 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1"); 2814 // Make it really non-Latin1 (replace the Xs with a non-Latin1 character). 2815 two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d; 2816 v8::Local<v8::String> source = 2817 v8::String::NewFromTwoByte(isolate, two_byte_source); 2818 v8::Local<v8::Value> result = CompileRun(source); 2819 CHECK(result->IsString()); 2820 v8::Local<v8::String> expected_name = 2821 v8::String::NewFromTwoByte(isolate, two_byte_name); 2822 CHECK(result->Equals(expected_name)); 2823 i::DeleteArray(two_byte_source); 2824 i::DeleteArray(two_byte_name); 2825 } 2826 2827 2828 TEST(FuncNameInferrerEscaped) { 2829 // The same as FuncNameInferrerTwoByte, except that we express the two-byte 2830 // character as a unicode escape. 2831 i::FLAG_allow_natives_syntax = true; 2832 v8::Isolate* isolate = CcTest::isolate(); 2833 v8::HandleScope scope(isolate); 2834 LocalContext env; 2835 uint16_t* two_byte_source = AsciiToTwoByteString( 2836 "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; " 2837 "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)"); 2838 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1"); 2839 // Fix to correspond to the non-ASCII name in two_byte_source. 2840 two_byte_name[6] = 0x010d; 2841 v8::Local<v8::String> source = 2842 v8::String::NewFromTwoByte(isolate, two_byte_source); 2843 v8::Local<v8::Value> result = CompileRun(source); 2844 CHECK(result->IsString()); 2845 v8::Local<v8::String> expected_name = 2846 v8::String::NewFromTwoByte(isolate, two_byte_name); 2847 CHECK(result->Equals(expected_name)); 2848 i::DeleteArray(two_byte_source); 2849 i::DeleteArray(two_byte_name); 2850 } 2851 2852 2853 TEST(RegressionLazyFunctionWithErrorWithArg) { 2854 // The bug occurred when a lazy function had an error which requires a 2855 // parameter (such as "unknown label" here). The error message was processed 2856 // before the AstValueFactory containing the error message string was 2857 // internalized. 2858 v8::Isolate* isolate = CcTest::isolate(); 2859 v8::HandleScope scope(isolate); 2860 LocalContext env; 2861 i::FLAG_lazy = true; 2862 i::FLAG_min_preparse_length = 0; 2863 CompileRun("function this_is_lazy() {\n" 2864 " break p;\n" 2865 "}\n" 2866 "this_is_lazy();\n"); 2867 } 2868 2869 2870 TEST(SerializationOfMaybeAssignmentFlag) { 2871 i::Isolate* isolate = CcTest::i_isolate(); 2872 i::Factory* factory = isolate->factory(); 2873 i::HandleScope scope(isolate); 2874 LocalContext env; 2875 2876 const char* src = 2877 "function h() {" 2878 " var result = [];" 2879 " function f() {" 2880 " result.push(2);" 2881 " }" 2882 " function assertResult(r) {" 2883 " f();" 2884 " result = [];" 2885 " }" 2886 " assertResult([2]);" 2887 " assertResult([2]);" 2888 " return f;" 2889 "};" 2890 "h();"; 2891 2892 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1); 2893 i::SNPrintF(program, "%s", src); 2894 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start()); 2895 source->PrintOn(stdout); 2896 printf("\n"); 2897 i::Zone zone(isolate); 2898 v8::Local<v8::Value> v = CompileRun(src); 2899 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v); 2900 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o); 2901 i::Context* context = f->context(); 2902 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); 2903 avf.Internalize(isolate); 2904 const i::AstRawString* name = avf.GetOneByteString("result"); 2905 i::Handle<i::String> str = name->string(); 2906 CHECK(str->IsInternalizedString()); 2907 i::Scope* global_scope = 2908 new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone); 2909 global_scope->Initialize(); 2910 i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone); 2911 DCHECK(s != global_scope); 2912 DCHECK(name != NULL); 2913 2914 // Get result from h's function context (that is f's context) 2915 i::Variable* var = s->Lookup(name); 2916 2917 CHECK(var != NULL); 2918 // Maybe assigned should survive deserialization 2919 CHECK(var->maybe_assigned() == i::kMaybeAssigned); 2920 // TODO(sigurds) Figure out if is_used should survive context serialization. 2921 } 2922 2923 2924 TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) { 2925 i::Isolate* isolate = CcTest::i_isolate(); 2926 i::Factory* factory = isolate->factory(); 2927 i::HandleScope scope(isolate); 2928 LocalContext env; 2929 2930 2931 const char* src = 2932 "function f(x) {" 2933 " var a = arguments;" 2934 " function g(i) {" 2935 " ++a[0];" 2936 " };" 2937 " return g;" 2938 " }" 2939 "f(0);"; 2940 2941 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1); 2942 i::SNPrintF(program, "%s", src); 2943 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start()); 2944 source->PrintOn(stdout); 2945 printf("\n"); 2946 i::Zone zone(isolate); 2947 v8::Local<v8::Value> v = CompileRun(src); 2948 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v); 2949 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o); 2950 i::Context* context = f->context(); 2951 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); 2952 avf.Internalize(isolate); 2953 2954 i::Scope* global_scope = 2955 new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone); 2956 global_scope->Initialize(); 2957 i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone); 2958 DCHECK(s != global_scope); 2959 const i::AstRawString* name_x = avf.GetOneByteString("x"); 2960 2961 // Get result from f's function context (that is g's outer context) 2962 i::Variable* var_x = s->Lookup(name_x); 2963 CHECK(var_x != NULL); 2964 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned); 2965 } 2966 2967 2968 TEST(ExportsMaybeAssigned) { 2969 i::FLAG_use_strict = true; 2970 i::FLAG_harmony_scoping = true; 2971 i::FLAG_harmony_modules = true; 2972 2973 i::Isolate* isolate = CcTest::i_isolate(); 2974 i::Factory* factory = isolate->factory(); 2975 i::HandleScope scope(isolate); 2976 LocalContext env; 2977 2978 const char* src = 2979 "module A {" 2980 " export var x = 1;" 2981 " export function f() { return x };" 2982 " export const y = 2;" 2983 " module B {}" 2984 " export module C {}" 2985 "};" 2986 "A.f"; 2987 2988 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1); 2989 i::SNPrintF(program, "%s", src); 2990 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start()); 2991 source->PrintOn(stdout); 2992 printf("\n"); 2993 i::Zone zone(isolate); 2994 v8::Local<v8::Value> v = CompileRun(src); 2995 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v); 2996 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o); 2997 i::Context* context = f->context(); 2998 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); 2999 avf.Internalize(isolate); 3000 3001 i::Scope* global_scope = 3002 new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone); 3003 global_scope->Initialize(); 3004 i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone); 3005 DCHECK(s != global_scope); 3006 const i::AstRawString* name_x = avf.GetOneByteString("x"); 3007 const i::AstRawString* name_f = avf.GetOneByteString("f"); 3008 const i::AstRawString* name_y = avf.GetOneByteString("y"); 3009 const i::AstRawString* name_B = avf.GetOneByteString("B"); 3010 const i::AstRawString* name_C = avf.GetOneByteString("C"); 3011 3012 // Get result from h's function context (that is f's context) 3013 i::Variable* var_x = s->Lookup(name_x); 3014 CHECK(var_x != NULL); 3015 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned); 3016 i::Variable* var_f = s->Lookup(name_f); 3017 CHECK(var_f != NULL); 3018 CHECK(var_f->maybe_assigned() == i::kMaybeAssigned); 3019 i::Variable* var_y = s->Lookup(name_y); 3020 CHECK(var_y != NULL); 3021 CHECK(var_y->maybe_assigned() == i::kNotAssigned); 3022 i::Variable* var_B = s->Lookup(name_B); 3023 CHECK(var_B != NULL); 3024 CHECK(var_B->maybe_assigned() == i::kNotAssigned); 3025 i::Variable* var_C = s->Lookup(name_C); 3026 CHECK(var_C != NULL); 3027 CHECK(var_C->maybe_assigned() == i::kNotAssigned); 3028 } 3029 3030 3031 TEST(InnerAssignment) { 3032 i::Isolate* isolate = CcTest::i_isolate(); 3033 i::Factory* factory = isolate->factory(); 3034 i::HandleScope scope(isolate); 3035 LocalContext env; 3036 3037 const char* prefix = "function f() {"; 3038 const char* midfix = " function g() {"; 3039 const char* suffix = "}}"; 3040 struct { const char* source; bool assigned; bool strict; } outers[] = { 3041 // Actual assignments. 3042 { "var x; var x = 5;", true, false }, 3043 { "var x; { var x = 5; }", true, false }, 3044 { "'use strict'; let x; x = 6;", true, true }, 3045 { "var x = 5; function x() {}", true, false }, 3046 // Actual non-assignments. 3047 { "var x;", false, false }, 3048 { "var x = 5;", false, false }, 3049 { "'use strict'; let x;", false, true }, 3050 { "'use strict'; let x = 6;", false, true }, 3051 { "'use strict'; var x = 0; { let x = 6; }", false, true }, 3052 { "'use strict'; var x = 0; { let x; x = 6; }", false, true }, 3053 { "'use strict'; let x = 0; { let x = 6; }", false, true }, 3054 { "'use strict'; let x = 0; { let x; x = 6; }", false, true }, 3055 { "var x; try {} catch (x) { x = 5; }", false, false }, 3056 { "function x() {}", false, false }, 3057 // Eval approximation. 3058 { "var x; eval('');", true, false }, 3059 { "eval(''); var x;", true, false }, 3060 { "'use strict'; let x; eval('');", true, true }, 3061 { "'use strict'; eval(''); let x;", true, true }, 3062 // Non-assignments not recognized, because the analysis is approximative. 3063 { "var x; var x;", true, false }, 3064 { "var x = 5; var x;", true, false }, 3065 { "var x; { var x; }", true, false }, 3066 { "var x; function x() {}", true, false }, 3067 { "function x() {}; var x;", true, false }, 3068 { "var x; try {} catch (x) { var x = 5; }", true, false }, 3069 }; 3070 struct { const char* source; bool assigned; bool with; } inners[] = { 3071 // Actual assignments. 3072 { "x = 1;", true, false }, 3073 { "x++;", true, false }, 3074 { "++x;", true, false }, 3075 { "x--;", true, false }, 3076 { "--x;", true, false }, 3077 { "{ x = 1; }", true, false }, 3078 { "'use strict'; { let x; }; x = 0;", true, false }, 3079 { "'use strict'; { const x = 1; }; x = 0;", true, false }, 3080 { "'use strict'; { function x() {} }; x = 0;", true, false }, 3081 { "with ({}) { x = 1; }", true, true }, 3082 { "eval('');", true, false }, 3083 { "'use strict'; { let y; eval('') }", true, false }, 3084 { "function h() { x = 0; }", true, false }, 3085 { "(function() { x = 0; })", true, false }, 3086 { "(function() { x = 0; })", true, false }, 3087 { "with ({}) (function() { x = 0; })", true, true }, 3088 // Actual non-assignments. 3089 { "", false, false }, 3090 { "x;", false, false }, 3091 { "var x;", false, false }, 3092 { "var x = 8;", false, false }, 3093 { "var x; x = 8;", false, false }, 3094 { "'use strict'; let x;", false, false }, 3095 { "'use strict'; let x = 8;", false, false }, 3096 { "'use strict'; let x; x = 8;", false, false }, 3097 { "'use strict'; const x = 8;", false, false }, 3098 { "function x() {}", false, false }, 3099 { "function x() { x = 0; }", false, false }, 3100 { "function h(x) { x = 0; }", false, false }, 3101 { "'use strict'; { let x; x = 0; }", false, false }, 3102 { "{ var x; }; x = 0;", false, false }, 3103 { "with ({}) {}", false, true }, 3104 { "var x; { with ({}) { x = 1; } }", false, true }, 3105 { "try {} catch(x) { x = 0; }", false, false }, 3106 { "try {} catch(x) { with ({}) { x = 1; } }", false, true }, 3107 // Eval approximation. 3108 { "eval('');", true, false }, 3109 { "function h() { eval(''); }", true, false }, 3110 { "(function() { eval(''); })", true, false }, 3111 // Shadowing not recognized because of eval approximation. 3112 { "var x; eval('');", true, false }, 3113 { "'use strict'; let x; eval('');", true, false }, 3114 { "try {} catch(x) { eval(''); }", true, false }, 3115 { "function x() { eval(''); }", true, false }, 3116 { "(function(x) { eval(''); })", true, false }, 3117 }; 3118 3119 // Used to trigger lazy compilation of function 3120 int comment_len = 2048; 3121 i::ScopedVector<char> comment(comment_len + 1); 3122 i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0); 3123 int prefix_len = Utf8LengthHelper(prefix); 3124 int midfix_len = Utf8LengthHelper(midfix); 3125 int suffix_len = Utf8LengthHelper(suffix); 3126 for (unsigned i = 0; i < arraysize(outers); ++i) { 3127 const char* outer = outers[i].source; 3128 int outer_len = Utf8LengthHelper(outer); 3129 for (unsigned j = 0; j < arraysize(inners); ++j) { 3130 for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) { 3131 for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) { 3132 if (outers[i].strict && inners[j].with) continue; 3133 const char* inner = inners[j].source; 3134 int inner_len = Utf8LengthHelper(inner); 3135 3136 int outer_comment_len = outer_lazy ? comment_len : 0; 3137 int inner_comment_len = inner_lazy ? comment_len : 0; 3138 const char* outer_comment = outer_lazy ? comment.start() : ""; 3139 const char* inner_comment = inner_lazy ? comment.start() : ""; 3140 int len = prefix_len + outer_comment_len + outer_len + midfix_len + 3141 inner_comment_len + inner_len + suffix_len; 3142 i::ScopedVector<char> program(len + 1); 3143 3144 i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer, 3145 midfix, inner_comment, inner, suffix); 3146 i::Handle<i::String> source = 3147 factory->InternalizeUtf8String(program.start()); 3148 source->PrintOn(stdout); 3149 printf("\n"); 3150 3151 i::Handle<i::Script> script = factory->NewScript(source); 3152 i::CompilationInfoWithZone info(script); 3153 i::Parser::ParseInfo parse_info = { 3154 isolate->stack_guard()->real_climit(), 3155 isolate->heap()->HashSeed(), isolate->unicode_cache()}; 3156 i::Parser parser(&info, &parse_info); 3157 parser.set_allow_harmony_scoping(true); 3158 CHECK(parser.Parse()); 3159 CHECK(i::Rewriter::Rewrite(&info)); 3160 CHECK(i::Scope::Analyze(&info)); 3161 CHECK(info.function() != NULL); 3162 3163 i::Scope* scope = info.function()->scope(); 3164 CHECK_EQ(scope->inner_scopes()->length(), 1); 3165 i::Scope* inner_scope = scope->inner_scopes()->at(0); 3166 const i::AstRawString* var_name = 3167 info.ast_value_factory()->GetOneByteString("x"); 3168 i::Variable* var = inner_scope->Lookup(var_name); 3169 bool expected = outers[i].assigned || inners[j].assigned; 3170 CHECK(var != NULL); 3171 CHECK(var->is_used() || !expected); 3172 CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected); 3173 } 3174 } 3175 } 3176 } 3177 } 3178 3179 namespace { 3180 3181 int* global_use_counts = NULL; 3182 3183 void MockUseCounterCallback(v8::Isolate* isolate, 3184 v8::Isolate::UseCounterFeature feature) { 3185 ++global_use_counts[feature]; 3186 } 3187 3188 } 3189 3190 3191 TEST(UseAsmUseCount) { 3192 i::Isolate* isolate = CcTest::i_isolate(); 3193 i::HandleScope scope(isolate); 3194 LocalContext env; 3195 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {}; 3196 global_use_counts = use_counts; 3197 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback); 3198 CompileRun("\"use asm\";\n" 3199 "var foo = 1;\n" 3200 "\"use asm\";\n" // Only the first one counts. 3201 "function bar() { \"use asm\"; var baz = 1; }"); 3202 CHECK_EQ(2, use_counts[v8::Isolate::kUseAsm]); 3203 } 3204 3205 3206 TEST(ErrorsArrowFunctions) { 3207 // Tests that parser and preparser generate the same kind of errors 3208 // on invalid arrow function syntax. 3209 const char* context_data[][2] = { 3210 {"", ";"}, 3211 {"v = ", ";"}, 3212 {"bar ? (", ") : baz;"}, 3213 {"bar ? baz : (", ");"}, 3214 {"bar[", "];"}, 3215 {"bar, ", ";"}, 3216 {"", ", bar;"}, 3217 {NULL, NULL} 3218 }; 3219 3220 const char* statement_data[] = { 3221 "=> 0", 3222 "=>", 3223 "() =>", 3224 "=> {}", 3225 ") => {}", 3226 ", => {}", 3227 "(,) => {}", 3228 "return => {}", 3229 "() => {'value': 42}", 3230 3231 // Check that the early return introduced in ParsePrimaryExpression 3232 // does not accept stray closing parentheses. 3233 ")", 3234 ") => 0", 3235 "foo[()]", 3236 "()", 3237 3238 // Parameter lists with extra parens should be recognized as errors. 3239 "(()) => 0", 3240 "((x)) => 0", 3241 "((x, y)) => 0", 3242 "(x, (y)) => 0", 3243 "((x, y, z)) => 0", 3244 "(x, (y, z)) => 0", 3245 "((x, y), z) => 0", 3246 3247 // Parameter lists are always validated as strict, so those are errors. 3248 "eval => {}", 3249 "arguments => {}", 3250 "yield => {}", 3251 "interface => {}", 3252 "(eval) => {}", 3253 "(arguments) => {}", 3254 "(yield) => {}", 3255 "(interface) => {}", 3256 "(eval, bar) => {}", 3257 "(bar, eval) => {}", 3258 "(bar, arguments) => {}", 3259 "(bar, yield) => {}", 3260 "(bar, interface) => {}", 3261 // TODO(aperez): Detecting duplicates does not work in PreParser. 3262 // "(bar, bar) => {}", 3263 3264 // The parameter list is parsed as an expression, but only 3265 // a comma-separated list of identifier is valid. 3266 "32 => {}", 3267 "(32) => {}", 3268 "(a, 32) => {}", 3269 "if => {}", 3270 "(if) => {}", 3271 "(a, if) => {}", 3272 "a + b => {}", 3273 "(a + b) => {}", 3274 "(a + b, c) => {}", 3275 "(a, b - c) => {}", 3276 "\"a\" => {}", 3277 "(\"a\") => {}", 3278 "(\"a\", b) => {}", 3279 "(a, \"b\") => {}", 3280 "-a => {}", 3281 "(-a) => {}", 3282 "(-a, b) => {}", 3283 "(a, -b) => {}", 3284 "{} => {}", 3285 "({}) => {}", 3286 "(a, {}) => {}", 3287 "({}, a) => {}", 3288 "a++ => {}", 3289 "(a++) => {}", 3290 "(a++, b) => {}", 3291 "(a, b++) => {}", 3292 "[] => {}", 3293 "([]) => {}", 3294 "(a, []) => {}", 3295 "([], a) => {}", 3296 "(a = b) => {}", 3297 "(a = b, c) => {}", 3298 "(a, b = c) => {}", 3299 "(foo ? bar : baz) => {}", 3300 "(a, foo ? bar : baz) => {}", 3301 "(foo ? bar : baz, a) => {}", 3302 NULL 3303 }; 3304 3305 // The test is quite slow, so run it with a reduced set of flags. 3306 static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping}; 3307 static const ParserFlag always_flags[] = { kAllowArrowFunctions }; 3308 RunParserSyncTest(context_data, statement_data, kError, flags, 3309 arraysize(flags), always_flags, arraysize(always_flags)); 3310 } 3311 3312 3313 TEST(NoErrorsArrowFunctions) { 3314 // Tests that parser and preparser accept valid arrow functions syntax. 3315 const char* context_data[][2] = { 3316 {"", ";"}, 3317 {"bar ? (", ") : baz;"}, 3318 {"bar ? baz : (", ");"}, 3319 {"bar, ", ";"}, 3320 {"", ", bar;"}, 3321 {NULL, NULL} 3322 }; 3323 3324 const char* statement_data[] = { 3325 "() => {}", 3326 "() => { return 42 }", 3327 "x => { return x; }", 3328 "(x) => { return x; }", 3329 "(x, y) => { return x + y; }", 3330 "(x, y, z) => { return x + y + z; }", 3331 "(x, y) => { x.a = y; }", 3332 "() => 42", 3333 "x => x", 3334 "x => x * x", 3335 "(x) => x", 3336 "(x) => x * x", 3337 "(x, y) => x + y", 3338 "(x, y, z) => x, y, z", 3339 "(x, y) => x.a = y", 3340 "() => ({'value': 42})", 3341 "x => y => x + y", 3342 "(x, y) => (u, v) => x*u + y*v", 3343 "(x, y) => z => z * (x + y)", 3344 "x => (y, z) => z * (x + y)", 3345 3346 // Those are comma-separated expressions, with arrow functions as items. 3347 // They stress the code for validating arrow function parameter lists. 3348 "a, b => 0", 3349 "a, b, (c, d) => 0", 3350 "(a, b, (c, d) => 0)", 3351 "(a, b) => 0, (c, d) => 1", 3352 "(a, b => {}, a => a + 1)", 3353 "((a, b) => {}, (a => a + 1))", 3354 "(a, (a, (b, c) => 0))", 3355 3356 // Arrow has more precedence, this is the same as: foo ? bar : (baz = {}) 3357 "foo ? bar : baz => {}", 3358 NULL 3359 }; 3360 3361 static const ParserFlag always_flags[] = {kAllowArrowFunctions}; 3362 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, 3363 always_flags, arraysize(always_flags)); 3364 } 3365 3366 3367 TEST(NoErrorsSuper) { 3368 // Tests that parser and preparser accept 'super' keyword in right places. 3369 const char* context_data[][2] = {{"", ";"}, 3370 {"k = ", ";"}, 3371 {"foo(", ");"}, 3372 {NULL, NULL}}; 3373 3374 const char* statement_data[] = { 3375 "super.x", 3376 "super[27]", 3377 "new super", 3378 "new super()", 3379 "new super(12, 45)", 3380 "new new super", 3381 "new new super()", 3382 "new new super()()", 3383 "z.super", // Ok, property lookup. 3384 NULL}; 3385 3386 static const ParserFlag always_flags[] = {kAllowClasses}; 3387 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, 3388 always_flags, arraysize(always_flags)); 3389 } 3390 3391 3392 TEST(ErrorsSuper) { 3393 // Tests that parser and preparser generate same errors for 'super'. 3394 const char* context_data[][2] = {{"", ";"}, 3395 {"k = ", ";"}, 3396 {"foo(", ");"}, 3397 {NULL, NULL}}; 3398 3399 const char* statement_data[] = { 3400 "super = x", 3401 "y = super", 3402 "f(super)", 3403 NULL}; 3404 3405 static const ParserFlag always_flags[] = {kAllowClasses}; 3406 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, 3407 always_flags, arraysize(always_flags)); 3408 } 3409 3410 3411 TEST(NoErrorsMethodDefinition) { 3412 const char* context_data[][2] = {{"({", "});"}, 3413 {"'use strict'; ({", "});"}, 3414 {"({*", "});"}, 3415 {"'use strict'; ({*", "});"}, 3416 {NULL, NULL}}; 3417 3418 const char* object_literal_body_data[] = { 3419 "m() {}", 3420 "m(x) { return x; }", 3421 "m(x, y) {}, n() {}", 3422 "set(x, y) {}", 3423 "get(x, y) {}", 3424 NULL 3425 }; 3426 3427 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; 3428 RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0, 3429 always_flags, arraysize(always_flags)); 3430 } 3431 3432 3433 TEST(MethodDefinitionNames) { 3434 const char* context_data[][2] = {{"({", "(x, y) {}});"}, 3435 {"'use strict'; ({", "(x, y) {}});"}, 3436 {"({*", "(x, y) {}});"}, 3437 {"'use strict'; ({*", "(x, y) {}});"}, 3438 {NULL, NULL}}; 3439 3440 const char* name_data[] = { 3441 "m", 3442 "'m'", 3443 "\"m\"", 3444 "\"m n\"", 3445 "true", 3446 "false", 3447 "null", 3448 "0", 3449 "1.2", 3450 "1e1", 3451 "1E1", 3452 "1e+1", 3453 "1e-1", 3454 3455 // Keywords 3456 "async", 3457 "await", 3458 "break", 3459 "case", 3460 "catch", 3461 "class", 3462 "const", 3463 "continue", 3464 "debugger", 3465 "default", 3466 "delete", 3467 "do", 3468 "else", 3469 "enum", 3470 "export", 3471 "extends", 3472 "finally", 3473 "for", 3474 "function", 3475 "if", 3476 "implements", 3477 "import", 3478 "in", 3479 "instanceof", 3480 "interface", 3481 "let", 3482 "new", 3483 "package", 3484 "private", 3485 "protected", 3486 "public", 3487 "return", 3488 "static", 3489 "super", 3490 "switch", 3491 "this", 3492 "throw", 3493 "try", 3494 "typeof", 3495 "var", 3496 "void", 3497 "while", 3498 "with", 3499 "yield", 3500 NULL 3501 }; 3502 3503 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; 3504 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0, 3505 always_flags, arraysize(always_flags)); 3506 } 3507 3508 3509 TEST(MethodDefinitionStrictFormalParamereters) { 3510 const char* context_data[][2] = {{"({method(", "){}});"}, 3511 {"'use strict'; ({method(", "){}});"}, 3512 {"({*method(", "){}});"}, 3513 {"'use strict'; ({*method(", "){}});"}, 3514 {NULL, NULL}}; 3515 3516 const char* params_data[] = { 3517 "x, x", 3518 "x, y, x", 3519 "eval", 3520 "arguments", 3521 "var", 3522 "const", 3523 NULL 3524 }; 3525 3526 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; 3527 RunParserSyncTest(context_data, params_data, kError, NULL, 0, 3528 always_flags, arraysize(always_flags)); 3529 } 3530 3531 3532 TEST(MethodDefinitionDuplicateProperty) { 3533 // Duplicate properties are allowed in ES6 but we haven't removed that check 3534 // yet. 3535 const char* context_data[][2] = {{"'use strict'; ({", "});"}, 3536 {NULL, NULL}}; 3537 3538 const char* params_data[] = { 3539 "x: 1, x() {}", 3540 "x() {}, x: 1", 3541 "x() {}, get x() {}", 3542 "x() {}, set x(_) {}", 3543 "x() {}, x() {}", 3544 "x() {}, y() {}, x() {}", 3545 "x() {}, \"x\"() {}", 3546 "x() {}, 'x'() {}", 3547 "0() {}, '0'() {}", 3548 "1.0() {}, 1: 1", 3549 3550 "x: 1, *x() {}", 3551 "*x() {}, x: 1", 3552 "*x() {}, get x() {}", 3553 "*x() {}, set x(_) {}", 3554 "*x() {}, *x() {}", 3555 "*x() {}, y() {}, *x() {}", 3556 "*x() {}, *\"x\"() {}", 3557 "*x() {}, *'x'() {}", 3558 "*0() {}, *'0'() {}", 3559 "*1.0() {}, 1: 1", 3560 3561 NULL 3562 }; 3563 3564 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; 3565 RunParserSyncTest(context_data, params_data, kError, NULL, 0, 3566 always_flags, arraysize(always_flags)); 3567 } 3568 3569 3570 TEST(ClassExpressionNoErrors) { 3571 const char* context_data[][2] = {{"(", ");"}, 3572 {"var C = ", ";"}, 3573 {"bar, ", ";"}, 3574 {NULL, NULL}}; 3575 const char* class_data[] = { 3576 "class {}", 3577 "class name {}", 3578 "class extends F {}", 3579 "class name extends F {}", 3580 "class extends (F, G) {}", 3581 "class name extends (F, G) {}", 3582 "class extends class {} {}", 3583 "class name extends class {} {}", 3584 "class extends class base {} {}", 3585 "class name extends class base {} {}", 3586 NULL}; 3587 3588 static const ParserFlag always_flags[] = {kAllowClasses}; 3589 RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0, 3590 always_flags, arraysize(always_flags)); 3591 } 3592 3593 3594 TEST(ClassDeclarationNoErrors) { 3595 const char* context_data[][2] = {{"", ""}, 3596 {"{", "}"}, 3597 {"if (true) {", "}"}, 3598 {NULL, NULL}}; 3599 const char* statement_data[] = { 3600 "class name {}", 3601 "class name extends F {}", 3602 "class name extends (F, G) {}", 3603 "class name extends class {} {}", 3604 "class name extends class base {} {}", 3605 NULL}; 3606 3607 static const ParserFlag always_flags[] = {kAllowClasses}; 3608 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, 3609 always_flags, arraysize(always_flags)); 3610 } 3611 3612 3613 TEST(ClassBodyNoErrors) { 3614 // Tests that parser and preparser accept valid class syntax. 3615 const char* context_data[][2] = {{"(class {", "});"}, 3616 {"(class extends Base {", "});"}, 3617 {"class C {", "}"}, 3618 {"class C extends Base {", "}"}, 3619 {NULL, NULL}}; 3620 const char* class_body_data[] = { 3621 ";", 3622 ";;", 3623 "m() {}", 3624 "m() {};", 3625 "; m() {}", 3626 "m() {}; n(x) {}", 3627 "get x() {}", 3628 "set x(v) {}", 3629 "get() {}", 3630 "set() {}", 3631 "*g() {}", 3632 "*g() {};", 3633 "; *g() {}", 3634 "*g() {}; *h(x) {}", 3635 "static() {}", 3636 "static m() {}", 3637 "static get x() {}", 3638 "static set x(v) {}", 3639 "static get() {}", 3640 "static set() {}", 3641 "static static() {}", 3642 "static get static() {}", 3643 "static set static(v) {}", 3644 "*static() {}", 3645 "*get() {}", 3646 "*set() {}", 3647 "static *g() {}", 3648 NULL}; 3649 3650 static const ParserFlag always_flags[] = { 3651 kAllowClasses, 3652 kAllowHarmonyObjectLiterals 3653 }; 3654 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0, 3655 always_flags, arraysize(always_flags)); 3656 } 3657 3658 3659 TEST(ClassPropertyNameNoErrors) { 3660 const char* context_data[][2] = {{"(class {", "() {}});"}, 3661 {"(class { get ", "() {}});"}, 3662 {"(class { set ", "(v) {}});"}, 3663 {"(class { static ", "() {}});"}, 3664 {"(class { static get ", "() {}});"}, 3665 {"(class { static set ", "(v) {}});"}, 3666 {"(class { *", "() {}});"}, 3667 {"(class { static *", "() {}});"}, 3668 {"class C {", "() {}}"}, 3669 {"class C { get ", "() {}}"}, 3670 {"class C { set ", "(v) {}}"}, 3671 {"class C { static ", "() {}}"}, 3672 {"class C { static get ", "() {}}"}, 3673 {"class C { static set ", "(v) {}}"}, 3674 {"class C { *", "() {}}"}, 3675 {"class C { static *", "() {}}"}, 3676 {NULL, NULL}}; 3677 const char* name_data[] = { 3678 "42", 3679 "42.5", 3680 "42e2", 3681 "42e+2", 3682 "42e-2", 3683 "null", 3684 "false", 3685 "true", 3686 "'str'", 3687 "\"str\"", 3688 "static", 3689 "get", 3690 "set", 3691 "var", 3692 "const", 3693 "let", 3694 "this", 3695 "class", 3696 "function", 3697 "yield", 3698 "if", 3699 "else", 3700 "for", 3701 "while", 3702 "do", 3703 "try", 3704 "catch", 3705 "finally", 3706 NULL}; 3707 3708 static const ParserFlag always_flags[] = { 3709 kAllowClasses, 3710 kAllowHarmonyObjectLiterals 3711 }; 3712 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0, 3713 always_flags, arraysize(always_flags)); 3714 } 3715 3716 3717 TEST(ClassExpressionErrors) { 3718 const char* context_data[][2] = {{"(", ");"}, 3719 {"var C = ", ";"}, 3720 {"bar, ", ";"}, 3721 {NULL, NULL}}; 3722 const char* class_data[] = { 3723 "class", 3724 "class name", 3725 "class name extends", 3726 "class extends", 3727 "class {", 3728 "class { m }", 3729 "class { m; n }", 3730 "class { m: 1 }", 3731 "class { m(); n() }", 3732 "class { get m }", 3733 "class { get m() }", 3734 "class { get m() { }", 3735 "class { set m() {} }", // Missing required parameter. 3736 "class { m() {}, n() {} }", // No commas allowed. 3737 NULL}; 3738 3739 static const ParserFlag always_flags[] = { 3740 kAllowClasses, 3741 kAllowHarmonyObjectLiterals 3742 }; 3743 RunParserSyncTest(context_data, class_data, kError, NULL, 0, 3744 always_flags, arraysize(always_flags)); 3745 } 3746 3747 3748 TEST(ClassDeclarationErrors) { 3749 const char* context_data[][2] = {{"", ""}, 3750 {"{", "}"}, 3751 {"if (true) {", "}"}, 3752 {NULL, NULL}}; 3753 const char* class_data[] = { 3754 "class", 3755 "class name", 3756 "class name extends", 3757 "class extends", 3758 "class name {", 3759 "class name { m }", 3760 "class name { m; n }", 3761 "class name { m: 1 }", 3762 "class name { m(); n() }", 3763 "class name { get x }", 3764 "class name { get x() }", 3765 "class name { set x() {) }", // missing required param 3766 "class {}", // Name is required for declaration 3767 "class extends base {}", 3768 "class name { *", 3769 "class name { * }", 3770 "class name { *; }", 3771 "class name { *get x() {} }", 3772 "class name { *set x(_) {} }", 3773 "class name { *static m() {} }", 3774 NULL}; 3775 3776 static const ParserFlag always_flags[] = { 3777 kAllowClasses, 3778 kAllowHarmonyNumericLiterals 3779 }; 3780 RunParserSyncTest(context_data, class_data, kError, NULL, 0, 3781 always_flags, arraysize(always_flags)); 3782 } 3783 3784 3785 TEST(ClassNameErrors) { 3786 const char* context_data[][2] = {{"class ", "{}"}, 3787 {"(class ", "{});"}, 3788 {"'use strict'; class ", "{}"}, 3789 {"'use strict'; (class ", "{});"}, 3790 {NULL, NULL}}; 3791 const char* class_name[] = { 3792 "arguments", 3793 "eval", 3794 "implements", 3795 "interface", 3796 "let", 3797 "package", 3798 "private", 3799 "protected", 3800 "public", 3801 "static", 3802 "var", 3803 "yield", 3804 NULL}; 3805 3806 static const ParserFlag always_flags[] = { 3807 kAllowClasses, 3808 kAllowHarmonyObjectLiterals 3809 }; 3810 RunParserSyncTest(context_data, class_name, kError, NULL, 0, 3811 always_flags, arraysize(always_flags)); 3812 } 3813 3814 3815 TEST(ClassGetterParamNameErrors) { 3816 const char* context_data[][2] = { 3817 {"class C { get name(", ") {} }"}, 3818 {"(class { get name(", ") {} });"}, 3819 {"'use strict'; class C { get name(", ") {} }"}, 3820 {"'use strict'; (class { get name(", ") {} })"}, 3821 {NULL, NULL} 3822 }; 3823 3824 const char* class_name[] = { 3825 "arguments", 3826 "eval", 3827 "implements", 3828 "interface", 3829 "let", 3830 "package", 3831 "private", 3832 "protected", 3833 "public", 3834 "static", 3835 "var", 3836 "yield", 3837 NULL}; 3838 3839 static const ParserFlag always_flags[] = { 3840 kAllowClasses, 3841 kAllowHarmonyObjectLiterals 3842 }; 3843 RunParserSyncTest(context_data, class_name, kError, NULL, 0, 3844 always_flags, arraysize(always_flags)); 3845 } 3846 3847 3848 TEST(ClassStaticPrototypeErrors) { 3849 const char* context_data[][2] = {{"class C {", "}"}, 3850 {"(class {", "});"}, 3851 {NULL, NULL}}; 3852 3853 const char* class_body_data[] = { 3854 "static prototype() {}", 3855 "static get prototype() {}", 3856 "static set prototype(_) {}", 3857 "static *prototype() {}", 3858 NULL}; 3859 3860 static const ParserFlag always_flags[] = { 3861 kAllowClasses, 3862 kAllowHarmonyObjectLiterals 3863 }; 3864 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, 3865 always_flags, arraysize(always_flags)); 3866 } 3867 3868 3869 TEST(ClassSpecialConstructorErrors) { 3870 const char* context_data[][2] = {{"class C {", "}"}, 3871 {"(class {", "});"}, 3872 {NULL, NULL}}; 3873 3874 const char* class_body_data[] = { 3875 "get constructor() {}", 3876 "get constructor(_) {}", 3877 "*constructor() {}", 3878 NULL}; 3879 3880 static const ParserFlag always_flags[] = { 3881 kAllowClasses, 3882 kAllowHarmonyObjectLiterals 3883 }; 3884 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, 3885 always_flags, arraysize(always_flags)); 3886 } 3887 3888 3889 TEST(ClassConstructorNoErrors) { 3890 const char* context_data[][2] = {{"class C {", "}"}, 3891 {"(class {", "});"}, 3892 {NULL, NULL}}; 3893 3894 const char* class_body_data[] = { 3895 "constructor() {}", 3896 "static constructor() {}", 3897 "static get constructor() {}", 3898 "static set constructor(_) {}", 3899 "static *constructor() {}", 3900 NULL}; 3901 3902 static const ParserFlag always_flags[] = { 3903 kAllowClasses, 3904 kAllowHarmonyObjectLiterals 3905 }; 3906 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0, 3907 always_flags, arraysize(always_flags)); 3908 } 3909 3910 3911 TEST(ClassMultipleConstructorErrors) { 3912 // We currently do not allow any duplicate properties in class bodies. This 3913 // test ensures that when we change that we still throw on duplicate 3914 // constructors. 3915 const char* context_data[][2] = {{"class C {", "}"}, 3916 {"(class {", "});"}, 3917 {NULL, NULL}}; 3918 3919 const char* class_body_data[] = { 3920 "constructor() {}; constructor() {}", 3921 NULL}; 3922 3923 static const ParserFlag always_flags[] = { 3924 kAllowClasses, 3925 kAllowHarmonyObjectLiterals 3926 }; 3927 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, 3928 always_flags, arraysize(always_flags)); 3929 } 3930 3931 3932 // TODO(arv): We should allow duplicate property names. 3933 // https://code.google.com/p/v8/issues/detail?id=3570 3934 DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) { 3935 const char* context_data[][2] = {{"class C {", "}"}, 3936 {"(class {", "});"}, 3937 {NULL, NULL}}; 3938 3939 const char* class_body_data[] = { 3940 "constructor() {}; static constructor() {}", 3941 "m() {}; static m() {}", 3942 "m() {}; m() {}", 3943 NULL}; 3944 3945 static const ParserFlag always_flags[] = { 3946 kAllowClasses, 3947 kAllowHarmonyObjectLiterals 3948 }; 3949 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0, 3950 always_flags, arraysize(always_flags)); 3951 } 3952 3953 3954 TEST(ClassesAreStrictErrors) { 3955 const char* context_data[][2] = {{"", ""}, 3956 {"(", ");"}, 3957 {NULL, NULL}}; 3958 3959 const char* class_body_data[] = { 3960 "class C { method() { with ({}) {} } }", 3961 "class C extends function() { with ({}) {} } {}", 3962 "class C { *method() { with ({}) {} } }", 3963 NULL}; 3964 3965 static const ParserFlag always_flags[] = { 3966 kAllowClasses, 3967 kAllowHarmonyObjectLiterals 3968 }; 3969 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, 3970 always_flags, arraysize(always_flags)); 3971 } 3972