1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "src/ast-numbering.h"
36 #include "src/ast-value-factory.h"
37 #include "src/compiler.h"
38 #include "src/execution.h"
39 #include "src/isolate.h"
40 #include "src/objects.h"
41 #include "src/parser.h"
42 #include "src/preparser.h"
43 #include "src/rewriter.h"
44 #include "src/scanner-character-streams.h"
45 #include "src/token.h"
46 #include "src/utils.h"
48 #include "test/cctest/cctest.h"
53 i::Token::Value token;
56 static const KeywordToken keywords[] = {
57 #define KEYWORD(t, s, d) { s, i::Token::t },
58 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
60 { NULL, i::Token::IDENTIFIER }
63 KeywordToken key_token;
64 i::UnicodeCache unicode_cache;
66 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
67 const i::byte* keyword =
68 reinterpret_cast<const i::byte*>(key_token.keyword);
69 int length = i::StrLength(key_token.keyword);
70 CHECK(static_cast<int>(sizeof(buffer)) >= length);
72 i::Utf8ToUtf16CharacterStream stream(keyword, length);
73 i::Scanner scanner(&unicode_cache);
74 // The scanner should parse Harmony keywords for this test.
75 scanner.SetHarmonyScoping(true);
76 scanner.SetHarmonyModules(true);
77 scanner.SetHarmonyClasses(true);
78 scanner.Initialize(&stream);
79 CHECK_EQ(key_token.token, scanner.Next());
80 CHECK_EQ(i::Token::EOS, scanner.Next());
82 // Removing characters will make keyword matching fail.
84 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
85 i::Scanner scanner(&unicode_cache);
86 scanner.Initialize(&stream);
87 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
88 CHECK_EQ(i::Token::EOS, scanner.Next());
90 // Adding characters will make keyword matching fail.
91 static const char chars_to_append[] = { 'z', '0', '_' };
92 for (int j = 0; j < static_cast<int>(arraysize(chars_to_append)); ++j) {
93 i::MemMove(buffer, keyword, length);
94 buffer[length] = chars_to_append[j];
95 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
96 i::Scanner scanner(&unicode_cache);
97 scanner.Initialize(&stream);
98 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
99 CHECK_EQ(i::Token::EOS, scanner.Next());
101 // Replacing characters will make keyword matching fail.
103 i::MemMove(buffer, keyword, length);
104 buffer[length - 1] = '_';
105 i::Utf8ToUtf16CharacterStream stream(buffer, length);
106 i::Scanner scanner(&unicode_cache);
107 scanner.Initialize(&stream);
108 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
109 CHECK_EQ(i::Token::EOS, scanner.Next());
115 TEST(ScanHTMLEndComments) {
116 v8::V8::Initialize();
117 v8::Isolate* isolate = CcTest::isolate();
118 v8::HandleScope handles(isolate);
120 // Regression test. See:
121 // http://code.google.com/p/chromium/issues/detail?id=53548
122 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
123 // is only whitespace before it on the line (with comments considered as
124 // whitespace, even a multiline-comment containing a newline).
125 // This was not the case if it occurred before the first real token
127 const char* tests[] = {
128 // Before first real token.
129 "--> is eol-comment\nvar y = 37;\n",
130 "\n --> is eol-comment\nvar y = 37;\n",
131 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
132 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
133 // After first real token.
134 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
135 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
139 const char* fail_tests[] = {
140 "x --> is eol-comment\nvar y = 37;\n",
141 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
142 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
143 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
144 "var x = 42; --> is eol-comment\nvar y = 37;\n",
145 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
149 // Parser/Scanner needs a stack limit.
150 CcTest::i_isolate()->stack_guard()->SetStackLimit(
151 i::GetCurrentStackPosition() - 128 * 1024);
152 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
153 for (int i = 0; tests[i]; i++) {
154 const i::byte* source =
155 reinterpret_cast<const i::byte*>(tests[i]);
156 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i]));
157 i::CompleteParserRecorder log;
158 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
159 scanner.Initialize(&stream);
161 i::AstValueFactory ast_value_factory(
162 &zone, CcTest::i_isolate()->heap()->HashSeed());
163 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
165 preparser.set_allow_lazy(true);
166 i::PreParser::PreParseResult result = preparser.PreParseProgram();
167 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
168 CHECK(!log.HasError());
171 for (int i = 0; fail_tests[i]; i++) {
172 const i::byte* source =
173 reinterpret_cast<const i::byte*>(fail_tests[i]);
174 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i]));
175 i::CompleteParserRecorder log;
176 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
177 scanner.Initialize(&stream);
179 i::AstValueFactory ast_value_factory(
180 &zone, CcTest::i_isolate()->heap()->HashSeed());
181 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
183 preparser.set_allow_lazy(true);
184 i::PreParser::PreParseResult result = preparser.PreParseProgram();
185 // Even in the case of a syntax error, kPreParseSuccess is returned.
186 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
187 CHECK(log.HasError());
192 class ScriptResource : public v8::String::ExternalOneByteStringResource {
194 ScriptResource(const char* data, size_t length)
195 : data_(data), length_(length) { }
197 const char* data() const { return data_; }
198 size_t length() const { return length_; }
206 TEST(UsingCachedData) {
207 v8::Isolate* isolate = CcTest::isolate();
208 v8::HandleScope handles(isolate);
209 v8::Local<v8::Context> context = v8::Context::New(isolate);
210 v8::Context::Scope context_scope(context);
211 CcTest::i_isolate()->stack_guard()->SetStackLimit(
212 i::GetCurrentStackPosition() - 128 * 1024);
214 // Source containing functions that might be lazily compiled and all types
215 // of symbols (string, propertyName, regexp).
218 "function foo(a) { return function nolazy(b) { return a + b; } }"
219 "function bar(a) { if (a) return function lazy(b) { return b; } }"
220 "var z = {'string': 'string literal', bareword: 'propertyName', "
221 " 42: 'number literal', for: 'keyword as propertyName', "
222 " f\\u006fr: 'keyword propertyname with escape'};"
223 "var v = /RegExp Literal/;"
224 "var w = /RegExp Literal\\u0020With Escape/gin;"
225 "var y = { get getter() { return 42; }, "
226 " set setter(v) { this.value = v; }};"
227 "var f = a => function (b) { return a + b; };"
228 "var g = a => b => a + b;";
229 int source_length = i::StrLength(source);
231 // ScriptResource will be deleted when the corresponding String is GCd.
232 v8::ScriptCompiler::Source script_source(v8::String::NewExternal(
233 isolate, new ScriptResource(source, source_length)));
234 i::FLAG_harmony_arrow_functions = true;
235 i::FLAG_min_preparse_length = 0;
236 v8::ScriptCompiler::Compile(isolate, &script_source,
237 v8::ScriptCompiler::kProduceParserCache);
238 CHECK(script_source.GetCachedData());
240 // Compile the script again, using the cached data.
241 bool lazy_flag = i::FLAG_lazy;
243 v8::ScriptCompiler::Compile(isolate, &script_source,
244 v8::ScriptCompiler::kConsumeParserCache);
245 i::FLAG_lazy = false;
246 v8::ScriptCompiler::CompileUnbound(isolate, &script_source,
247 v8::ScriptCompiler::kConsumeParserCache);
248 i::FLAG_lazy = lazy_flag;
252 TEST(PreparseFunctionDataIsUsed) {
253 // This tests that we actually do use the function data generated by the
256 // Make preparsing work for short scripts.
257 i::FLAG_min_preparse_length = 0;
258 i::FLAG_harmony_arrow_functions = true;
260 v8::Isolate* isolate = CcTest::isolate();
261 v8::HandleScope handles(isolate);
262 v8::Local<v8::Context> context = v8::Context::New(isolate);
263 v8::Context::Scope context_scope(context);
264 CcTest::i_isolate()->stack_guard()->SetStackLimit(
265 i::GetCurrentStackPosition() - 128 * 1024);
267 const char* good_code[] = {
268 "function this_is_lazy() { var a; } function foo() { return 25; } foo();",
269 "var this_is_lazy = () => { var a; }; var foo = () => 25; foo();",
272 // Insert a syntax error inside the lazy function.
273 const char* bad_code[] = {
274 "function this_is_lazy() { if ( } function foo() { return 25; } foo();",
275 "var this_is_lazy = () => { if ( }; var foo = () => 25; foo();",
278 for (unsigned i = 0; i < arraysize(good_code); i++) {
279 v8::ScriptCompiler::Source good_source(v8_str(good_code[i]));
280 v8::ScriptCompiler::Compile(isolate, &good_source,
281 v8::ScriptCompiler::kProduceDataToCache);
283 const v8::ScriptCompiler::CachedData* cached_data =
284 good_source.GetCachedData();
285 CHECK(cached_data->data != NULL);
286 CHECK_GT(cached_data->length, 0);
288 // Now compile the erroneous code with the good preparse data. If the
289 // preparse data is used, the lazy function is skipped and it should
291 v8::ScriptCompiler::Source bad_source(
292 v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData(
293 cached_data->data, cached_data->length));
294 v8::Local<v8::Value> result =
295 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
296 CHECK(result->IsInt32());
297 CHECK_EQ(25, result->Int32Value());
302 TEST(StandAlonePreParser) {
303 v8::V8::Initialize();
305 CcTest::i_isolate()->stack_guard()->SetStackLimit(
306 i::GetCurrentStackPosition() - 128 * 1024);
308 const char* programs[] = {
311 "function foo(x, y) { return x + y; }",
312 "%ArgleBargle(glop);",
313 "var x = new new Function('this.x = 42');",
314 "var f = (x, y) => x + y;",
318 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
319 for (int i = 0; programs[i]; i++) {
320 const char* program = programs[i];
321 i::Utf8ToUtf16CharacterStream stream(
322 reinterpret_cast<const i::byte*>(program),
323 static_cast<unsigned>(strlen(program)));
324 i::CompleteParserRecorder log;
325 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
326 scanner.Initialize(&stream);
329 i::AstValueFactory ast_value_factory(
330 &zone, CcTest::i_isolate()->heap()->HashSeed());
331 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
333 preparser.set_allow_lazy(true);
334 preparser.set_allow_natives(true);
335 preparser.set_allow_harmony_arrow_functions(true);
336 i::PreParser::PreParseResult result = preparser.PreParseProgram();
337 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
338 CHECK(!log.HasError());
343 TEST(StandAlonePreParserNoNatives) {
344 v8::V8::Initialize();
346 CcTest::i_isolate()->stack_guard()->SetStackLimit(
347 i::GetCurrentStackPosition() - 128 * 1024);
349 const char* programs[] = {
350 "%ArgleBargle(glop);",
351 "var x = %_IsSmi(42);",
355 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
356 for (int i = 0; programs[i]; i++) {
357 const char* program = programs[i];
358 i::Utf8ToUtf16CharacterStream stream(
359 reinterpret_cast<const i::byte*>(program),
360 static_cast<unsigned>(strlen(program)));
361 i::CompleteParserRecorder log;
362 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
363 scanner.Initialize(&stream);
365 // Preparser defaults to disallowing natives syntax.
367 i::AstValueFactory ast_value_factory(
368 &zone, CcTest::i_isolate()->heap()->HashSeed());
369 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
371 preparser.set_allow_lazy(true);
372 i::PreParser::PreParseResult result = preparser.PreParseProgram();
373 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
374 CHECK(log.HasError());
379 TEST(PreparsingObjectLiterals) {
380 // Regression test for a bug where the symbol stream produced by PreParser
381 // didn't match what Parser wanted to consume.
382 v8::Isolate* isolate = CcTest::isolate();
383 v8::HandleScope handles(isolate);
384 v8::Local<v8::Context> context = v8::Context::New(isolate);
385 v8::Context::Scope context_scope(context);
386 CcTest::i_isolate()->stack_guard()->SetStackLimit(
387 i::GetCurrentStackPosition() - 128 * 1024);
390 const char* source = "var myo = {if: \"foo\"}; myo.if;";
391 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
392 CHECK(result->IsString());
393 v8::String::Utf8Value utf8(result);
394 CHECK_EQ(0, strcmp("foo", *utf8));
398 const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
399 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
400 CHECK(result->IsString());
401 v8::String::Utf8Value utf8(result);
402 CHECK_EQ(0, strcmp("foo", *utf8));
406 const char* source = "var myo = {1: \"foo\"}; myo[1];";
407 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
408 CHECK(result->IsString());
409 v8::String::Utf8Value utf8(result);
410 CHECK_EQ(0, strcmp("foo", *utf8));
415 TEST(RegressChromium62639) {
416 v8::V8::Initialize();
417 i::Isolate* isolate = CcTest::i_isolate();
419 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
422 const char* program = "var x = 'something';\n"
423 "escape: function() {}";
424 // Fails parsing expecting an identifier after "function".
425 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
426 // and then used the invalid currently scanned literal. This always
427 // failed in debug mode, and sometimes crashed in release mode.
429 i::Utf8ToUtf16CharacterStream stream(
430 reinterpret_cast<const i::byte*>(program),
431 static_cast<unsigned>(strlen(program)));
432 i::CompleteParserRecorder log;
433 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
434 scanner.Initialize(&stream);
436 i::AstValueFactory ast_value_factory(&zone,
437 CcTest::i_isolate()->heap()->HashSeed());
438 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
439 CcTest::i_isolate()->stack_guard()->real_climit());
440 preparser.set_allow_lazy(true);
441 i::PreParser::PreParseResult result = preparser.PreParseProgram();
442 // Even in the case of a syntax error, kPreParseSuccess is returned.
443 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
444 CHECK(log.HasError());
449 v8::V8::Initialize();
450 i::Isolate* isolate = CcTest::i_isolate();
451 i::Factory* factory = isolate->factory();
453 // Preparsing didn't consider the catch clause of a try statement
454 // as with-content, which made it assume that a function inside
455 // the block could be lazily compiled, and an extra, unexpected,
456 // entry was added to the data.
457 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
460 const char* program =
461 "try { } catch (e) { var foo = function () { /* first */ } }"
462 "var bar = function () { /* second */ }";
464 v8::HandleScope handles(CcTest::isolate());
465 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program);
466 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
467 i::CompleteParserRecorder log;
468 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
469 scanner.Initialize(&stream);
471 i::AstValueFactory ast_value_factory(&zone,
472 CcTest::i_isolate()->heap()->HashSeed());
473 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
474 CcTest::i_isolate()->stack_guard()->real_climit());
475 preparser.set_allow_lazy(true);
476 i::PreParser::PreParseResult result = preparser.PreParseProgram();
477 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
478 i::ScriptData* sd = log.GetScriptData();
479 i::ParseData* pd = i::ParseData::FromCachedData(sd);
483 static_cast<int>(strstr(program, "function") - program);
484 int first_lbrace = first_function + i::StrLength("function () ");
485 CHECK_EQ('{', program[first_lbrace]);
486 i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
487 CHECK(!entry1.is_valid());
489 int second_function =
490 static_cast<int>(strstr(program + first_lbrace, "function") - program);
492 second_function + i::StrLength("function () ");
493 CHECK_EQ('{', program[second_lbrace]);
494 i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
495 CHECK(entry2.is_valid());
496 CHECK_EQ('}', program[entry2.end_pos() - 1]);
502 TEST(PreParseOverflow) {
503 v8::V8::Initialize();
505 CcTest::i_isolate()->stack_guard()->SetStackLimit(
506 i::GetCurrentStackPosition() - 128 * 1024);
508 size_t kProgramSize = 1024 * 1024;
509 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
510 memset(program.get(), '(', kProgramSize);
511 program[kProgramSize] = '\0';
513 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
515 i::Utf8ToUtf16CharacterStream stream(
516 reinterpret_cast<const i::byte*>(program.get()),
517 static_cast<unsigned>(kProgramSize));
518 i::CompleteParserRecorder log;
519 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
520 scanner.Initialize(&stream);
523 i::AstValueFactory ast_value_factory(&zone,
524 CcTest::i_isolate()->heap()->HashSeed());
525 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
527 preparser.set_allow_lazy(true);
528 preparser.set_allow_harmony_arrow_functions(true);
529 i::PreParser::PreParseResult result = preparser.PreParseProgram();
530 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
534 class TestExternalResource: public v8::String::ExternalStringResource {
536 explicit TestExternalResource(uint16_t* data, int length)
537 : data_(data), length_(static_cast<size_t>(length)) { }
539 ~TestExternalResource() { }
541 const uint16_t* data() const {
545 size_t length() const {
554 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
556 void TestCharacterStream(const char* one_byte_source, unsigned length,
557 unsigned start = 0, unsigned end = 0) {
558 if (end == 0) end = length;
559 unsigned sub_length = end - start;
560 i::Isolate* isolate = CcTest::i_isolate();
561 i::Factory* factory = isolate->factory();
562 i::HandleScope test_scope(isolate);
563 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
564 for (unsigned i = 0; i < length; i++) {
565 uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]);
567 i::Vector<const char> one_byte_vector(one_byte_source,
568 static_cast<int>(length));
569 i::Handle<i::String> one_byte_string =
570 factory->NewStringFromAscii(one_byte_vector).ToHandleChecked();
571 TestExternalResource resource(uc16_buffer.get(), length);
572 i::Handle<i::String> uc16_string(
573 factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked());
575 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
576 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
577 i::GenericStringUtf16CharacterStream string_stream(one_byte_string, start,
579 i::Utf8ToUtf16CharacterStream utf8_stream(
580 reinterpret_cast<const i::byte*>(one_byte_source), end);
581 utf8_stream.SeekForward(start);
585 // Read streams one char at a time
586 CHECK_EQU(i, uc16_stream.pos());
587 CHECK_EQU(i, string_stream.pos());
588 CHECK_EQU(i, utf8_stream.pos());
589 int32_t c0 = one_byte_source[i];
590 int32_t c1 = uc16_stream.Advance();
591 int32_t c2 = string_stream.Advance();
592 int32_t c3 = utf8_stream.Advance();
597 CHECK_EQU(i, uc16_stream.pos());
598 CHECK_EQU(i, string_stream.pos());
599 CHECK_EQU(i, utf8_stream.pos());
601 while (i > start + sub_length / 4) {
602 // Pushback, re-read, pushback again.
603 int32_t c0 = one_byte_source[i - 1];
604 CHECK_EQU(i, uc16_stream.pos());
605 CHECK_EQU(i, string_stream.pos());
606 CHECK_EQU(i, utf8_stream.pos());
607 uc16_stream.PushBack(c0);
608 string_stream.PushBack(c0);
609 utf8_stream.PushBack(c0);
611 CHECK_EQU(i, uc16_stream.pos());
612 CHECK_EQU(i, string_stream.pos());
613 CHECK_EQU(i, utf8_stream.pos());
614 int32_t c1 = uc16_stream.Advance();
615 int32_t c2 = string_stream.Advance();
616 int32_t c3 = utf8_stream.Advance();
618 CHECK_EQU(i, uc16_stream.pos());
619 CHECK_EQU(i, string_stream.pos());
620 CHECK_EQU(i, utf8_stream.pos());
624 uc16_stream.PushBack(c0);
625 string_stream.PushBack(c0);
626 utf8_stream.PushBack(c0);
628 CHECK_EQU(i, uc16_stream.pos());
629 CHECK_EQU(i, string_stream.pos());
630 CHECK_EQU(i, utf8_stream.pos());
632 unsigned halfway = start + sub_length / 2;
633 uc16_stream.SeekForward(halfway - i);
634 string_stream.SeekForward(halfway - i);
635 utf8_stream.SeekForward(halfway - i);
637 CHECK_EQU(i, uc16_stream.pos());
638 CHECK_EQU(i, string_stream.pos());
639 CHECK_EQU(i, utf8_stream.pos());
642 // Read streams one char at a time
643 CHECK_EQU(i, uc16_stream.pos());
644 CHECK_EQU(i, string_stream.pos());
645 CHECK_EQU(i, utf8_stream.pos());
646 int32_t c0 = one_byte_source[i];
647 int32_t c1 = uc16_stream.Advance();
648 int32_t c2 = string_stream.Advance();
649 int32_t c3 = utf8_stream.Advance();
654 CHECK_EQU(i, uc16_stream.pos());
655 CHECK_EQU(i, string_stream.pos());
656 CHECK_EQU(i, utf8_stream.pos());
659 int32_t c1 = uc16_stream.Advance();
660 int32_t c2 = string_stream.Advance();
661 int32_t c3 = utf8_stream.Advance();
668 TEST(CharacterStreams) {
669 v8::Isolate* isolate = CcTest::isolate();
670 v8::HandleScope handles(isolate);
671 v8::Local<v8::Context> context = v8::Context::New(isolate);
672 v8::Context::Scope context_scope(context);
674 TestCharacterStream("abc\0\n\r\x7f", 7);
675 static const unsigned kBigStringSize = 4096;
676 char buffer[kBigStringSize + 1];
677 for (unsigned i = 0; i < kBigStringSize; i++) {
678 buffer[i] = static_cast<char>(i & 0x7f);
680 TestCharacterStream(buffer, kBigStringSize);
682 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
684 TestCharacterStream("\0", 1);
685 TestCharacterStream("", 0);
689 TEST(Utf8CharacterStream) {
690 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
691 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
693 static const int kAllUtf8CharsSize =
694 (unibrow::Utf8::kMaxOneByteChar + 1) +
695 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
696 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
697 static const unsigned kAllUtf8CharsSizeU =
698 static_cast<unsigned>(kAllUtf8CharsSize);
700 char buffer[kAllUtf8CharsSizeU];
702 for (int i = 0; i <= kMaxUC16Char; i++) {
703 cursor += unibrow::Utf8::Encode(buffer + cursor,
705 unibrow::Utf16::kNoPreviousCharacter);
707 DCHECK(cursor == kAllUtf8CharsSizeU);
709 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
711 for (int i = 0; i <= kMaxUC16Char; i++) {
712 CHECK_EQU(i, stream.pos());
713 int32_t c = stream.Advance();
715 CHECK_EQU(i + 1, stream.pos());
717 for (int i = kMaxUC16Char; i >= 0; i--) {
718 CHECK_EQU(i + 1, stream.pos());
720 CHECK_EQU(i, stream.pos());
723 while (stream.pos() < kMaxUC16CharU) {
724 CHECK_EQU(i, stream.pos());
725 int progress = static_cast<int>(stream.SeekForward(12));
727 int32_t c = stream.Advance();
728 if (i <= kMaxUC16Char) {
734 CHECK_EQU(i, stream.pos());
740 void TestStreamScanner(i::Utf16CharacterStream* stream,
741 i::Token::Value* expected_tokens,
742 int skip_pos = 0, // Zero means not skipping.
744 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
745 scanner.Initialize(stream);
749 i::Token::Value expected = expected_tokens[i];
750 i::Token::Value actual = scanner.Next();
751 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
752 if (scanner.location().end_pos == skip_pos) {
753 scanner.SeekForward(skip_to);
756 } while (expected_tokens[i] != i::Token::ILLEGAL);
760 TEST(StreamScanner) {
761 v8::V8::Initialize();
763 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
764 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
765 static_cast<unsigned>(strlen(str1)));
766 i::Token::Value expectations1[] = {
768 i::Token::IDENTIFIER,
769 i::Token::IDENTIFIER,
776 i::Token::IDENTIFIER,
780 TestStreamScanner(&stream1, expectations1, 0, 0);
782 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
783 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
784 static_cast<unsigned>(strlen(str2)));
785 i::Token::Value expectations2[] = {
796 DCHECK_EQ('{', str2[19]);
797 DCHECK_EQ('}', str2[37]);
798 TestStreamScanner(&stream2, expectations2, 20, 37);
800 const char* str3 = "{}}}}";
801 i::Token::Value expectations3[] = {
810 // Skip zero-four RBRACEs.
811 for (int i = 0; i <= 4; i++) {
812 expectations3[6 - i] = i::Token::ILLEGAL;
813 expectations3[5 - i] = i::Token::EOS;
814 i::Utf8ToUtf16CharacterStream stream3(
815 reinterpret_cast<const i::byte*>(str3),
816 static_cast<unsigned>(strlen(str3)));
817 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
822 void TestScanRegExp(const char* re_source, const char* expected) {
823 i::Utf8ToUtf16CharacterStream stream(
824 reinterpret_cast<const i::byte*>(re_source),
825 static_cast<unsigned>(strlen(re_source)));
826 i::HandleScope scope(CcTest::i_isolate());
827 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
828 scanner.Initialize(&stream);
830 i::Token::Value start = scanner.peek();
831 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
832 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
833 scanner.Next(); // Current token is now the regexp literal.
835 i::AstValueFactory ast_value_factory(&zone,
836 CcTest::i_isolate()->heap()->HashSeed());
837 ast_value_factory.Internalize(CcTest::i_isolate());
838 i::Handle<i::String> val =
839 scanner.CurrentSymbol(&ast_value_factory)->string();
840 i::DisallowHeapAllocation no_alloc;
841 i::String::FlatContent content = val->GetFlatContent();
842 CHECK(content.IsOneByte());
843 i::Vector<const uint8_t> actual = content.ToOneByteVector();
844 for (int i = 0; i < actual.length(); i++) {
845 CHECK_NE('\0', expected[i]);
846 CHECK_EQ(expected[i], actual[i]);
851 TEST(RegExpScanning) {
852 v8::V8::Initialize();
854 // RegExp token with added garbage at the end. The scanner should only
855 // scan the RegExp until the terminating slash just before "flipperwald".
856 TestScanRegExp("/b/flipperwald", "b");
857 // Incomplete escape sequences doesn't hide the terminating slash.
858 TestScanRegExp("/\\x/flipperwald", "\\x");
859 TestScanRegExp("/\\u/flipperwald", "\\u");
860 TestScanRegExp("/\\u1/flipperwald", "\\u1");
861 TestScanRegExp("/\\u12/flipperwald", "\\u12");
862 TestScanRegExp("/\\u123/flipperwald", "\\u123");
863 TestScanRegExp("/\\c/flipperwald", "\\c");
864 TestScanRegExp("/\\c//flipperwald", "\\c");
865 // Slashes inside character classes are not terminating.
866 TestScanRegExp("/[/]/flipperwald", "[/]");
867 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
868 // Incomplete escape sequences inside a character class doesn't hide
869 // the end of the character class.
870 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
871 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
872 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
873 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
874 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
875 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
876 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
877 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
878 // Escaped ']'s wont end the character class.
879 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
880 // Escaped slashes are not terminating.
881 TestScanRegExp("/\\//flipperwald", "\\/");
882 // Starting with '=' works too.
883 TestScanRegExp("/=/", "=");
884 TestScanRegExp("/=?/", "=?");
888 static int Utf8LengthHelper(const char* s) {
889 int len = i::StrLength(s);
890 int character_length = len;
891 for (int i = 0; i < len; i++) {
892 unsigned char c = s[i];
893 int input_offset = 0;
894 int output_adjust = 0;
896 if (c < 0xc0) continue;
899 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
901 continue; // Handle first UTF-8 byte.
903 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
904 // This 4 byte sequence could have been coded as a 3 byte sequence.
905 // Record a single kBadChar for the first byte and continue.
909 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
910 character_length -= 2;
911 } else if (c >= 0xe0) {
912 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
913 // This 3 byte sequence could have been coded as a 2 byte sequence.
914 // Record a single kBadChar for the first byte and continue.
918 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
921 if ((c & 0x1e) == 0) {
922 // This 2 byte sequence could have been coded as a 1 byte sequence.
923 // Record a single kBadChar for the first byte and continue.
927 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
931 for (int j = 1; j <= input_offset; j++) {
932 if ((s[i + j] & 0xc0) != 0x80) {
933 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
934 // which is a single UTF-16 code unit.
941 character_length -= output_adjust;
945 return character_length;
949 TEST(ScopeUsesArgumentsSuperThis) {
950 static const struct {
954 { "function f() {", "}" },
955 { "var f = () => {", "};" },
956 { "class C { constructor() {", "} }" },
962 SUPER_PROPERTY = 1 << 1,
964 INNER_ARGUMENTS = 1 << 3,
965 INNER_SUPER_PROPERTY = 1 << 4,
969 static const struct {
974 {"return this", THIS},
975 {"return arguments", ARGUMENTS},
976 {"return super.x", SUPER_PROPERTY},
977 {"return arguments[0]", ARGUMENTS},
978 {"return this + arguments[0]", ARGUMENTS | THIS},
979 {"return this + arguments[0] + super.x",
980 ARGUMENTS | SUPER_PROPERTY | THIS},
981 {"return x => this + x", INNER_THIS},
982 {"return x => super.f() + x", INNER_SUPER_PROPERTY},
983 {"this.foo = 42;", THIS},
984 {"this.foo();", THIS},
985 {"if (foo()) { this.f() }", THIS},
986 {"if (foo()) { super.f() }", SUPER_PROPERTY},
987 {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
988 {"while (true) { this.f() }", THIS},
989 {"while (true) { super.f() }", SUPER_PROPERTY},
990 {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
991 // Multiple nesting levels must work as well.
992 {"while (true) { while (true) { while (true) return this } }", THIS},
993 {"while (true) { while (true) { while (true) return super.f() } }",
995 {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
996 // Note that propagation of the inner_uses_this() value does not
997 // cross boundaries of normal functions onto parent scopes.
998 {"return function (x) { return this + x }", NONE},
999 {"return { m(x) { return super.m() + x } }", NONE},
1000 {"var x = function () { this.foo = 42 };", NONE},
1001 {"var x = { m() { super.foo = 42 } };", NONE},
1002 {"if (1) { return function () { while (true) new this() } }", NONE},
1003 {"if (1) { return { m() { while (true) super.m() } } }", NONE},
1004 {"return function (x) { return () => this }", NONE},
1005 {"return { m(x) { return () => super.m() } }", NONE},
1006 // Flags must be correctly set when using block scoping.
1007 {"\"use strict\"; while (true) { let x; this, arguments; }",
1008 INNER_ARGUMENTS | INNER_THIS},
1009 {"\"use strict\"; while (true) { let x; this, super.f(), arguments; }",
1010 INNER_ARGUMENTS | INNER_SUPER_PROPERTY | INNER_THIS},
1011 {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
1012 {"\"use strict\"; if (foo()) { let x; super.f() }",
1013 INNER_SUPER_PROPERTY},
1014 {"\"use strict\"; if (1) {"
1015 " let x; return { m() { return this + super.m() + arguments } }"
1020 i::Isolate* isolate = CcTest::i_isolate();
1021 i::Factory* factory = isolate->factory();
1023 v8::HandleScope handles(CcTest::isolate());
1024 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1025 v8::Context::Scope context_scope(context);
1027 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1030 for (unsigned j = 0; j < arraysize(surroundings); ++j) {
1031 for (unsigned i = 0; i < arraysize(source_data); ++i) {
1032 // Super property is only allowed in constructor and method.
1033 if (((source_data[i].expected & SUPER_PROPERTY) ||
1034 (source_data[i].expected & INNER_SUPER_PROPERTY) ||
1035 (source_data[i].expected == NONE)) && j != 2) {
1038 int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
1039 i::StrLength(surroundings[j].suffix) +
1040 i::StrLength(source_data[i].body);
1041 i::ScopedVector<char> program(kProgramByteSize + 1);
1042 i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
1043 source_data[i].body, surroundings[j].suffix);
1044 i::Handle<i::String> source =
1045 factory->NewStringFromUtf8(i::CStrVector(program.start()))
1047 i::Handle<i::Script> script = factory->NewScript(source);
1048 i::CompilationInfoWithZone info(script);
1049 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
1050 isolate->heap()->HashSeed(), isolate->unicode_cache());
1051 parser.set_allow_harmony_arrow_functions(true);
1052 parser.set_allow_harmony_classes(true);
1053 parser.set_allow_harmony_object_literals(true);
1054 parser.set_allow_harmony_scoping(true);
1055 parser.set_allow_harmony_sloppy(true);
1056 info.MarkAsGlobal();
1057 CHECK(parser.Parse(&info));
1058 CHECK(i::Rewriter::Rewrite(&info));
1059 CHECK(i::Scope::Analyze(&info));
1060 CHECK(info.function() != NULL);
1062 i::Scope* script_scope = info.function()->scope();
1063 CHECK(script_scope->is_script_scope());
1064 CHECK_EQ(1, script_scope->inner_scopes()->length());
1066 i::Scope* scope = script_scope->inner_scopes()->at(0);
1067 // Adjust for constructor scope.
1069 CHECK_EQ(1, scope->inner_scopes()->length());
1070 scope = scope->inner_scopes()->at(0);
1072 CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
1073 scope->uses_arguments());
1074 CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
1075 scope->uses_super_property());
1076 CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
1077 CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
1078 scope->inner_uses_arguments());
1079 CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
1080 scope->inner_uses_super_property());
1081 CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
1082 scope->inner_uses_this());
1088 TEST(ScopePositions) {
1089 v8::internal::FLAG_harmony_scoping = true;
1091 // Test the parser for correctly setting the start and end positions
1092 // of a scope. We check the scope positions of exactly one scope
1093 // nested in the global scope of a program. 'inner source' is the
1094 // source code that determines the part of the source belonging
1095 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
1096 // parts of the source that belong to the global scope.
1098 const char* outer_prefix;
1099 const char* inner_source;
1100 const char* outer_suffix;
1101 i::ScopeType scope_type;
1102 i::LanguageMode language_mode;
1105 const SourceData source_data[] = {
1106 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
1107 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
1108 { " with ({}) ", "{\n"
1111 " more;", i::WITH_SCOPE, i::SLOPPY },
1112 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
1113 { " with ({}) ", "statement", "\n"
1114 " more;", i::WITH_SCOPE, i::SLOPPY },
1116 " ", "statement;", "\n"
1117 " more;", i::WITH_SCOPE, i::SLOPPY },
1118 { " try {} catch ", "(e) { block; }", " more;",
1119 i::CATCH_SCOPE, i::SLOPPY },
1120 { " try {} catch ", "(e) { block; }", "; more;",
1121 i::CATCH_SCOPE, i::SLOPPY },
1122 { " try {} catch ", "(e) {\n"
1125 " more;", i::CATCH_SCOPE, i::SLOPPY },
1126 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
1127 i::CATCH_SCOPE, i::SLOPPY },
1129 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
1131 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
1136 " more;", i::BLOCK_SCOPE, i::STRICT },
1138 " function fun", "(a,b) { infunction; }", " more;",
1139 i::FUNCTION_SCOPE, i::SLOPPY },
1141 " function fun", "(a,b) {\n"
1144 " more;", i::FUNCTION_SCOPE, i::SLOPPY },
1145 { " start;\n", "(a,b) => a + b", "; more;",
1146 i::ARROW_SCOPE, i::SLOPPY },
1147 { " start;\n", "(a,b) => { return a+b; }", "\nmore;",
1148 i::ARROW_SCOPE, i::SLOPPY },
1150 " (function fun", "(a,b) { infunction; }", ")();",
1151 i::FUNCTION_SCOPE, i::SLOPPY },
1152 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
1153 i::BLOCK_SCOPE, i::STRICT },
1154 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
1155 i::BLOCK_SCOPE, i::STRICT },
1156 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
1159 " more;", i::BLOCK_SCOPE, i::STRICT },
1160 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
1161 i::BLOCK_SCOPE, i::STRICT },
1162 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
1163 " more;", i::BLOCK_SCOPE, i::STRICT },
1164 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
1166 " more;", i::BLOCK_SCOPE, i::STRICT },
1167 { " for ", "(let x in {}) { block; }", " more;",
1168 i::BLOCK_SCOPE, i::STRICT },
1169 { " for ", "(let x in {}) { block; }", "; more;",
1170 i::BLOCK_SCOPE, i::STRICT },
1171 { " for ", "(let x in {}) {\n"
1174 " more;", i::BLOCK_SCOPE, i::STRICT },
1175 { " for ", "(let x in {}) statement;", " more;",
1176 i::BLOCK_SCOPE, i::STRICT },
1177 { " for ", "(let x in {}) statement", "\n"
1178 " more;", i::BLOCK_SCOPE, i::STRICT },
1179 { " for ", "(let x in {})\n"
1181 " more;", i::BLOCK_SCOPE, i::STRICT },
1182 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
1183 // the preparser off in terms of byte offsets.
1185 { " 'foo\355\240\201\355\260\211';\n"
1186 " (function fun", "(a,b) { infunction; }", ")();",
1187 i::FUNCTION_SCOPE, i::SLOPPY },
1189 { " 'foo\360\220\220\212';\n"
1190 " (function fun", "(a,b) { infunction; }", ")();",
1191 i::FUNCTION_SCOPE, i::SLOPPY },
1192 // 3 byte encoding of \u0fff.
1193 { " 'foo\340\277\277';\n"
1194 " (function fun", "(a,b) { infunction; }", ")();",
1195 i::FUNCTION_SCOPE, i::SLOPPY },
1196 // Broken 6 byte encoding with missing last byte.
1197 { " 'foo\355\240\201\355\211';\n"
1198 " (function fun", "(a,b) { infunction; }", ")();",
1199 i::FUNCTION_SCOPE, i::SLOPPY },
1200 // Broken 3 byte encoding of \u0fff with missing last byte.
1201 { " 'foo\340\277';\n"
1202 " (function fun", "(a,b) { infunction; }", ")();",
1203 i::FUNCTION_SCOPE, i::SLOPPY },
1204 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
1206 " (function fun", "(a,b) { infunction; }", ")();",
1207 i::FUNCTION_SCOPE, i::SLOPPY },
1208 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
1209 { " 'foo\340\203\277';\n"
1210 " (function fun", "(a,b) { infunction; }", ")();",
1211 i::FUNCTION_SCOPE, i::SLOPPY },
1212 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
1213 { " 'foo\340\201\277';\n"
1214 " (function fun", "(a,b) { infunction; }", ")();",
1215 i::FUNCTION_SCOPE, i::SLOPPY },
1216 // Unpaired lead surrogate.
1217 { " 'foo\355\240\201';\n"
1218 " (function fun", "(a,b) { infunction; }", ")();",
1219 i::FUNCTION_SCOPE, i::SLOPPY },
1220 // Unpaired lead surrogate where following code point is a 3 byte sequence.
1221 { " 'foo\355\240\201\340\277\277';\n"
1222 " (function fun", "(a,b) { infunction; }", ")();",
1223 i::FUNCTION_SCOPE, i::SLOPPY },
1224 // Unpaired lead surrogate where following code point is a 4 byte encoding
1225 // of a trail surrogate.
1226 { " 'foo\355\240\201\360\215\260\211';\n"
1227 " (function fun", "(a,b) { infunction; }", ")();",
1228 i::FUNCTION_SCOPE, i::SLOPPY },
1229 // Unpaired trail surrogate.
1230 { " 'foo\355\260\211';\n"
1231 " (function fun", "(a,b) { infunction; }", ")();",
1232 i::FUNCTION_SCOPE, i::SLOPPY },
1233 // 2 byte encoding of \u00ff.
1234 { " 'foo\303\277';\n"
1235 " (function fun", "(a,b) { infunction; }", ")();",
1236 i::FUNCTION_SCOPE, i::SLOPPY },
1237 // Broken 2 byte encoding of \u00ff with missing last byte.
1239 " (function fun", "(a,b) { infunction; }", ")();",
1240 i::FUNCTION_SCOPE, i::SLOPPY },
1241 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
1242 { " 'foo\301\277';\n"
1243 " (function fun", "(a,b) { infunction; }", ")();",
1244 i::FUNCTION_SCOPE, i::SLOPPY },
1245 // Illegal 5 byte encoding.
1246 { " 'foo\370\277\277\277\277';\n"
1247 " (function fun", "(a,b) { infunction; }", ")();",
1248 i::FUNCTION_SCOPE, i::SLOPPY },
1249 // Illegal 6 byte encoding.
1250 { " 'foo\374\277\277\277\277\277';\n"
1251 " (function fun", "(a,b) { infunction; }", ")();",
1252 i::FUNCTION_SCOPE, i::SLOPPY },
1253 // Illegal 0xfe byte
1254 { " 'foo\376\277\277\277\277\277\277';\n"
1255 " (function fun", "(a,b) { infunction; }", ")();",
1256 i::FUNCTION_SCOPE, i::SLOPPY },
1257 // Illegal 0xff byte
1258 { " 'foo\377\277\277\277\277\277\277\277';\n"
1259 " (function fun", "(a,b) { infunction; }", ")();",
1260 i::FUNCTION_SCOPE, i::SLOPPY },
1262 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
1263 i::FUNCTION_SCOPE, i::SLOPPY },
1265 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
1266 i::FUNCTION_SCOPE, i::SLOPPY },
1267 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
1270 i::Isolate* isolate = CcTest::i_isolate();
1271 i::Factory* factory = isolate->factory();
1273 v8::HandleScope handles(CcTest::isolate());
1274 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1275 v8::Context::Scope context_scope(context);
1277 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1280 for (int i = 0; source_data[i].outer_prefix; i++) {
1281 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1282 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1283 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1284 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1285 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1286 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1287 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1288 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1289 i::ScopedVector<char> program(kProgramByteSize + 1);
1290 i::SNPrintF(program, "%s%s%s",
1291 source_data[i].outer_prefix,
1292 source_data[i].inner_source,
1293 source_data[i].outer_suffix);
1295 // Parse program source.
1296 i::Handle<i::String> source = factory->NewStringFromUtf8(
1297 i::CStrVector(program.start())).ToHandleChecked();
1298 CHECK_EQ(source->length(), kProgramSize);
1299 i::Handle<i::Script> script = factory->NewScript(source);
1300 i::CompilationInfoWithZone info(script);
1301 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
1302 isolate->heap()->HashSeed(), isolate->unicode_cache());
1303 parser.set_allow_lazy(true);
1304 parser.set_allow_harmony_scoping(true);
1305 parser.set_allow_harmony_arrow_functions(true);
1306 info.MarkAsGlobal();
1307 info.SetLanguageMode(source_data[i].language_mode);
1308 parser.Parse(&info);
1309 CHECK(info.function() != NULL);
1311 // Check scope types and positions.
1312 i::Scope* scope = info.function()->scope();
1313 CHECK(scope->is_script_scope());
1314 CHECK_EQ(scope->start_position(), 0);
1315 CHECK_EQ(scope->end_position(), kProgramSize);
1316 CHECK_EQ(scope->inner_scopes()->length(), 1);
1318 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1319 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
1320 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1321 // The end position of a token is one position after the last
1322 // character belonging to that token.
1323 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1328 const char* ReadString(unsigned* start) {
1329 int length = start[0];
1330 char* result = i::NewArray<char>(length + 1);
1331 for (int i = 0; i < length; i++) {
1332 result[i] = start[i + 1];
1334 result[length] = '\0';
1339 i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
1340 i::Isolate* isolate = CcTest::i_isolate();
1341 i::Factory* factory = isolate->factory();
1342 const char* message =
1343 ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
1344 i::Handle<i::String> format = v8::Utils::OpenHandle(
1345 *v8::String::NewFromUtf8(CcTest::isolate(), message));
1346 int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
1347 const char* arg = NULL;
1348 i::Handle<i::JSArray> args_array;
1349 if (arg_count == 1) {
1350 // Position after text found by skipping past length field and
1351 // length field content words.
1352 int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
1353 data[i::PreparseDataConstants::kMessageTextPos];
1354 arg = ReadString(&data[pos]);
1355 args_array = factory->NewJSArray(1);
1356 i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
1357 NONE, i::SLOPPY).Check();
1359 CHECK_EQ(0, arg_count);
1360 args_array = factory->NewJSArray(0);
1363 i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
1364 i::Handle<i::Object> format_fun = i::Object::GetProperty(
1365 isolate, builtins, "FormatMessage").ToHandleChecked();
1366 i::Handle<i::Object> arg_handles[] = { format, args_array };
1367 i::Handle<i::Object> result = i::Execution::Call(
1368 isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked();
1369 CHECK(result->IsString());
1370 i::DeleteArray(message);
1371 i::DeleteArray(arg);
1373 return i::Handle<i::String>::cast(result);
1380 kAllowHarmonyScoping,
1381 kAllowHarmonyModules,
1382 kAllowHarmonyNumericLiterals,
1383 kAllowHarmonyArrowFunctions,
1384 kAllowHarmonyClasses,
1385 kAllowHarmonyObjectLiterals,
1386 kAllowHarmonyRestParameters,
1387 kAllowHarmonyTemplates,
1388 kAllowHarmonySloppy,
1389 kAllowHarmonyUnicode,
1390 kAllowHarmonyComputedPropertyNames,
1395 enum ParserSyncTestResult {
1401 template <typename Traits>
1402 void SetParserFlags(i::ParserBase<Traits>* parser,
1403 i::EnumSet<ParserFlag> flags) {
1404 parser->set_allow_lazy(flags.Contains(kAllowLazy));
1405 parser->set_allow_natives(flags.Contains(kAllowNatives));
1406 parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
1407 parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
1408 parser->set_allow_harmony_numeric_literals(
1409 flags.Contains(kAllowHarmonyNumericLiterals));
1410 parser->set_allow_harmony_object_literals(
1411 flags.Contains(kAllowHarmonyObjectLiterals));
1412 parser->set_allow_harmony_arrow_functions(
1413 flags.Contains(kAllowHarmonyArrowFunctions));
1414 parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
1415 parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
1416 parser->set_allow_harmony_rest_params(
1417 flags.Contains(kAllowHarmonyRestParameters));
1418 parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
1419 parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
1420 parser->set_allow_harmony_computed_property_names(
1421 flags.Contains(kAllowHarmonyComputedPropertyNames));
1422 parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode));
1426 void TestParserSyncWithFlags(i::Handle<i::String> source,
1427 i::EnumSet<ParserFlag> flags,
1428 ParserSyncTestResult result) {
1429 i::Isolate* isolate = CcTest::i_isolate();
1430 i::Factory* factory = isolate->factory();
1432 uintptr_t stack_limit = isolate->stack_guard()->real_climit();
1433 int preparser_materialized_literals = -1;
1434 int parser_materialized_literals = -2;
1436 // Preparse the data.
1437 i::CompleteParserRecorder log;
1439 i::Scanner scanner(isolate->unicode_cache());
1440 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1442 i::AstValueFactory ast_value_factory(
1443 &zone, CcTest::i_isolate()->heap()->HashSeed());
1444 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
1446 SetParserFlags(&preparser, flags);
1447 scanner.Initialize(&stream);
1448 i::PreParser::PreParseResult result = preparser.PreParseProgram(
1449 &preparser_materialized_literals);
1450 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1453 bool preparse_error = log.HasError();
1456 i::FunctionLiteral* function;
1458 i::Handle<i::Script> script = factory->NewScript(source);
1459 i::CompilationInfoWithZone info(script);
1460 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
1461 isolate->heap()->HashSeed(), isolate->unicode_cache());
1462 SetParserFlags(&parser, flags);
1463 info.MarkAsGlobal();
1464 parser.Parse(&info);
1465 function = info.function();
1467 parser_materialized_literals = function->materialized_literal_count();
1471 // Check that preparsing fails iff parsing fails.
1472 if (function == NULL) {
1473 // Extract exception from the parser.
1474 CHECK(isolate->has_pending_exception());
1475 i::Handle<i::JSObject> exception_handle(
1476 i::JSObject::cast(isolate->pending_exception()));
1477 i::Handle<i::String> message_string =
1478 i::Handle<i::String>::cast(i::Object::GetProperty(
1479 isolate, exception_handle, "message").ToHandleChecked());
1481 if (result == kSuccess) {
1482 v8::base::OS::Print(
1483 "Parser failed on:\n"
1487 "However, we expected no error.",
1488 source->ToCString().get(), message_string->ToCString().get());
1492 if (!preparse_error) {
1493 v8::base::OS::Print(
1494 "Parser failed on:\n"
1498 "However, the preparser succeeded",
1499 source->ToCString().get(), message_string->ToCString().get());
1502 // Check that preparser and parser produce the same error.
1503 i::Handle<i::String> preparser_message =
1504 FormatMessage(log.ErrorMessageData());
1505 if (!i::String::Equals(message_string, preparser_message)) {
1506 v8::base::OS::Print(
1507 "Expected parser and preparser to produce the same error on:\n"
1509 "However, found the following error messages\n"
1511 "\tpreparser: %s\n",
1512 source->ToCString().get(),
1513 message_string->ToCString().get(),
1514 preparser_message->ToCString().get());
1517 } else if (preparse_error) {
1518 v8::base::OS::Print(
1519 "Preparser failed on:\n"
1523 "However, the parser succeeded",
1524 source->ToCString().get(),
1525 FormatMessage(log.ErrorMessageData())->ToCString().get());
1527 } else if (result == kError) {
1528 v8::base::OS::Print(
1529 "Expected error on:\n"
1531 "However, parser and preparser succeeded",
1532 source->ToCString().get());
1534 } else if (preparser_materialized_literals != parser_materialized_literals) {
1535 v8::base::OS::Print(
1536 "Preparser materialized literals (%d) differ from Parser materialized "
1537 "literals (%d) on:\n"
1539 "However, parser and preparser succeeded",
1540 preparser_materialized_literals, parser_materialized_literals,
1541 source->ToCString().get());
1547 void TestParserSync(const char* source,
1548 const ParserFlag* varying_flags,
1549 size_t varying_flags_length,
1550 ParserSyncTestResult result = kSuccessOrError,
1551 const ParserFlag* always_true_flags = NULL,
1552 size_t always_true_flags_length = 0,
1553 const ParserFlag* always_false_flags = NULL,
1554 size_t always_false_flags_length = 0) {
1555 i::Handle<i::String> str =
1556 CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
1557 for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
1558 i::EnumSet<ParserFlag> flags;
1559 for (size_t flag_index = 0; flag_index < varying_flags_length;
1561 if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]);
1563 for (size_t flag_index = 0; flag_index < always_true_flags_length;
1565 flags.Add(always_true_flags[flag_index]);
1567 for (size_t flag_index = 0; flag_index < always_false_flags_length;
1569 flags.Remove(always_false_flags[flag_index]);
1571 TestParserSyncWithFlags(str, flags, result);
1577 const char* context_data[][2] = {
1580 { "if (true) ", " else {}" },
1581 { "if (true) {} else ", "" },
1582 { "if (true) ", "" },
1583 { "do ", " while (false)" },
1584 { "while (false) ", "" },
1585 { "for (;;) ", "" },
1586 { "with ({})", "" },
1587 { "switch (12) { case 12: ", "}" },
1588 { "switch (12) { default: ", "}" },
1589 { "switch (12) { ", "case 12: }" },
1594 const char* statement_data[] = {
1602 "if (false) {} else ;",
1603 "if (false) {} else {}",
1604 "if (false) {} else 12",
1608 "do {} while (false)",
1618 // TODO(marja): activate once parsing 'return' is merged into ParserBase.
1625 "switch ({}) { default: }",
1630 "try {} catch(e) {}",
1631 "try {} finally {}",
1632 "try {} catch(e) {} finally {}",
1637 const char* termination_data[] = {
1646 v8::HandleScope handles(CcTest::isolate());
1647 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1648 v8::Context::Scope context_scope(context);
1650 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1651 i::GetCurrentStackPosition() - 128 * 1024);
1653 for (int i = 0; context_data[i][0] != NULL; ++i) {
1654 for (int j = 0; statement_data[j] != NULL; ++j) {
1655 for (int k = 0; termination_data[k] != NULL; ++k) {
1656 int kPrefixLen = i::StrLength(context_data[i][0]);
1657 int kStatementLen = i::StrLength(statement_data[j]);
1658 int kTerminationLen = i::StrLength(termination_data[k]);
1659 int kSuffixLen = i::StrLength(context_data[i][1]);
1660 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1661 + kSuffixLen + i::StrLength("label: for (;;) { }");
1663 // Plug the source code pieces together.
1664 i::ScopedVector<char> program(kProgramSize + 1);
1665 int length = i::SNPrintF(program,
1666 "label: for (;;) { %s%s%s%s }",
1669 termination_data[k],
1670 context_data[i][1]);
1671 CHECK(length == kProgramSize);
1672 TestParserSync(program.start(), NULL, 0);
1677 // Neither Harmony numeric literals nor our natives syntax have any
1678 // interaction with the flags above, so test these separately to reduce
1679 // the combinatorial explosion.
1680 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
1681 TestParserSync("0o1234", flags2, arraysize(flags2));
1682 TestParserSync("0b1011", flags2, arraysize(flags2));
1684 static const ParserFlag flags3[] = { kAllowNatives };
1685 TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
1690 // Test that syntax error caused by octal literal is reported correctly as
1691 // such (issue 2220).
1692 v8::V8::Initialize();
1693 v8::HandleScope scope(CcTest::isolate());
1694 v8::Context::Scope context_scope(
1695 v8::Context::New(CcTest::isolate()));
1696 v8::TryCatch try_catch;
1697 const char* script =
1698 "\"use strict\"; \n"
1699 "a = function() { \n"
1700 " b = function() { \n"
1704 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
1705 CHECK(try_catch.HasCaught());
1706 v8::String::Utf8Value exception(try_catch.Exception());
1708 strcmp("SyntaxError: Octal literals are not allowed in strict mode.",
1713 void RunParserSyncTest(const char* context_data[][2],
1714 const char* statement_data[],
1715 ParserSyncTestResult result,
1716 const ParserFlag* flags = NULL,
1718 const ParserFlag* always_true_flags = NULL,
1719 int always_true_len = 0,
1720 const ParserFlag* always_false_flags = NULL,
1721 int always_false_len = 0) {
1722 v8::HandleScope handles(CcTest::isolate());
1723 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1724 v8::Context::Scope context_scope(context);
1726 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1727 i::GetCurrentStackPosition() - 128 * 1024);
1729 // Experimental feature flags should not go here; pass the flags as
1730 // always_true_flags if the test needs them.
1731 static const ParserFlag default_flags[] = {
1735 ParserFlag* generated_flags = NULL;
1736 if (flags == NULL) {
1737 flags = default_flags;
1738 flags_len = arraysize(default_flags);
1739 if (always_true_flags != NULL || always_false_flags != NULL) {
1740 // Remove always_true/false_flags from default_flags (if present).
1741 CHECK((always_true_flags != NULL) == (always_true_len > 0));
1742 CHECK((always_false_flags != NULL) == (always_false_len > 0));
1743 generated_flags = new ParserFlag[flags_len + always_true_len];
1745 for (int i = 0; i < flags_len; ++i) {
1746 bool use_flag = true;
1747 for (int j = 0; use_flag && j < always_true_len; ++j) {
1748 if (flags[i] == always_true_flags[j]) use_flag = false;
1750 for (int j = 0; use_flag && j < always_false_len; ++j) {
1751 if (flags[i] == always_false_flags[j]) use_flag = false;
1753 if (use_flag) generated_flags[flag_index++] = flags[i];
1755 flags_len = flag_index;
1756 flags = generated_flags;
1759 for (int i = 0; context_data[i][0] != NULL; ++i) {
1760 for (int j = 0; statement_data[j] != NULL; ++j) {
1761 int kPrefixLen = i::StrLength(context_data[i][0]);
1762 int kStatementLen = i::StrLength(statement_data[j]);
1763 int kSuffixLen = i::StrLength(context_data[i][1]);
1764 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
1766 // Plug the source code pieces together.
1767 i::ScopedVector<char> program(kProgramSize + 1);
1768 int length = i::SNPrintF(program,
1772 context_data[i][1]);
1773 CHECK(length == kProgramSize);
1774 TestParserSync(program.start(),
1784 delete[] generated_flags;
1788 TEST(ErrorsEvalAndArguments) {
1789 // Tests that both preparsing and parsing produce the right kind of errors for
1790 // using "eval" and "arguments" as identifiers. Without the strict mode, it's
1791 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it
1793 const char* context_data[][2] = {
1794 {"\"use strict\";", ""},
1795 {"\"use strong\";", ""},
1796 {"var eval; function test_func() {\"use strict\"; ", "}"},
1797 {"var eval; function test_func() {\"use strong\"; ", "}"},
1800 const char* statement_data[] = {
1804 "var foo, arguments;",
1805 "try { } catch (eval) { }",
1806 "try { } catch (arguments) { }",
1807 "function eval() { }",
1808 "function arguments() { }",
1809 "function foo(eval) { }",
1810 "function foo(arguments) { }",
1811 "function foo(bar, eval) { }",
1812 "function foo(bar, arguments) { }",
1814 "(arguments) => { }",
1815 "(foo, eval) => { }",
1816 "(foo, arguments) => { }",
1819 "var foo = eval = 1;",
1820 "var foo = arguments = 1;",
1828 static const ParserFlag always_flags[] = {kAllowStrongMode};
1829 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
1830 arraysize(always_flags));
1834 TEST(NoErrorsEvalAndArgumentsSloppy) {
1835 // Tests that both preparsing and parsing accept "eval" and "arguments" as
1836 // identifiers when needed.
1837 const char* context_data[][2] = {
1839 { "function test_func() {", "}"},
1843 const char* statement_data[] = {
1847 "var foo, arguments;",
1848 "try { } catch (eval) { }",
1849 "try { } catch (arguments) { }",
1850 "function eval() { }",
1851 "function arguments() { }",
1852 "function foo(eval) { }",
1853 "function foo(arguments) { }",
1854 "function foo(bar, eval) { }",
1855 "function foo(bar, arguments) { }",
1858 "var foo = eval = 1;",
1859 "var foo = arguments = 1;",
1867 RunParserSyncTest(context_data, statement_data, kSuccess);
1871 TEST(NoErrorsEvalAndArgumentsStrict) {
1872 const char* context_data[][2] = {
1873 { "\"use strict\";", "" },
1874 { "function test_func() { \"use strict\";", "}" },
1875 { "() => { \"use strict\"; ", "}" },
1879 const char* statement_data[] = {
1883 "var foo = arguments;",
1884 "var foo = { eval: 1 };",
1885 "var foo = { arguments: 1 };",
1886 "var foo = { }; foo.eval = {};",
1887 "var foo = { }; foo.arguments = {};",
1891 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
1892 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1893 always_flags, arraysize(always_flags));
1897 #define FUTURE_STRICT_RESERVED_WORDS(V) \
1909 #define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
1916 #define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
1918 "var foo, " #NAME ";", \
1919 "try { } catch (" #NAME ") { }", \
1920 "function " #NAME "() { }", \
1921 "(function " #NAME "() { })", \
1922 "function foo(" #NAME ") { }", \
1923 "function foo(bar, " #NAME ") { }", \
1926 "var foo = " #NAME " = 1;", \
1931 TEST(ErrorsFutureStrictReservedWords) {
1932 // Tests that both preparsing and parsing produce the right kind of errors for
1933 // using future strict reserved words as identifiers. Without the strict mode,
1934 // it's ok to use future strict reserved words as identifiers. With the strict
1936 const char* context_data[][2] = {
1937 {"function test_func() {\"use strict\"; ", "}"},
1938 {"() => { \"use strict\"; ", "}"},
1939 {"function test_func() {\"use strong\"; ", "}"},
1940 {"() => { \"use strong\"; ", "}"},
1943 const char* statement_data[] {
1944 LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
1948 static const ParserFlag always_flags[] = {kAllowStrongMode};
1949 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
1950 arraysize(always_flags));
1951 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
1952 arraysize(always_flags));
1956 #undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
1959 TEST(NoErrorsFutureStrictReservedWords) {
1960 const char* context_data[][2] = {
1962 { "function test_func() {", "}"},
1967 const char* statement_data[] = {
1968 FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
1972 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
1973 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1974 always_flags, arraysize(always_flags));
1976 static const ParserFlag classes_flags[] = {
1977 kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
1978 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1979 classes_flags, arraysize(classes_flags));
1983 TEST(ErrorsReservedWords) {
1984 // Tests that both preparsing and parsing produce the right kind of errors for
1985 // using future reserved words as identifiers. These tests don't depend on the
1987 const char* context_data[][2] = {
1989 { "\"use strict\";", "" },
1990 { "var eval; function test_func() {", "}"},
1991 { "var eval; function test_func() {\"use strict\"; ", "}"},
1992 { "var eval; () => {", "}"},
1993 { "var eval; () => {\"use strict\"; ", "}"},
1997 const char* statement_data[] = {
2000 "try { } catch (super) { }",
2001 "function super() { }",
2002 "function foo(super) { }",
2003 "function foo(bar, super) { }",
2005 "(bar, super) => { }",
2007 "var foo = super = 1;",
2010 "function foo super",
2014 RunParserSyncTest(context_data, statement_data, kError);
2018 TEST(NoErrorsLetSloppyAllModes) {
2019 // In sloppy mode, it's okay to use "let" as identifier.
2020 const char* context_data[][2] = {
2022 { "function f() {", "}" },
2023 { "(function f() {", "})" },
2027 const char* statement_data[] = {
2030 "try { } catch (let) { }",
2031 "function let() { }",
2032 "(function let() { })",
2033 "function foo(let) { }",
2034 "function foo(bar, let) { }",
2036 "var foo = let = 1;",
2041 "function let(let) { let: let(let + let(0)); }",
2043 "({ get let() { 1 } })",
2048 RunParserSyncTest(context_data, statement_data, kSuccess);
2052 TEST(NoErrorsYieldSloppyAllModes) {
2053 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2054 // generator (see other test).
2055 const char* context_data[][2] = {
2057 { "function not_gen() {", "}" },
2058 { "(function not_gen() {", "})" },
2062 const char* statement_data[] = {
2065 "try { } catch (yield) { }",
2066 "function yield() { }",
2067 "(function yield() { })",
2068 "function foo(yield) { }",
2069 "function foo(bar, yield) { }",
2071 "var foo = yield = 1;",
2076 "function yield(yield) { yield: yield (yield + yield(0)); }",
2078 "({ get yield() { 1 } })",
2084 RunParserSyncTest(context_data, statement_data, kSuccess);
2088 TEST(NoErrorsYieldSloppyGeneratorsEnabled) {
2089 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2090 // generator (see next test).
2091 const char* context_data[][2] = {
2093 { "function not_gen() {", "}" },
2094 { "function * gen() { function not_gen() {", "} }" },
2095 { "(function not_gen() {", "})" },
2096 { "(function * gen() { (function not_gen() {", "}) })" },
2100 const char* statement_data[] = {
2103 "try { } catch (yield) { }",
2104 "function yield() { }",
2105 "(function yield() { })",
2106 "function foo(yield) { }",
2107 "function foo(bar, yield) { }",
2108 "function * yield() { }",
2109 "(function * yield() { })",
2111 "var foo = yield = 1;",
2116 "function yield(yield) { yield: yield (yield + yield(0)); }",
2118 "({ get yield() { 1 } })",
2124 RunParserSyncTest(context_data, statement_data, kSuccess);
2128 TEST(ErrorsYieldStrict) {
2129 const char* context_data[][2] = {
2130 {"\"use strict\";", ""},
2131 {"\"use strict\"; function not_gen() {", "}"},
2132 {"function test_func() {\"use strict\"; ", "}"},
2133 {"\"use strict\"; function * gen() { function not_gen() {", "} }"},
2134 {"\"use strict\"; (function not_gen() {", "})"},
2135 {"\"use strict\"; (function * gen() { (function not_gen() {", "}) })"},
2136 {"() => {\"use strict\"; ", "}"},
2137 {"\"use strong\";", ""},
2138 {"\"use strong\"; function not_gen() {", "}"},
2139 {"function test_func() {\"use strong\"; ", "}"},
2140 {"\"use strong\"; function * gen() { function not_gen() {", "} }"},
2141 {"\"use strong\"; (function not_gen() {", "})"},
2142 {"\"use strong\"; (function * gen() { (function not_gen() {", "}) })"},
2143 {"() => {\"use strong\"; ", "}"},
2146 const char* statement_data[] = {
2149 "try { } catch (yield) { }",
2150 "function yield() { }",
2151 "(function yield() { })",
2152 "function foo(yield) { }",
2153 "function foo(bar, yield) { }",
2154 "function * yield() { }",
2155 "(function * yield() { })",
2157 "var foo = yield = 1;",
2164 static const ParserFlag always_flags[] = {kAllowStrongMode};
2165 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
2166 arraysize(always_flags));
2170 TEST(NoErrorsGenerator) {
2171 const char* context_data[][2] = {
2172 { "function * gen() {", "}" },
2173 { "(function * gen() {", "})" },
2174 { "(function * () {", "})" },
2178 const char* statement_data[] = {
2179 // A generator without a body is valid.
2181 // Valid yield expressions inside generators.
2186 "yield * yield * 1;",
2187 "yield 3 + (yield 4);",
2188 "yield * 3 + (yield * 4);",
2189 "(yield * 3) + (yield * 4);",
2190 "yield 3; yield 4;",
2191 "yield * 3; yield * 4;",
2192 "(function (yield) { })",
2193 "yield { yield: 12 }",
2194 "yield /* comment */ { yield: 12 }",
2195 "yield * \n { yield: 12 }",
2196 "yield /* comment */ * \n { yield: 12 }",
2197 // You can return in a generator.
2199 "yield * 1; return",
2200 "yield 1; return 37",
2201 "yield * 1; return 37",
2202 "yield 1; return 37; yield 'dead';",
2203 "yield * 1; return 37; yield * 'dead';",
2204 // Yield is still a valid key in object literals.
2206 "({ get yield() { } })",
2207 // Yield without RHS.
2211 "yield /* comment */"
2212 "yield // comment\n"
2218 "(yield) ? yield : yield",
2219 "(yield) \n ? yield : yield",
2220 // If there is a newline before the next token, we don't look for RHS.
2221 "yield\nfor (;;) {}",
2225 RunParserSyncTest(context_data, statement_data, kSuccess);
2229 TEST(ErrorsYieldGenerator) {
2230 const char* context_data[][2] = {
2231 { "function * gen() {", "}" },
2232 { "\"use strict\"; function * gen() {", "}" },
2236 const char* statement_data[] = {
2237 // Invalid yield expressions inside generators.
2240 "try { } catch (yield) { }",
2241 "function yield() { }",
2242 // The name of the NFE is let-bound in the generator, which does not permit
2243 // yield to be an identifier.
2244 "(function yield() { })",
2245 "(function * yield() { })",
2246 // Yield isn't valid as a formal parameter for generators.
2247 "function * foo(yield) { }",
2248 "(function * foo(yield) { })",
2250 "var foo = yield = 1;",
2255 // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which
2257 "yield 3 + yield 4;",
2260 // Parses as yield (/ yield): invalid.
2264 // Invalid (no newline allowed between yield and *).
2266 // Invalid (we see a newline, so we parse {yield:42} as a statement, not an
2267 // object literal, and yield is not a valid label).
2268 "yield\n{yield: 42}",
2269 "yield /* comment */\n {yield: 42}",
2270 "yield //comment\n {yield: 42}",
2274 RunParserSyncTest(context_data, statement_data, kError);
2278 TEST(ErrorsNameOfStrictFunction) {
2279 // Tests that illegal tokens as names of a strict function produce the correct
2281 const char* context_data[][2] = {
2283 { "\"use strict\"; function", ""},
2284 { "\"use strong\"; function", ""},
2285 { "function * ", ""},
2286 { "\"use strict\"; function * ", ""},
2287 { "\"use strong\"; function * ", ""},
2291 const char* statement_data[] = {
2292 "eval() {\"use strict\";}",
2293 "arguments() {\"use strict\";}",
2294 "interface() {\"use strict\";}",
2295 "yield() {\"use strict\";}",
2296 // Future reserved words are always illegal
2298 "super() {\"use strict\";}",
2302 static const ParserFlag always_flags[] = {kAllowStrongMode};
2303 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
2304 arraysize(always_flags));
2308 TEST(NoErrorsNameOfStrictFunction) {
2309 const char* context_data[][2] = {
2314 const char* statement_data[] = {
2322 RunParserSyncTest(context_data, statement_data, kSuccess);
2326 TEST(NoErrorsNameOfStrictGenerator) {
2327 const char* context_data[][2] = {
2328 { "function * ", ""},
2332 const char* statement_data[] = {
2340 RunParserSyncTest(context_data, statement_data, kSuccess);
2344 TEST(ErrorsIllegalWordsAsLabelsSloppy) {
2345 // Using future reserved words as labels is always an error.
2346 const char* context_data[][2] = {
2348 { "function test_func() {", "}" },
2353 const char* statement_data[] = {
2354 "super: while(true) { break super; }",
2358 RunParserSyncTest(context_data, statement_data, kError);
2362 TEST(ErrorsIllegalWordsAsLabelsStrict) {
2363 // Tests that illegal tokens as labels produce the correct errors.
2364 const char* context_data[][2] = {
2365 {"\"use strict\";", ""},
2366 {"function test_func() {\"use strict\"; ", "}"},
2367 {"() => {\"use strict\"; ", "}"},
2368 {"\"use strong\";", ""},
2369 {"function test_func() {\"use strong\"; ", "}"},
2370 {"() => {\"use strong\"; ", "}"},
2373 #define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
2374 const char* statement_data[] = {
2375 "super: while(true) { break super; }",
2376 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
2379 #undef LABELLED_WHILE
2381 static const ParserFlag always_flags[] = {kAllowStrongMode};
2382 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
2383 arraysize(always_flags));
2387 TEST(NoErrorsIllegalWordsAsLabels) {
2388 // Using eval and arguments as labels is legal even in strict mode.
2389 const char* context_data[][2] = {
2391 { "function test_func() {", "}" },
2393 { "\"use strict\";", "" },
2394 { "\"use strict\"; function test_func() {", "}" },
2395 { "\"use strict\"; () => {", "}" },
2399 const char* statement_data[] = {
2400 "mylabel: while(true) { break mylabel; }",
2401 "eval: while(true) { break eval; }",
2402 "arguments: while(true) { break arguments; }",
2406 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
2407 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2408 always_flags, arraysize(always_flags));
2412 TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
2413 const char* context_data[][2] = {
2415 { "function test_func() {", "}" },
2420 #define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
2421 const char* statement_data[] {
2422 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
2425 #undef LABELLED_WHILE
2427 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
2428 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2429 always_flags, arraysize(always_flags));
2433 TEST(ErrorsParenthesizedLabels) {
2434 // Parenthesized identifiers shouldn't be recognized as labels.
2435 const char* context_data[][2] = {
2437 { "function test_func() {", "}" },
2442 const char* statement_data[] = {
2443 "(mylabel): while(true) { break mylabel; }",
2447 RunParserSyncTest(context_data, statement_data, kError);
2451 TEST(NoErrorsParenthesizedDirectivePrologue) {
2452 // Parenthesized directive prologue shouldn't be recognized.
2453 const char* context_data[][2] = {
2458 const char* statement_data[] = {
2459 "(\"use strict\"); var eval;",
2460 "(\"use strong\"); var eval;",
2464 static const ParserFlag always_flags[] = {kAllowStrongMode};
2465 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2466 always_flags, arraysize(always_flags));
2470 TEST(ErrorsNotAnIdentifierName) {
2471 const char* context_data[][2] = {
2473 { "\"use strict\";", ""},
2477 const char* statement_data[] = {
2478 "var foo = {}; foo.{;",
2479 "var foo = {}; foo.};",
2480 "var foo = {}; foo.=;",
2481 "var foo = {}; foo.888;",
2482 "var foo = {}; foo.-;",
2483 "var foo = {}; foo.--;",
2487 RunParserSyncTest(context_data, statement_data, kError);
2491 TEST(NoErrorsIdentifierNames) {
2492 // Keywords etc. are valid as property names.
2493 const char* context_data[][2] = {
2495 { "\"use strict\";", ""},
2499 const char* statement_data[] = {
2500 "var foo = {}; foo.if;",
2501 "var foo = {}; foo.yield;",
2502 "var foo = {}; foo.super;",
2503 "var foo = {}; foo.interface;",
2504 "var foo = {}; foo.eval;",
2505 "var foo = {}; foo.arguments;",
2509 RunParserSyncTest(context_data, statement_data, kSuccess);
2513 TEST(DontRegressPreParserDataSizes) {
2514 // These tests make sure that Parser doesn't start producing less "preparse
2515 // data" (data which the embedder can cache).
2516 v8::V8::Initialize();
2517 v8::Isolate* isolate = CcTest::isolate();
2518 v8::HandleScope handles(isolate);
2520 CcTest::i_isolate()->stack_guard()->SetStackLimit(
2521 i::GetCurrentStackPosition() - 128 * 1024);
2524 const char* program;
2530 {"function foo() {}", 1},
2531 {"function foo() {} function bar() {}", 2},
2532 // Getter / setter functions are recorded as functions if they're on the top
2534 {"var x = {get foo(){} };", 1},
2535 // Functions insize lazy functions are not recorded.
2536 {"function lazy() { function a() {} function b() {} function c() {} }", 1},
2537 {"function lazy() { var x = {get foo(){} } }", 1},
2541 for (int i = 0; test_cases[i].program; i++) {
2542 const char* program = test_cases[i].program;
2543 i::Factory* factory = CcTest::i_isolate()->factory();
2544 i::Handle<i::String> source =
2545 factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
2546 i::Handle<i::Script> script = factory->NewScript(source);
2547 i::CompilationInfoWithZone info(script);
2548 i::ScriptData* sd = NULL;
2549 info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
2550 i::Parser::ParseStatic(&info, true);
2551 i::ParseData* pd = i::ParseData::FromCachedData(sd);
2553 if (pd->FunctionCount() != test_cases[i].functions) {
2554 v8::base::OS::Print(
2555 "Expected preparse data for program:\n"
2557 "to contain %d functions, however, received %d functions.\n",
2558 program, test_cases[i].functions, pd->FunctionCount());
2567 TEST(FunctionDeclaresItselfStrict) {
2568 // Tests that we produce the right kinds of errors when a function declares
2569 // itself strict (we cannot produce there errors as soon as we see the
2570 // offending identifiers, because we don't know at that point whether the
2571 // function is strict or not).
2572 const char* context_data[][2] = {
2573 {"function eval() {", "}"},
2574 {"function arguments() {", "}"},
2575 {"function yield() {", "}"},
2576 {"function interface() {", "}"},
2577 {"function foo(eval) {", "}"},
2578 {"function foo(arguments) {", "}"},
2579 {"function foo(yield) {", "}"},
2580 {"function foo(interface) {", "}"},
2581 {"function foo(bar, eval) {", "}"},
2582 {"function foo(bar, arguments) {", "}"},
2583 {"function foo(bar, yield) {", "}"},
2584 {"function foo(bar, interface) {", "}"},
2585 {"function foo(bar, bar) {", "}"},
2589 const char* strict_statement_data[] = {
2595 const char* non_strict_statement_data[] = {
2600 static const ParserFlag always_flags[] = {kAllowStrongMode};
2601 RunParserSyncTest(context_data, strict_statement_data, kError, NULL, 0,
2602 always_flags, arraysize(always_flags));
2603 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess, NULL, 0,
2604 always_flags, arraysize(always_flags));
2608 TEST(ErrorsTryWithoutCatchOrFinally) {
2609 const char* context_data[][2] = {
2614 const char* statement_data[] = {
2617 "try { } catch (e) foo();",
2618 "try { } catch { }",
2619 "try { } finally foo();",
2623 RunParserSyncTest(context_data, statement_data, kError);
2627 TEST(NoErrorsTryCatchFinally) {
2628 const char* context_data[][2] = {
2633 const char* statement_data[] = {
2634 "try { } catch (e) { }",
2635 "try { } catch (e) { } finally { }",
2636 "try { } finally { }",
2640 RunParserSyncTest(context_data, statement_data, kSuccess);
2644 TEST(ErrorsRegexpLiteral) {
2645 const char* context_data[][2] = {
2650 const char* statement_data[] = {
2655 RunParserSyncTest(context_data, statement_data, kError);
2659 TEST(NoErrorsRegexpLiteral) {
2660 const char* context_data[][2] = {
2665 const char* statement_data[] = {
2668 "/foo/whatever", // This is an error but not detected by the parser.
2672 RunParserSyncTest(context_data, statement_data, kSuccess);
2677 const char* context_data[][2] = {
2682 const char* statement_data[] = {
2683 "%someintrinsic(arg)",
2687 // This test requires kAllowNatives to succeed.
2688 static const ParserFlag always_true_flags[] = {
2692 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2693 always_true_flags, 1);
2697 TEST(NoErrorsNewExpression) {
2698 const char* context_data[][2] = {
2704 const char* statement_data[] = {
2709 // The first () will be processed as a part of the NewExpression and the
2710 // second () will be processed as part of LeftHandSideExpression.
2712 // The first () will be processed as a part of the inner NewExpression and
2713 // the second () will be processed as a part of the outer NewExpression.
2718 "new foo.bar().baz;",
2721 "new foo[bar][baz];",
2722 "new foo[bar]()[baz];",
2723 "new foo[bar].baz(baz)()[bar].baz;",
2724 "new \"foo\"", // Runtime error
2725 "new 1", // Runtime error
2727 "(new new Function(\"this.x = 1\")).x;",
2728 "new new Test_Two(String, 2).v(0123).length;",
2732 RunParserSyncTest(context_data, statement_data, kSuccess);
2736 TEST(ErrorsNewExpression) {
2737 const char* context_data[][2] = {
2743 const char* statement_data[] = {
2751 RunParserSyncTest(context_data, statement_data, kError);
2755 TEST(StrictObjectLiteralChecking) {
2756 const char* context_data[][2] = {
2757 {"\"use strict\"; var myobject = {", "};"},
2758 {"\"use strict\"; var myobject = {", ",};"},
2759 {"var myobject = {", "};"},
2760 {"var myobject = {", ",};"},
2764 // These are only errors in strict mode.
2765 const char* statement_data[] = {
2767 "\"foo\": 1, \"foo\": 2",
2768 "foo: 1, \"foo\": 2",
2771 "get: 1, get: 2", // Not a getter for real, just a property called get.
2772 "set: 1, set: 2", // Not a setter for real, just a property called set.
2776 RunParserSyncTest(context_data, statement_data, kSuccess);
2780 TEST(ErrorsObjectLiteralChecking) {
2781 const char* context_data[][2] = {
2782 {"\"use strict\"; var myobject = {", "};"},
2783 {"var myobject = {", "};"},
2787 const char* statement_data[] = {
2789 // Wrong number of parameters
2794 // Parsing FunctionLiteral for getter or setter fails
2796 "get foo() \"error\"",
2800 RunParserSyncTest(context_data, statement_data, kError);
2804 TEST(NoErrorsObjectLiteralChecking) {
2805 const char* context_data[][2] = {
2806 {"var myobject = {", "};"},
2807 {"var myobject = {", ",};"},
2808 {"\"use strict\"; var myobject = {", "};"},
2809 {"\"use strict\"; var myobject = {", ",};"},
2813 const char* statement_data[] = {
2814 "foo: 1, get foo() {}",
2815 "foo: 1, set foo(v) {}",
2816 "\"foo\": 1, get \"foo\"() {}",
2817 "\"foo\": 1, set \"foo\"(v) {}",
2819 "1: 1, set 1(v) {}",
2820 "get foo() {}, get foo() {}",
2821 "set foo(_) {}, set foo(v) {}",
2822 "foo: 1, get \"foo\"() {}",
2823 "foo: 1, set \"foo\"(v) {}",
2824 "\"foo\": 1, get foo() {}",
2825 "\"foo\": 1, set foo(v) {}",
2826 "1: 1, get \"1\"() {}",
2827 "1: 1, set \"1\"(v) {}",
2828 "\"1\": 1, get 1() {}",
2829 "\"1\": 1, set 1(v) {}",
2831 "\"foo\": 1, \"bar\": 2",
2833 // Syntax: IdentifierName ':' AssignmentExpression
2834 "foo: bar = 5 + baz",
2835 // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}'
2839 // Syntax: 'set' PropertyName '(' PropertySetParameterList ')'
2840 // '{' FunctionBody '}'
2842 "set \"foo\"(v) {}",
2844 // Non-colliding getters and setters -> no errors
2845 "foo: 1, get bar() {}",
2846 "foo: 1, set bar(v) {}",
2847 "\"foo\": 1, get \"bar\"() {}",
2848 "\"foo\": 1, set \"bar\"(v) {}",
2850 "1: 1, set 2(v) {}",
2851 "get: 1, get foo() {}",
2852 "set: 1, set foo(_) {}",
2853 // Keywords, future reserved and strict future reserved are also allowed as
2863 RunParserSyncTest(context_data, statement_data, kSuccess);
2867 TEST(TooManyArguments) {
2868 const char* context_data[][2] = {
2873 using v8::internal::Code;
2874 char statement[Code::kMaxArguments * 2 + 1];
2875 for (int i = 0; i < Code::kMaxArguments; ++i) {
2876 statement[2 * i] = '0';
2877 statement[2 * i + 1] = ',';
2879 statement[Code::kMaxArguments * 2] = 0;
2881 const char* statement_data[] = {
2886 // The test is quite slow, so run it with a reduced set of flags.
2887 static const ParserFlag empty_flags[] = {kAllowLazy};
2888 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
2892 TEST(StrictDelete) {
2893 // "delete <Identifier>" is not allowed in strict mode.
2894 const char* strong_context_data[][2] = {
2895 {"\"use strong\"; ", ""},
2899 const char* strict_context_data[][2] = {
2900 {"\"use strict\"; ", ""},
2904 const char* sloppy_context_data[][2] = {
2909 // These are errors in the strict mode.
2910 const char* sloppy_statement_data[] = {
2915 "delete interface;",
2919 // These are always OK
2920 const char* good_statement_data[] = {
2929 "delete new foo();",
2930 "delete new foo(bar);",
2934 // These are always errors
2935 const char* bad_statement_data[] = {
2940 static const ParserFlag always_flags[] = {kAllowStrongMode};
2941 RunParserSyncTest(strong_context_data, sloppy_statement_data, kError, NULL, 0,
2942 always_flags, arraysize(always_flags));
2943 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError, NULL, 0,
2944 always_flags, arraysize(always_flags));
2945 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess, NULL,
2946 0, always_flags, arraysize(always_flags));
2948 RunParserSyncTest(strong_context_data, good_statement_data, kError, NULL, 0,
2949 always_flags, arraysize(always_flags));
2950 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess, NULL, 0,
2951 always_flags, arraysize(always_flags));
2952 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess, NULL, 0,
2953 always_flags, arraysize(always_flags));
2955 RunParserSyncTest(strong_context_data, bad_statement_data, kError, NULL, 0,
2956 always_flags, arraysize(always_flags));
2957 RunParserSyncTest(strict_context_data, bad_statement_data, kError, NULL, 0,
2958 always_flags, arraysize(always_flags));
2959 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError, NULL, 0,
2960 always_flags, arraysize(always_flags));
2964 TEST(InvalidLeftHandSide) {
2965 const char* assignment_context_data[][2] = {
2967 {"\"use strict\"; ", " = 1;"},
2971 const char* prefix_context_data[][2] = {
2973 {"\"use strict\"; ++", ";"},
2977 const char* postfix_context_data[][2] = {
2979 {"\"use strict\"; ", "++;"},
2983 // Good left hand sides for assigment or prefix / postfix operations.
2984 const char* good_statement_data[] = {
3001 "this.foo[foo].bar(this)(bar)[foo]()",
3005 // Bad left hand sides for assigment or prefix / postfix operations.
3006 const char* bad_statement_data_common[] = {
3011 "if", // Unexpected token
3012 "{x: 1}", // Unexpected token
3016 "new new foo()[bar]", // means: new (new foo()[bar])
3017 "new new foo().bar", // means: new (new foo()[bar])
3021 // These are not okay for assignment, but okay for prefix / postix.
3022 const char* bad_statement_data_for_assignment[] = {
3029 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
3030 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
3031 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
3034 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
3035 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
3037 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
3038 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);
3042 TEST(FuncNameInferrerBasic) {
3043 // Tests that function names are inferred properly.
3044 i::FLAG_allow_natives_syntax = true;
3045 v8::Isolate* isolate = CcTest::isolate();
3046 v8::HandleScope scope(isolate);
3048 CompileRun("var foo1 = function() {}; "
3049 "var foo2 = function foo3() {}; "
3050 "function not_ctor() { "
3051 " var foo4 = function() {}; "
3052 " return %FunctionGetInferredName(foo4); "
3054 "function Ctor() { "
3055 " var foo5 = function() {}; "
3056 " return %FunctionGetInferredName(foo5); "
3058 "var obj1 = { foo6: function() {} }; "
3059 "var obj2 = { 'foo7': function() {} }; "
3061 "obj3[1] = function() {}; "
3063 "obj4[1] = function foo8() {}; "
3065 "obj5['foo9'] = function() {}; "
3066 "var obj6 = { obj7 : { foo10: function() {} } };");
3067 ExpectString("%FunctionGetInferredName(foo1)", "foo1");
3068 // foo2 is not unnamed -> its name is not inferred.
3069 ExpectString("%FunctionGetInferredName(foo2)", "");
3070 ExpectString("not_ctor()", "foo4");
3071 ExpectString("Ctor()", "Ctor.foo5");
3072 ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6");
3073 ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7");
3074 ExpectString("%FunctionGetInferredName(obj3[1])",
3075 "obj3.(anonymous function)");
3076 ExpectString("%FunctionGetInferredName(obj4[1])", "");
3077 ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9");
3078 ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10");
3082 TEST(FuncNameInferrerTwoByte) {
3083 // Tests function name inferring in cases where some parts of the inferred
3084 // function name are two-byte strings.
3085 i::FLAG_allow_natives_syntax = true;
3086 v8::Isolate* isolate = CcTest::isolate();
3087 v8::HandleScope scope(isolate);
3089 uint16_t* two_byte_source = AsciiToTwoByteString(
3090 "var obj1 = { oXj2 : { foo1: function() {} } }; "
3091 "%FunctionGetInferredName(obj1.oXj2.foo1)");
3092 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3093 // Make it really non-Latin1 (replace the Xs with a non-Latin1 character).
3094 two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d;
3095 v8::Local<v8::String> source =
3096 v8::String::NewFromTwoByte(isolate, two_byte_source);
3097 v8::Local<v8::Value> result = CompileRun(source);
3098 CHECK(result->IsString());
3099 v8::Local<v8::String> expected_name =
3100 v8::String::NewFromTwoByte(isolate, two_byte_name);
3101 CHECK(result->Equals(expected_name));
3102 i::DeleteArray(two_byte_source);
3103 i::DeleteArray(two_byte_name);
3107 TEST(FuncNameInferrerEscaped) {
3108 // The same as FuncNameInferrerTwoByte, except that we express the two-byte
3109 // character as a unicode escape.
3110 i::FLAG_allow_natives_syntax = true;
3111 v8::Isolate* isolate = CcTest::isolate();
3112 v8::HandleScope scope(isolate);
3114 uint16_t* two_byte_source = AsciiToTwoByteString(
3115 "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; "
3116 "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)");
3117 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3118 // Fix to correspond to the non-ASCII name in two_byte_source.
3119 two_byte_name[6] = 0x010d;
3120 v8::Local<v8::String> source =
3121 v8::String::NewFromTwoByte(isolate, two_byte_source);
3122 v8::Local<v8::Value> result = CompileRun(source);
3123 CHECK(result->IsString());
3124 v8::Local<v8::String> expected_name =
3125 v8::String::NewFromTwoByte(isolate, two_byte_name);
3126 CHECK(result->Equals(expected_name));
3127 i::DeleteArray(two_byte_source);
3128 i::DeleteArray(two_byte_name);
3132 TEST(RegressionLazyFunctionWithErrorWithArg) {
3133 // The bug occurred when a lazy function had an error which requires a
3134 // parameter (such as "unknown label" here). The error message was processed
3135 // before the AstValueFactory containing the error message string was
3137 v8::Isolate* isolate = CcTest::isolate();
3138 v8::HandleScope scope(isolate);
3140 i::FLAG_lazy = true;
3141 i::FLAG_min_preparse_length = 0;
3142 CompileRun("function this_is_lazy() {\n"
3145 "this_is_lazy();\n");
3149 TEST(SerializationOfMaybeAssignmentFlag) {
3150 i::Isolate* isolate = CcTest::i_isolate();
3151 i::Factory* factory = isolate->factory();
3152 i::HandleScope scope(isolate);
3161 " function assertResult(r) {"
3165 " assertResult([2]);"
3166 " assertResult([2]);"
3171 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3172 i::SNPrintF(program, "%s", src);
3173 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3174 source->PrintOn(stdout);
3177 v8::Local<v8::Value> v = CompileRun(src);
3178 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3179 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3180 i::Context* context = f->context();
3181 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3182 avf.Internalize(isolate);
3183 const i::AstRawString* name = avf.GetOneByteString("result");
3184 i::Handle<i::String> str = name->string();
3185 CHECK(str->IsInternalizedString());
3186 i::Scope* script_scope =
3187 new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
3188 script_scope->Initialize();
3190 i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
3191 DCHECK(s != script_scope);
3192 DCHECK(name != NULL);
3194 // Get result from h's function context (that is f's context)
3195 i::Variable* var = s->Lookup(name);
3198 // Maybe assigned should survive deserialization
3199 CHECK(var->maybe_assigned() == i::kMaybeAssigned);
3200 // TODO(sigurds) Figure out if is_used should survive context serialization.
3204 TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
3205 i::Isolate* isolate = CcTest::i_isolate();
3206 i::Factory* factory = isolate->factory();
3207 i::HandleScope scope(isolate);
3213 " var a = arguments;"
3221 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3222 i::SNPrintF(program, "%s", src);
3223 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3224 source->PrintOn(stdout);
3227 v8::Local<v8::Value> v = CompileRun(src);
3228 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3229 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3230 i::Context* context = f->context();
3231 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3232 avf.Internalize(isolate);
3234 i::Scope* script_scope =
3235 new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
3236 script_scope->Initialize();
3238 i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
3239 DCHECK(s != script_scope);
3240 const i::AstRawString* name_x = avf.GetOneByteString("x");
3242 // Get result from f's function context (that is g's outer context)
3243 i::Variable* var_x = s->Lookup(name_x);
3244 CHECK(var_x != NULL);
3245 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
3249 TEST(ExportsMaybeAssigned) {
3250 i::FLAG_use_strict = true;
3251 i::FLAG_harmony_scoping = true;
3252 i::FLAG_harmony_modules = true;
3254 i::Isolate* isolate = CcTest::i_isolate();
3255 i::Factory* factory = isolate->factory();
3256 i::HandleScope scope(isolate);
3261 " export var x = 1;"
3262 " export function f() { return x };"
3263 " export const y = 2;"
3265 " export module C {}"
3269 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3270 i::SNPrintF(program, "%s", src);
3271 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3272 source->PrintOn(stdout);
3275 v8::Local<v8::Value> v = CompileRun(src);
3276 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3277 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3278 i::Context* context = f->context();
3279 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3280 avf.Internalize(isolate);
3282 i::Scope* script_scope =
3283 new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
3284 script_scope->Initialize();
3286 i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
3287 DCHECK(s != script_scope);
3288 const i::AstRawString* name_x = avf.GetOneByteString("x");
3289 const i::AstRawString* name_f = avf.GetOneByteString("f");
3290 const i::AstRawString* name_y = avf.GetOneByteString("y");
3291 const i::AstRawString* name_B = avf.GetOneByteString("B");
3292 const i::AstRawString* name_C = avf.GetOneByteString("C");
3294 // Get result from h's function context (that is f's context)
3295 i::Variable* var_x = s->Lookup(name_x);
3296 CHECK(var_x != NULL);
3297 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
3298 i::Variable* var_f = s->Lookup(name_f);
3299 CHECK(var_f != NULL);
3300 CHECK(var_f->maybe_assigned() == i::kMaybeAssigned);
3301 i::Variable* var_y = s->Lookup(name_y);
3302 CHECK(var_y != NULL);
3303 CHECK(var_y->maybe_assigned() == i::kNotAssigned);
3304 i::Variable* var_B = s->Lookup(name_B);
3305 CHECK(var_B != NULL);
3306 CHECK(var_B->maybe_assigned() == i::kNotAssigned);
3307 i::Variable* var_C = s->Lookup(name_C);
3308 CHECK(var_C != NULL);
3309 CHECK(var_C->maybe_assigned() == i::kNotAssigned);
3313 TEST(InnerAssignment) {
3314 i::Isolate* isolate = CcTest::i_isolate();
3315 i::Factory* factory = isolate->factory();
3316 i::HandleScope scope(isolate);
3319 const char* prefix = "function f() {";
3320 const char* midfix = " function g() {";
3321 const char* suffix = "}}";
3322 struct { const char* source; bool assigned; bool strict; } outers[] = {
3323 // Actual assignments.
3324 { "var x; var x = 5;", true, false },
3325 { "var x; { var x = 5; }", true, false },
3326 { "'use strict'; let x; x = 6;", true, true },
3327 { "var x = 5; function x() {}", true, false },
3328 // Actual non-assignments.
3329 { "var x;", false, false },
3330 { "var x = 5;", false, false },
3331 { "'use strict'; let x;", false, true },
3332 { "'use strict'; let x = 6;", false, true },
3333 { "'use strict'; var x = 0; { let x = 6; }", false, true },
3334 { "'use strict'; var x = 0; { let x; x = 6; }", false, true },
3335 { "'use strict'; let x = 0; { let x = 6; }", false, true },
3336 { "'use strict'; let x = 0; { let x; x = 6; }", false, true },
3337 { "var x; try {} catch (x) { x = 5; }", false, false },
3338 { "function x() {}", false, false },
3339 // Eval approximation.
3340 { "var x; eval('');", true, false },
3341 { "eval(''); var x;", true, false },
3342 { "'use strict'; let x; eval('');", true, true },
3343 { "'use strict'; eval(''); let x;", true, true },
3344 // Non-assignments not recognized, because the analysis is approximative.
3345 { "var x; var x;", true, false },
3346 { "var x = 5; var x;", true, false },
3347 { "var x; { var x; }", true, false },
3348 { "var x; function x() {}", true, false },
3349 { "function x() {}; var x;", true, false },
3350 { "var x; try {} catch (x) { var x = 5; }", true, false },
3352 struct { const char* source; bool assigned; bool with; } inners[] = {
3353 // Actual assignments.
3354 { "x = 1;", true, false },
3355 { "x++;", true, false },
3356 { "++x;", true, false },
3357 { "x--;", true, false },
3358 { "--x;", true, false },
3359 { "{ x = 1; }", true, false },
3360 { "'use strict'; { let x; }; x = 0;", true, false },
3361 { "'use strict'; { const x = 1; }; x = 0;", true, false },
3362 { "'use strict'; { function x() {} }; x = 0;", true, false },
3363 { "with ({}) { x = 1; }", true, true },
3364 { "eval('');", true, false },
3365 { "'use strict'; { let y; eval('') }", true, false },
3366 { "function h() { x = 0; }", true, false },
3367 { "(function() { x = 0; })", true, false },
3368 { "(function() { x = 0; })", true, false },
3369 { "with ({}) (function() { x = 0; })", true, true },
3370 // Actual non-assignments.
3371 { "", false, false },
3372 { "x;", false, false },
3373 { "var x;", false, false },
3374 { "var x = 8;", false, false },
3375 { "var x; x = 8;", false, false },
3376 { "'use strict'; let x;", false, false },
3377 { "'use strict'; let x = 8;", false, false },
3378 { "'use strict'; let x; x = 8;", false, false },
3379 { "'use strict'; const x = 8;", false, false },
3380 { "function x() {}", false, false },
3381 { "function x() { x = 0; }", false, false },
3382 { "function h(x) { x = 0; }", false, false },
3383 { "'use strict'; { let x; x = 0; }", false, false },
3384 { "{ var x; }; x = 0;", false, false },
3385 { "with ({}) {}", false, true },
3386 { "var x; { with ({}) { x = 1; } }", false, true },
3387 { "try {} catch(x) { x = 0; }", false, false },
3388 { "try {} catch(x) { with ({}) { x = 1; } }", false, true },
3389 // Eval approximation.
3390 { "eval('');", true, false },
3391 { "function h() { eval(''); }", true, false },
3392 { "(function() { eval(''); })", true, false },
3393 // Shadowing not recognized because of eval approximation.
3394 { "var x; eval('');", true, false },
3395 { "'use strict'; let x; eval('');", true, false },
3396 { "try {} catch(x) { eval(''); }", true, false },
3397 { "function x() { eval(''); }", true, false },
3398 { "(function(x) { eval(''); })", true, false },
3401 // Used to trigger lazy compilation of function
3402 int comment_len = 2048;
3403 i::ScopedVector<char> comment(comment_len + 1);
3404 i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0);
3405 int prefix_len = Utf8LengthHelper(prefix);
3406 int midfix_len = Utf8LengthHelper(midfix);
3407 int suffix_len = Utf8LengthHelper(suffix);
3408 for (unsigned i = 0; i < arraysize(outers); ++i) {
3409 const char* outer = outers[i].source;
3410 int outer_len = Utf8LengthHelper(outer);
3411 for (unsigned j = 0; j < arraysize(inners); ++j) {
3412 for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) {
3413 for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) {
3414 if (outers[i].strict && inners[j].with) continue;
3415 const char* inner = inners[j].source;
3416 int inner_len = Utf8LengthHelper(inner);
3418 int outer_comment_len = outer_lazy ? comment_len : 0;
3419 int inner_comment_len = inner_lazy ? comment_len : 0;
3420 const char* outer_comment = outer_lazy ? comment.start() : "";
3421 const char* inner_comment = inner_lazy ? comment.start() : "";
3422 int len = prefix_len + outer_comment_len + outer_len + midfix_len +
3423 inner_comment_len + inner_len + suffix_len;
3424 i::ScopedVector<char> program(len + 1);
3426 i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer,
3427 midfix, inner_comment, inner, suffix);
3428 i::Handle<i::String> source =
3429 factory->InternalizeUtf8String(program.start());
3430 source->PrintOn(stdout);
3433 i::Handle<i::Script> script = factory->NewScript(source);
3434 i::CompilationInfoWithZone info(script);
3435 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
3436 isolate->heap()->HashSeed(),
3437 isolate->unicode_cache());
3438 parser.set_allow_harmony_scoping(true);
3439 CHECK(parser.Parse(&info));
3440 CHECK(i::Compiler::Analyze(&info));
3441 CHECK(info.function() != NULL);
3443 i::Scope* scope = info.function()->scope();
3444 CHECK_EQ(scope->inner_scopes()->length(), 1);
3445 i::Scope* inner_scope = scope->inner_scopes()->at(0);
3446 const i::AstRawString* var_name =
3447 info.ast_value_factory()->GetOneByteString("x");
3448 i::Variable* var = inner_scope->Lookup(var_name);
3449 bool expected = outers[i].assigned || inners[j].assigned;
3451 CHECK(var->is_used() || !expected);
3452 CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected);
3461 int* global_use_counts = NULL;
3463 void MockUseCounterCallback(v8::Isolate* isolate,
3464 v8::Isolate::UseCounterFeature feature) {
3465 ++global_use_counts[feature];
3471 TEST(UseAsmUseCount) {
3472 i::Isolate* isolate = CcTest::i_isolate();
3473 i::HandleScope scope(isolate);
3475 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3476 global_use_counts = use_counts;
3477 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3478 CompileRun("\"use asm\";\n"
3480 "\"use asm\";\n" // Only the first one counts.
3481 "function bar() { \"use asm\"; var baz = 1; }");
3482 CHECK_EQ(2, use_counts[v8::Isolate::kUseAsm]);
3486 TEST(ErrorsArrowFunctions) {
3487 // Tests that parser and preparser generate the same kind of errors
3488 // on invalid arrow function syntax.
3489 const char* context_data[][2] = {
3492 {"bar ? (", ") : baz;"},
3493 {"bar ? baz : (", ");"},
3500 const char* statement_data[] = {
3509 "() => {'value': 42}",
3511 // Check that the early return introduced in ParsePrimaryExpression
3512 // does not accept stray closing parentheses.
3518 // Parameter lists with extra parens should be recognized as errors.
3527 // Parameter lists are always validated as strict, so those are errors.
3533 "(arguments) => {}",
3535 "(interface) => {}",
3536 "(eval, bar) => {}",
3537 "(bar, eval) => {}",
3538 "(bar, arguments) => {}",
3539 "(bar, yield) => {}",
3540 "(bar, interface) => {}",
3541 // TODO(aperez): Detecting duplicates does not work in PreParser.
3542 // "(bar, bar) => {}",
3544 // The parameter list is parsed as an expression, but only
3545 // a comma-separated list of identifier is valid.
3579 "(foo ? bar : baz) => {}",
3580 "(a, foo ? bar : baz) => {}",
3581 "(foo ? bar : baz, a) => {}",
3585 // The test is quite slow, so run it with a reduced set of flags.
3586 static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
3587 static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
3588 RunParserSyncTest(context_data, statement_data, kError, flags,
3589 arraysize(flags), always_flags, arraysize(always_flags));
3593 TEST(NoErrorsArrowFunctions) {
3594 // Tests that parser and preparser accept valid arrow functions syntax.
3595 const char* context_data[][2] = {
3597 {"bar ? (", ") : baz;"},
3598 {"bar ? baz : (", ");"},
3604 const char* statement_data[] = {
3606 "() => { return 42 }",
3607 "x => { return x; }",
3608 "(x) => { return x; }",
3609 "(x, y) => { return x + y; }",
3610 "(x, y, z) => { return x + y + z; }",
3611 "(x, y) => { x.a = y; }",
3618 "(x, y, z) => x, y, z",
3619 "(x, y) => x.a = y",
3620 "() => ({'value': 42})",
3622 "(x, y) => (u, v) => x*u + y*v",
3623 "(x, y) => z => z * (x + y)",
3624 "x => (y, z) => z * (x + y)",
3626 // Those are comma-separated expressions, with arrow functions as items.
3627 // They stress the code for validating arrow function parameter lists.
3629 "a, b, (c, d) => 0",
3630 "(a, b, (c, d) => 0)",
3631 "(a, b) => 0, (c, d) => 1",
3632 "(a, b => {}, a => a + 1)",
3633 "((a, b) => {}, (a => a + 1))",
3634 "(a, (a, (b, c) => 0))",
3636 // Arrow has more precedence, this is the same as: foo ? bar : (baz = {})
3637 "foo ? bar : baz => {}",
3641 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
3642 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3643 always_flags, arraysize(always_flags));
3647 TEST(SuperNoErrors) {
3648 // Tests that parser and preparser accept 'super' keyword in right places.
3649 const char* context_data[][2] = {
3650 {"class C { m() { ", "; } }"},
3651 {"class C { m() { k = ", "; } }"},
3652 {"class C { m() { foo(", "); } }"},
3653 {"class C { m() { () => ", "; } }"},
3657 const char* statement_data[] = {
3664 "z.super", // Ok, property lookup.
3668 static const ParserFlag always_flags[] = {
3669 kAllowHarmonyArrowFunctions,
3670 kAllowHarmonyClasses,
3671 kAllowHarmonyObjectLiterals,
3674 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3675 always_flags, arraysize(always_flags));
3680 const char* context_data[][2] = {
3681 {"class C { m() { ", "; } }"},
3682 {"class C { m() { k = ", "; } }"},
3683 {"class C { m() { foo(", "); } }"},
3684 {"class C { m() { () => ", "; } }"},
3688 const char* expression_data[] = {
3695 "new super(12, 45)",
3698 "new new super()()",
3702 static const ParserFlag always_flags[] = {
3703 kAllowHarmonyClasses,
3704 kAllowHarmonyObjectLiterals,
3707 RunParserSyncTest(context_data, expression_data, kError, NULL, 0,
3708 always_flags, arraysize(always_flags));
3713 const char* context_data[][2] = {{"", ""},
3716 const char* success_data[] = {
3717 "class C extends B { constructor() { super(); } }",
3718 "class C extends B { constructor() { () => super(); } }",
3722 static const ParserFlag always_flags[] = {
3723 kAllowHarmonyArrowFunctions,
3724 kAllowHarmonyClasses,
3725 kAllowHarmonyObjectLiterals,
3728 RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0,
3729 always_flags, arraysize(always_flags));
3731 const char* error_data[] = {
3732 "class C { constructor() { super(); } }",
3733 "class C { method() { super(); } }",
3734 "class C { method() { () => super(); } }",
3735 "class C { *method() { super(); } }",
3736 "class C { get x() { super(); } }",
3737 "class C { set x(_) { super(); } }",
3738 "({ method() { super(); } })",
3739 "({ *method() { super(); } })",
3740 "({ get x() { super(); } })",
3741 "({ set x(_) { super(); } })",
3742 "({ f: function() { super(); } })",
3743 "(function() { super(); })",
3744 "var f = function() { super(); }",
3745 "({ f: function*() { super(); } })",
3746 "(function*() { super(); })",
3747 "var f = function*() { super(); }",
3751 RunParserSyncTest(context_data, error_data, kError, NULL, 0,
3752 always_flags, arraysize(always_flags));
3756 TEST(SuperNewNoErrors) {
3757 const char* context_data[][2] = {
3758 {"class C { constructor() { ", " } }"},
3759 {"class C { *method() { ", " } }"},
3760 {"class C { get x() { ", " } }"},
3761 {"class C { set x(_) { ", " } }"},
3762 {"({ method() { ", " } })"},
3763 {"({ *method() { ", " } })"},
3764 {"({ get x() { ", " } })"},
3765 {"({ set x(_) { ", " } })"},
3769 const char* expression_data[] = {
3772 "() => new super.x;",
3773 "() => new super.x();",
3777 static const ParserFlag always_flags[] = {
3778 kAllowHarmonyArrowFunctions,
3779 kAllowHarmonyClasses,
3780 kAllowHarmonyObjectLiterals,
3783 RunParserSyncTest(context_data, expression_data, kSuccess, NULL, 0,
3784 always_flags, arraysize(always_flags));
3788 TEST(SuperNewErrors) {
3789 const char* context_data[][2] = {
3790 {"class C { method() { ", " } }"},
3791 {"class C { *method() { ", " } }"},
3792 {"class C { get x() { ", " } }"},
3793 {"class C { set x(_) { ", " } }"},
3794 {"({ method() { ", " } })"},
3795 {"({ *method() { ", " } })"},
3796 {"({ get x() { ", " } })"},
3797 {"({ set x(_) { ", " } })"},
3798 {"({ f: function() { ", " } })"},
3799 {"(function() { ", " })"},
3800 {"var f = function() { ", " }"},
3801 {"({ f: function*() { ", " } })"},
3802 {"(function*() { ", " })"},
3803 {"var f = function*() { ", " }"},
3807 const char* statement_data[] = {
3811 "() => new super();",
3815 static const ParserFlag always_flags[] = {
3816 kAllowHarmonyArrowFunctions,
3817 kAllowHarmonyClasses,
3818 kAllowHarmonyObjectLiterals,
3821 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
3822 always_flags, arraysize(always_flags));
3826 TEST(SuperErrorsNonMethods) {
3827 // super is only allowed in methods, accessors and constructors.
3828 const char* context_data[][2] = {
3833 {"if (true) {", "}"},
3834 {"if (false) {} else {", "}"},
3835 {"while (true) {", "}"},
3836 {"function f() {", "}"},
3837 {"class C extends (", ") {}"},
3838 {"class C { m() { function f() {", "} } }"},
3839 {"({ m() { function f() {", "} } })"},
3843 const char* statement_data[] = {
3860 static const ParserFlag always_flags[] = {
3861 kAllowHarmonyClasses,
3862 kAllowHarmonyObjectLiterals,
3865 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
3866 always_flags, arraysize(always_flags));
3870 TEST(NoErrorsMethodDefinition) {
3871 const char* context_data[][2] = {{"({", "});"},
3872 {"'use strict'; ({", "});"},
3874 {"'use strict'; ({*", "});"},
3877 const char* object_literal_body_data[] = {
3879 "m(x) { return x; }",
3880 "m(x, y) {}, n() {}",
3886 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3887 RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0,
3888 always_flags, arraysize(always_flags));
3892 TEST(MethodDefinitionNames) {
3893 const char* context_data[][2] = {{"({", "(x, y) {}});"},
3894 {"'use strict'; ({", "(x, y) {}});"},
3895 {"({*", "(x, y) {}});"},
3896 {"'use strict'; ({*", "(x, y) {}});"},
3899 const char* name_data[] = {
3962 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3963 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
3964 always_flags, arraysize(always_flags));
3968 TEST(MethodDefinitionStrictFormalParamereters) {
3969 const char* context_data[][2] = {{"({method(", "){}});"},
3970 {"'use strict'; ({method(", "){}});"},
3971 {"({*method(", "){}});"},
3972 {"'use strict'; ({*method(", "){}});"},
3975 const char* params_data[] = {
3983 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3984 RunParserSyncTest(context_data, params_data, kError, NULL, 0,
3985 always_flags, arraysize(always_flags));
3989 TEST(MethodDefinitionEvalArguments) {
3990 const char* strict_context_data[][2] =
3991 {{"'use strict'; ({method(", "){}});"},
3992 {"'use strict'; ({*method(", "){}});"},
3994 const char* sloppy_context_data[][2] =
3995 {{"({method(", "){}});"},
3996 {"({*method(", "){}});"},
3999 const char* data[] = {
4004 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4006 // Fail in strict mode
4007 RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
4008 arraysize(always_flags));
4010 // OK in sloppy mode
4011 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
4012 arraysize(always_flags));
4016 TEST(MethodDefinitionDuplicateEvalArguments) {
4017 const char* context_data[][2] =
4018 {{"'use strict'; ({method(", "){}});"},
4019 {"'use strict'; ({*method(", "){}});"},
4020 {"({method(", "){}});"},
4021 {"({*method(", "){}});"},
4024 const char* data[] = {
4027 "arguments, arguments",
4028 "arguments, a, arguments",
4031 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4033 // In strict mode, the error is using "eval" or "arguments" as parameter names
4034 // In sloppy mode, the error is that eval / arguments are duplicated
4035 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4036 arraysize(always_flags));
4040 TEST(MethodDefinitionDuplicateProperty) {
4041 const char* context_data[][2] = {{"'use strict'; ({", "});"},
4044 const char* params_data[] = {
4047 "x() {}, get x() {}",
4048 "x() {}, set x(_) {}",
4050 "x() {}, y() {}, x() {}",
4051 "x() {}, \"x\"() {}",
4058 "*x() {}, get x() {}",
4059 "*x() {}, set x(_) {}",
4061 "*x() {}, y() {}, *x() {}",
4062 "*x() {}, *\"x\"() {}",
4063 "*x() {}, *'x'() {}",
4064 "*0() {}, *'0'() {}",
4070 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4071 RunParserSyncTest(context_data, params_data, kSuccess, NULL, 0,
4072 always_flags, arraysize(always_flags));
4076 TEST(ClassExpressionNoErrors) {
4077 const char* context_data[][2] = {{"(", ");"},
4081 const char* class_data[] = {
4084 "class extends F {}",
4085 "class name extends F {}",
4086 "class extends (F, G) {}",
4087 "class name extends (F, G) {}",
4088 "class extends class {} {}",
4089 "class name extends class {} {}",
4090 "class extends class base {} {}",
4091 "class name extends class base {} {}",
4094 static const ParserFlag always_flags[] = {
4095 kAllowHarmonyClasses, kAllowHarmonySloppy};
4096 RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
4097 always_flags, arraysize(always_flags));
4101 TEST(ClassDeclarationNoErrors) {
4102 const char* context_data[][2] = {{"'use strict'; ", ""},
4103 {"'use strict'; {", "}"},
4104 {"'use strict'; if (true) {", "}"},
4106 const char* statement_data[] = {
4108 "class name extends F {}",
4109 "class name extends (F, G) {}",
4110 "class name extends class {} {}",
4111 "class name extends class base {} {}",
4114 static const ParserFlag always_flags[] = {
4115 kAllowHarmonyClasses, kAllowHarmonyScoping};
4116 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
4117 always_flags, arraysize(always_flags));
4121 TEST(ClassBodyNoErrors) {
4122 // Tests that parser and preparser accept valid class syntax.
4123 const char* context_data[][2] = {{"(class {", "});"},
4124 {"(class extends Base {", "});"},
4126 {"class C extends Base {", "}"},
4128 const char* class_body_data[] = {
4142 "*g() {}; *h(x) {}",
4145 "static get x() {}",
4146 "static set x(v) {}",
4149 "static static() {}",
4150 "static get static() {}",
4151 "static set static(v) {}",
4158 static const ParserFlag always_flags[] = {
4159 kAllowHarmonyClasses,
4160 kAllowHarmonyObjectLiterals,
4163 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4164 always_flags, arraysize(always_flags));
4168 TEST(ClassPropertyNameNoErrors) {
4169 const char* context_data[][2] = {{"(class {", "() {}});"},
4170 {"(class { get ", "() {}});"},
4171 {"(class { set ", "(v) {}});"},
4172 {"(class { static ", "() {}});"},
4173 {"(class { static get ", "() {}});"},
4174 {"(class { static set ", "(v) {}});"},
4175 {"(class { *", "() {}});"},
4176 {"(class { static *", "() {}});"},
4177 {"class C {", "() {}}"},
4178 {"class C { get ", "() {}}"},
4179 {"class C { set ", "(v) {}}"},
4180 {"class C { static ", "() {}}"},
4181 {"class C { static get ", "() {}}"},
4182 {"class C { static set ", "(v) {}}"},
4183 {"class C { *", "() {}}"},
4184 {"class C { static *", "() {}}"},
4186 const char* name_data[] = {
4217 static const ParserFlag always_flags[] = {
4218 kAllowHarmonyClasses,
4219 kAllowHarmonyObjectLiterals,
4222 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
4223 always_flags, arraysize(always_flags));
4227 TEST(ClassExpressionErrors) {
4228 const char* context_data[][2] = {{"(", ");"},
4232 const char* class_data[] = {
4235 "class name extends",
4241 "class { m(); n() }",
4243 "class { get m() }",
4244 "class { get m() { }",
4245 "class { set m() {} }", // Missing required parameter.
4246 "class { m() {}, n() {} }", // No commas allowed.
4249 static const ParserFlag always_flags[] = {
4250 kAllowHarmonyClasses,
4251 kAllowHarmonyObjectLiterals,
4254 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
4255 always_flags, arraysize(always_flags));
4259 TEST(ClassDeclarationErrors) {
4260 const char* context_data[][2] = {{"", ""},
4262 {"if (true) {", "}"},
4264 const char* class_data[] = {
4267 "class name extends",
4271 "class name { m; n }",
4272 "class name { m: 1 }",
4273 "class name { m(); n() }",
4274 "class name { get x }",
4275 "class name { get x() }",
4276 "class name { set x() {) }", // missing required param
4277 "class {}", // Name is required for declaration
4278 "class extends base {}",
4281 "class name { *; }",
4282 "class name { *get x() {} }",
4283 "class name { *set x(_) {} }",
4284 "class name { *static m() {} }",
4287 static const ParserFlag always_flags[] = {
4288 kAllowHarmonyClasses,
4289 kAllowHarmonyNumericLiterals,
4292 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
4293 always_flags, arraysize(always_flags));
4297 TEST(ClassNameErrors) {
4298 const char* context_data[][2] = {{"class ", "{}"},
4299 {"(class ", "{});"},
4300 {"'use strict'; class ", "{}"},
4301 {"'use strict'; (class ", "{});"},
4303 const char* class_name[] = {
4318 static const ParserFlag always_flags[] = {
4319 kAllowHarmonyClasses,
4320 kAllowHarmonyObjectLiterals,
4323 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
4324 always_flags, arraysize(always_flags));
4328 TEST(ClassGetterParamNameErrors) {
4329 const char* context_data[][2] = {
4330 {"class C { get name(", ") {} }"},
4331 {"(class { get name(", ") {} });"},
4332 {"'use strict'; class C { get name(", ") {} }"},
4333 {"'use strict'; (class { get name(", ") {} })"},
4337 const char* class_name[] = {
4352 static const ParserFlag always_flags[] = {
4353 kAllowHarmonyClasses,
4354 kAllowHarmonyObjectLiterals,
4357 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
4358 always_flags, arraysize(always_flags));
4362 TEST(ClassStaticPrototypeErrors) {
4363 const char* context_data[][2] = {{"class C {", "}"},
4364 {"(class {", "});"},
4367 const char* class_body_data[] = {
4368 "static prototype() {}",
4369 "static get prototype() {}",
4370 "static set prototype(_) {}",
4371 "static *prototype() {}",
4372 "static 'prototype'() {}",
4373 "static *'prototype'() {}",
4374 "static prot\\u006ftype() {}",
4375 "static 'prot\\u006ftype'() {}",
4376 "static get 'prot\\u006ftype'() {}",
4377 "static set 'prot\\u006ftype'(_) {}",
4378 "static *'prot\\u006ftype'() {}",
4381 static const ParserFlag always_flags[] = {
4382 kAllowHarmonyClasses,
4383 kAllowHarmonyObjectLiterals,
4386 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4387 always_flags, arraysize(always_flags));
4391 TEST(ClassSpecialConstructorErrors) {
4392 const char* context_data[][2] = {{"class C {", "}"},
4393 {"(class {", "});"},
4396 const char* class_body_data[] = {
4397 "get constructor() {}",
4398 "get constructor(_) {}",
4399 "*constructor() {}",
4400 "get 'constructor'() {}",
4401 "*'constructor'() {}",
4402 "get c\\u006fnstructor() {}",
4403 "*c\\u006fnstructor() {}",
4404 "get 'c\\u006fnstructor'() {}",
4405 "get 'c\\u006fnstructor'(_) {}",
4406 "*'c\\u006fnstructor'() {}",
4409 static const ParserFlag always_flags[] = {
4410 kAllowHarmonyClasses,
4411 kAllowHarmonyObjectLiterals,
4414 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4415 always_flags, arraysize(always_flags));
4419 TEST(ClassConstructorNoErrors) {
4420 const char* context_data[][2] = {{"class C {", "}"},
4421 {"(class {", "});"},
4424 const char* class_body_data[] = {
4426 "static constructor() {}",
4427 "static get constructor() {}",
4428 "static set constructor(_) {}",
4429 "static *constructor() {}",
4432 static const ParserFlag always_flags[] = {
4433 kAllowHarmonyClasses,
4434 kAllowHarmonyObjectLiterals,
4437 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4438 always_flags, arraysize(always_flags));
4442 TEST(ClassMultipleConstructorErrors) {
4443 const char* context_data[][2] = {{"class C {", "}"},
4444 {"(class {", "});"},
4447 const char* class_body_data[] = {
4448 "constructor() {}; constructor() {}",
4451 static const ParserFlag always_flags[] = {
4452 kAllowHarmonyClasses,
4453 kAllowHarmonyObjectLiterals,
4456 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4457 always_flags, arraysize(always_flags));
4461 TEST(ClassMultiplePropertyNamesNoErrors) {
4462 const char* context_data[][2] = {{"class C {", "}"},
4463 {"(class {", "});"},
4466 const char* class_body_data[] = {
4467 "constructor() {}; static constructor() {}",
4468 "m() {}; static m() {}",
4470 "static m() {}; static m() {}",
4471 "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
4474 static const ParserFlag always_flags[] = {
4475 kAllowHarmonyClasses,
4476 kAllowHarmonyObjectLiterals,
4479 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4480 always_flags, arraysize(always_flags));
4484 TEST(ClassesAreStrictErrors) {
4485 const char* context_data[][2] = {{"", ""},
4489 const char* class_body_data[] = {
4490 "class C { method() { with ({}) {} } }",
4491 "class C extends function() { with ({}) {} } {}",
4492 "class C { *method() { with ({}) {} } }",
4495 static const ParserFlag always_flags[] = {
4496 kAllowHarmonyClasses,
4497 kAllowHarmonyObjectLiterals,
4500 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4501 always_flags, arraysize(always_flags));
4505 TEST(ObjectLiteralPropertyShorthandKeywordsError) {
4506 const char* context_data[][2] = {{"({", "});"},
4507 {"'use strict'; ({", "});"},
4510 const char* name_data[] = {
4550 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4551 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4552 always_flags, arraysize(always_flags));
4556 TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
4557 const char* context_data[][2] = {{"({", "});"},
4560 const char* name_data[] = {
4573 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4574 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
4575 always_flags, arraysize(always_flags));
4577 const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
4579 RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0,
4580 always_flags, arraysize(always_flags));
4584 TEST(ObjectLiteralPropertyShorthandError) {
4585 const char* context_data[][2] = {{"({", "});"},
4586 {"'use strict'; ({", "});"},
4589 const char* name_data[] = {
4602 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4603 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4604 always_flags, arraysize(always_flags));
4608 TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
4609 const char* context_data[][2] = {{"", ""},
4612 const char* name_data[] = {
4613 "function* g() { ({yield}); }",
4617 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4618 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4619 always_flags, arraysize(always_flags));
4623 TEST(ConstParsingInForIn) {
4624 const char* context_data[][2] = {{"'use strict';", ""},
4625 {"function foo(){ 'use strict';", "}"},
4628 const char* data[] = {
4629 "for(const x = 1; ; ) {}",
4630 "for(const x = 1, y = 2;;){}",
4631 "for(const x in [1,2,3]) {}",
4632 "for(const x of [1,2,3]) {}",
4634 static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
4635 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4636 arraysize(always_flags));
4640 TEST(ConstParsingInForInError) {
4641 const char* context_data[][2] = {{"'use strict';", ""},
4642 {"function foo(){ 'use strict';", "}"},
4645 const char* data[] = {
4646 "for(const x,y = 1; ; ) {}",
4647 "for(const x = 4 in [1,2,3]) {}",
4648 "for(const x = 4, y in [1,2,3]) {}",
4649 "for(const x = 4 of [1,2,3]) {}",
4650 "for(const x = 4, y of [1,2,3]) {}",
4651 "for(const x = 1, y = 2 in []) {}",
4652 "for(const x,y in []) {}",
4653 "for(const x = 1, y = 2 of []) {}",
4654 "for(const x,y of []) {}",
4656 static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
4657 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4658 arraysize(always_flags));
4662 TEST(InvalidUnicodeEscapes) {
4663 const char* context_data[][2] = {{"", ""},
4664 {"'use strict';", ""},
4666 const char* data[] = {
4667 "var foob\\u123r = 0;",
4668 "var \\u123roo = 0;",
4670 // No escapes allowed in regexp flags
4673 // Braces gone wrong
4674 "var foob\\u{c481r = 0;",
4675 "var foob\\uc481}r = 0;",
4676 "var \\u{0052oo = 0;",
4677 "var \\u0052}oo = 0;",
4678 "\"foob\\u{c481r\"",
4679 "var foob\\u{}ar = 0;",
4680 // Too high value for the unicode escape
4682 // Not an unicode escape
4683 "var foob\\v1234r = 0;",
4684 "var foob\\U1234r = 0;",
4685 "var foob\\v{1234}r = 0;",
4686 "var foob\\U{1234}r = 0;",
4688 static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
4689 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4690 arraysize(always_flags));
4694 TEST(UnicodeEscapes) {
4695 const char* context_data[][2] = {{"", ""},
4696 {"'use strict';", ""},
4698 const char* data[] = {
4699 // Identifier starting with escape
4700 "var \\u0052oo = 0;",
4701 "var \\u{0052}oo = 0;",
4702 "var \\u{52}oo = 0;",
4703 "var \\u{00000000052}oo = 0;",
4704 // Identifier with an escape but not starting with an escape
4705 "var foob\\uc481r = 0;",
4706 "var foob\\u{c481}r = 0;",
4707 // String with an escape
4709 "\"foob\\{uc481}r\"",
4710 // This character is a valid unicode character, representable as a surrogate
4711 // pair, not representable as 4 hex digits.
4712 "\"foo\\u{10e6d}\"",
4713 // Max value for the unicode escape
4716 static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
4717 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4718 arraysize(always_flags));
4722 TEST(ScanTemplateLiterals) {
4723 const char* context_data[][2] = {{"'use strict';", ""},
4724 {"function foo(){ 'use strict';"
4725 " var a, b, c; return ", "}"},
4728 const char* data[] = {
4730 "`no-subst-template`",
4731 "`template-head${a}`",
4733 "`${a}template-tail`",
4734 "`template-head${a}template-tail`",
4736 "`a${a}b${b}c${c}`",
4737 "`${a}a${b}b${c}c`",
4738 "`foo\n\nbar\r\nbaz`",
4739 "`foo\n\n${ bar }\r\nbaz`",
4740 "`foo${a /* comment */}`",
4741 "`foo${a // comment\n}`",
4745 "`foo${/* comment */ a}`",
4746 "`foo${// comment\na}`",
4752 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4753 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4754 arraysize(always_flags));
4758 TEST(ScanTaggedTemplateLiterals) {
4759 const char* context_data[][2] = {{"'use strict';", ""},
4760 {"function foo(){ 'use strict';"
4761 " function tag() {}"
4762 " var a, b, c; return ", "}"},
4765 const char* data[] = {
4767 "tag `no-subst-template`",
4768 "tag`template-head${a}`",
4770 "tag `${a}template-tail`",
4771 "tag `template-head${a}template-tail`",
4772 "tag\n`${a}${b}${c}`",
4773 "tag\r\n`a${a}b${b}c${c}`",
4774 "tag `${a}a${b}b${c}c`",
4775 "tag\t`foo\n\nbar\r\nbaz`",
4776 "tag\r`foo\n\n${ bar }\r\nbaz`",
4777 "tag`foo${a /* comment */}`",
4778 "tag`foo${a // comment\n}`",
4780 "tag`foo${a \r\n}`",
4782 "tag`foo${/* comment */ a}`",
4783 "tag`foo${// comment\na}`",
4785 "tag`foo${\r\n a}`",
4787 "tag`foo${'a' in a}`",
4789 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4790 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4791 arraysize(always_flags));
4795 TEST(TemplateMaterializedLiterals) {
4796 const char* context_data[][2] = {
4799 "function tag() {}\n"
4806 const char* data[] = {
4818 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4819 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4820 arraysize(always_flags));
4824 TEST(ScanUnterminatedTemplateLiterals) {
4825 const char* context_data[][2] = {{"'use strict';", ""},
4826 {"function foo(){ 'use strict';"
4827 " var a, b, c; return ", "}"},
4830 const char* data[] = {
4831 "`no-subst-template",
4832 "`template-head${a}",
4833 "`${a}template-tail",
4834 "`template-head${a}template-tail",
4838 "`foo\n\nbar\r\nbaz",
4839 "`foo\n\n${ bar }\r\nbaz",
4840 "`foo${a /* comment } */`",
4841 "`foo${a /* comment } `*/",
4842 "`foo${a // comment}`",
4846 "`foo${/* comment */ a`",
4847 "`foo${// commenta}`",
4854 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4855 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4856 arraysize(always_flags));
4860 TEST(TemplateLiteralsIllegalTokens) {
4861 const char* context_data[][2] = {{"'use strict';", ""},
4862 {"function foo(){ 'use strict';"
4863 " var a, b, c; return ", "}"},
4865 const char* data[] = {
4869 "`hello${1}\\x${2}`",
4873 "`hello${1}\\x\n${2}`",
4876 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4877 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4878 arraysize(always_flags));
4882 TEST(ParseRestParameters) {
4883 const char* context_data[][2] = {{"'use strict';(function(",
4884 "){ return args;})(1, [], /regexp/, 'str',"
4886 {"(function(", "){ return args;})(1, [],"
4887 "/regexp/, 'str', function(){});"},
4890 const char* data[] = {
4901 "...\t\n\t\t\n args",
4902 "a, ... \n \n args",
4904 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4905 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4906 arraysize(always_flags));
4910 TEST(ParseRestParametersErrors) {
4911 const char* context_data[][2] = {{"'use strict';(function(",
4912 "){ return args;}(1, [], /regexp/, 'str',"
4914 {"(function(", "){ return args;}(1, [],"
4915 "/regexp/, 'str', function(){});"},
4918 const char* data[] = {
4926 "a, ... args,\r\nb",
4929 "...args\t\n\t\t\n, b",
4930 "a, ... args, \n \n b",
4936 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4937 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4938 arraysize(always_flags));
4942 TEST(RestParametersEvalArguments) {
4943 const char* strict_context_data[][2] =
4944 {{"'use strict';(function(",
4945 "){ return;})(1, [], /regexp/, 'str',function(){});"},
4947 const char* sloppy_context_data[][2] =
4949 "){ return;})(1, [],/regexp/, 'str', function(){});"},
4952 const char* data[] = {
4956 "arguments, ...args",
4959 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4961 // Fail in strict mode
4962 RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
4963 arraysize(always_flags));
4965 // OK in sloppy mode
4966 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
4967 arraysize(always_flags));
4971 TEST(RestParametersDuplicateEvalArguments) {
4972 const char* context_data[][2] =
4973 {{"'use strict';(function(",
4974 "){ return;})(1, [], /regexp/, 'str',function(){});"},
4976 "){ return;})(1, [],/regexp/, 'str', function(){});"},
4979 const char* data[] = {
4981 "eval, eval, ...args",
4982 "arguments, ...arguments",
4983 "arguments, arguments, ...args",
4986 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4988 // In strict mode, the error is using "eval" or "arguments" as parameter names
4989 // In sloppy mode, the error is that eval / arguments are duplicated
4990 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4991 arraysize(always_flags));
4995 TEST(LexicalScopingSloppyMode) {
4996 const char* context_data[][2] = {
4998 {"function f() {", "}"},
5001 const char* bad_data[] = {
5003 "for(let x = 1;;){}",
5004 "for(let x of []){}",
5005 "for(let x in []){}",
5007 "class C extends D {}",
5009 "(class extends D {})",
5011 "(class C extends D {})",
5013 static const ParserFlag always_true_flags[] = {
5014 kAllowHarmonyScoping, kAllowHarmonyClasses};
5015 static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
5016 RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
5017 always_true_flags, arraysize(always_true_flags),
5018 always_false_flags, arraysize(always_false_flags));
5020 const char* good_data[] = {
5024 RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0,
5025 always_true_flags, arraysize(always_true_flags),
5026 always_false_flags, arraysize(always_false_flags));
5030 TEST(ComputedPropertyName) {
5031 const char* context_data[][2] = {{"({[", "]: 1});"},
5032 {"({get [", "]() {}});"},
5033 {"({set [", "](_) {}});"},
5034 {"({[", "]() {}});"},
5035 {"({*[", "]() {}});"},
5036 {"(class {get [", "]() {}});"},
5037 {"(class {set [", "](_) {}});"},
5038 {"(class {[", "]() {}});"},
5039 {"(class {*[", "]() {}});"},
5041 const char* error_data[] = {
5046 static const ParserFlag always_flags[] = {
5047 kAllowHarmonyClasses,
5048 kAllowHarmonyComputedPropertyNames,
5049 kAllowHarmonyObjectLiterals,
5050 kAllowHarmonySloppy,
5052 RunParserSyncTest(context_data, error_data, kError, NULL, 0,
5053 always_flags, arraysize(always_flags));
5055 const char* name_data[] = {
5064 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
5065 always_flags, arraysize(always_flags));
5069 TEST(ComputedPropertyNameShorthandError) {
5070 const char* context_data[][2] = {{"({", "});"},
5072 const char* error_data[] = {
5077 static const ParserFlag always_flags[] = {
5078 kAllowHarmonyClasses,
5079 kAllowHarmonyComputedPropertyNames,
5080 kAllowHarmonyObjectLiterals,
5081 kAllowHarmonySloppy,
5083 RunParserSyncTest(context_data, error_data, kError, NULL, 0,
5084 always_flags, arraysize(always_flags));
5088 TEST(BasicImportExportParsing) {
5089 const char* kSources[] = {
5090 "export let x = 0;",
5091 "export var y = 0;",
5092 "export const z = 0;",
5093 "export function func() { };",
5094 "export class C { };",
5096 "function f() {}; f(); export { f };",
5097 "var a, b, c; export { a, b as baz, c };",
5098 "var d, e; export { d as dreary, e, };",
5099 "export default function f() {}",
5100 "export default class C {}",
5101 "export default 42",
5102 "var x; export default x = 7",
5103 "export { Q } from 'somemodule.js';",
5104 "export * from 'somemodule.js';",
5105 "var foo; export { foo as for };",
5106 "export { arguments } from 'm.js';",
5107 "export { for } from 'm.js';",
5108 "export { yield } from 'm.js'",
5109 "export { static } from 'm.js'",
5110 "export { let } from 'm.js'",
5112 "import 'somemodule.js';",
5113 "import { } from 'm.js';",
5114 "import { a } from 'm.js';",
5115 "import { a, b as d, c, } from 'm.js';",
5116 "import * as thing from 'm.js';",
5117 "import thing from 'm.js';",
5118 "import thing, * as rest from 'm.js';",
5119 "import thing, { a, b, c } from 'm.js';",
5120 "import { arguments as a } from 'm.js';",
5121 "import { for as f } from 'm.js';",
5122 "import { yield as y } from 'm.js';",
5123 "import { static as s } from 'm.js';",
5124 "import { let as l } from 'm.js';",
5127 i::Isolate* isolate = CcTest::i_isolate();
5128 i::Factory* factory = isolate->factory();
5130 v8::HandleScope handles(CcTest::isolate());
5131 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
5132 v8::Context::Scope context_scope(context);
5134 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5137 for (unsigned i = 0; i < arraysize(kSources); ++i) {
5138 int kProgramByteSize = i::StrLength(kSources[i]);
5139 i::ScopedVector<char> program(kProgramByteSize + 1);
5140 i::SNPrintF(program, "%s", kSources[i]);
5141 i::Handle<i::String> source =
5142 factory->NewStringFromUtf8(i::CStrVector(program.start()))
5145 // Show that parsing as a module works
5147 i::Handle<i::Script> script = factory->NewScript(source);
5148 i::CompilationInfoWithZone info(script);
5149 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
5150 isolate->heap()->HashSeed(), isolate->unicode_cache());
5151 parser.set_allow_harmony_classes(true);
5152 parser.set_allow_harmony_modules(true);
5153 parser.set_allow_harmony_scoping(true);
5154 info.MarkAsModule();
5155 if (!parser.Parse(&info)) {
5156 i::Handle<i::JSObject> exception_handle(
5157 i::JSObject::cast(isolate->pending_exception()));
5158 i::Handle<i::String> message_string =
5159 i::Handle<i::String>::cast(i::Object::GetProperty(
5160 isolate, exception_handle, "message").ToHandleChecked());
5162 v8::base::OS::Print(
5163 "Parser failed on:\n"
5167 "However, we expected no error.",
5168 source->ToCString().get(), message_string->ToCString().get());
5173 // And that parsing a script does not.
5175 i::Handle<i::Script> script = factory->NewScript(source);
5176 i::CompilationInfoWithZone info(script);
5177 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
5178 isolate->heap()->HashSeed(), isolate->unicode_cache());
5179 parser.set_allow_harmony_classes(true);
5180 parser.set_allow_harmony_modules(true);
5181 parser.set_allow_harmony_scoping(true);
5182 info.MarkAsGlobal();
5183 CHECK(!parser.Parse(&info));
5189 TEST(ImportExportParsingErrors) {
5190 const char* kErrorSources[] = {
5192 "var a; export { a",
5193 "var a; export { a,",
5194 "var a; export { a, ;",
5195 "var a; export { a as };",
5196 "var a, b; export { a as , b};",
5198 "var foo, bar; export { foo bar };",
5202 "export default var x = 7;",
5203 "export default let x = 7;",
5204 "export default const x = 7;",
5207 "export { Q } from;",
5208 "export default from 'module.js';",
5210 "export { for as foo }",
5211 "export { arguments }",
5212 "export { arguments as foo }",
5213 "var a; export { a, a };",
5216 "import from 'm.js';",
5221 "import { , } from 'm.js';",
5222 "import { a } from;",
5223 "import { a } 'm.js';",
5224 "import , from 'm.js';",
5225 "import a , from 'm.js';",
5226 "import a { b, c } from 'm.js';",
5227 "import arguments from 'm.js';",
5228 "import eval from 'm.js';",
5229 "import { arguments } from 'm.js';",
5230 "import { eval } from 'm.js';",
5231 "import { a as arguments } from 'm.js';",
5232 "import { for } from 'm.js';",
5233 "import { y as yield } from 'm.js'",
5234 "import { s as static } from 'm.js'",
5235 "import { l as let } from 'm.js'",
5236 "import { x }, def from 'm.js';",
5237 "import def, def2 from 'm.js';",
5238 "import * as x, def from 'm.js';",
5239 "import * as x, * as y from 'm.js';",
5240 "import {x}, {y} from 'm.js';",
5241 "import * as x, {y} from 'm.js';",
5243 // TODO(ES6): These two forms should be supported
5244 "export default function() {};",
5245 "export default class {};"
5248 i::Isolate* isolate = CcTest::i_isolate();
5249 i::Factory* factory = isolate->factory();
5251 v8::HandleScope handles(CcTest::isolate());
5252 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
5253 v8::Context::Scope context_scope(context);
5255 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5258 for (unsigned i = 0; i < arraysize(kErrorSources); ++i) {
5259 int kProgramByteSize = i::StrLength(kErrorSources[i]);
5260 i::ScopedVector<char> program(kProgramByteSize + 1);
5261 i::SNPrintF(program, "%s", kErrorSources[i]);
5262 i::Handle<i::String> source =
5263 factory->NewStringFromUtf8(i::CStrVector(program.start()))
5266 i::Handle<i::Script> script = factory->NewScript(source);
5267 i::CompilationInfoWithZone info(script);
5268 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
5269 isolate->heap()->HashSeed(), isolate->unicode_cache());
5270 parser.set_allow_harmony_classes(true);
5271 parser.set_allow_harmony_modules(true);
5272 parser.set_allow_harmony_scoping(true);
5273 info.MarkAsModule();
5274 CHECK(!parser.Parse(&info));
5279 TEST(DuplicateProtoError) {
5280 const char* context_data[][2] = {
5282 {"'use strict'; ({", "});"},
5285 const char* error_data[] = {
5286 "__proto__: {}, __proto__: {}",
5287 "__proto__: {}, \"__proto__\": {}",
5288 "__proto__: {}, \"__\x70roto__\": {}",
5289 "__proto__: {}, a: 1, __proto__: {}",
5293 RunParserSyncTest(context_data, error_data, kError);
5297 TEST(DuplicateProtoNoError) {
5298 const char* context_data[][2] = {
5300 {"'use strict'; ({", "});"},
5303 const char* error_data[] = {
5304 "__proto__: {}, ['__proto__']: {}",
5305 "__proto__: {}, __proto__() {}",
5306 "__proto__: {}, get __proto__() {}",
5307 "__proto__: {}, set __proto__(v) {}",
5308 "__proto__: {}, __proto__",
5312 static const ParserFlag always_flags[] = {
5313 kAllowHarmonyComputedPropertyNames,
5314 kAllowHarmonyObjectLiterals,
5316 RunParserSyncTest(context_data, error_data, kSuccess, NULL, 0,
5317 always_flags, arraysize(always_flags));
5321 TEST(DeclarationsError) {
5322 const char* context_data[][2] = {{"'use strict'; if (true)", ""},
5323 {"'use strict'; if (false) {} else", ""},
5324 {"'use strict'; while (false)", ""},
5325 {"'use strict'; for (;;)", ""},
5326 {"'use strict'; for (x in y)", ""},
5327 {"'use strict'; do ", " while (false)"},
5328 {"'use strong'; if (true)", ""},
5329 {"'use strong'; if (false) {} else", ""},
5330 {"'use strong'; while (false)", ""},
5331 {"'use strong'; for (;;)", ""},
5332 {"'use strong'; for (x in y)", ""},
5333 {"'use strong'; do ", " while (false)"},
5336 const char* statement_data[] = {
5342 static const ParserFlag always_flags[] = {
5343 kAllowHarmonyClasses, kAllowHarmonyScoping, kAllowStrongMode};
5344 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
5345 always_flags, arraysize(always_flags));
5349 void TestLanguageMode(const char* source,
5350 i::LanguageMode expected_language_mode) {
5351 i::Isolate* isolate = CcTest::i_isolate();
5352 i::Factory* factory = isolate->factory();
5353 v8::HandleScope handles(CcTest::isolate());
5354 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
5355 v8::Context::Scope context_scope(context);
5356 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5359 i::Handle<i::Script> script =
5360 factory->NewScript(factory->NewStringFromAsciiChecked(source));
5361 i::CompilationInfoWithZone info(script);
5362 i::Parser parser(&info, isolate->stack_guard()->real_climit(),
5363 isolate->heap()->HashSeed(), isolate->unicode_cache());
5364 parser.set_allow_strong_mode(true);
5365 info.MarkAsGlobal();
5366 parser.Parse(&info);
5367 CHECK(info.function() != NULL);
5368 CHECK_EQ(expected_language_mode, info.function()->language_mode());
5372 TEST(LanguageModeDirectives) {
5373 TestLanguageMode("\"use nothing\"", i::SLOPPY);
5374 TestLanguageMode("\"use strict\"", i::STRICT);
5375 TestLanguageMode("\"use strong\"", i::STRONG);
5377 TestLanguageMode("var x = 1; \"use strict\"", i::SLOPPY);
5378 TestLanguageMode("var x = 1; \"use strong\"", i::SLOPPY);
5380 // Test that multiple directives ("use strict" / "use strong") put the parser
5381 // into the correct mode.
5382 TestLanguageMode("\"use strict\"; \"use strong\";", i::STRONG);
5383 TestLanguageMode("\"use strong\"; \"use strict\";", i::STRONG);
5385 TestLanguageMode("\"use some future directive\"; \"use strict\";", i::STRICT);
5386 TestLanguageMode("\"use some future directive\"; \"use strong\";", i::STRONG);
5390 TEST(PropertyNameEvalArguments) {
5391 const char* context_data[][2] = {{"'use strict';", ""},
5392 {"'use strong';", ""},
5395 const char* statement_data[] = {
5399 "({arguments() {}})",
5401 "({*arguments() {}})",
5402 "({get eval() {}})",
5403 "({get arguments() {}})",
5404 "({set eval(_) {}})",
5405 "({set arguments(_) {}})",
5407 "class C {eval() {}}",
5408 "class C {arguments() {}}",
5409 "class C {*eval() {}}",
5410 "class C {*arguments() {}}",
5411 "class C {get eval() {}}",
5412 "class C {get arguments() {}}",
5413 "class C {set eval(_) {}}",
5414 "class C {set arguments(_) {}}",
5416 "class C {static eval() {}}",
5417 "class C {static arguments() {}}",
5418 "class C {static *eval() {}}",
5419 "class C {static *arguments() {}}",
5420 "class C {static get eval() {}}",
5421 "class C {static get arguments() {}}",
5422 "class C {static set eval(_) {}}",
5423 "class C {static set arguments(_) {}}",
5427 static const ParserFlag always_flags[] = {
5428 kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowHarmonyScoping,
5430 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
5431 always_flags, arraysize(always_flags));
5435 TEST(FunctionLiteralDuplicateParameters) {
5436 const char* strict_context_data[][2] =
5437 {{"'use strict';(function(", "){})();"},
5438 {"(function(", ") { 'use strict'; })();"},
5439 {"'use strict'; function fn(", ") {}; fn();"},
5440 {"function fn(", ") { 'use strict'; }; fn();"},
5441 {"'use strong';(function(", "){})();"},
5442 {"(function(", ") { 'use strong'; })();"},
5443 {"'use strong'; function fn(", ") {}; fn();"},
5444 {"function fn(", ") { 'use strong'; }; fn();"},
5447 const char* sloppy_context_data[][2] =
5448 {{"(function(", "){})();"},
5449 {"(function(", ") {})();"},
5450 {"function fn(", ") {}; fn();"},
5451 {"function fn(", ") {}; fn();"},
5454 const char* data[] = {
5459 "a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, w",
5462 static const ParserFlag always_flags[] = { kAllowStrongMode };
5463 RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
5464 arraysize(always_flags));
5465 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, NULL, 0);
5469 TEST(VarForbiddenInStrongMode) {
5470 const char* strong_context_data[][2] =
5471 {{"'use strong'; ", ""},
5472 {"function f() {'use strong'; ", "}"},
5473 {"function f() {'use strong'; while (true) { ", "} }"},
5476 const char* strict_context_data[][2] =
5477 {{"'use strict'; ", ""},
5478 {"function f() {'use strict'; ", "}"},
5479 {"function f() {'use strict'; while (true) { ", "} }"},
5482 const char* sloppy_context_data[][2] =
5484 {"function f() { ", "}"},
5487 const char* var_declarations[] = {
5489 "for (var i = 0; i < 10; i++) { }",
5492 const char* let_declarations[] = {
5494 "for (let i = 0; i < 10; i++) { }",
5497 const char* const_declarations[] = {
5501 static const ParserFlag always_flags[] = {kAllowStrongMode,
5502 kAllowHarmonyScoping};
5503 RunParserSyncTest(strong_context_data, var_declarations, kError, NULL, 0,
5504 always_flags, arraysize(always_flags));
5505 RunParserSyncTest(strong_context_data, let_declarations, kSuccess, NULL, 0,
5506 always_flags, arraysize(always_flags));
5507 RunParserSyncTest(strong_context_data, const_declarations, kSuccess, NULL, 0,
5508 always_flags, arraysize(always_flags));
5510 RunParserSyncTest(strict_context_data, var_declarations, kSuccess, NULL, 0,
5511 always_flags, arraysize(always_flags));
5512 RunParserSyncTest(strict_context_data, let_declarations, kSuccess, NULL, 0,
5513 always_flags, arraysize(always_flags));
5515 RunParserSyncTest(sloppy_context_data, var_declarations, kSuccess, NULL, 0,
5516 always_flags, arraysize(always_flags));
5517 // At the moment, let declarations are only available in strict mode.
5518 RunParserSyncTest(sloppy_context_data, let_declarations, kError, NULL, 0,
5519 always_flags, arraysize(always_flags));
5523 TEST(StrongEmptySubStatements) {
5524 const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
5525 const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
5526 const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
5528 const char* data[] = {
5536 "for (const x = 0;;);",
5537 "for (const x in []);",
5538 "for (const x of []);",
5541 static const ParserFlag always_flags[] = {
5542 kAllowStrongMode, kAllowHarmonyScoping
5544 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
5545 arraysize(always_flags));
5546 RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
5547 arraysize(always_flags));
5548 RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
5549 arraysize(always_flags));
5554 const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
5555 const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
5556 const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
5558 const char* data[] = {
5560 "for (const x in []) {}",
5563 static const ParserFlag always_flags[] = {
5564 kAllowStrongMode, kAllowHarmonyScoping
5566 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
5567 arraysize(always_flags));
5568 RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
5569 arraysize(always_flags));
5570 RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
5571 arraysize(always_flags));