1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "src/v8.h"
33
34 #include "src/ast/ast.h"
35 #include "src/ast/ast-numbering.h"
36 #include "src/ast/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/parsing/parser.h"
42 #include "src/parsing/preparser.h"
43 #include "src/parsing/rewriter.h"
44 #include "src/parsing/scanner-character-streams.h"
45 #include "src/parsing/token.h"
46 #include "src/utils.h"
47
48 #include "test/cctest/cctest.h"
49
TEST(ScanKeywords)50 TEST(ScanKeywords) {
51 struct KeywordToken {
52 const char* keyword;
53 i::Token::Value token;
54 };
55
56 static const KeywordToken keywords[] = {
57 #define KEYWORD(t, s, d) { s, i::Token::t },
58 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
59 #undef KEYWORD
60 { NULL, i::Token::IDENTIFIER }
61 };
62
63 KeywordToken key_token;
64 i::UnicodeCache unicode_cache;
65 i::byte buffer[32];
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);
71 {
72 i::Utf8ToUtf16CharacterStream stream(keyword, length);
73 i::Scanner scanner(&unicode_cache);
74 scanner.Initialize(&stream);
75 CHECK_EQ(key_token.token, scanner.Next());
76 CHECK_EQ(i::Token::EOS, scanner.Next());
77 }
78 // Removing characters will make keyword matching fail.
79 {
80 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
81 i::Scanner scanner(&unicode_cache);
82 scanner.Initialize(&stream);
83 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
84 CHECK_EQ(i::Token::EOS, scanner.Next());
85 }
86 // Adding characters will make keyword matching fail.
87 static const char chars_to_append[] = { 'z', '0', '_' };
88 for (int j = 0; j < static_cast<int>(arraysize(chars_to_append)); ++j) {
89 i::MemMove(buffer, keyword, length);
90 buffer[length] = chars_to_append[j];
91 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
92 i::Scanner scanner(&unicode_cache);
93 scanner.Initialize(&stream);
94 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
95 CHECK_EQ(i::Token::EOS, scanner.Next());
96 }
97 // Replacing characters will make keyword matching fail.
98 {
99 i::MemMove(buffer, keyword, length);
100 buffer[length - 1] = '_';
101 i::Utf8ToUtf16CharacterStream stream(buffer, length);
102 i::Scanner scanner(&unicode_cache);
103 scanner.Initialize(&stream);
104 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
105 CHECK_EQ(i::Token::EOS, scanner.Next());
106 }
107 }
108 }
109
110
TEST(ScanHTMLEndComments)111 TEST(ScanHTMLEndComments) {
112 v8::V8::Initialize();
113 v8::Isolate* isolate = CcTest::isolate();
114 v8::HandleScope handles(isolate);
115
116 // Regression test. See:
117 // http://code.google.com/p/chromium/issues/detail?id=53548
118 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
119 // is only whitespace before it on the line (with comments considered as
120 // whitespace, even a multiline-comment containing a newline).
121 // This was not the case if it occurred before the first real token
122 // in the input.
123 const char* tests[] = {
124 // Before first real token.
125 "--> is eol-comment\nvar y = 37;\n",
126 "\n --> is eol-comment\nvar y = 37;\n",
127 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
128 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
129 // After first real token.
130 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
131 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
132 NULL
133 };
134
135 const char* fail_tests[] = {
136 "x --> is eol-comment\nvar y = 37;\n",
137 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
138 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
139 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
140 "var x = 42; --> is eol-comment\nvar y = 37;\n",
141 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
142 NULL
143 };
144
145 // Parser/Scanner needs a stack limit.
146 CcTest::i_isolate()->stack_guard()->SetStackLimit(
147 i::GetCurrentStackPosition() - 128 * 1024);
148 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
149 for (int i = 0; tests[i]; i++) {
150 const i::byte* source =
151 reinterpret_cast<const i::byte*>(tests[i]);
152 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i]));
153 i::CompleteParserRecorder log;
154 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
155 scanner.Initialize(&stream);
156 i::Zone zone(CcTest::i_isolate()->allocator());
157 i::AstValueFactory ast_value_factory(
158 &zone, CcTest::i_isolate()->heap()->HashSeed());
159 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
160 stack_limit);
161 preparser.set_allow_lazy(true);
162 i::PreParser::PreParseResult result = preparser.PreParseProgram();
163 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
164 CHECK(!log.HasError());
165 }
166
167 for (int i = 0; fail_tests[i]; i++) {
168 const i::byte* source =
169 reinterpret_cast<const i::byte*>(fail_tests[i]);
170 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i]));
171 i::CompleteParserRecorder log;
172 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
173 scanner.Initialize(&stream);
174 i::Zone zone(CcTest::i_isolate()->allocator());
175 i::AstValueFactory ast_value_factory(
176 &zone, CcTest::i_isolate()->heap()->HashSeed());
177 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
178 stack_limit);
179 preparser.set_allow_lazy(true);
180 i::PreParser::PreParseResult result = preparser.PreParseProgram();
181 // Even in the case of a syntax error, kPreParseSuccess is returned.
182 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
183 CHECK(log.HasError());
184 }
185 }
186
187
188 class ScriptResource : public v8::String::ExternalOneByteStringResource {
189 public:
ScriptResource(const char * data,size_t length)190 ScriptResource(const char* data, size_t length)
191 : data_(data), length_(length) { }
192
data() const193 const char* data() const { return data_; }
length() const194 size_t length() const { return length_; }
195
196 private:
197 const char* data_;
198 size_t length_;
199 };
200
201
TEST(UsingCachedData)202 TEST(UsingCachedData) {
203 // Producing cached parser data while parsing eagerly is not supported.
204 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) return;
205
206 v8::Isolate* isolate = CcTest::isolate();
207 v8::HandleScope handles(isolate);
208 v8::Local<v8::Context> context = v8::Context::New(isolate);
209 v8::Context::Scope context_scope(context);
210 CcTest::i_isolate()->stack_guard()->SetStackLimit(
211 i::GetCurrentStackPosition() - 128 * 1024);
212
213 // Source containing functions that might be lazily compiled and all types
214 // of symbols (string, propertyName, regexp).
215 const char* source =
216 "var x = 42;"
217 "function foo(a) { return function nolazy(b) { return a + b; } }"
218 "function bar(a) { if (a) return function lazy(b) { return b; } }"
219 "var z = {'string': 'string literal', bareword: 'propertyName', "
220 " 42: 'number literal', for: 'keyword as propertyName', "
221 " f\\u006fr: 'keyword propertyname with escape'};"
222 "var v = /RegExp Literal/;"
223 "var w = /RegExp Literal\\u0020With Escape/gi;"
224 "var y = { get getter() { return 42; }, "
225 " set setter(v) { this.value = v; }};"
226 "var f = a => function (b) { return a + b; };"
227 "var g = a => b => a + b;";
228 int source_length = i::StrLength(source);
229
230 // ScriptResource will be deleted when the corresponding String is GCd.
231 v8::ScriptCompiler::Source script_source(
232 v8::String::NewExternalOneByte(isolate,
233 new ScriptResource(source, source_length))
234 .ToLocalChecked());
235 i::FLAG_min_preparse_length = 0;
236 v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &script_source,
237 v8::ScriptCompiler::kProduceParserCache)
238 .ToLocalChecked();
239 CHECK(script_source.GetCachedData());
240
241 // Compile the script again, using the cached data.
242 bool lazy_flag = i::FLAG_lazy;
243 i::FLAG_lazy = true;
244 v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &script_source,
245 v8::ScriptCompiler::kConsumeParserCache)
246 .ToLocalChecked();
247 i::FLAG_lazy = false;
248 v8::ScriptCompiler::CompileUnboundScript(
249 isolate, &script_source, v8::ScriptCompiler::kConsumeParserCache)
250 .ToLocalChecked();
251 i::FLAG_lazy = lazy_flag;
252 }
253
254
TEST(PreparseFunctionDataIsUsed)255 TEST(PreparseFunctionDataIsUsed) {
256 // Producing cached parser data while parsing eagerly is not supported.
257 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) return;
258
259 // This tests that we actually do use the function data generated by the
260 // preparser.
261
262 // Make preparsing work for short scripts.
263 i::FLAG_min_preparse_length = 0;
264
265 v8::Isolate* isolate = CcTest::isolate();
266 v8::HandleScope handles(isolate);
267 v8::Local<v8::Context> context = v8::Context::New(isolate);
268 v8::Context::Scope context_scope(context);
269 CcTest::i_isolate()->stack_guard()->SetStackLimit(
270 i::GetCurrentStackPosition() - 128 * 1024);
271
272 const char* good_code[] = {
273 "function this_is_lazy() { var a; } function foo() { return 25; } foo();",
274 "var this_is_lazy = () => { var a; }; var foo = () => 25; foo();",
275 };
276
277 // Insert a syntax error inside the lazy function.
278 const char* bad_code[] = {
279 "function this_is_lazy() { if ( } function foo() { return 25; } foo();",
280 "var this_is_lazy = () => { if ( }; var foo = () => 25; foo();",
281 };
282
283 for (unsigned i = 0; i < arraysize(good_code); i++) {
284 v8::ScriptCompiler::Source good_source(v8_str(good_code[i]));
285 v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &good_source,
286 v8::ScriptCompiler::kProduceParserCache)
287 .ToLocalChecked();
288
289 const v8::ScriptCompiler::CachedData* cached_data =
290 good_source.GetCachedData();
291 CHECK(cached_data->data != NULL);
292 CHECK_GT(cached_data->length, 0);
293
294 // Now compile the erroneous code with the good preparse data. If the
295 // preparse data is used, the lazy function is skipped and it should
296 // compile fine.
297 v8::ScriptCompiler::Source bad_source(
298 v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData(
299 cached_data->data, cached_data->length));
300 v8::Local<v8::Value> result =
301 CompileRun(isolate->GetCurrentContext(), &bad_source,
302 v8::ScriptCompiler::kConsumeParserCache);
303 CHECK(result->IsInt32());
304 CHECK_EQ(25, result->Int32Value(isolate->GetCurrentContext()).FromJust());
305 }
306 }
307
308
TEST(StandAlonePreParser)309 TEST(StandAlonePreParser) {
310 v8::V8::Initialize();
311
312 CcTest::i_isolate()->stack_guard()->SetStackLimit(
313 i::GetCurrentStackPosition() - 128 * 1024);
314
315 const char* programs[] = {
316 "{label: 42}",
317 "var x = 42;",
318 "function foo(x, y) { return x + y; }",
319 "%ArgleBargle(glop);",
320 "var x = new new Function('this.x = 42');",
321 "var f = (x, y) => x + y;",
322 NULL
323 };
324
325 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
326 for (int i = 0; programs[i]; i++) {
327 const char* program = programs[i];
328 i::Utf8ToUtf16CharacterStream stream(
329 reinterpret_cast<const i::byte*>(program),
330 static_cast<unsigned>(strlen(program)));
331 i::CompleteParserRecorder log;
332 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
333 scanner.Initialize(&stream);
334
335 i::Zone zone(CcTest::i_isolate()->allocator());
336 i::AstValueFactory ast_value_factory(
337 &zone, CcTest::i_isolate()->heap()->HashSeed());
338 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
339 stack_limit);
340 preparser.set_allow_lazy(true);
341 preparser.set_allow_natives(true);
342 i::PreParser::PreParseResult result = preparser.PreParseProgram();
343 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
344 CHECK(!log.HasError());
345 }
346 }
347
348
TEST(StandAlonePreParserNoNatives)349 TEST(StandAlonePreParserNoNatives) {
350 v8::V8::Initialize();
351
352 CcTest::i_isolate()->stack_guard()->SetStackLimit(
353 i::GetCurrentStackPosition() - 128 * 1024);
354
355 const char* programs[] = {
356 "%ArgleBargle(glop);",
357 "var x = %_IsSmi(42);",
358 NULL
359 };
360
361 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
362 for (int i = 0; programs[i]; i++) {
363 const char* program = programs[i];
364 i::Utf8ToUtf16CharacterStream stream(
365 reinterpret_cast<const i::byte*>(program),
366 static_cast<unsigned>(strlen(program)));
367 i::CompleteParserRecorder log;
368 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
369 scanner.Initialize(&stream);
370
371 // Preparser defaults to disallowing natives syntax.
372 i::Zone zone(CcTest::i_isolate()->allocator());
373 i::AstValueFactory ast_value_factory(
374 &zone, CcTest::i_isolate()->heap()->HashSeed());
375 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
376 stack_limit);
377 preparser.set_allow_lazy(true);
378 i::PreParser::PreParseResult result = preparser.PreParseProgram();
379 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
380 CHECK(log.HasError());
381 }
382 }
383
384
TEST(PreparsingObjectLiterals)385 TEST(PreparsingObjectLiterals) {
386 // Regression test for a bug where the symbol stream produced by PreParser
387 // didn't match what Parser wanted to consume.
388 v8::Isolate* isolate = CcTest::isolate();
389 v8::HandleScope handles(isolate);
390 v8::Local<v8::Context> context = v8::Context::New(isolate);
391 v8::Context::Scope context_scope(context);
392 CcTest::i_isolate()->stack_guard()->SetStackLimit(
393 i::GetCurrentStackPosition() - 128 * 1024);
394
395 {
396 const char* source = "var myo = {if: \"foo\"}; myo.if;";
397 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
398 CHECK(result->IsString());
399 v8::String::Utf8Value utf8(result);
400 CHECK_EQ(0, strcmp("foo", *utf8));
401 }
402
403 {
404 const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
405 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
406 CHECK(result->IsString());
407 v8::String::Utf8Value utf8(result);
408 CHECK_EQ(0, strcmp("foo", *utf8));
409 }
410
411 {
412 const char* source = "var myo = {1: \"foo\"}; myo[1];";
413 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
414 CHECK(result->IsString());
415 v8::String::Utf8Value utf8(result);
416 CHECK_EQ(0, strcmp("foo", *utf8));
417 }
418 }
419
420
TEST(RegressChromium62639)421 TEST(RegressChromium62639) {
422 v8::V8::Initialize();
423 i::Isolate* isolate = CcTest::i_isolate();
424
425 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
426 128 * 1024);
427
428 const char* program = "var x = 'something';\n"
429 "escape: function() {}";
430 // Fails parsing expecting an identifier after "function".
431 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
432 // and then used the invalid currently scanned literal. This always
433 // failed in debug mode, and sometimes crashed in release mode.
434
435 i::Utf8ToUtf16CharacterStream stream(
436 reinterpret_cast<const i::byte*>(program),
437 static_cast<unsigned>(strlen(program)));
438 i::CompleteParserRecorder log;
439 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
440 scanner.Initialize(&stream);
441 i::Zone zone(CcTest::i_isolate()->allocator());
442 i::AstValueFactory ast_value_factory(&zone,
443 CcTest::i_isolate()->heap()->HashSeed());
444 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
445 CcTest::i_isolate()->stack_guard()->real_climit());
446 preparser.set_allow_lazy(true);
447 i::PreParser::PreParseResult result = preparser.PreParseProgram();
448 // Even in the case of a syntax error, kPreParseSuccess is returned.
449 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
450 CHECK(log.HasError());
451 }
452
453
TEST(Regress928)454 TEST(Regress928) {
455 v8::V8::Initialize();
456 i::Isolate* isolate = CcTest::i_isolate();
457 i::Factory* factory = isolate->factory();
458
459 // Preparsing didn't consider the catch clause of a try statement
460 // as with-content, which made it assume that a function inside
461 // the block could be lazily compiled, and an extra, unexpected,
462 // entry was added to the data.
463 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
464 128 * 1024);
465
466 const char* program =
467 "try { } catch (e) { var foo = function () { /* first */ } }"
468 "var bar = function () { /* second */ }";
469
470 v8::HandleScope handles(CcTest::isolate());
471 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program);
472 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
473 i::CompleteParserRecorder log;
474 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
475 scanner.Initialize(&stream);
476 i::Zone zone(CcTest::i_isolate()->allocator());
477 i::AstValueFactory ast_value_factory(&zone,
478 CcTest::i_isolate()->heap()->HashSeed());
479 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
480 CcTest::i_isolate()->stack_guard()->real_climit());
481 preparser.set_allow_lazy(true);
482 i::PreParser::PreParseResult result = preparser.PreParseProgram();
483 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
484 i::ScriptData* sd = log.GetScriptData();
485 i::ParseData* pd = i::ParseData::FromCachedData(sd);
486 pd->Initialize();
487
488 int first_function =
489 static_cast<int>(strstr(program, "function") - program);
490 int first_lbrace = first_function + i::StrLength("function () ");
491 CHECK_EQ('{', program[first_lbrace]);
492 i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
493 CHECK(!entry1.is_valid());
494
495 int second_function =
496 static_cast<int>(strstr(program + first_lbrace, "function") - program);
497 int second_lbrace =
498 second_function + i::StrLength("function () ");
499 CHECK_EQ('{', program[second_lbrace]);
500 i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
501 CHECK(entry2.is_valid());
502 CHECK_EQ('}', program[entry2.end_pos() - 1]);
503 delete sd;
504 delete pd;
505 }
506
507
TEST(PreParseOverflow)508 TEST(PreParseOverflow) {
509 v8::V8::Initialize();
510
511 CcTest::i_isolate()->stack_guard()->SetStackLimit(
512 i::GetCurrentStackPosition() - 128 * 1024);
513
514 size_t kProgramSize = 1024 * 1024;
515 v8::base::SmartArrayPointer<char> program(
516 i::NewArray<char>(kProgramSize + 1));
517 memset(program.get(), '(', kProgramSize);
518 program[kProgramSize] = '\0';
519
520 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
521
522 i::Utf8ToUtf16CharacterStream stream(
523 reinterpret_cast<const i::byte*>(program.get()),
524 static_cast<unsigned>(kProgramSize));
525 i::CompleteParserRecorder log;
526 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
527 scanner.Initialize(&stream);
528
529 i::Zone zone(CcTest::i_isolate()->allocator());
530 i::AstValueFactory ast_value_factory(&zone,
531 CcTest::i_isolate()->heap()->HashSeed());
532 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
533 stack_limit);
534 preparser.set_allow_lazy(true);
535 i::PreParser::PreParseResult result = preparser.PreParseProgram();
536 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
537 }
538
539
540 class TestExternalResource: public v8::String::ExternalStringResource {
541 public:
TestExternalResource(uint16_t * data,int length)542 explicit TestExternalResource(uint16_t* data, int length)
543 : data_(data), length_(static_cast<size_t>(length)) { }
544
~TestExternalResource()545 ~TestExternalResource() { }
546
data() const547 const uint16_t* data() const {
548 return data_;
549 }
550
length() const551 size_t length() const {
552 return length_;
553 }
554 private:
555 uint16_t* data_;
556 size_t length_;
557 };
558
559
560 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
561
TestCharacterStream(const char * one_byte_source,unsigned length,unsigned start=0,unsigned end=0)562 void TestCharacterStream(const char* one_byte_source, unsigned length,
563 unsigned start = 0, unsigned end = 0) {
564 if (end == 0) end = length;
565 unsigned sub_length = end - start;
566 i::Isolate* isolate = CcTest::i_isolate();
567 i::Factory* factory = isolate->factory();
568 i::HandleScope test_scope(isolate);
569 v8::base::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
570 for (unsigned i = 0; i < length; i++) {
571 uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]);
572 }
573 i::Vector<const char> one_byte_vector(one_byte_source,
574 static_cast<int>(length));
575 i::Handle<i::String> one_byte_string =
576 factory->NewStringFromAscii(one_byte_vector).ToHandleChecked();
577 TestExternalResource resource(uc16_buffer.get(), length);
578 i::Handle<i::String> uc16_string(
579 factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked());
580
581 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
582 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
583 i::GenericStringUtf16CharacterStream string_stream(one_byte_string, start,
584 end);
585 i::Utf8ToUtf16CharacterStream utf8_stream(
586 reinterpret_cast<const i::byte*>(one_byte_source), end);
587 utf8_stream.SeekForward(start);
588
589 unsigned i = start;
590 while (i < end) {
591 // Read streams one char at a time
592 CHECK_EQU(i, uc16_stream.pos());
593 CHECK_EQU(i, string_stream.pos());
594 CHECK_EQU(i, utf8_stream.pos());
595 int32_t c0 = one_byte_source[i];
596 int32_t c1 = uc16_stream.Advance();
597 int32_t c2 = string_stream.Advance();
598 int32_t c3 = utf8_stream.Advance();
599 i++;
600 CHECK_EQ(c0, c1);
601 CHECK_EQ(c0, c2);
602 CHECK_EQ(c0, c3);
603 CHECK_EQU(i, uc16_stream.pos());
604 CHECK_EQU(i, string_stream.pos());
605 CHECK_EQU(i, utf8_stream.pos());
606 }
607 while (i > start + sub_length / 4) {
608 // Pushback, re-read, pushback again.
609 int32_t c0 = one_byte_source[i - 1];
610 CHECK_EQU(i, uc16_stream.pos());
611 CHECK_EQU(i, string_stream.pos());
612 CHECK_EQU(i, utf8_stream.pos());
613 uc16_stream.PushBack(c0);
614 string_stream.PushBack(c0);
615 utf8_stream.PushBack(c0);
616 i--;
617 CHECK_EQU(i, uc16_stream.pos());
618 CHECK_EQU(i, string_stream.pos());
619 CHECK_EQU(i, utf8_stream.pos());
620 int32_t c1 = uc16_stream.Advance();
621 int32_t c2 = string_stream.Advance();
622 int32_t c3 = utf8_stream.Advance();
623 i++;
624 CHECK_EQU(i, uc16_stream.pos());
625 CHECK_EQU(i, string_stream.pos());
626 CHECK_EQU(i, utf8_stream.pos());
627 CHECK_EQ(c0, c1);
628 CHECK_EQ(c0, c2);
629 CHECK_EQ(c0, c3);
630 uc16_stream.PushBack(c0);
631 string_stream.PushBack(c0);
632 utf8_stream.PushBack(c0);
633 i--;
634 CHECK_EQU(i, uc16_stream.pos());
635 CHECK_EQU(i, string_stream.pos());
636 CHECK_EQU(i, utf8_stream.pos());
637 }
638 unsigned halfway = start + sub_length / 2;
639 uc16_stream.SeekForward(halfway - i);
640 string_stream.SeekForward(halfway - i);
641 utf8_stream.SeekForward(halfway - i);
642 i = halfway;
643 CHECK_EQU(i, uc16_stream.pos());
644 CHECK_EQU(i, string_stream.pos());
645 CHECK_EQU(i, utf8_stream.pos());
646
647 while (i < end) {
648 // Read streams one char at a time
649 CHECK_EQU(i, uc16_stream.pos());
650 CHECK_EQU(i, string_stream.pos());
651 CHECK_EQU(i, utf8_stream.pos());
652 int32_t c0 = one_byte_source[i];
653 int32_t c1 = uc16_stream.Advance();
654 int32_t c2 = string_stream.Advance();
655 int32_t c3 = utf8_stream.Advance();
656 i++;
657 CHECK_EQ(c0, c1);
658 CHECK_EQ(c0, c2);
659 CHECK_EQ(c0, c3);
660 CHECK_EQU(i, uc16_stream.pos());
661 CHECK_EQU(i, string_stream.pos());
662 CHECK_EQU(i, utf8_stream.pos());
663 }
664
665 int32_t c1 = uc16_stream.Advance();
666 int32_t c2 = string_stream.Advance();
667 int32_t c3 = utf8_stream.Advance();
668 CHECK_LT(c1, 0);
669 CHECK_LT(c2, 0);
670 CHECK_LT(c3, 0);
671 }
672
673
TEST(CharacterStreams)674 TEST(CharacterStreams) {
675 v8::Isolate* isolate = CcTest::isolate();
676 v8::HandleScope handles(isolate);
677 v8::Local<v8::Context> context = v8::Context::New(isolate);
678 v8::Context::Scope context_scope(context);
679
680 TestCharacterStream("abc\0\n\r\x7f", 7);
681 static const unsigned kBigStringSize = 4096;
682 char buffer[kBigStringSize + 1];
683 for (unsigned i = 0; i < kBigStringSize; i++) {
684 buffer[i] = static_cast<char>(i & 0x7f);
685 }
686 TestCharacterStream(buffer, kBigStringSize);
687
688 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
689
690 TestCharacterStream("\0", 1);
691 TestCharacterStream("", 0);
692 }
693
694
TEST(Utf8CharacterStream)695 TEST(Utf8CharacterStream) {
696 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
697 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
698
699 static const int kAllUtf8CharsSize =
700 (unibrow::Utf8::kMaxOneByteChar + 1) +
701 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
702 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
703 static const unsigned kAllUtf8CharsSizeU =
704 static_cast<unsigned>(kAllUtf8CharsSize);
705
706 char buffer[kAllUtf8CharsSizeU];
707 unsigned cursor = 0;
708 for (int i = 0; i <= kMaxUC16Char; i++) {
709 cursor += unibrow::Utf8::Encode(buffer + cursor, i,
710 unibrow::Utf16::kNoPreviousCharacter, true);
711 }
712 CHECK(cursor == kAllUtf8CharsSizeU);
713
714 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
715 kAllUtf8CharsSizeU);
716 int32_t bad = unibrow::Utf8::kBadChar;
717 for (int i = 0; i <= kMaxUC16Char; i++) {
718 CHECK_EQU(i, stream.pos());
719 int32_t c = stream.Advance();
720 if (i >= 0xd800 && i <= 0xdfff) {
721 CHECK_EQ(bad, c);
722 } else {
723 CHECK_EQ(i, c);
724 }
725 CHECK_EQU(i + 1, stream.pos());
726 }
727 for (int i = kMaxUC16Char; i >= 0; i--) {
728 CHECK_EQU(i + 1, stream.pos());
729 stream.PushBack(i);
730 CHECK_EQU(i, stream.pos());
731 }
732 int i = 0;
733 while (stream.pos() < kMaxUC16CharU) {
734 CHECK_EQU(i, stream.pos());
735 int progress = static_cast<int>(stream.SeekForward(12));
736 i += progress;
737 int32_t c = stream.Advance();
738 if (i >= 0xd800 && i <= 0xdfff) {
739 CHECK_EQ(bad, c);
740 } else if (i <= kMaxUC16Char) {
741 CHECK_EQ(i, c);
742 } else {
743 CHECK_EQ(-1, c);
744 }
745 i += 1;
746 CHECK_EQU(i, stream.pos());
747 }
748 }
749
750 #undef CHECK_EQU
751
TestStreamScanner(i::Utf16CharacterStream * stream,i::Token::Value * expected_tokens,int skip_pos=0,int skip_to=0)752 void TestStreamScanner(i::Utf16CharacterStream* stream,
753 i::Token::Value* expected_tokens,
754 int skip_pos = 0, // Zero means not skipping.
755 int skip_to = 0) {
756 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
757 scanner.Initialize(stream);
758
759 int i = 0;
760 do {
761 i::Token::Value expected = expected_tokens[i];
762 i::Token::Value actual = scanner.Next();
763 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
764 if (scanner.location().end_pos == skip_pos) {
765 scanner.SeekForward(skip_to);
766 }
767 i++;
768 } while (expected_tokens[i] != i::Token::ILLEGAL);
769 }
770
771
TEST(StreamScanner)772 TEST(StreamScanner) {
773 v8::V8::Initialize();
774
775 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
776 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
777 static_cast<unsigned>(strlen(str1)));
778 i::Token::Value expectations1[] = {
779 i::Token::LBRACE,
780 i::Token::IDENTIFIER,
781 i::Token::IDENTIFIER,
782 i::Token::FOR,
783 i::Token::COLON,
784 i::Token::MUL,
785 i::Token::DIV,
786 i::Token::LT,
787 i::Token::SUB,
788 i::Token::IDENTIFIER,
789 i::Token::EOS,
790 i::Token::ILLEGAL
791 };
792 TestStreamScanner(&stream1, expectations1, 0, 0);
793
794 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
795 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
796 static_cast<unsigned>(strlen(str2)));
797 i::Token::Value expectations2[] = {
798 i::Token::CASE,
799 i::Token::DEFAULT,
800 i::Token::CONST,
801 i::Token::LBRACE,
802 // Skipped part here
803 i::Token::RBRACE,
804 i::Token::DO,
805 i::Token::EOS,
806 i::Token::ILLEGAL
807 };
808 CHECK_EQ('{', str2[19]);
809 CHECK_EQ('}', str2[37]);
810 TestStreamScanner(&stream2, expectations2, 20, 37);
811
812 const char* str3 = "{}}}}";
813 i::Token::Value expectations3[] = {
814 i::Token::LBRACE,
815 i::Token::RBRACE,
816 i::Token::RBRACE,
817 i::Token::RBRACE,
818 i::Token::RBRACE,
819 i::Token::EOS,
820 i::Token::ILLEGAL
821 };
822 // Skip zero-four RBRACEs.
823 for (int i = 0; i <= 4; i++) {
824 expectations3[6 - i] = i::Token::ILLEGAL;
825 expectations3[5 - i] = i::Token::EOS;
826 i::Utf8ToUtf16CharacterStream stream3(
827 reinterpret_cast<const i::byte*>(str3),
828 static_cast<unsigned>(strlen(str3)));
829 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
830 }
831 }
832
833
TestScanRegExp(const char * re_source,const char * expected)834 void TestScanRegExp(const char* re_source, const char* expected) {
835 i::Utf8ToUtf16CharacterStream stream(
836 reinterpret_cast<const i::byte*>(re_source),
837 static_cast<unsigned>(strlen(re_source)));
838 i::HandleScope scope(CcTest::i_isolate());
839 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
840 scanner.Initialize(&stream);
841
842 i::Token::Value start = scanner.peek();
843 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
844 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
845 scanner.Next(); // Current token is now the regexp literal.
846 i::Zone zone(CcTest::i_isolate()->allocator());
847 i::AstValueFactory ast_value_factory(&zone,
848 CcTest::i_isolate()->heap()->HashSeed());
849 ast_value_factory.Internalize(CcTest::i_isolate());
850 i::Handle<i::String> val =
851 scanner.CurrentSymbol(&ast_value_factory)->string();
852 i::DisallowHeapAllocation no_alloc;
853 i::String::FlatContent content = val->GetFlatContent();
854 CHECK(content.IsOneByte());
855 i::Vector<const uint8_t> actual = content.ToOneByteVector();
856 for (int i = 0; i < actual.length(); i++) {
857 CHECK_NE('\0', expected[i]);
858 CHECK_EQ(expected[i], actual[i]);
859 }
860 }
861
862
TEST(RegExpScanning)863 TEST(RegExpScanning) {
864 v8::V8::Initialize();
865
866 // RegExp token with added garbage at the end. The scanner should only
867 // scan the RegExp until the terminating slash just before "flipperwald".
868 TestScanRegExp("/b/flipperwald", "b");
869 // Incomplete escape sequences doesn't hide the terminating slash.
870 TestScanRegExp("/\\x/flipperwald", "\\x");
871 TestScanRegExp("/\\u/flipperwald", "\\u");
872 TestScanRegExp("/\\u1/flipperwald", "\\u1");
873 TestScanRegExp("/\\u12/flipperwald", "\\u12");
874 TestScanRegExp("/\\u123/flipperwald", "\\u123");
875 TestScanRegExp("/\\c/flipperwald", "\\c");
876 TestScanRegExp("/\\c//flipperwald", "\\c");
877 // Slashes inside character classes are not terminating.
878 TestScanRegExp("/[/]/flipperwald", "[/]");
879 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
880 // Incomplete escape sequences inside a character class doesn't hide
881 // the end of the character class.
882 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
883 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
884 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
885 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
886 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
887 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
888 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
889 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
890 // Escaped ']'s wont end the character class.
891 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
892 // Escaped slashes are not terminating.
893 TestScanRegExp("/\\//flipperwald", "\\/");
894 // Starting with '=' works too.
895 TestScanRegExp("/=/", "=");
896 TestScanRegExp("/=?/", "=?");
897 }
898
899
Utf8LengthHelper(const char * s)900 static int Utf8LengthHelper(const char* s) {
901 int len = i::StrLength(s);
902 int character_length = len;
903 for (int i = 0; i < len; i++) {
904 unsigned char c = s[i];
905 int input_offset = 0;
906 int output_adjust = 0;
907 if (c > 0x7f) {
908 if (c < 0xc0) continue;
909 if (c >= 0xf0) {
910 if (c >= 0xf8) {
911 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
912 // byte.
913 continue; // Handle first UTF-8 byte.
914 }
915 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
916 // This 4 byte sequence could have been coded as a 3 byte sequence.
917 // Record a single kBadChar for the first byte and continue.
918 continue;
919 }
920 input_offset = 3;
921 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
922 character_length -= 2;
923 } else if (c >= 0xe0) {
924 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
925 // This 3 byte sequence could have been coded as a 2 byte sequence.
926 // Record a single kBadChar for the first byte and continue.
927 continue;
928 }
929 if (c == 0xed) {
930 unsigned char d = s[i + 1];
931 if ((d < 0x80) || (d > 0x9f)) {
932 // This 3 byte sequence is part of a surrogate pair which is not
933 // supported by UTF-8. Record a single kBadChar for the first byte
934 // and continue.
935 continue;
936 }
937 }
938 input_offset = 2;
939 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
940 output_adjust = 2;
941 } else {
942 if ((c & 0x1e) == 0) {
943 // This 2 byte sequence could have been coded as a 1 byte sequence.
944 // Record a single kBadChar for the first byte and continue.
945 continue;
946 }
947 input_offset = 1;
948 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
949 output_adjust = 1;
950 }
951 bool bad = false;
952 for (int j = 1; j <= input_offset; j++) {
953 if ((s[i + j] & 0xc0) != 0x80) {
954 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
955 // which is a single UTF-16 code unit.
956 bad = true;
957 break;
958 }
959 }
960 if (!bad) {
961 i += input_offset;
962 character_length -= output_adjust;
963 }
964 }
965 }
966 return character_length;
967 }
968
969
TEST(ScopeUsesArgumentsSuperThis)970 TEST(ScopeUsesArgumentsSuperThis) {
971 static const struct {
972 const char* prefix;
973 const char* suffix;
974 } surroundings[] = {
975 { "function f() {", "}" },
976 { "var f = () => {", "};" },
977 { "class C { constructor() {", "} }" },
978 };
979
980 enum Expected {
981 NONE = 0,
982 ARGUMENTS = 1,
983 SUPER_PROPERTY = 1 << 1,
984 THIS = 1 << 2,
985 EVAL = 1 << 4
986 };
987
988 // clang-format off
989 static const struct {
990 const char* body;
991 int expected;
992 } source_data[] = {
993 {"", NONE},
994 {"return this", THIS},
995 {"return arguments", ARGUMENTS},
996 {"return super.x", SUPER_PROPERTY},
997 {"return arguments[0]", ARGUMENTS},
998 {"return this + arguments[0]", ARGUMENTS | THIS},
999 {"return this + arguments[0] + super.x",
1000 ARGUMENTS | SUPER_PROPERTY | THIS},
1001 {"return x => this + x", THIS},
1002 {"return x => super.f() + x", SUPER_PROPERTY},
1003 {"this.foo = 42;", THIS},
1004 {"this.foo();", THIS},
1005 {"if (foo()) { this.f() }", THIS},
1006 {"if (foo()) { super.f() }", SUPER_PROPERTY},
1007 {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
1008 {"while (true) { this.f() }", THIS},
1009 {"while (true) { super.f() }", SUPER_PROPERTY},
1010 {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
1011 // Multiple nesting levels must work as well.
1012 {"while (true) { while (true) { while (true) return this } }", THIS},
1013 {"while (true) { while (true) { while (true) return super.f() } }",
1014 SUPER_PROPERTY},
1015 {"if (1) { return () => { while (true) new this() } }", THIS},
1016 {"return function (x) { return this + x }", NONE},
1017 {"return { m(x) { return super.m() + x } }", NONE},
1018 {"var x = function () { this.foo = 42 };", NONE},
1019 {"var x = { m() { super.foo = 42 } };", NONE},
1020 {"if (1) { return function () { while (true) new this() } }", NONE},
1021 {"if (1) { return { m() { while (true) super.m() } } }", NONE},
1022 {"return function (x) { return () => this }", NONE},
1023 {"return { m(x) { return () => super.m() } }", NONE},
1024 // Flags must be correctly set when using block scoping.
1025 {"\"use strict\"; while (true) { let x; this, arguments; }",
1026 THIS},
1027 {"\"use strict\"; while (true) { let x; this, super.f(), arguments; }",
1028 SUPER_PROPERTY | THIS},
1029 {"\"use strict\"; if (foo()) { let x; this.f() }", THIS},
1030 {"\"use strict\"; if (foo()) { let x; super.f() }", SUPER_PROPERTY},
1031 {"\"use strict\"; if (1) {"
1032 " let x; return { m() { return this + super.m() + arguments } }"
1033 "}",
1034 NONE},
1035 {"eval(42)", EVAL},
1036 {"if (1) { eval(42) }", EVAL},
1037 {"eval('super.x')", EVAL},
1038 {"eval('this.x')", EVAL},
1039 {"eval('arguments')", EVAL},
1040 };
1041 // clang-format on
1042
1043 i::Isolate* isolate = CcTest::i_isolate();
1044 i::Factory* factory = isolate->factory();
1045
1046 v8::HandleScope handles(CcTest::isolate());
1047 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
1048 v8::Context::Scope context_scope(context);
1049
1050 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1051 128 * 1024);
1052
1053 for (unsigned j = 0; j < arraysize(surroundings); ++j) {
1054 for (unsigned i = 0; i < arraysize(source_data); ++i) {
1055 // Super property is only allowed in constructor and method.
1056 if (((source_data[i].expected & SUPER_PROPERTY) ||
1057 (source_data[i].expected == NONE)) && j != 2) {
1058 continue;
1059 }
1060 int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
1061 i::StrLength(surroundings[j].suffix) +
1062 i::StrLength(source_data[i].body);
1063 i::ScopedVector<char> program(kProgramByteSize + 1);
1064 i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
1065 source_data[i].body, surroundings[j].suffix);
1066 i::Handle<i::String> source =
1067 factory->NewStringFromUtf8(i::CStrVector(program.start()))
1068 .ToHandleChecked();
1069 i::Handle<i::Script> script = factory->NewScript(source);
1070 i::Zone zone(CcTest::i_isolate()->allocator());
1071 i::ParseInfo info(&zone, script);
1072 i::Parser parser(&info);
1073 info.set_global();
1074 CHECK(parser.Parse(&info));
1075 CHECK(i::Rewriter::Rewrite(&info));
1076 CHECK(i::Scope::Analyze(&info));
1077 CHECK(info.literal() != NULL);
1078
1079 i::Scope* script_scope = info.literal()->scope();
1080 CHECK(script_scope->is_script_scope());
1081 CHECK_EQ(1, script_scope->inner_scopes()->length());
1082
1083 i::Scope* scope = script_scope->inner_scopes()->at(0);
1084 // Adjust for constructor scope.
1085 if (j == 2) {
1086 CHECK_EQ(1, scope->inner_scopes()->length());
1087 scope = scope->inner_scopes()->at(0);
1088 }
1089 CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
1090 scope->uses_arguments());
1091 CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
1092 scope->uses_super_property());
1093 if ((source_data[i].expected & THIS) != 0) {
1094 // Currently the is_used() flag is conservative; all variables in a
1095 // script scope are marked as used.
1096 CHECK(
1097 scope->Lookup(info.ast_value_factory()->this_string())->is_used());
1098 }
1099 CHECK_EQ((source_data[i].expected & EVAL) != 0, scope->calls_eval());
1100 }
1101 }
1102 }
1103
1104
CheckParsesToNumber(const char * source,bool with_dot)1105 static void CheckParsesToNumber(const char* source, bool with_dot) {
1106 v8::V8::Initialize();
1107 HandleAndZoneScope handles;
1108
1109 i::Isolate* isolate = CcTest::i_isolate();
1110 i::Factory* factory = isolate->factory();
1111
1112 std::string full_source = "function f() { return ";
1113 full_source += source;
1114 full_source += "; }";
1115
1116 i::Handle<i::String> source_code =
1117 factory->NewStringFromUtf8(i::CStrVector(full_source.c_str()))
1118 .ToHandleChecked();
1119
1120 i::Handle<i::Script> script = factory->NewScript(source_code);
1121
1122 i::ParseInfo info(handles.main_zone(), script);
1123 i::Parser parser(&info);
1124 info.set_global();
1125 info.set_lazy(false);
1126 info.set_allow_lazy_parsing(false);
1127 info.set_toplevel(true);
1128
1129 CHECK(i::Compiler::ParseAndAnalyze(&info));
1130
1131 CHECK(info.scope()->declarations()->length() == 1);
1132 i::FunctionLiteral* fun =
1133 info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun();
1134 CHECK(fun->body()->length() == 1);
1135 CHECK(fun->body()->at(0)->IsReturnStatement());
1136 i::ReturnStatement* ret = fun->body()->at(0)->AsReturnStatement();
1137 i::Literal* lit = ret->expression()->AsLiteral();
1138 if (lit != NULL) {
1139 const i::AstValue* val = lit->raw_value();
1140 CHECK(with_dot == val->ContainsDot());
1141 } else if (with_dot) {
1142 i::BinaryOperation* bin = ret->expression()->AsBinaryOperation();
1143 CHECK(bin != NULL);
1144 CHECK_EQ(i::Token::MUL, bin->op());
1145 i::Literal* rlit = bin->right()->AsLiteral();
1146 const i::AstValue* val = rlit->raw_value();
1147 CHECK(with_dot == val->ContainsDot());
1148 CHECK_EQ(1.0, val->AsNumber());
1149 }
1150 }
1151
1152
TEST(ParseNumbers)1153 TEST(ParseNumbers) {
1154 CheckParsesToNumber("1.", true);
1155 CheckParsesToNumber("1.34", true);
1156 CheckParsesToNumber("134", false);
1157 CheckParsesToNumber("134e44", false);
1158 CheckParsesToNumber("134.e44", true);
1159 CheckParsesToNumber("134.44e44", true);
1160 CheckParsesToNumber(".44", true);
1161
1162 CheckParsesToNumber("-1.", true);
1163 CheckParsesToNumber("-1.0", true);
1164 CheckParsesToNumber("-1.34", true);
1165 CheckParsesToNumber("-134", false);
1166 CheckParsesToNumber("-134e44", false);
1167 CheckParsesToNumber("-134.e44", true);
1168 CheckParsesToNumber("-134.44e44", true);
1169 CheckParsesToNumber("-.44", true);
1170
1171 CheckParsesToNumber("+x", true);
1172 }
1173
1174
TEST(ScopePositions)1175 TEST(ScopePositions) {
1176 // Test the parser for correctly setting the start and end positions
1177 // of a scope. We check the scope positions of exactly one scope
1178 // nested in the global scope of a program. 'inner source' is the
1179 // source code that determines the part of the source belonging
1180 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
1181 // parts of the source that belong to the global scope.
1182 struct SourceData {
1183 const char* outer_prefix;
1184 const char* inner_source;
1185 const char* outer_suffix;
1186 i::ScopeType scope_type;
1187 i::LanguageMode language_mode;
1188 };
1189
1190 const SourceData source_data[] = {
1191 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
1192 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
1193 { " with ({}) ", "{\n"
1194 " block;\n"
1195 " }", "\n"
1196 " more;", i::WITH_SCOPE, i::SLOPPY },
1197 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
1198 { " with ({}) ", "statement", "\n"
1199 " more;", i::WITH_SCOPE, i::SLOPPY },
1200 { " with ({})\n"
1201 " ", "statement;", "\n"
1202 " more;", i::WITH_SCOPE, i::SLOPPY },
1203 { " try {} catch ", "(e) { block; }", " more;",
1204 i::CATCH_SCOPE, i::SLOPPY },
1205 { " try {} catch ", "(e) { block; }", "; more;",
1206 i::CATCH_SCOPE, i::SLOPPY },
1207 { " try {} catch ", "(e) {\n"
1208 " block;\n"
1209 " }", "\n"
1210 " more;", i::CATCH_SCOPE, i::SLOPPY },
1211 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
1212 i::CATCH_SCOPE, i::SLOPPY },
1213 { " start;\n"
1214 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
1215 { " start;\n"
1216 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
1217 { " start;\n"
1218 " ", "{\n"
1219 " let block;\n"
1220 " }", "\n"
1221 " more;", i::BLOCK_SCOPE, i::STRICT },
1222 { " start;\n"
1223 " function fun", "(a,b) { infunction; }", " more;",
1224 i::FUNCTION_SCOPE, i::SLOPPY },
1225 { " start;\n"
1226 " function fun", "(a,b) {\n"
1227 " infunction;\n"
1228 " }", "\n"
1229 " more;", i::FUNCTION_SCOPE, i::SLOPPY },
1230 { " start;\n", "(a,b) => a + b", "; more;",
1231 i::FUNCTION_SCOPE, i::SLOPPY },
1232 { " start;\n", "(a,b) => { return a+b; }", "\nmore;",
1233 i::FUNCTION_SCOPE, i::SLOPPY },
1234 { " start;\n"
1235 " (function fun", "(a,b) { infunction; }", ")();",
1236 i::FUNCTION_SCOPE, i::SLOPPY },
1237 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
1238 i::BLOCK_SCOPE, i::STRICT },
1239 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
1240 i::BLOCK_SCOPE, i::STRICT },
1241 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
1242 " block;\n"
1243 " }", "\n"
1244 " more;", i::BLOCK_SCOPE, i::STRICT },
1245 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
1246 i::BLOCK_SCOPE, i::STRICT },
1247 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
1248 " more;", i::BLOCK_SCOPE, i::STRICT },
1249 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
1250 " statement;", "\n"
1251 " more;", i::BLOCK_SCOPE, i::STRICT },
1252 { " for ", "(let x in {}) { block; }", " more;",
1253 i::BLOCK_SCOPE, i::STRICT },
1254 { " for ", "(let x in {}) { block; }", "; more;",
1255 i::BLOCK_SCOPE, i::STRICT },
1256 { " for ", "(let x in {}) {\n"
1257 " block;\n"
1258 " }", "\n"
1259 " more;", i::BLOCK_SCOPE, i::STRICT },
1260 { " for ", "(let x in {}) statement;", " more;",
1261 i::BLOCK_SCOPE, i::STRICT },
1262 { " for ", "(let x in {}) statement", "\n"
1263 " more;", i::BLOCK_SCOPE, i::STRICT },
1264 { " for ", "(let x in {})\n"
1265 " statement;", "\n"
1266 " more;", i::BLOCK_SCOPE, i::STRICT },
1267 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
1268 // the preparser off in terms of byte offsets.
1269 // 6 byte encoding.
1270 { " 'foo\355\240\201\355\260\211';\n"
1271 " (function fun", "(a,b) { infunction; }", ")();",
1272 i::FUNCTION_SCOPE, i::SLOPPY },
1273 // 4 byte encoding.
1274 { " 'foo\360\220\220\212';\n"
1275 " (function fun", "(a,b) { infunction; }", ")();",
1276 i::FUNCTION_SCOPE, i::SLOPPY },
1277 // 3 byte encoding of \u0fff.
1278 { " 'foo\340\277\277';\n"
1279 " (function fun", "(a,b) { infunction; }", ")();",
1280 i::FUNCTION_SCOPE, i::SLOPPY },
1281 // Broken 6 byte encoding with missing last byte.
1282 { " 'foo\355\240\201\355\211';\n"
1283 " (function fun", "(a,b) { infunction; }", ")();",
1284 i::FUNCTION_SCOPE, i::SLOPPY },
1285 // Broken 3 byte encoding of \u0fff with missing last byte.
1286 { " 'foo\340\277';\n"
1287 " (function fun", "(a,b) { infunction; }", ")();",
1288 i::FUNCTION_SCOPE, i::SLOPPY },
1289 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
1290 { " 'foo\340';\n"
1291 " (function fun", "(a,b) { infunction; }", ")();",
1292 i::FUNCTION_SCOPE, i::SLOPPY },
1293 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
1294 { " 'foo\340\203\277';\n"
1295 " (function fun", "(a,b) { infunction; }", ")();",
1296 i::FUNCTION_SCOPE, i::SLOPPY },
1297 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
1298 { " 'foo\340\201\277';\n"
1299 " (function fun", "(a,b) { infunction; }", ")();",
1300 i::FUNCTION_SCOPE, i::SLOPPY },
1301 // Unpaired lead surrogate.
1302 { " 'foo\355\240\201';\n"
1303 " (function fun", "(a,b) { infunction; }", ")();",
1304 i::FUNCTION_SCOPE, i::SLOPPY },
1305 // Unpaired lead surrogate where following code point is a 3 byte sequence.
1306 { " 'foo\355\240\201\340\277\277';\n"
1307 " (function fun", "(a,b) { infunction; }", ")();",
1308 i::FUNCTION_SCOPE, i::SLOPPY },
1309 // Unpaired lead surrogate where following code point is a 4 byte encoding
1310 // of a trail surrogate.
1311 { " 'foo\355\240\201\360\215\260\211';\n"
1312 " (function fun", "(a,b) { infunction; }", ")();",
1313 i::FUNCTION_SCOPE, i::SLOPPY },
1314 // Unpaired trail surrogate.
1315 { " 'foo\355\260\211';\n"
1316 " (function fun", "(a,b) { infunction; }", ")();",
1317 i::FUNCTION_SCOPE, i::SLOPPY },
1318 // 2 byte encoding of \u00ff.
1319 { " 'foo\303\277';\n"
1320 " (function fun", "(a,b) { infunction; }", ")();",
1321 i::FUNCTION_SCOPE, i::SLOPPY },
1322 // Broken 2 byte encoding of \u00ff with missing last byte.
1323 { " 'foo\303';\n"
1324 " (function fun", "(a,b) { infunction; }", ")();",
1325 i::FUNCTION_SCOPE, i::SLOPPY },
1326 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
1327 { " 'foo\301\277';\n"
1328 " (function fun", "(a,b) { infunction; }", ")();",
1329 i::FUNCTION_SCOPE, i::SLOPPY },
1330 // Illegal 5 byte encoding.
1331 { " 'foo\370\277\277\277\277';\n"
1332 " (function fun", "(a,b) { infunction; }", ")();",
1333 i::FUNCTION_SCOPE, i::SLOPPY },
1334 // Illegal 6 byte encoding.
1335 { " 'foo\374\277\277\277\277\277';\n"
1336 " (function fun", "(a,b) { infunction; }", ")();",
1337 i::FUNCTION_SCOPE, i::SLOPPY },
1338 // Illegal 0xfe byte
1339 { " 'foo\376\277\277\277\277\277\277';\n"
1340 " (function fun", "(a,b) { infunction; }", ")();",
1341 i::FUNCTION_SCOPE, i::SLOPPY },
1342 // Illegal 0xff byte
1343 { " 'foo\377\277\277\277\277\277\277\277';\n"
1344 " (function fun", "(a,b) { infunction; }", ")();",
1345 i::FUNCTION_SCOPE, i::SLOPPY },
1346 { " 'foo';\n"
1347 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
1348 i::FUNCTION_SCOPE, i::SLOPPY },
1349 { " 'foo';\n"
1350 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
1351 i::FUNCTION_SCOPE, i::SLOPPY },
1352 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
1353 };
1354
1355 i::Isolate* isolate = CcTest::i_isolate();
1356 i::Factory* factory = isolate->factory();
1357
1358 v8::HandleScope handles(CcTest::isolate());
1359 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
1360 v8::Context::Scope context_scope(context);
1361
1362 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1363 128 * 1024);
1364
1365 for (int i = 0; source_data[i].outer_prefix; i++) {
1366 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1367 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1368 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1369 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1370 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1371 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1372 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1373 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1374 i::ScopedVector<char> program(kProgramByteSize + 1);
1375 i::SNPrintF(program, "%s%s%s",
1376 source_data[i].outer_prefix,
1377 source_data[i].inner_source,
1378 source_data[i].outer_suffix);
1379
1380 // Parse program source.
1381 i::Handle<i::String> source = factory->NewStringFromUtf8(
1382 i::CStrVector(program.start())).ToHandleChecked();
1383 CHECK_EQ(source->length(), kProgramSize);
1384 i::Handle<i::Script> script = factory->NewScript(source);
1385 i::Zone zone(CcTest::i_isolate()->allocator());
1386 i::ParseInfo info(&zone, script);
1387 i::Parser parser(&info);
1388 parser.set_allow_lazy(true);
1389 info.set_global();
1390 info.set_language_mode(source_data[i].language_mode);
1391 parser.Parse(&info);
1392 CHECK(info.literal() != NULL);
1393
1394 // Check scope types and positions.
1395 i::Scope* scope = info.literal()->scope();
1396 CHECK(scope->is_script_scope());
1397 CHECK_EQ(scope->start_position(), 0);
1398 CHECK_EQ(scope->end_position(), kProgramSize);
1399 CHECK_EQ(scope->inner_scopes()->length(), 1);
1400
1401 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1402 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
1403 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1404 // The end position of a token is one position after the last
1405 // character belonging to that token.
1406 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1407 }
1408 }
1409
1410
TEST(DiscardFunctionBody)1411 TEST(DiscardFunctionBody) {
1412 // Test that inner function bodies are discarded if possible.
1413 // See comments in ParseFunctionLiteral in parser.cc.
1414 const char* discard_sources[] = {
1415 "(function f() { function g() { var a; } })();",
1416 "(function f() { function g() { { function h() { } } } })();",
1417 /* TODO(conradw): In future it may be possible to apply this optimisation
1418 * to these productions.
1419 "(function f() { 0, function g() { var a; } })();",
1420 "(function f() { 0, { g() { var a; } } })();",
1421 "(function f() { 0, class c { g() { var a; } } })();", */
1422 NULL};
1423
1424 i::Isolate* isolate = CcTest::i_isolate();
1425 i::Factory* factory = isolate->factory();
1426 v8::HandleScope handles(CcTest::isolate());
1427 i::FunctionLiteral* function;
1428
1429 for (int i = 0; discard_sources[i]; i++) {
1430 const char* source = discard_sources[i];
1431 i::Handle<i::String> source_code =
1432 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked();
1433 i::Handle<i::Script> script = factory->NewScript(source_code);
1434 i::Zone zone(CcTest::i_isolate()->allocator());
1435 i::ParseInfo info(&zone, script);
1436 info.set_allow_lazy_parsing();
1437 i::Parser parser(&info);
1438 parser.Parse(&info);
1439 function = info.literal();
1440 CHECK_NOT_NULL(function);
1441 CHECK_NOT_NULL(function->body());
1442 CHECK_EQ(1, function->body()->length());
1443 i::FunctionLiteral* inner =
1444 function->body()->first()->AsExpressionStatement()->expression()->
1445 AsCall()->expression()->AsFunctionLiteral();
1446 i::Scope* inner_scope = inner->scope();
1447 i::FunctionLiteral* fun = nullptr;
1448 if (inner_scope->declarations()->length() > 1) {
1449 fun = inner_scope->declarations()->at(1)->AsFunctionDeclaration()->fun();
1450 } else {
1451 // TODO(conradw): This path won't be hit until the other test cases can be
1452 // uncommented.
1453 UNREACHABLE();
1454 CHECK_NOT_NULL(inner->body());
1455 CHECK_GE(2, inner->body()->length());
1456 i::Expression* exp = inner->body()->at(1)->AsExpressionStatement()->
1457 expression()->AsBinaryOperation()->right();
1458 if (exp->IsFunctionLiteral()) {
1459 fun = exp->AsFunctionLiteral();
1460 } else if (exp->IsObjectLiteral()) {
1461 fun = exp->AsObjectLiteral()->properties()->at(0)->value()->
1462 AsFunctionLiteral();
1463 } else {
1464 fun = exp->AsClassLiteral()->properties()->at(0)->value()->
1465 AsFunctionLiteral();
1466 }
1467 }
1468 CHECK_NULL(fun->body());
1469 }
1470 }
1471
1472
ReadString(unsigned * start)1473 const char* ReadString(unsigned* start) {
1474 int length = start[0];
1475 char* result = i::NewArray<char>(length + 1);
1476 for (int i = 0; i < length; i++) {
1477 result[i] = start[i + 1];
1478 }
1479 result[length] = '\0';
1480 return result;
1481 }
1482
1483
FormatMessage(i::Vector<unsigned> data)1484 i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
1485 i::Isolate* isolate = CcTest::i_isolate();
1486 int message = data[i::PreparseDataConstants::kMessageTemplatePos];
1487 int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
1488 i::Handle<i::Object> arg_object;
1489 if (arg_count == 1) {
1490 // Position after text found by skipping past length field and
1491 // length field content words.
1492 const char* arg =
1493 ReadString(&data[i::PreparseDataConstants::kMessageArgPos]);
1494 arg_object = v8::Utils::OpenHandle(*v8_str(arg));
1495 i::DeleteArray(arg);
1496 } else {
1497 CHECK_EQ(0, arg_count);
1498 arg_object = isolate->factory()->undefined_value();
1499 }
1500
1501 data.Dispose();
1502 return i::MessageTemplate::FormatMessage(isolate, message, arg_object);
1503 }
1504
1505 enum ParserFlag {
1506 kAllowLazy,
1507 kAllowNatives,
1508 kAllowHarmonyFunctionSent,
1509 kAllowHarmonyRestrictiveDeclarations,
1510 kAllowHarmonyExponentiationOperator,
1511 kAllowHarmonyForIn,
1512 kAllowHarmonyAsyncAwait,
1513 kAllowHarmonyRestrictiveGenerators,
1514 };
1515
1516 enum ParserSyncTestResult {
1517 kSuccessOrError,
1518 kSuccess,
1519 kError
1520 };
1521
1522 template <typename Traits>
SetParserFlags(i::ParserBase<Traits> * parser,i::EnumSet<ParserFlag> flags)1523 void SetParserFlags(i::ParserBase<Traits>* parser,
1524 i::EnumSet<ParserFlag> flags) {
1525 parser->set_allow_lazy(flags.Contains(kAllowLazy));
1526 parser->set_allow_natives(flags.Contains(kAllowNatives));
1527 parser->set_allow_harmony_function_sent(
1528 flags.Contains(kAllowHarmonyFunctionSent));
1529 parser->set_allow_harmony_restrictive_declarations(
1530 flags.Contains(kAllowHarmonyRestrictiveDeclarations));
1531 parser->set_allow_harmony_exponentiation_operator(
1532 flags.Contains(kAllowHarmonyExponentiationOperator));
1533 parser->set_allow_harmony_for_in(flags.Contains(kAllowHarmonyForIn));
1534 parser->set_allow_harmony_async_await(
1535 flags.Contains(kAllowHarmonyAsyncAwait));
1536 parser->set_allow_harmony_restrictive_generators(
1537 flags.Contains(kAllowHarmonyRestrictiveGenerators));
1538 }
1539
1540
TestParserSyncWithFlags(i::Handle<i::String> source,i::EnumSet<ParserFlag> flags,ParserSyncTestResult result,bool is_module=false,bool test_preparser=true)1541 void TestParserSyncWithFlags(i::Handle<i::String> source,
1542 i::EnumSet<ParserFlag> flags,
1543 ParserSyncTestResult result,
1544 bool is_module = false,
1545 bool test_preparser = true) {
1546 i::Isolate* isolate = CcTest::i_isolate();
1547 i::Factory* factory = isolate->factory();
1548
1549 uintptr_t stack_limit = isolate->stack_guard()->real_climit();
1550 int preparser_materialized_literals = -1;
1551 int parser_materialized_literals = -2;
1552
1553 // Preparse the data.
1554 i::CompleteParserRecorder log;
1555 if (test_preparser) {
1556 i::Scanner scanner(isolate->unicode_cache());
1557 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1558 i::Zone zone(CcTest::i_isolate()->allocator());
1559 i::AstValueFactory ast_value_factory(
1560 &zone, CcTest::i_isolate()->heap()->HashSeed());
1561 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
1562 stack_limit);
1563 SetParserFlags(&preparser, flags);
1564 scanner.Initialize(&stream);
1565 i::PreParser::PreParseResult result =
1566 preparser.PreParseProgram(&preparser_materialized_literals, is_module);
1567 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1568 }
1569 bool preparse_error = log.HasError();
1570
1571 // Parse the data
1572 i::FunctionLiteral* function;
1573 {
1574 i::Handle<i::Script> script = factory->NewScript(source);
1575 i::Zone zone(CcTest::i_isolate()->allocator());
1576 i::ParseInfo info(&zone, script);
1577 i::Parser parser(&info);
1578 SetParserFlags(&parser, flags);
1579 if (is_module) {
1580 info.set_module();
1581 } else {
1582 info.set_global();
1583 }
1584 parser.Parse(&info);
1585 function = info.literal();
1586 if (function) {
1587 parser_materialized_literals = function->materialized_literal_count();
1588 }
1589 }
1590
1591 // Check that preparsing fails iff parsing fails.
1592 if (function == NULL) {
1593 // Extract exception from the parser.
1594 CHECK(isolate->has_pending_exception());
1595 i::Handle<i::JSObject> exception_handle(
1596 i::JSObject::cast(isolate->pending_exception()));
1597 i::Handle<i::String> message_string = i::Handle<i::String>::cast(
1598 i::JSReceiver::GetProperty(isolate, exception_handle, "message")
1599 .ToHandleChecked());
1600
1601 if (result == kSuccess) {
1602 v8::base::OS::Print(
1603 "Parser failed on:\n"
1604 "\t%s\n"
1605 "with error:\n"
1606 "\t%s\n"
1607 "However, we expected no error.",
1608 source->ToCString().get(), message_string->ToCString().get());
1609 CHECK(false);
1610 }
1611
1612 if (test_preparser && !preparse_error) {
1613 v8::base::OS::Print(
1614 "Parser failed on:\n"
1615 "\t%s\n"
1616 "with error:\n"
1617 "\t%s\n"
1618 "However, the preparser succeeded",
1619 source->ToCString().get(), message_string->ToCString().get());
1620 CHECK(false);
1621 }
1622 // Check that preparser and parser produce the same error.
1623 if (test_preparser) {
1624 i::Handle<i::String> preparser_message =
1625 FormatMessage(log.ErrorMessageData());
1626 if (!i::String::Equals(message_string, preparser_message)) {
1627 v8::base::OS::Print(
1628 "Expected parser and preparser to produce the same error on:\n"
1629 "\t%s\n"
1630 "However, found the following error messages\n"
1631 "\tparser: %s\n"
1632 "\tpreparser: %s\n",
1633 source->ToCString().get(), message_string->ToCString().get(),
1634 preparser_message->ToCString().get());
1635 CHECK(false);
1636 }
1637 }
1638 } else if (test_preparser && preparse_error) {
1639 v8::base::OS::Print(
1640 "Preparser failed on:\n"
1641 "\t%s\n"
1642 "with error:\n"
1643 "\t%s\n"
1644 "However, the parser succeeded",
1645 source->ToCString().get(),
1646 FormatMessage(log.ErrorMessageData())->ToCString().get());
1647 CHECK(false);
1648 } else if (result == kError) {
1649 v8::base::OS::Print(
1650 "Expected error on:\n"
1651 "\t%s\n"
1652 "However, parser and preparser succeeded",
1653 source->ToCString().get());
1654 CHECK(false);
1655 } else if (test_preparser &&
1656 preparser_materialized_literals != parser_materialized_literals) {
1657 v8::base::OS::Print(
1658 "Preparser materialized literals (%d) differ from Parser materialized "
1659 "literals (%d) on:\n"
1660 "\t%s\n"
1661 "However, parser and preparser succeeded",
1662 preparser_materialized_literals, parser_materialized_literals,
1663 source->ToCString().get());
1664 CHECK(false);
1665 }
1666 }
1667
1668
TestParserSync(const char * source,const ParserFlag * varying_flags,size_t varying_flags_length,ParserSyncTestResult result=kSuccessOrError,const ParserFlag * always_true_flags=NULL,size_t always_true_flags_length=0,const ParserFlag * always_false_flags=NULL,size_t always_false_flags_length=0,bool is_module=false,bool test_preparser=true)1669 void TestParserSync(const char* source, const ParserFlag* varying_flags,
1670 size_t varying_flags_length,
1671 ParserSyncTestResult result = kSuccessOrError,
1672 const ParserFlag* always_true_flags = NULL,
1673 size_t always_true_flags_length = 0,
1674 const ParserFlag* always_false_flags = NULL,
1675 size_t always_false_flags_length = 0,
1676 bool is_module = false, bool test_preparser = true) {
1677 i::Handle<i::String> str =
1678 CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
1679 for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
1680 i::EnumSet<ParserFlag> flags;
1681 for (size_t flag_index = 0; flag_index < varying_flags_length;
1682 ++flag_index) {
1683 if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]);
1684 }
1685 for (size_t flag_index = 0; flag_index < always_true_flags_length;
1686 ++flag_index) {
1687 flags.Add(always_true_flags[flag_index]);
1688 }
1689 for (size_t flag_index = 0; flag_index < always_false_flags_length;
1690 ++flag_index) {
1691 flags.Remove(always_false_flags[flag_index]);
1692 }
1693 TestParserSyncWithFlags(str, flags, result, is_module, test_preparser);
1694 }
1695 }
1696
1697
TEST(ParserSync)1698 TEST(ParserSync) {
1699 const char* context_data[][2] = {
1700 { "", "" },
1701 { "{", "}" },
1702 { "if (true) ", " else {}" },
1703 { "if (true) {} else ", "" },
1704 { "if (true) ", "" },
1705 { "do ", " while (false)" },
1706 { "while (false) ", "" },
1707 { "for (;;) ", "" },
1708 { "with ({})", "" },
1709 { "switch (12) { case 12: ", "}" },
1710 { "switch (12) { default: ", "}" },
1711 { "switch (12) { ", "case 12: }" },
1712 { "label2: ", "" },
1713 { NULL, NULL }
1714 };
1715
1716 const char* statement_data[] = {
1717 "{}",
1718 "var x",
1719 "var x = 1",
1720 "const x",
1721 "const x = 1",
1722 ";",
1723 "12",
1724 "if (false) {} else ;",
1725 "if (false) {} else {}",
1726 "if (false) {} else 12",
1727 "if (false) ;",
1728 "if (false) {}",
1729 "if (false) 12",
1730 "do {} while (false)",
1731 "for (;;) ;",
1732 "for (;;) {}",
1733 "for (;;) 12",
1734 "continue",
1735 "continue label",
1736 "continue\nlabel",
1737 "break",
1738 "break label",
1739 "break\nlabel",
1740 // TODO(marja): activate once parsing 'return' is merged into ParserBase.
1741 // "return",
1742 // "return 12",
1743 // "return\n12",
1744 "with ({}) ;",
1745 "with ({}) {}",
1746 "with ({}) 12",
1747 "switch ({}) { default: }",
1748 "label3: ",
1749 "throw",
1750 "throw 12",
1751 "throw\n12",
1752 "try {} catch(e) {}",
1753 "try {} finally {}",
1754 "try {} catch(e) {} finally {}",
1755 "debugger",
1756 NULL
1757 };
1758
1759 const char* termination_data[] = {
1760 "",
1761 ";",
1762 "\n",
1763 ";\n",
1764 "\n;",
1765 NULL
1766 };
1767
1768 v8::HandleScope handles(CcTest::isolate());
1769 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
1770 v8::Context::Scope context_scope(context);
1771
1772 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1773 i::GetCurrentStackPosition() - 128 * 1024);
1774
1775 for (int i = 0; context_data[i][0] != NULL; ++i) {
1776 for (int j = 0; statement_data[j] != NULL; ++j) {
1777 for (int k = 0; termination_data[k] != NULL; ++k) {
1778 int kPrefixLen = i::StrLength(context_data[i][0]);
1779 int kStatementLen = i::StrLength(statement_data[j]);
1780 int kTerminationLen = i::StrLength(termination_data[k]);
1781 int kSuffixLen = i::StrLength(context_data[i][1]);
1782 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1783 + kSuffixLen + i::StrLength("label: for (;;) { }");
1784
1785 // Plug the source code pieces together.
1786 i::ScopedVector<char> program(kProgramSize + 1);
1787 int length = i::SNPrintF(program,
1788 "label: for (;;) { %s%s%s%s }",
1789 context_data[i][0],
1790 statement_data[j],
1791 termination_data[k],
1792 context_data[i][1]);
1793 CHECK(length == kProgramSize);
1794 TestParserSync(program.start(), NULL, 0);
1795 }
1796 }
1797 }
1798
1799 // Neither Harmony numeric literals nor our natives syntax have any
1800 // interaction with the flags above, so test these separately to reduce
1801 // the combinatorial explosion.
1802 TestParserSync("0o1234", NULL, 0);
1803 TestParserSync("0b1011", NULL, 0);
1804
1805 static const ParserFlag flags3[] = { kAllowNatives };
1806 TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
1807 }
1808
1809
TEST(StrictOctal)1810 TEST(StrictOctal) {
1811 // Test that syntax error caused by octal literal is reported correctly as
1812 // such (issue 2220).
1813 v8::V8::Initialize();
1814 v8::HandleScope scope(CcTest::isolate());
1815 v8::Context::Scope context_scope(
1816 v8::Context::New(CcTest::isolate()));
1817 v8::TryCatch try_catch(CcTest::isolate());
1818 const char* script =
1819 "\"use strict\"; \n"
1820 "a = function() { \n"
1821 " b = function() { \n"
1822 " 01; \n"
1823 " }; \n"
1824 "}; \n";
1825 v8_compile(v8_str(script));
1826 CHECK(try_catch.HasCaught());
1827 v8::String::Utf8Value exception(try_catch.Exception());
1828 CHECK_EQ(0,
1829 strcmp("SyntaxError: Octal literals are not allowed in strict mode.",
1830 *exception));
1831 }
1832
1833
RunParserSyncTest(const char * context_data[][2],const char * statement_data[],ParserSyncTestResult result,const ParserFlag * flags=NULL,int flags_len=0,const ParserFlag * always_true_flags=NULL,int always_true_len=0,const ParserFlag * always_false_flags=NULL,int always_false_len=0,bool is_module=false,bool test_preparser=true)1834 void RunParserSyncTest(const char* context_data[][2],
1835 const char* statement_data[],
1836 ParserSyncTestResult result,
1837 const ParserFlag* flags = NULL, int flags_len = 0,
1838 const ParserFlag* always_true_flags = NULL,
1839 int always_true_len = 0,
1840 const ParserFlag* always_false_flags = NULL,
1841 int always_false_len = 0, bool is_module = false,
1842 bool test_preparser = true) {
1843 v8::HandleScope handles(CcTest::isolate());
1844 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
1845 v8::Context::Scope context_scope(context);
1846
1847 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1848 i::GetCurrentStackPosition() - 128 * 1024);
1849
1850 // Experimental feature flags should not go here; pass the flags as
1851 // always_true_flags if the test needs them.
1852 static const ParserFlag default_flags[] = {
1853 kAllowLazy,
1854 kAllowNatives,
1855 };
1856 ParserFlag* generated_flags = NULL;
1857 if (flags == NULL) {
1858 flags = default_flags;
1859 flags_len = arraysize(default_flags);
1860 if (always_true_flags != NULL || always_false_flags != NULL) {
1861 // Remove always_true/false_flags from default_flags (if present).
1862 CHECK((always_true_flags != NULL) == (always_true_len > 0));
1863 CHECK((always_false_flags != NULL) == (always_false_len > 0));
1864 generated_flags = new ParserFlag[flags_len + always_true_len];
1865 int flag_index = 0;
1866 for (int i = 0; i < flags_len; ++i) {
1867 bool use_flag = true;
1868 for (int j = 0; use_flag && j < always_true_len; ++j) {
1869 if (flags[i] == always_true_flags[j]) use_flag = false;
1870 }
1871 for (int j = 0; use_flag && j < always_false_len; ++j) {
1872 if (flags[i] == always_false_flags[j]) use_flag = false;
1873 }
1874 if (use_flag) generated_flags[flag_index++] = flags[i];
1875 }
1876 flags_len = flag_index;
1877 flags = generated_flags;
1878 }
1879 }
1880 for (int i = 0; context_data[i][0] != NULL; ++i) {
1881 for (int j = 0; statement_data[j] != NULL; ++j) {
1882 int kPrefixLen = i::StrLength(context_data[i][0]);
1883 int kStatementLen = i::StrLength(statement_data[j]);
1884 int kSuffixLen = i::StrLength(context_data[i][1]);
1885 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
1886
1887 // Plug the source code pieces together.
1888 i::ScopedVector<char> program(kProgramSize + 1);
1889 int length = i::SNPrintF(program,
1890 "%s%s%s",
1891 context_data[i][0],
1892 statement_data[j],
1893 context_data[i][1]);
1894 CHECK(length == kProgramSize);
1895 TestParserSync(program.start(), flags, flags_len, result,
1896 always_true_flags, always_true_len, always_false_flags,
1897 always_false_len, is_module, test_preparser);
1898 }
1899 }
1900 delete[] generated_flags;
1901 }
1902
1903
RunModuleParserSyncTest(const char * context_data[][2],const char * statement_data[],ParserSyncTestResult result,const ParserFlag * flags=NULL,int flags_len=0,const ParserFlag * always_true_flags=NULL,int always_true_len=0,const ParserFlag * always_false_flags=NULL,int always_false_len=0,bool test_preparser=true)1904 void RunModuleParserSyncTest(const char* context_data[][2],
1905 const char* statement_data[],
1906 ParserSyncTestResult result,
1907 const ParserFlag* flags = NULL, int flags_len = 0,
1908 const ParserFlag* always_true_flags = NULL,
1909 int always_true_len = 0,
1910 const ParserFlag* always_false_flags = NULL,
1911 int always_false_len = 0,
1912 bool test_preparser = true) {
1913 RunParserSyncTest(context_data, statement_data, result, flags, flags_len,
1914 always_true_flags, always_true_len, always_false_flags,
1915 always_false_len, true, test_preparser);
1916 }
1917
1918
TEST(ErrorsEvalAndArguments)1919 TEST(ErrorsEvalAndArguments) {
1920 // Tests that both preparsing and parsing produce the right kind of errors for
1921 // using "eval" and "arguments" as identifiers. Without the strict mode, it's
1922 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it
1923 // isn't.
1924 const char* context_data[][2] = {
1925 {"\"use strict\";", ""},
1926 {"var eval; function test_func() {\"use strict\"; ", "}"},
1927 {NULL, NULL}};
1928
1929 const char* statement_data[] = {
1930 "var eval;",
1931 "var arguments",
1932 "var foo, eval;",
1933 "var foo, arguments;",
1934 "try { } catch (eval) { }",
1935 "try { } catch (arguments) { }",
1936 "function eval() { }",
1937 "function arguments() { }",
1938 "function foo(eval) { }",
1939 "function foo(arguments) { }",
1940 "function foo(bar, eval) { }",
1941 "function foo(bar, arguments) { }",
1942 "(eval) => { }",
1943 "(arguments) => { }",
1944 "(foo, eval) => { }",
1945 "(foo, arguments) => { }",
1946 "eval = 1;",
1947 "arguments = 1;",
1948 "var foo = eval = 1;",
1949 "var foo = arguments = 1;",
1950 "++eval;",
1951 "++arguments;",
1952 "eval++;",
1953 "arguments++;",
1954 NULL
1955 };
1956
1957 RunParserSyncTest(context_data, statement_data, kError);
1958 }
1959
1960
TEST(NoErrorsEvalAndArgumentsSloppy)1961 TEST(NoErrorsEvalAndArgumentsSloppy) {
1962 // Tests that both preparsing and parsing accept "eval" and "arguments" as
1963 // identifiers when needed.
1964 const char* context_data[][2] = {
1965 { "", "" },
1966 { "function test_func() {", "}"},
1967 { NULL, NULL }
1968 };
1969
1970 const char* statement_data[] = {
1971 "var eval;",
1972 "var arguments",
1973 "var foo, eval;",
1974 "var foo, arguments;",
1975 "try { } catch (eval) { }",
1976 "try { } catch (arguments) { }",
1977 "function eval() { }",
1978 "function arguments() { }",
1979 "function foo(eval) { }",
1980 "function foo(arguments) { }",
1981 "function foo(bar, eval) { }",
1982 "function foo(bar, arguments) { }",
1983 "eval = 1;",
1984 "arguments = 1;",
1985 "var foo = eval = 1;",
1986 "var foo = arguments = 1;",
1987 "++eval;",
1988 "++arguments;",
1989 "eval++;",
1990 "arguments++;",
1991 NULL
1992 };
1993
1994 RunParserSyncTest(context_data, statement_data, kSuccess);
1995 }
1996
1997
TEST(NoErrorsEvalAndArgumentsStrict)1998 TEST(NoErrorsEvalAndArgumentsStrict) {
1999 const char* context_data[][2] = {
2000 { "\"use strict\";", "" },
2001 { "function test_func() { \"use strict\";", "}" },
2002 { "() => { \"use strict\"; ", "}" },
2003 { NULL, NULL }
2004 };
2005
2006 const char* statement_data[] = {
2007 "eval;",
2008 "arguments;",
2009 "var foo = eval;",
2010 "var foo = arguments;",
2011 "var foo = { eval: 1 };",
2012 "var foo = { arguments: 1 };",
2013 "var foo = { }; foo.eval = {};",
2014 "var foo = { }; foo.arguments = {};",
2015 NULL
2016 };
2017
2018 RunParserSyncTest(context_data, statement_data, kSuccess);
2019 }
2020
2021 #define FUTURE_STRICT_RESERVED_WORDS_NO_LET(V) \
2022 V(implements) \
2023 V(interface) \
2024 V(package) \
2025 V(private) \
2026 V(protected) \
2027 V(public) \
2028 V(static) \
2029 V(yield)
2030
2031 #define FUTURE_STRICT_RESERVED_WORDS(V) \
2032 V(let) \
2033 FUTURE_STRICT_RESERVED_WORDS_NO_LET(V)
2034
2035 #define LIMITED_FUTURE_STRICT_RESERVED_WORDS_NO_LET(V) \
2036 V(implements) \
2037 V(static) \
2038 V(yield)
2039
2040 #define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
2041 V(let) \
2042 LIMITED_FUTURE_STRICT_RESERVED_WORDS_NO_LET(V)
2043
2044 #define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
2045 "var " #NAME ";", \
2046 "var foo, " #NAME ";", \
2047 "try { } catch (" #NAME ") { }", \
2048 "function " #NAME "() { }", \
2049 "(function " #NAME "() { })", \
2050 "function foo(" #NAME ") { }", \
2051 "function foo(bar, " #NAME ") { }", \
2052 #NAME " = 1;", \
2053 #NAME " += 1;", \
2054 "var foo = " #NAME " = 1;", \
2055 "++" #NAME ";", \
2056 #NAME " ++;",
2057
2058 // clang-format off
2059 #define FUTURE_STRICT_RESERVED_LEX_BINDINGS(NAME) \
2060 "let " #NAME ";", \
2061 "for (let " #NAME "; false; ) {}", \
2062 "for (let " #NAME " in {}) {}", \
2063 "for (let " #NAME " of []) {}", \
2064 "const " #NAME " = null;", \
2065 "for (const " #NAME " = null; false; ) {}", \
2066 "for (const " #NAME " in {}) {}", \
2067 "for (const " #NAME " of []) {}",
2068 // clang-format on
2069
TEST(ErrorsFutureStrictReservedWords)2070 TEST(ErrorsFutureStrictReservedWords) {
2071 // Tests that both preparsing and parsing produce the right kind of errors for
2072 // using future strict reserved words as identifiers. Without the strict mode,
2073 // it's ok to use future strict reserved words as identifiers. With the strict
2074 // mode, it isn't.
2075 const char* strict_contexts[][2] = {
2076 {"function test_func() {\"use strict\"; ", "}"},
2077 {"() => { \"use strict\"; ", "}"},
2078 {NULL, NULL}};
2079
2080 // clang-format off
2081 const char* statement_data[] {
2082 LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
2083 LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_LEX_BINDINGS)
2084 NULL
2085 };
2086 // clang-format on
2087
2088 RunParserSyncTest(strict_contexts, statement_data, kError);
2089
2090 // From ES2015, 13.3.1.1 Static Semantics: Early Errors:
2091 //
2092 // > LexicalDeclaration : LetOrConst BindingList ;
2093 // >
2094 // > - It is a Syntax Error if the BoundNames of BindingList contains "let".
2095 const char* non_strict_contexts[][2] = {{"", ""},
2096 {"function test_func() {", "}"},
2097 {"() => {", "}"},
2098 {NULL, NULL}};
2099 const char* invalid_statements[] = {FUTURE_STRICT_RESERVED_LEX_BINDINGS("let")
2100 NULL};
2101
2102 RunParserSyncTest(non_strict_contexts, invalid_statements, kError);
2103 }
2104
2105 #undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
2106
2107
TEST(NoErrorsFutureStrictReservedWords)2108 TEST(NoErrorsFutureStrictReservedWords) {
2109 const char* context_data[][2] = {
2110 { "", "" },
2111 { "function test_func() {", "}"},
2112 { "() => {", "}" },
2113 { NULL, NULL }
2114 };
2115
2116 // clang-format off
2117 const char* statement_data[] = {
2118 FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
2119 FUTURE_STRICT_RESERVED_WORDS_NO_LET(FUTURE_STRICT_RESERVED_LEX_BINDINGS)
2120 NULL
2121 };
2122 // clang-format on
2123
2124 RunParserSyncTest(context_data, statement_data, kSuccess);
2125 }
2126
2127
TEST(ErrorsReservedWords)2128 TEST(ErrorsReservedWords) {
2129 // Tests that both preparsing and parsing produce the right kind of errors for
2130 // using future reserved words as identifiers. These tests don't depend on the
2131 // strict mode.
2132 const char* context_data[][2] = {
2133 { "", "" },
2134 { "\"use strict\";", "" },
2135 { "var eval; function test_func() {", "}"},
2136 { "var eval; function test_func() {\"use strict\"; ", "}"},
2137 { "var eval; () => {", "}"},
2138 { "var eval; () => {\"use strict\"; ", "}"},
2139 { NULL, NULL }
2140 };
2141
2142 const char* statement_data[] = {
2143 "var super;",
2144 "var foo, super;",
2145 "try { } catch (super) { }",
2146 "function super() { }",
2147 "function foo(super) { }",
2148 "function foo(bar, super) { }",
2149 "(super) => { }",
2150 "(bar, super) => { }",
2151 "super = 1;",
2152 "var foo = super = 1;",
2153 "++super;",
2154 "super++;",
2155 "function foo super",
2156 NULL
2157 };
2158
2159 RunParserSyncTest(context_data, statement_data, kError);
2160 }
2161
2162
TEST(NoErrorsLetSloppyAllModes)2163 TEST(NoErrorsLetSloppyAllModes) {
2164 // In sloppy mode, it's okay to use "let" as identifier.
2165 const char* context_data[][2] = {
2166 { "", "" },
2167 { "function f() {", "}" },
2168 { "(function f() {", "})" },
2169 { NULL, NULL }
2170 };
2171
2172 const char* statement_data[] = {
2173 "var let;",
2174 "var foo, let;",
2175 "try { } catch (let) { }",
2176 "function let() { }",
2177 "(function let() { })",
2178 "function foo(let) { }",
2179 "function foo(bar, let) { }",
2180 "let = 1;",
2181 "var foo = let = 1;",
2182 "let * 2;",
2183 "++let;",
2184 "let++;",
2185 "let: 34",
2186 "function let(let) { let: let(let + let(0)); }",
2187 "({ let: 1 })",
2188 "({ get let() { 1 } })",
2189 "let(100)",
2190 NULL
2191 };
2192
2193 RunParserSyncTest(context_data, statement_data, kSuccess);
2194 }
2195
2196
TEST(NoErrorsYieldSloppyAllModes)2197 TEST(NoErrorsYieldSloppyAllModes) {
2198 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2199 // generator (see other test).
2200 const char* context_data[][2] = {
2201 { "", "" },
2202 { "function not_gen() {", "}" },
2203 { "(function not_gen() {", "})" },
2204 { NULL, NULL }
2205 };
2206
2207 const char* statement_data[] = {
2208 "var yield;",
2209 "var foo, yield;",
2210 "try { } catch (yield) { }",
2211 "function yield() { }",
2212 "(function yield() { })",
2213 "function foo(yield) { }",
2214 "function foo(bar, yield) { }",
2215 "yield = 1;",
2216 "var foo = yield = 1;",
2217 "yield * 2;",
2218 "++yield;",
2219 "yield++;",
2220 "yield: 34",
2221 "function yield(yield) { yield: yield (yield + yield(0)); }",
2222 "({ yield: 1 })",
2223 "({ get yield() { 1 } })",
2224 "yield(100)",
2225 "yield[100]",
2226 NULL
2227 };
2228
2229 RunParserSyncTest(context_data, statement_data, kSuccess);
2230 }
2231
2232
TEST(NoErrorsYieldSloppyGeneratorsEnabled)2233 TEST(NoErrorsYieldSloppyGeneratorsEnabled) {
2234 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2235 // generator (see next test).
2236 const char* context_data[][2] = {
2237 { "", "" },
2238 { "function not_gen() {", "}" },
2239 { "function * gen() { function not_gen() {", "} }" },
2240 { "(function not_gen() {", "})" },
2241 { "(function * gen() { (function not_gen() {", "}) })" },
2242 { NULL, NULL }
2243 };
2244
2245 const char* statement_data[] = {
2246 "var yield;",
2247 "var foo, yield;",
2248 "try { } catch (yield) { }",
2249 "function yield() { }",
2250 "(function yield() { })",
2251 "function foo(yield) { }",
2252 "function foo(bar, yield) { }",
2253 "function * yield() { }",
2254 "yield = 1;",
2255 "var foo = yield = 1;",
2256 "yield * 2;",
2257 "++yield;",
2258 "yield++;",
2259 "yield: 34",
2260 "function yield(yield) { yield: yield (yield + yield(0)); }",
2261 "({ yield: 1 })",
2262 "({ get yield() { 1 } })",
2263 "yield(100)",
2264 "yield[100]",
2265 NULL
2266 };
2267
2268 RunParserSyncTest(context_data, statement_data, kSuccess);
2269 }
2270
2271
TEST(ErrorsYieldStrict)2272 TEST(ErrorsYieldStrict) {
2273 const char* context_data[][2] = {
2274 {"\"use strict\";", ""},
2275 {"\"use strict\"; function not_gen() {", "}"},
2276 {"function test_func() {\"use strict\"; ", "}"},
2277 {"\"use strict\"; function * gen() { function not_gen() {", "} }"},
2278 {"\"use strict\"; (function not_gen() {", "})"},
2279 {"\"use strict\"; (function * gen() { (function not_gen() {", "}) })"},
2280 {"() => {\"use strict\"; ", "}"},
2281 {NULL, NULL}};
2282
2283 const char* statement_data[] = {
2284 "var yield;",
2285 "var foo, yield;",
2286 "try { } catch (yield) { }",
2287 "function yield() { }",
2288 "(function yield() { })",
2289 "function foo(yield) { }",
2290 "function foo(bar, yield) { }",
2291 "function * yield() { }",
2292 "(function * yield() { })",
2293 "yield = 1;",
2294 "var foo = yield = 1;",
2295 "++yield;",
2296 "yield++;",
2297 "yield: 34;",
2298 NULL
2299 };
2300
2301 RunParserSyncTest(context_data, statement_data, kError);
2302 }
2303
2304
TEST(ErrorsYieldSloppy)2305 TEST(ErrorsYieldSloppy) {
2306 const char* context_data[][2] = {
2307 { "", "" },
2308 { "function not_gen() {", "}" },
2309 { "(function not_gen() {", "})" },
2310 { NULL, NULL }
2311 };
2312
2313 const char* statement_data[] = {
2314 "(function * yield() { })",
2315 NULL
2316 };
2317
2318 RunParserSyncTest(context_data, statement_data, kError);
2319 }
2320
2321
TEST(NoErrorsGenerator)2322 TEST(NoErrorsGenerator) {
2323 // clang-format off
2324 const char* context_data[][2] = {
2325 { "function * gen() {", "}" },
2326 { "(function * gen() {", "})" },
2327 { "(function * () {", "})" },
2328 { NULL, NULL }
2329 };
2330
2331 const char* statement_data[] = {
2332 // A generator without a body is valid.
2333 ""
2334 // Valid yield expressions inside generators.
2335 "yield 2;",
2336 "yield * 2;",
2337 "yield * \n 2;",
2338 "yield yield 1;",
2339 "yield * yield * 1;",
2340 "yield 3 + (yield 4);",
2341 "yield * 3 + (yield * 4);",
2342 "(yield * 3) + (yield * 4);",
2343 "yield 3; yield 4;",
2344 "yield * 3; yield * 4;",
2345 "(function (yield) { })",
2346 "(function yield() { })",
2347 "yield { yield: 12 }",
2348 "yield /* comment */ { yield: 12 }",
2349 "yield * \n { yield: 12 }",
2350 "yield /* comment */ * \n { yield: 12 }",
2351 // You can return in a generator.
2352 "yield 1; return",
2353 "yield * 1; return",
2354 "yield 1; return 37",
2355 "yield * 1; return 37",
2356 "yield 1; return 37; yield 'dead';",
2357 "yield * 1; return 37; yield * 'dead';",
2358 // Yield is still a valid key in object literals.
2359 "({ yield: 1 })",
2360 "({ get yield() { } })",
2361 // And in assignment pattern computed properties
2362 "({ [yield]: x } = { })",
2363 // Yield without RHS.
2364 "yield;",
2365 "yield",
2366 "yield\n",
2367 "yield /* comment */"
2368 "yield // comment\n"
2369 "(yield)",
2370 "[yield]",
2371 "{yield}",
2372 "yield, yield",
2373 "yield; yield",
2374 "(yield) ? yield : yield",
2375 "(yield) \n ? yield : yield",
2376 // If there is a newline before the next token, we don't look for RHS.
2377 "yield\nfor (;;) {}",
2378 "x = class extends (yield) {}",
2379 "x = class extends f(yield) {}",
2380 "x = class extends (null, yield) { }",
2381 "x = class extends (a ? null : yield) { }",
2382 NULL
2383 };
2384 // clang-format on
2385
2386 RunParserSyncTest(context_data, statement_data, kSuccess);
2387 }
2388
2389
TEST(ErrorsYieldGenerator)2390 TEST(ErrorsYieldGenerator) {
2391 // clang-format off
2392 const char* context_data[][2] = {
2393 { "function * gen() {", "}" },
2394 { "\"use strict\"; function * gen() {", "}" },
2395 { NULL, NULL }
2396 };
2397
2398 const char* statement_data[] = {
2399 // Invalid yield expressions inside generators.
2400 "var yield;",
2401 "var foo, yield;",
2402 "try { } catch (yield) { }",
2403 "function yield() { }",
2404 // The name of the NFE is bound in the generator, which does not permit
2405 // yield to be an identifier.
2406 "(function * yield() { })",
2407 // Yield isn't valid as a formal parameter for generators.
2408 "function * foo(yield) { }",
2409 "(function * foo(yield) { })",
2410 "yield = 1;",
2411 "var foo = yield = 1;",
2412 "++yield;",
2413 "yield++;",
2414 "yield *",
2415 "(yield *)",
2416 // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which
2417 // is invalid.
2418 "yield 3 + yield 4;",
2419 "yield: 34",
2420 "yield ? 1 : 2",
2421 // Parses as yield (/ yield): invalid.
2422 "yield / yield",
2423 "+ yield",
2424 "+ yield 3",
2425 // Invalid (no newline allowed between yield and *).
2426 "yield\n*3",
2427 // Invalid (we see a newline, so we parse {yield:42} as a statement, not an
2428 // object literal, and yield is not a valid label).
2429 "yield\n{yield: 42}",
2430 "yield /* comment */\n {yield: 42}",
2431 "yield //comment\n {yield: 42}",
2432 // Destructuring binding and assignment are both disallowed
2433 "var [yield] = [42];",
2434 "var {foo: yield} = {a: 42};",
2435 "[yield] = [42];",
2436 "({a: yield} = {a: 42});",
2437 // Also disallow full yield expressions on LHS
2438 "var [yield 24] = [42];",
2439 "var {foo: yield 24} = {a: 42};",
2440 "[yield 24] = [42];",
2441 "({a: yield 24} = {a: 42});",
2442 "for (yield 'x' in {});",
2443 "for (yield 'x' of {});",
2444 "for (yield 'x' in {} in {});",
2445 "for (yield 'x' in {} of {});",
2446 "class C extends yield { }",
2447 NULL
2448 };
2449 // clang-format on
2450
2451 RunParserSyncTest(context_data, statement_data, kError);
2452 }
2453
2454
TEST(ErrorsNameOfStrictFunction)2455 TEST(ErrorsNameOfStrictFunction) {
2456 // Tests that illegal tokens as names of a strict function produce the correct
2457 // errors.
2458 const char* context_data[][2] = {
2459 { "function ", ""},
2460 { "\"use strict\"; function", ""},
2461 { "function * ", ""},
2462 { "\"use strict\"; function * ", ""},
2463 { NULL, NULL }
2464 };
2465
2466 const char* statement_data[] = {
2467 "eval() {\"use strict\";}",
2468 "arguments() {\"use strict\";}",
2469 "interface() {\"use strict\";}",
2470 "yield() {\"use strict\";}",
2471 // Future reserved words are always illegal
2472 "super() { }",
2473 "super() {\"use strict\";}",
2474 NULL
2475 };
2476
2477 RunParserSyncTest(context_data, statement_data, kError);
2478 }
2479
2480
TEST(NoErrorsNameOfStrictFunction)2481 TEST(NoErrorsNameOfStrictFunction) {
2482 const char* context_data[][2] = {
2483 { "function ", ""},
2484 { NULL, NULL }
2485 };
2486
2487 const char* statement_data[] = {
2488 "eval() { }",
2489 "arguments() { }",
2490 "interface() { }",
2491 "yield() { }",
2492 NULL
2493 };
2494
2495 RunParserSyncTest(context_data, statement_data, kSuccess);
2496 }
2497
2498
TEST(NoErrorsNameOfStrictGenerator)2499 TEST(NoErrorsNameOfStrictGenerator) {
2500 const char* context_data[][2] = {
2501 { "function * ", ""},
2502 { NULL, NULL }
2503 };
2504
2505 const char* statement_data[] = {
2506 "eval() { }",
2507 "arguments() { }",
2508 "interface() { }",
2509 "yield() { }",
2510 NULL
2511 };
2512
2513 RunParserSyncTest(context_data, statement_data, kSuccess);
2514 }
2515
2516
TEST(ErrorsIllegalWordsAsLabelsSloppy)2517 TEST(ErrorsIllegalWordsAsLabelsSloppy) {
2518 // Using future reserved words as labels is always an error.
2519 const char* context_data[][2] = {
2520 { "", ""},
2521 { "function test_func() {", "}" },
2522 { "() => {", "}" },
2523 { NULL, NULL }
2524 };
2525
2526 const char* statement_data[] = {
2527 "super: while(true) { break super; }",
2528 NULL
2529 };
2530
2531 RunParserSyncTest(context_data, statement_data, kError);
2532 }
2533
2534
TEST(ErrorsIllegalWordsAsLabelsStrict)2535 TEST(ErrorsIllegalWordsAsLabelsStrict) {
2536 // Tests that illegal tokens as labels produce the correct errors.
2537 const char* context_data[][2] = {
2538 {"\"use strict\";", ""},
2539 {"function test_func() {\"use strict\"; ", "}"},
2540 {"() => {\"use strict\"; ", "}"},
2541 {NULL, NULL}};
2542
2543 #define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
2544 const char* statement_data[] = {
2545 "super: while(true) { break super; }",
2546 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
2547 NULL
2548 };
2549 #undef LABELLED_WHILE
2550
2551 RunParserSyncTest(context_data, statement_data, kError);
2552 }
2553
2554
TEST(NoErrorsIllegalWordsAsLabels)2555 TEST(NoErrorsIllegalWordsAsLabels) {
2556 // Using eval and arguments as labels is legal even in strict mode.
2557 const char* context_data[][2] = {
2558 { "", ""},
2559 { "function test_func() {", "}" },
2560 { "() => {", "}" },
2561 { "\"use strict\";", "" },
2562 { "\"use strict\"; function test_func() {", "}" },
2563 { "\"use strict\"; () => {", "}" },
2564 { NULL, NULL }
2565 };
2566
2567 const char* statement_data[] = {
2568 "mylabel: while(true) { break mylabel; }",
2569 "eval: while(true) { break eval; }",
2570 "arguments: while(true) { break arguments; }",
2571 NULL
2572 };
2573
2574 RunParserSyncTest(context_data, statement_data, kSuccess);
2575 }
2576
2577
TEST(NoErrorsFutureStrictReservedAsLabelsSloppy)2578 TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
2579 const char* context_data[][2] = {
2580 { "", ""},
2581 { "function test_func() {", "}" },
2582 { "() => {", "}" },
2583 { NULL, NULL }
2584 };
2585
2586 #define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
2587 const char* statement_data[] {
2588 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
2589 NULL
2590 };
2591 #undef LABELLED_WHILE
2592
2593 RunParserSyncTest(context_data, statement_data, kSuccess);
2594 }
2595
2596
TEST(ErrorsParenthesizedLabels)2597 TEST(ErrorsParenthesizedLabels) {
2598 // Parenthesized identifiers shouldn't be recognized as labels.
2599 const char* context_data[][2] = {
2600 { "", ""},
2601 { "function test_func() {", "}" },
2602 { "() => {", "}" },
2603 { NULL, NULL }
2604 };
2605
2606 const char* statement_data[] = {
2607 "(mylabel): while(true) { break mylabel; }",
2608 NULL
2609 };
2610
2611 RunParserSyncTest(context_data, statement_data, kError);
2612 }
2613
2614
TEST(NoErrorsParenthesizedDirectivePrologue)2615 TEST(NoErrorsParenthesizedDirectivePrologue) {
2616 // Parenthesized directive prologue shouldn't be recognized.
2617 const char* context_data[][2] = {
2618 { "", ""},
2619 { NULL, NULL }
2620 };
2621
2622 const char* statement_data[] = {
2623 "(\"use strict\"); var eval;",
2624 NULL
2625 };
2626
2627 RunParserSyncTest(context_data, statement_data, kSuccess);
2628 }
2629
2630
TEST(ErrorsNotAnIdentifierName)2631 TEST(ErrorsNotAnIdentifierName) {
2632 const char* context_data[][2] = {
2633 { "", ""},
2634 { "\"use strict\";", ""},
2635 { NULL, NULL }
2636 };
2637
2638 const char* statement_data[] = {
2639 "var foo = {}; foo.{;",
2640 "var foo = {}; foo.};",
2641 "var foo = {}; foo.=;",
2642 "var foo = {}; foo.888;",
2643 "var foo = {}; foo.-;",
2644 "var foo = {}; foo.--;",
2645 NULL
2646 };
2647
2648 RunParserSyncTest(context_data, statement_data, kError);
2649 }
2650
2651
TEST(NoErrorsIdentifierNames)2652 TEST(NoErrorsIdentifierNames) {
2653 // Keywords etc. are valid as property names.
2654 const char* context_data[][2] = {
2655 { "", ""},
2656 { "\"use strict\";", ""},
2657 { NULL, NULL }
2658 };
2659
2660 const char* statement_data[] = {
2661 "var foo = {}; foo.if;",
2662 "var foo = {}; foo.yield;",
2663 "var foo = {}; foo.super;",
2664 "var foo = {}; foo.interface;",
2665 "var foo = {}; foo.eval;",
2666 "var foo = {}; foo.arguments;",
2667 NULL
2668 };
2669
2670 RunParserSyncTest(context_data, statement_data, kSuccess);
2671 }
2672
2673
TEST(DontRegressPreParserDataSizes)2674 TEST(DontRegressPreParserDataSizes) {
2675 // These tests make sure that Parser doesn't start producing less "preparse
2676 // data" (data which the embedder can cache).
2677 v8::V8::Initialize();
2678 v8::Isolate* isolate = CcTest::isolate();
2679 v8::HandleScope handles(isolate);
2680
2681 CcTest::i_isolate()->stack_guard()->SetStackLimit(
2682 i::GetCurrentStackPosition() - 128 * 1024);
2683
2684 struct TestCase {
2685 const char* program;
2686 int functions;
2687 } test_cases[] = {
2688 // No functions.
2689 {"var x = 42;", 0},
2690 // Functions.
2691 {"function foo() {}", 1},
2692 {"function foo() {} function bar() {}", 2},
2693 // Getter / setter functions are recorded as functions if they're on the top
2694 // level.
2695 {"var x = {get foo(){} };", 1},
2696 // Functions insize lazy functions are not recorded.
2697 {"function lazy() { function a() {} function b() {} function c() {} }", 1},
2698 {"function lazy() { var x = {get foo(){} } }", 1},
2699 {NULL, 0}
2700 };
2701
2702 for (int i = 0; test_cases[i].program; i++) {
2703 const char* program = test_cases[i].program;
2704 i::Factory* factory = CcTest::i_isolate()->factory();
2705 i::Handle<i::String> source =
2706 factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
2707 i::Handle<i::Script> script = factory->NewScript(source);
2708 i::Zone zone(CcTest::i_isolate()->allocator());
2709 i::ParseInfo info(&zone, script);
2710 i::ScriptData* sd = NULL;
2711 info.set_cached_data(&sd);
2712 info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
2713 info.set_allow_lazy_parsing();
2714 i::Parser::ParseStatic(&info);
2715 i::ParseData* pd = i::ParseData::FromCachedData(sd);
2716
2717 if (pd->FunctionCount() != test_cases[i].functions) {
2718 v8::base::OS::Print(
2719 "Expected preparse data for program:\n"
2720 "\t%s\n"
2721 "to contain %d functions, however, received %d functions.\n",
2722 program, test_cases[i].functions, pd->FunctionCount());
2723 CHECK(false);
2724 }
2725 delete sd;
2726 delete pd;
2727 }
2728 }
2729
2730
TEST(FunctionDeclaresItselfStrict)2731 TEST(FunctionDeclaresItselfStrict) {
2732 // Tests that we produce the right kinds of errors when a function declares
2733 // itself strict (we cannot produce there errors as soon as we see the
2734 // offending identifiers, because we don't know at that point whether the
2735 // function is strict or not).
2736 const char* context_data[][2] = {
2737 {"function eval() {", "}"},
2738 {"function arguments() {", "}"},
2739 {"function yield() {", "}"},
2740 {"function interface() {", "}"},
2741 {"function foo(eval) {", "}"},
2742 {"function foo(arguments) {", "}"},
2743 {"function foo(yield) {", "}"},
2744 {"function foo(interface) {", "}"},
2745 {"function foo(bar, eval) {", "}"},
2746 {"function foo(bar, arguments) {", "}"},
2747 {"function foo(bar, yield) {", "}"},
2748 {"function foo(bar, interface) {", "}"},
2749 {"function foo(bar, bar) {", "}"},
2750 { NULL, NULL }
2751 };
2752
2753 const char* strict_statement_data[] = {
2754 "\"use strict\";",
2755 NULL
2756 };
2757
2758 const char* non_strict_statement_data[] = {
2759 ";",
2760 NULL
2761 };
2762
2763 RunParserSyncTest(context_data, strict_statement_data, kError);
2764 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
2765 }
2766
2767
TEST(ErrorsTryWithoutCatchOrFinally)2768 TEST(ErrorsTryWithoutCatchOrFinally) {
2769 const char* context_data[][2] = {
2770 {"", ""},
2771 { NULL, NULL }
2772 };
2773
2774 const char* statement_data[] = {
2775 "try { }",
2776 "try { } foo();",
2777 "try { } catch (e) foo();",
2778 "try { } catch { }",
2779 "try { } finally foo();",
2780 NULL
2781 };
2782
2783 RunParserSyncTest(context_data, statement_data, kError);
2784 }
2785
2786
TEST(NoErrorsTryCatchFinally)2787 TEST(NoErrorsTryCatchFinally) {
2788 const char* context_data[][2] = {
2789 {"", ""},
2790 { NULL, NULL }
2791 };
2792
2793 const char* statement_data[] = {
2794 "try { } catch (e) { }",
2795 "try { } catch (e) { } finally { }",
2796 "try { } finally { }",
2797 NULL
2798 };
2799
2800 RunParserSyncTest(context_data, statement_data, kSuccess);
2801 }
2802
2803
TEST(ErrorsRegexpLiteral)2804 TEST(ErrorsRegexpLiteral) {
2805 const char* context_data[][2] = {
2806 {"var r = ", ""},
2807 { NULL, NULL }
2808 };
2809
2810 const char* statement_data[] = {
2811 "/unterminated",
2812 NULL
2813 };
2814
2815 RunParserSyncTest(context_data, statement_data, kError);
2816 }
2817
2818
TEST(NoErrorsRegexpLiteral)2819 TEST(NoErrorsRegexpLiteral) {
2820 const char* context_data[][2] = {
2821 {"var r = ", ""},
2822 { NULL, NULL }
2823 };
2824
2825 const char* statement_data[] = {
2826 "/foo/",
2827 "/foo/g",
2828 NULL
2829 };
2830
2831 RunParserSyncTest(context_data, statement_data, kSuccess);
2832 }
2833
2834
TEST(NoErrorsNewExpression)2835 TEST(NoErrorsNewExpression) {
2836 const char* context_data[][2] = {
2837 {"", ""},
2838 {"var f =", ""},
2839 { NULL, NULL }
2840 };
2841
2842 const char* statement_data[] = {
2843 "new foo",
2844 "new foo();",
2845 "new foo(1);",
2846 "new foo(1, 2);",
2847 // The first () will be processed as a part of the NewExpression and the
2848 // second () will be processed as part of LeftHandSideExpression.
2849 "new foo()();",
2850 // The first () will be processed as a part of the inner NewExpression and
2851 // the second () will be processed as a part of the outer NewExpression.
2852 "new new foo()();",
2853 "new foo.bar;",
2854 "new foo.bar();",
2855 "new foo.bar.baz;",
2856 "new foo.bar().baz;",
2857 "new foo[bar];",
2858 "new foo[bar]();",
2859 "new foo[bar][baz];",
2860 "new foo[bar]()[baz];",
2861 "new foo[bar].baz(baz)()[bar].baz;",
2862 "new \"foo\"", // Runtime error
2863 "new 1", // Runtime error
2864 // This even runs:
2865 "(new new Function(\"this.x = 1\")).x;",
2866 "new new Test_Two(String, 2).v(0123).length;",
2867 NULL
2868 };
2869
2870 RunParserSyncTest(context_data, statement_data, kSuccess);
2871 }
2872
2873
TEST(ErrorsNewExpression)2874 TEST(ErrorsNewExpression) {
2875 const char* context_data[][2] = {
2876 {"", ""},
2877 {"var f =", ""},
2878 { NULL, NULL }
2879 };
2880
2881 const char* statement_data[] = {
2882 "new foo bar",
2883 "new ) foo",
2884 "new ++foo",
2885 "new foo ++",
2886 NULL
2887 };
2888
2889 RunParserSyncTest(context_data, statement_data, kError);
2890 }
2891
2892
TEST(StrictObjectLiteralChecking)2893 TEST(StrictObjectLiteralChecking) {
2894 const char* context_data[][2] = {
2895 {"\"use strict\"; var myobject = {", "};"},
2896 {"\"use strict\"; var myobject = {", ",};"},
2897 {"var myobject = {", "};"},
2898 {"var myobject = {", ",};"},
2899 { NULL, NULL }
2900 };
2901
2902 // These are only errors in strict mode.
2903 const char* statement_data[] = {
2904 "foo: 1, foo: 2",
2905 "\"foo\": 1, \"foo\": 2",
2906 "foo: 1, \"foo\": 2",
2907 "1: 1, 1: 2",
2908 "1: 1, \"1\": 2",
2909 "get: 1, get: 2", // Not a getter for real, just a property called get.
2910 "set: 1, set: 2", // Not a setter for real, just a property called set.
2911 NULL
2912 };
2913
2914 RunParserSyncTest(context_data, statement_data, kSuccess);
2915 }
2916
2917
TEST(ErrorsObjectLiteralChecking)2918 TEST(ErrorsObjectLiteralChecking) {
2919 const char* context_data[][2] = {
2920 {"\"use strict\"; var myobject = {", "};"},
2921 {"var myobject = {", "};"},
2922 { NULL, NULL }
2923 };
2924
2925 const char* statement_data[] = {
2926 ",",
2927 // Wrong number of parameters
2928 "get bar(x) {}",
2929 "get bar(x, y) {}",
2930 "set bar() {}",
2931 "set bar(x, y) {}",
2932 // Parsing FunctionLiteral for getter or setter fails
2933 "get foo( +",
2934 "get foo() \"error\"",
2935 NULL
2936 };
2937
2938 RunParserSyncTest(context_data, statement_data, kError);
2939 }
2940
2941
TEST(NoErrorsObjectLiteralChecking)2942 TEST(NoErrorsObjectLiteralChecking) {
2943 const char* context_data[][2] = {
2944 {"var myobject = {", "};"},
2945 {"var myobject = {", ",};"},
2946 {"\"use strict\"; var myobject = {", "};"},
2947 {"\"use strict\"; var myobject = {", ",};"},
2948 { NULL, NULL }
2949 };
2950
2951 const char* statement_data[] = {
2952 "foo: 1, get foo() {}",
2953 "foo: 1, set foo(v) {}",
2954 "\"foo\": 1, get \"foo\"() {}",
2955 "\"foo\": 1, set \"foo\"(v) {}",
2956 "1: 1, get 1() {}",
2957 "1: 1, set 1(v) {}",
2958 "get foo() {}, get foo() {}",
2959 "set foo(_) {}, set foo(v) {}",
2960 "foo: 1, get \"foo\"() {}",
2961 "foo: 1, set \"foo\"(v) {}",
2962 "\"foo\": 1, get foo() {}",
2963 "\"foo\": 1, set foo(v) {}",
2964 "1: 1, get \"1\"() {}",
2965 "1: 1, set \"1\"(v) {}",
2966 "\"1\": 1, get 1() {}",
2967 "\"1\": 1, set 1(v) {}",
2968 "foo: 1, bar: 2",
2969 "\"foo\": 1, \"bar\": 2",
2970 "1: 1, 2: 2",
2971 // Syntax: IdentifierName ':' AssignmentExpression
2972 "foo: bar = 5 + baz",
2973 // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}'
2974 "get foo() {}",
2975 "get \"foo\"() {}",
2976 "get 1() {}",
2977 // Syntax: 'set' PropertyName '(' PropertySetParameterList ')'
2978 // '{' FunctionBody '}'
2979 "set foo(v) {}",
2980 "set \"foo\"(v) {}",
2981 "set 1(v) {}",
2982 // Non-colliding getters and setters -> no errors
2983 "foo: 1, get bar() {}",
2984 "foo: 1, set bar(v) {}",
2985 "\"foo\": 1, get \"bar\"() {}",
2986 "\"foo\": 1, set \"bar\"(v) {}",
2987 "1: 1, get 2() {}",
2988 "1: 1, set 2(v) {}",
2989 "get: 1, get foo() {}",
2990 "set: 1, set foo(_) {}",
2991 // Keywords, future reserved and strict future reserved are also allowed as
2992 // property names.
2993 "if: 4",
2994 "interface: 5",
2995 "super: 6",
2996 "eval: 7",
2997 "arguments: 8",
2998 NULL
2999 };
3000
3001 RunParserSyncTest(context_data, statement_data, kSuccess);
3002 }
3003
3004
TEST(TooManyArguments)3005 TEST(TooManyArguments) {
3006 const char* context_data[][2] = {
3007 {"foo(", "0)"},
3008 { NULL, NULL }
3009 };
3010
3011 using v8::internal::Code;
3012 char statement[Code::kMaxArguments * 2 + 1];
3013 for (int i = 0; i < Code::kMaxArguments; ++i) {
3014 statement[2 * i] = '0';
3015 statement[2 * i + 1] = ',';
3016 }
3017 statement[Code::kMaxArguments * 2] = 0;
3018
3019 const char* statement_data[] = {
3020 statement,
3021 NULL
3022 };
3023
3024 // The test is quite slow, so run it with a reduced set of flags.
3025 static const ParserFlag empty_flags[] = {kAllowLazy};
3026 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
3027 }
3028
3029
TEST(StrictDelete)3030 TEST(StrictDelete) {
3031 // "delete <Identifier>" is not allowed in strict mode.
3032 const char* strict_context_data[][2] = {
3033 {"\"use strict\"; ", ""},
3034 { NULL, NULL }
3035 };
3036
3037 const char* sloppy_context_data[][2] = {
3038 {"", ""},
3039 { NULL, NULL }
3040 };
3041
3042 // These are errors in the strict mode.
3043 const char* sloppy_statement_data[] = {
3044 "delete foo;",
3045 "delete foo + 1;",
3046 "delete (foo);",
3047 "delete eval;",
3048 "delete interface;",
3049 NULL
3050 };
3051
3052 // These are always OK
3053 const char* good_statement_data[] = {
3054 "delete this;",
3055 "delete 1;",
3056 "delete 1 + 2;",
3057 "delete foo();",
3058 "delete foo.bar;",
3059 "delete foo[bar];",
3060 "delete foo--;",
3061 "delete --foo;",
3062 "delete new foo();",
3063 "delete new foo(bar);",
3064 NULL
3065 };
3066
3067 // These are always errors
3068 const char* bad_statement_data[] = {
3069 "delete if;",
3070 NULL
3071 };
3072
3073 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
3074 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
3075
3076 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
3077 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
3078
3079 RunParserSyncTest(strict_context_data, bad_statement_data, kError);
3080 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
3081 }
3082
3083
TEST(NoErrorsDeclsInCase)3084 TEST(NoErrorsDeclsInCase) {
3085 const char* context_data[][2] = {
3086 {"'use strict'; switch(x) { case 1:", "}"},
3087 {"function foo() {'use strict'; switch(x) { case 1:", "}}"},
3088 {"'use strict'; switch(x) { case 1: case 2:", "}"},
3089 {"function foo() {'use strict'; switch(x) { case 1: case 2:", "}}"},
3090 {"'use strict'; switch(x) { default:", "}"},
3091 {"function foo() {'use strict'; switch(x) { default:", "}}"},
3092 {"'use strict'; switch(x) { case 1: default:", "}"},
3093 {"function foo() {'use strict'; switch(x) { case 1: default:", "}}"},
3094 { nullptr, nullptr }
3095 };
3096
3097 const char* statement_data[] = {
3098 "function f() { }",
3099 "class C { }",
3100 "class C extends Q {}",
3101 "function f() { } class C {}",
3102 "function f() { }; class C {}",
3103 "class C {}; function f() {}",
3104 nullptr
3105 };
3106
3107 RunParserSyncTest(context_data, statement_data, kSuccess);
3108 }
3109
3110
TEST(InvalidLeftHandSide)3111 TEST(InvalidLeftHandSide) {
3112 const char* assignment_context_data[][2] = {
3113 {"", " = 1;"},
3114 {"\"use strict\"; ", " = 1;"},
3115 { NULL, NULL }
3116 };
3117
3118 const char* prefix_context_data[][2] = {
3119 {"++", ";"},
3120 {"\"use strict\"; ++", ";"},
3121 {NULL, NULL},
3122 };
3123
3124 const char* postfix_context_data[][2] = {
3125 {"", "++;"},
3126 {"\"use strict\"; ", "++;"},
3127 { NULL, NULL }
3128 };
3129
3130 // Good left hand sides for assigment or prefix / postfix operations.
3131 const char* good_statement_data[] = {
3132 "foo",
3133 "foo.bar",
3134 "foo[bar]",
3135 "foo()[bar]",
3136 "foo().bar",
3137 "this.foo",
3138 "this[foo]",
3139 "new foo()[bar]",
3140 "new foo().bar",
3141 "foo()",
3142 "foo(bar)",
3143 "foo[bar]()",
3144 "foo.bar()",
3145 "this()",
3146 "this.foo()",
3147 "this[foo].bar()",
3148 "this.foo[foo].bar(this)(bar)[foo]()",
3149 NULL
3150 };
3151
3152 // Bad left hand sides for assigment or prefix / postfix operations.
3153 const char* bad_statement_data_common[] = {
3154 "2",
3155 "new foo",
3156 "new foo()",
3157 "null",
3158 "if", // Unexpected token
3159 "{x: 1}", // Unexpected token
3160 "this",
3161 "\"bar\"",
3162 "(foo + bar)",
3163 "new new foo()[bar]", // means: new (new foo()[bar])
3164 "new new foo().bar", // means: new (new foo()[bar])
3165 NULL
3166 };
3167
3168 // These are not okay for assignment, but okay for prefix / postix.
3169 const char* bad_statement_data_for_assignment[] = {
3170 "++foo",
3171 "foo++",
3172 "foo + bar",
3173 NULL
3174 };
3175
3176 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
3177 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
3178 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
3179 kError);
3180
3181 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
3182 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
3183
3184 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
3185 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);
3186 }
3187
3188
TEST(FuncNameInferrerBasic)3189 TEST(FuncNameInferrerBasic) {
3190 // Tests that function names are inferred properly.
3191 i::FLAG_allow_natives_syntax = true;
3192 v8::Isolate* isolate = CcTest::isolate();
3193 v8::HandleScope scope(isolate);
3194 LocalContext env;
3195 CompileRun("var foo1 = function() {}; "
3196 "var foo2 = function foo3() {}; "
3197 "function not_ctor() { "
3198 " var foo4 = function() {}; "
3199 " return %FunctionGetInferredName(foo4); "
3200 "} "
3201 "function Ctor() { "
3202 " var foo5 = function() {}; "
3203 " return %FunctionGetInferredName(foo5); "
3204 "} "
3205 "var obj1 = { foo6: function() {} }; "
3206 "var obj2 = { 'foo7': function() {} }; "
3207 "var obj3 = {}; "
3208 "obj3[1] = function() {}; "
3209 "var obj4 = {}; "
3210 "obj4[1] = function foo8() {}; "
3211 "var obj5 = {}; "
3212 "obj5['foo9'] = function() {}; "
3213 "var obj6 = { obj7 : { foo10: function() {} } };");
3214 ExpectString("%FunctionGetInferredName(foo1)", "foo1");
3215 // foo2 is not unnamed -> its name is not inferred.
3216 ExpectString("%FunctionGetInferredName(foo2)", "");
3217 ExpectString("not_ctor()", "foo4");
3218 ExpectString("Ctor()", "Ctor.foo5");
3219 ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6");
3220 ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7");
3221 ExpectString("%FunctionGetInferredName(obj3[1])",
3222 "obj3.(anonymous function)");
3223 ExpectString("%FunctionGetInferredName(obj4[1])", "");
3224 ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9");
3225 ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10");
3226 }
3227
3228
TEST(FuncNameInferrerTwoByte)3229 TEST(FuncNameInferrerTwoByte) {
3230 // Tests function name inferring in cases where some parts of the inferred
3231 // function name are two-byte strings.
3232 i::FLAG_allow_natives_syntax = true;
3233 v8::Isolate* isolate = CcTest::isolate();
3234 v8::HandleScope scope(isolate);
3235 LocalContext env;
3236 uint16_t* two_byte_source = AsciiToTwoByteString(
3237 "var obj1 = { oXj2 : { foo1: function() {} } }; "
3238 "%FunctionGetInferredName(obj1.oXj2.foo1)");
3239 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3240 // Make it really non-Latin1 (replace the Xs with a non-Latin1 character).
3241 two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d;
3242 v8::Local<v8::String> source =
3243 v8::String::NewFromTwoByte(isolate, two_byte_source,
3244 v8::NewStringType::kNormal)
3245 .ToLocalChecked();
3246 v8::Local<v8::Value> result = CompileRun(source);
3247 CHECK(result->IsString());
3248 v8::Local<v8::String> expected_name =
3249 v8::String::NewFromTwoByte(isolate, two_byte_name,
3250 v8::NewStringType::kNormal)
3251 .ToLocalChecked();
3252 CHECK(result->Equals(isolate->GetCurrentContext(), expected_name).FromJust());
3253 i::DeleteArray(two_byte_source);
3254 i::DeleteArray(two_byte_name);
3255 }
3256
3257
TEST(FuncNameInferrerEscaped)3258 TEST(FuncNameInferrerEscaped) {
3259 // The same as FuncNameInferrerTwoByte, except that we express the two-byte
3260 // character as a unicode escape.
3261 i::FLAG_allow_natives_syntax = true;
3262 v8::Isolate* isolate = CcTest::isolate();
3263 v8::HandleScope scope(isolate);
3264 LocalContext env;
3265 uint16_t* two_byte_source = AsciiToTwoByteString(
3266 "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; "
3267 "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)");
3268 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3269 // Fix to correspond to the non-ASCII name in two_byte_source.
3270 two_byte_name[6] = 0x010d;
3271 v8::Local<v8::String> source =
3272 v8::String::NewFromTwoByte(isolate, two_byte_source,
3273 v8::NewStringType::kNormal)
3274 .ToLocalChecked();
3275 v8::Local<v8::Value> result = CompileRun(source);
3276 CHECK(result->IsString());
3277 v8::Local<v8::String> expected_name =
3278 v8::String::NewFromTwoByte(isolate, two_byte_name,
3279 v8::NewStringType::kNormal)
3280 .ToLocalChecked();
3281 CHECK(result->Equals(isolate->GetCurrentContext(), expected_name).FromJust());
3282 i::DeleteArray(two_byte_source);
3283 i::DeleteArray(two_byte_name);
3284 }
3285
3286
TEST(RegressionLazyFunctionWithErrorWithArg)3287 TEST(RegressionLazyFunctionWithErrorWithArg) {
3288 // Test only applies when lazy parsing.
3289 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) return;
3290
3291 // The bug occurred when a lazy function had an error which requires a
3292 // parameter (such as "unknown label" here). The error message was processed
3293 // before the AstValueFactory containing the error message string was
3294 // internalized.
3295 v8::Isolate* isolate = CcTest::isolate();
3296 v8::HandleScope scope(isolate);
3297 LocalContext env;
3298 i::FLAG_lazy = true;
3299 i::FLAG_min_preparse_length = 0;
3300 CompileRun("function this_is_lazy() {\n"
3301 " break p;\n"
3302 "}\n"
3303 "this_is_lazy();\n");
3304 }
3305
3306
TEST(SerializationOfMaybeAssignmentFlag)3307 TEST(SerializationOfMaybeAssignmentFlag) {
3308 i::Isolate* isolate = CcTest::i_isolate();
3309 i::Factory* factory = isolate->factory();
3310 i::HandleScope scope(isolate);
3311 LocalContext env;
3312
3313 const char* src =
3314 "function h() {"
3315 " var result = [];"
3316 " function f() {"
3317 " result.push(2);"
3318 " }"
3319 " function assertResult(r) {"
3320 " f();"
3321 " result = [];"
3322 " }"
3323 " assertResult([2]);"
3324 " assertResult([2]);"
3325 " return f;"
3326 "};"
3327 "h();";
3328
3329 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3330 i::SNPrintF(program, "%s", src);
3331 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3332 source->PrintOn(stdout);
3333 printf("\n");
3334 i::Zone zone(CcTest::i_isolate()->allocator());
3335 v8::Local<v8::Value> v = CompileRun(src);
3336 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3337 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3338 i::Context* context = f->context();
3339 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3340 avf.Internalize(isolate);
3341 const i::AstRawString* name = avf.GetOneByteString("result");
3342 i::Handle<i::String> str = name->string();
3343 CHECK(str->IsInternalizedString());
3344 i::Scope* script_scope =
3345 new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
3346 script_scope->Initialize();
3347 i::Scope* s =
3348 i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
3349 CHECK(s != script_scope);
3350 CHECK(name != NULL);
3351
3352 // Get result from h's function context (that is f's context)
3353 i::Variable* var = s->Lookup(name);
3354
3355 CHECK(var != NULL);
3356 // Maybe assigned should survive deserialization
3357 CHECK(var->maybe_assigned() == i::kMaybeAssigned);
3358 // TODO(sigurds) Figure out if is_used should survive context serialization.
3359 }
3360
3361
TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned)3362 TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
3363 i::Isolate* isolate = CcTest::i_isolate();
3364 i::Factory* factory = isolate->factory();
3365 i::HandleScope scope(isolate);
3366 LocalContext env;
3367
3368
3369 const char* src =
3370 "function f(x) {"
3371 " var a = arguments;"
3372 " function g(i) {"
3373 " ++a[0];"
3374 " };"
3375 " return g;"
3376 " }"
3377 "f(0);";
3378
3379 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3380 i::SNPrintF(program, "%s", src);
3381 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3382 source->PrintOn(stdout);
3383 printf("\n");
3384 i::Zone zone(CcTest::i_isolate()->allocator());
3385 v8::Local<v8::Value> v = CompileRun(src);
3386 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3387 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3388 i::Context* context = f->context();
3389 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3390 avf.Internalize(isolate);
3391
3392 i::Scope* script_scope =
3393 new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
3394 script_scope->Initialize();
3395 i::Scope* s =
3396 i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
3397 CHECK(s != script_scope);
3398 const i::AstRawString* name_x = avf.GetOneByteString("x");
3399
3400 // Get result from f's function context (that is g's outer context)
3401 i::Variable* var_x = s->Lookup(name_x);
3402 CHECK(var_x != NULL);
3403 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
3404 }
3405
3406
TEST(InnerAssignment)3407 TEST(InnerAssignment) {
3408 i::Isolate* isolate = CcTest::i_isolate();
3409 i::Factory* factory = isolate->factory();
3410 i::HandleScope scope(isolate);
3411 LocalContext env;
3412
3413 const char* prefix = "function f() {";
3414 const char* midfix = " function g() {";
3415 const char* suffix = "}}";
3416 struct { const char* source; bool assigned; bool strict; } outers[] = {
3417 // Actual assignments.
3418 { "var x; var x = 5;", true, false },
3419 { "var x; { var x = 5; }", true, false },
3420 { "'use strict'; let x; x = 6;", true, true },
3421 { "var x = 5; function x() {}", true, false },
3422 // Actual non-assignments.
3423 { "var x;", false, false },
3424 { "var x = 5;", false, false },
3425 { "'use strict'; let x;", false, true },
3426 { "'use strict'; let x = 6;", false, true },
3427 { "'use strict'; var x = 0; { let x = 6; }", false, true },
3428 { "'use strict'; var x = 0; { let x; x = 6; }", false, true },
3429 { "'use strict'; let x = 0; { let x = 6; }", false, true },
3430 { "'use strict'; let x = 0; { let x; x = 6; }", false, true },
3431 { "var x; try {} catch (x) { x = 5; }", false, false },
3432 { "function x() {}", false, false },
3433 // Eval approximation.
3434 { "var x; eval('');", true, false },
3435 { "eval(''); var x;", true, false },
3436 { "'use strict'; let x; eval('');", true, true },
3437 { "'use strict'; eval(''); let x;", true, true },
3438 // Non-assignments not recognized, because the analysis is approximative.
3439 { "var x; var x;", true, false },
3440 { "var x = 5; var x;", true, false },
3441 { "var x; { var x; }", true, false },
3442 { "var x; function x() {}", true, false },
3443 { "function x() {}; var x;", true, false },
3444 { "var x; try {} catch (x) { var x = 5; }", true, false },
3445 };
3446 struct { const char* source; bool assigned; bool with; } inners[] = {
3447 // Actual assignments.
3448 { "x = 1;", true, false },
3449 { "x++;", true, false },
3450 { "++x;", true, false },
3451 { "x--;", true, false },
3452 { "--x;", true, false },
3453 { "{ x = 1; }", true, false },
3454 { "'use strict'; { let x; }; x = 0;", true, false },
3455 { "'use strict'; { const x = 1; }; x = 0;", true, false },
3456 { "'use strict'; { function x() {} }; x = 0;", true, false },
3457 { "with ({}) { x = 1; }", true, true },
3458 { "eval('');", true, false },
3459 { "'use strict'; { let y; eval('') }", true, false },
3460 { "function h() { x = 0; }", true, false },
3461 { "(function() { x = 0; })", true, false },
3462 { "(function() { x = 0; })", true, false },
3463 { "with ({}) (function() { x = 0; })", true, true },
3464 // Actual non-assignments.
3465 { "", false, false },
3466 { "x;", false, false },
3467 { "var x;", false, false },
3468 { "var x = 8;", false, false },
3469 { "var x; x = 8;", false, false },
3470 { "'use strict'; let x;", false, false },
3471 { "'use strict'; let x = 8;", false, false },
3472 { "'use strict'; let x; x = 8;", false, false },
3473 { "'use strict'; const x = 8;", false, false },
3474 { "function x() {}", false, false },
3475 { "function x() { x = 0; }", false, false },
3476 { "function h(x) { x = 0; }", false, false },
3477 { "'use strict'; { let x; x = 0; }", false, false },
3478 { "{ var x; }; x = 0;", false, false },
3479 { "with ({}) {}", false, true },
3480 { "var x; { with ({}) { x = 1; } }", false, true },
3481 { "try {} catch(x) { x = 0; }", false, false },
3482 { "try {} catch(x) { with ({}) { x = 1; } }", false, true },
3483 // Eval approximation.
3484 { "eval('');", true, false },
3485 { "function h() { eval(''); }", true, false },
3486 { "(function() { eval(''); })", true, false },
3487 // Shadowing not recognized because of eval approximation.
3488 { "var x; eval('');", true, false },
3489 { "'use strict'; let x; eval('');", true, false },
3490 { "try {} catch(x) { eval(''); }", true, false },
3491 { "function x() { eval(''); }", true, false },
3492 { "(function(x) { eval(''); })", true, false },
3493 };
3494
3495 // Used to trigger lazy compilation of function
3496 int comment_len = 2048;
3497 i::ScopedVector<char> comment(comment_len + 1);
3498 i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0);
3499 int prefix_len = Utf8LengthHelper(prefix);
3500 int midfix_len = Utf8LengthHelper(midfix);
3501 int suffix_len = Utf8LengthHelper(suffix);
3502 for (unsigned i = 0; i < arraysize(outers); ++i) {
3503 const char* outer = outers[i].source;
3504 int outer_len = Utf8LengthHelper(outer);
3505 for (unsigned j = 0; j < arraysize(inners); ++j) {
3506 for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) {
3507 for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) {
3508 if (outers[i].strict && inners[j].with) continue;
3509 const char* inner = inners[j].source;
3510 int inner_len = Utf8LengthHelper(inner);
3511
3512 int outer_comment_len = outer_lazy ? comment_len : 0;
3513 int inner_comment_len = inner_lazy ? comment_len : 0;
3514 const char* outer_comment = outer_lazy ? comment.start() : "";
3515 const char* inner_comment = inner_lazy ? comment.start() : "";
3516 int len = prefix_len + outer_comment_len + outer_len + midfix_len +
3517 inner_comment_len + inner_len + suffix_len;
3518 i::ScopedVector<char> program(len + 1);
3519
3520 i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer,
3521 midfix, inner_comment, inner, suffix);
3522 i::Handle<i::String> source =
3523 factory->InternalizeUtf8String(program.start());
3524 source->PrintOn(stdout);
3525 printf("\n");
3526
3527 i::Handle<i::Script> script = factory->NewScript(source);
3528 i::Zone zone(CcTest::i_isolate()->allocator());
3529 i::ParseInfo info(&zone, script);
3530 i::Parser parser(&info);
3531 CHECK(parser.Parse(&info));
3532 CHECK(i::Compiler::Analyze(&info));
3533 CHECK(info.literal() != NULL);
3534
3535 i::Scope* scope = info.literal()->scope();
3536 CHECK_EQ(scope->inner_scopes()->length(), 1);
3537 i::Scope* inner_scope = scope->inner_scopes()->at(0);
3538 const i::AstRawString* var_name =
3539 info.ast_value_factory()->GetOneByteString("x");
3540 i::Variable* var = inner_scope->Lookup(var_name);
3541 bool expected = outers[i].assigned || inners[j].assigned;
3542 CHECK(var != NULL);
3543 CHECK(var->is_used() || !expected);
3544 CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected);
3545 }
3546 }
3547 }
3548 }
3549 }
3550
3551 namespace {
3552
3553 int* global_use_counts = NULL;
3554
MockUseCounterCallback(v8::Isolate * isolate,v8::Isolate::UseCounterFeature feature)3555 void MockUseCounterCallback(v8::Isolate* isolate,
3556 v8::Isolate::UseCounterFeature feature) {
3557 ++global_use_counts[feature];
3558 }
3559
3560 }
3561
3562
TEST(UseAsmUseCount)3563 TEST(UseAsmUseCount) {
3564 i::Isolate* isolate = CcTest::i_isolate();
3565 i::HandleScope scope(isolate);
3566 LocalContext env;
3567 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3568 global_use_counts = use_counts;
3569 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3570 CompileRun("\"use asm\";\n"
3571 "var foo = 1;\n"
3572 "function bar() { \"use asm\"; var baz = 1; }");
3573 CHECK_LT(0, use_counts[v8::Isolate::kUseAsm]);
3574 }
3575
3576
TEST(StrictModeUseCount)3577 TEST(StrictModeUseCount) {
3578 i::Isolate* isolate = CcTest::i_isolate();
3579 i::HandleScope scope(isolate);
3580 LocalContext env;
3581 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3582 global_use_counts = use_counts;
3583 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3584 CompileRun(
3585 "\"use strict\";\n"
3586 "function bar() { var baz = 1; }"); // strict mode inherits
3587 CHECK_LT(0, use_counts[v8::Isolate::kStrictMode]);
3588 CHECK_EQ(0, use_counts[v8::Isolate::kSloppyMode]);
3589 }
3590
3591
TEST(SloppyModeUseCount)3592 TEST(SloppyModeUseCount) {
3593 i::Isolate* isolate = CcTest::i_isolate();
3594 i::HandleScope scope(isolate);
3595 LocalContext env;
3596 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3597 global_use_counts = use_counts;
3598 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3599 CompileRun("function bar() { var baz = 1; }");
3600 CHECK_LT(0, use_counts[v8::Isolate::kSloppyMode]);
3601 CHECK_EQ(0, use_counts[v8::Isolate::kStrictMode]);
3602 }
3603
3604
TEST(BothModesUseCount)3605 TEST(BothModesUseCount) {
3606 i::Isolate* isolate = CcTest::i_isolate();
3607 i::HandleScope scope(isolate);
3608 LocalContext env;
3609 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3610 global_use_counts = use_counts;
3611 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3612 CompileRun("function bar() { 'use strict'; var baz = 1; }");
3613 CHECK_LT(0, use_counts[v8::Isolate::kSloppyMode]);
3614 CHECK_LT(0, use_counts[v8::Isolate::kStrictMode]);
3615 }
3616
3617
TEST(ErrorsArrowFormalParameters)3618 TEST(ErrorsArrowFormalParameters) {
3619 const char* context_data[][2] = {
3620 { "()", "=>{}" },
3621 { "()", "=>{};" },
3622 { "var x = ()", "=>{}" },
3623 { "var x = ()", "=>{};" },
3624
3625 { "a", "=>{}" },
3626 { "a", "=>{};" },
3627 { "var x = a", "=>{}" },
3628 { "var x = a", "=>{};" },
3629
3630 { "(a)", "=>{}" },
3631 { "(a)", "=>{};" },
3632 { "var x = (a)", "=>{}" },
3633 { "var x = (a)", "=>{};" },
3634
3635 { "(...a)", "=>{}" },
3636 { "(...a)", "=>{};" },
3637 { "var x = (...a)", "=>{}" },
3638 { "var x = (...a)", "=>{};" },
3639
3640 { "(a,b)", "=>{}" },
3641 { "(a,b)", "=>{};" },
3642 { "var x = (a,b)", "=>{}" },
3643 { "var x = (a,b)", "=>{};" },
3644
3645 { "(a,...b)", "=>{}" },
3646 { "(a,...b)", "=>{};" },
3647 { "var x = (a,...b)", "=>{}" },
3648 { "var x = (a,...b)", "=>{};" },
3649
3650 { nullptr, nullptr }
3651 };
3652 const char* assignment_expression_suffix_data[] = {
3653 "?c:d=>{}",
3654 "=c=>{}",
3655 "()",
3656 "(c)",
3657 "[1]",
3658 "[c]",
3659 ".c",
3660 "-c",
3661 "+c",
3662 "c++",
3663 "`c`",
3664 "`${c}`",
3665 "`template-head${c}`",
3666 "`${c}template-tail`",
3667 "`template-head${c}template-tail`",
3668 "`${c}template-tail`",
3669 nullptr
3670 };
3671
3672 RunParserSyncTest(context_data, assignment_expression_suffix_data, kError);
3673 }
3674
3675
TEST(ErrorsArrowFunctions)3676 TEST(ErrorsArrowFunctions) {
3677 // Tests that parser and preparser generate the same kind of errors
3678 // on invalid arrow function syntax.
3679
3680 // clang-format off
3681 const char* context_data[][2] = {
3682 {"", ";"},
3683 {"v = ", ";"},
3684 {"bar ? (", ") : baz;"},
3685 {"bar ? baz : (", ");"},
3686 {"bar[", "];"},
3687 {"bar, ", ";"},
3688 {"", ", bar;"},
3689 {NULL, NULL}
3690 };
3691
3692 const char* statement_data[] = {
3693 "=> 0",
3694 "=>",
3695 "() =>",
3696 "=> {}",
3697 ") => {}",
3698 ", => {}",
3699 "(,) => {}",
3700 "return => {}",
3701 "() => {'value': 42}",
3702
3703 // Check that the early return introduced in ParsePrimaryExpression
3704 // does not accept stray closing parentheses.
3705 ")",
3706 ") => 0",
3707 "foo[()]",
3708 "()",
3709
3710 // Parameter lists with extra parens should be recognized as errors.
3711 "(()) => 0",
3712 "((x)) => 0",
3713 "((x, y)) => 0",
3714 "(x, (y)) => 0",
3715 "((x, y, z)) => 0",
3716 "(x, (y, z)) => 0",
3717 "((x, y), z) => 0",
3718
3719 // Arrow function formal parameters are parsed as StrictFormalParameters,
3720 // which confusingly only implies that there are no duplicates. Words
3721 // reserved in strict mode, and eval or arguments, are indeed valid in
3722 // sloppy mode.
3723 "eval => { 'use strict'; 0 }",
3724 "arguments => { 'use strict'; 0 }",
3725 "yield => { 'use strict'; 0 }",
3726 "interface => { 'use strict'; 0 }",
3727 "(eval) => { 'use strict'; 0 }",
3728 "(arguments) => { 'use strict'; 0 }",
3729 "(yield) => { 'use strict'; 0 }",
3730 "(interface) => { 'use strict'; 0 }",
3731 "(eval, bar) => { 'use strict'; 0 }",
3732 "(bar, eval) => { 'use strict'; 0 }",
3733 "(bar, arguments) => { 'use strict'; 0 }",
3734 "(bar, yield) => { 'use strict'; 0 }",
3735 "(bar, interface) => { 'use strict'; 0 }",
3736 // TODO(aperez): Detecting duplicates does not work in PreParser.
3737 // "(bar, bar) => {}",
3738
3739 // The parameter list is parsed as an expression, but only
3740 // a comma-separated list of identifier is valid.
3741 "32 => {}",
3742 "(32) => {}",
3743 "(a, 32) => {}",
3744 "if => {}",
3745 "(if) => {}",
3746 "(a, if) => {}",
3747 "a + b => {}",
3748 "(a + b) => {}",
3749 "(a + b, c) => {}",
3750 "(a, b - c) => {}",
3751 "\"a\" => {}",
3752 "(\"a\") => {}",
3753 "(\"a\", b) => {}",
3754 "(a, \"b\") => {}",
3755 "-a => {}",
3756 "(-a) => {}",
3757 "(-a, b) => {}",
3758 "(a, -b) => {}",
3759 "{} => {}",
3760 "a++ => {}",
3761 "(a++) => {}",
3762 "(a++, b) => {}",
3763 "(a, b++) => {}",
3764 "[] => {}",
3765 "(foo ? bar : baz) => {}",
3766 "(a, foo ? bar : baz) => {}",
3767 "(foo ? bar : baz, a) => {}",
3768 "(a.b, c) => {}",
3769 "(c, a.b) => {}",
3770 "(a['b'], c) => {}",
3771 "(c, a['b']) => {}",
3772
3773 // crbug.com/582626
3774 "(...rest - a) => b",
3775 "(a, ...b - 10) => b",
3776
3777 NULL
3778 };
3779 // clang-format on
3780
3781 // The test is quite slow, so run it with a reduced set of flags.
3782 static const ParserFlag flags[] = {kAllowLazy};
3783 RunParserSyncTest(context_data, statement_data, kError, flags,
3784 arraysize(flags));
3785
3786 // In a context where a concise arrow body is parsed with [~In] variant,
3787 // ensure that an error is reported in both full parser and preparser.
3788 const char* loop_context_data[][2] = {{"for (", "; 0;);"},
3789 {nullptr, nullptr}};
3790 const char* loop_expr_data[] = {"f => 'key' in {}", nullptr};
3791 RunParserSyncTest(loop_context_data, loop_expr_data, kError, flags,
3792 arraysize(flags));
3793 }
3794
3795
TEST(NoErrorsArrowFunctions)3796 TEST(NoErrorsArrowFunctions) {
3797 // Tests that parser and preparser accept valid arrow functions syntax.
3798 // clang-format off
3799 const char* context_data[][2] = {
3800 {"", ";"},
3801 {"bar ? (", ") : baz;"},
3802 {"bar ? baz : (", ");"},
3803 {"bar, ", ";"},
3804 {"", ", bar;"},
3805 {NULL, NULL}
3806 };
3807
3808 const char* statement_data[] = {
3809 "() => {}",
3810 "() => { return 42 }",
3811 "x => { return x; }",
3812 "(x) => { return x; }",
3813 "(x, y) => { return x + y; }",
3814 "(x, y, z) => { return x + y + z; }",
3815 "(x, y) => { x.a = y; }",
3816 "() => 42",
3817 "x => x",
3818 "x => x * x",
3819 "(x) => x",
3820 "(x) => x * x",
3821 "(x, y) => x + y",
3822 "(x, y, z) => x, y, z",
3823 "(x, y) => x.a = y",
3824 "() => ({'value': 42})",
3825 "x => y => x + y",
3826 "(x, y) => (u, v) => x*u + y*v",
3827 "(x, y) => z => z * (x + y)",
3828 "x => (y, z) => z * (x + y)",
3829
3830 // Those are comma-separated expressions, with arrow functions as items.
3831 // They stress the code for validating arrow function parameter lists.
3832 "a, b => 0",
3833 "a, b, (c, d) => 0",
3834 "(a, b, (c, d) => 0)",
3835 "(a, b) => 0, (c, d) => 1",
3836 "(a, b => {}, a => a + 1)",
3837 "((a, b) => {}, (a => a + 1))",
3838 "(a, (a, (b, c) => 0))",
3839
3840 // Arrow has more precedence, this is the same as: foo ? bar : (baz = {})
3841 "foo ? bar : baz => {}",
3842
3843 // Arrows with non-simple parameters.
3844 "({}) => {}",
3845 "(a, {}) => {}",
3846 "({}, a) => {}",
3847 "([]) => {}",
3848 "(a, []) => {}",
3849 "([], a) => {}",
3850 "(a = b) => {}",
3851 "(a = b, c) => {}",
3852 "(a, b = c) => {}",
3853 "({a}) => {}",
3854 "(x = 9) => {}",
3855 "(x, y = 9) => {}",
3856 "(x = 9, y) => {}",
3857 "(x, y = 9, z) => {}",
3858 "(x, y = 9, z = 8) => {}",
3859 "(...a) => {}",
3860 "(x, ...a) => {}",
3861 "(x = 9, ...a) => {}",
3862 "(x, y = 9, ...a) => {}",
3863 "(x, y = 9, {b}, z = 8, ...a) => {}",
3864 "({a} = {}) => {}",
3865 "([x] = []) => {}",
3866 "({a = 42}) => {}",
3867 "([x = 0]) => {}",
3868 NULL
3869 };
3870 // clang-format on
3871
3872 RunParserSyncTest(context_data, statement_data, kSuccess);
3873
3874 static const ParserFlag flags[] = {kAllowLazy};
3875 // In a context where a concise arrow body is parsed with [~In] variant,
3876 // ensure that nested expressions can still use the 'in' operator,
3877 const char* loop_context_data[][2] = {{"for (", "; 0;);"},
3878 {nullptr, nullptr}};
3879 const char* loop_expr_data[] = {"f => ('key' in {})", nullptr};
3880 RunParserSyncTest(loop_context_data, loop_expr_data, kSuccess, flags,
3881 arraysize(flags));
3882 }
3883
3884
TEST(ArrowFunctionsSloppyParameterNames)3885 TEST(ArrowFunctionsSloppyParameterNames) {
3886 const char* strict_context_data[][2] = {
3887 {"'use strict'; ", ";"},
3888 {"'use strict'; bar ? (", ") : baz;"},
3889 {"'use strict'; bar ? baz : (", ");"},
3890 {"'use strict'; bar, ", ";"},
3891 {"'use strict'; ", ", bar;"},
3892 {NULL, NULL}
3893 };
3894
3895 const char* sloppy_context_data[][2] = {
3896 {"", ";"},
3897 {"bar ? (", ") : baz;"},
3898 {"bar ? baz : (", ");"},
3899 {"bar, ", ";"},
3900 {"", ", bar;"},
3901 {NULL, NULL}
3902 };
3903
3904 const char* statement_data[] = {
3905 "eval => {}",
3906 "arguments => {}",
3907 "yield => {}",
3908 "interface => {}",
3909 "(eval) => {}",
3910 "(arguments) => {}",
3911 "(yield) => {}",
3912 "(interface) => {}",
3913 "(eval, bar) => {}",
3914 "(bar, eval) => {}",
3915 "(bar, arguments) => {}",
3916 "(bar, yield) => {}",
3917 "(bar, interface) => {}",
3918 "(interface, eval) => {}",
3919 "(interface, arguments) => {}",
3920 "(eval, interface) => {}",
3921 "(arguments, interface) => {}",
3922 NULL
3923 };
3924
3925 RunParserSyncTest(strict_context_data, statement_data, kError);
3926 RunParserSyncTest(sloppy_context_data, statement_data, kSuccess);
3927 }
3928
3929
TEST(ArrowFunctionsYieldParameterNameInGenerator)3930 TEST(ArrowFunctionsYieldParameterNameInGenerator) {
3931 const char* sloppy_function_context_data[][2] = {
3932 {"(function f() { (", "); });"},
3933 {NULL, NULL}
3934 };
3935
3936 const char* strict_function_context_data[][2] = {
3937 {"(function f() {'use strict'; (", "); });"},
3938 {NULL, NULL}
3939 };
3940
3941 const char* generator_context_data[][2] = {
3942 {"(function *g() {'use strict'; (", "); });"},
3943 {"(function *g() { (", "); });"},
3944 {NULL, NULL}
3945 };
3946
3947 const char* arrow_data[] = {
3948 "yield => {}",
3949 "(yield) => {}",
3950 "(a, yield) => {}",
3951 "(yield, a) => {}",
3952 "(yield, ...a) => {}",
3953 "(a, ...yield) => {}",
3954 "({yield}) => {}",
3955 "([yield]) => {}",
3956 NULL
3957 };
3958
3959 RunParserSyncTest(sloppy_function_context_data, arrow_data, kSuccess);
3960 RunParserSyncTest(strict_function_context_data, arrow_data, kError);
3961 RunParserSyncTest(generator_context_data, arrow_data, kError);
3962 }
3963
3964
TEST(SuperNoErrors)3965 TEST(SuperNoErrors) {
3966 // Tests that parser and preparser accept 'super' keyword in right places.
3967 const char* context_data[][2] = {
3968 {"class C { m() { ", "; } }"},
3969 {"class C { m() { k = ", "; } }"},
3970 {"class C { m() { foo(", "); } }"},
3971 {"class C { m() { () => ", "; } }"},
3972 {NULL, NULL}
3973 };
3974
3975 const char* statement_data[] = {
3976 "super.x",
3977 "super[27]",
3978 "new super.x",
3979 "new super.x()",
3980 "new super[27]",
3981 "new super[27]()",
3982 "z.super", // Ok, property lookup.
3983 NULL
3984 };
3985
3986 RunParserSyncTest(context_data, statement_data, kSuccess);
3987 }
3988
3989
TEST(SuperErrors)3990 TEST(SuperErrors) {
3991 const char* context_data[][2] = {
3992 {"class C { m() { ", "; } }"},
3993 {"class C { m() { k = ", "; } }"},
3994 {"class C { m() { foo(", "); } }"},
3995 {"class C { m() { () => ", "; } }"},
3996 {NULL, NULL}
3997 };
3998
3999 const char* expression_data[] = {
4000 "super",
4001 "super = x",
4002 "y = super",
4003 "f(super)",
4004 "new super",
4005 "new super()",
4006 "new super(12, 45)",
4007 "new new super",
4008 "new new super()",
4009 "new new super()()",
4010 NULL
4011 };
4012
4013 RunParserSyncTest(context_data, expression_data, kError);
4014 }
4015
4016
TEST(SuperCall)4017 TEST(SuperCall) {
4018 const char* context_data[][2] = {{"", ""},
4019 {NULL, NULL}};
4020
4021 const char* success_data[] = {
4022 "class C extends B { constructor() { super(); } }",
4023 "class C extends B { constructor() { () => super(); } }",
4024 NULL
4025 };
4026
4027 RunParserSyncTest(context_data, success_data, kSuccess);
4028
4029 const char* error_data[] = {
4030 "class C { constructor() { super(); } }",
4031 "class C { method() { super(); } }",
4032 "class C { method() { () => super(); } }",
4033 "class C { *method() { super(); } }",
4034 "class C { get x() { super(); } }",
4035 "class C { set x(_) { super(); } }",
4036 "({ method() { super(); } })",
4037 "({ *method() { super(); } })",
4038 "({ get x() { super(); } })",
4039 "({ set x(_) { super(); } })",
4040 "({ f: function() { super(); } })",
4041 "(function() { super(); })",
4042 "var f = function() { super(); }",
4043 "({ f: function*() { super(); } })",
4044 "(function*() { super(); })",
4045 "var f = function*() { super(); }",
4046 NULL
4047 };
4048
4049 RunParserSyncTest(context_data, error_data, kError);
4050 }
4051
4052
TEST(SuperNewNoErrors)4053 TEST(SuperNewNoErrors) {
4054 const char* context_data[][2] = {
4055 {"class C { constructor() { ", " } }"},
4056 {"class C { *method() { ", " } }"},
4057 {"class C { get x() { ", " } }"},
4058 {"class C { set x(_) { ", " } }"},
4059 {"({ method() { ", " } })"},
4060 {"({ *method() { ", " } })"},
4061 {"({ get x() { ", " } })"},
4062 {"({ set x(_) { ", " } })"},
4063 {NULL, NULL}
4064 };
4065
4066 const char* expression_data[] = {
4067 "new super.x;",
4068 "new super.x();",
4069 "() => new super.x;",
4070 "() => new super.x();",
4071 NULL
4072 };
4073
4074 RunParserSyncTest(context_data, expression_data, kSuccess);
4075 }
4076
4077
TEST(SuperNewErrors)4078 TEST(SuperNewErrors) {
4079 const char* context_data[][2] = {
4080 {"class C { method() { ", " } }"},
4081 {"class C { *method() { ", " } }"},
4082 {"class C { get x() { ", " } }"},
4083 {"class C { set x(_) { ", " } }"},
4084 {"({ method() { ", " } })"},
4085 {"({ *method() { ", " } })"},
4086 {"({ get x() { ", " } })"},
4087 {"({ set x(_) { ", " } })"},
4088 {"({ f: function() { ", " } })"},
4089 {"(function() { ", " })"},
4090 {"var f = function() { ", " }"},
4091 {"({ f: function*() { ", " } })"},
4092 {"(function*() { ", " })"},
4093 {"var f = function*() { ", " }"},
4094 {NULL, NULL}
4095 };
4096
4097 const char* statement_data[] = {
4098 "new super;",
4099 "new super();",
4100 "() => new super;",
4101 "() => new super();",
4102 NULL
4103 };
4104
4105 RunParserSyncTest(context_data, statement_data, kError);
4106 }
4107
4108
TEST(SuperErrorsNonMethods)4109 TEST(SuperErrorsNonMethods) {
4110 // super is only allowed in methods, accessors and constructors.
4111 const char* context_data[][2] = {
4112 {"", ";"},
4113 {"k = ", ";"},
4114 {"foo(", ");"},
4115 {"if (", ") {}"},
4116 {"if (true) {", "}"},
4117 {"if (false) {} else {", "}"},
4118 {"while (true) {", "}"},
4119 {"function f() {", "}"},
4120 {"class C extends (", ") {}"},
4121 {"class C { m() { function f() {", "} } }"},
4122 {"({ m() { function f() {", "} } })"},
4123 {NULL, NULL}
4124 };
4125
4126 const char* statement_data[] = {
4127 "super",
4128 "super = x",
4129 "y = super",
4130 "f(super)",
4131 "super.x",
4132 "super[27]",
4133 "super.x()",
4134 "super[27]()",
4135 "super()",
4136 "new super.x",
4137 "new super.x()",
4138 "new super[27]",
4139 "new super[27]()",
4140 NULL
4141 };
4142
4143 RunParserSyncTest(context_data, statement_data, kError);
4144 }
4145
4146
TEST(NoErrorsMethodDefinition)4147 TEST(NoErrorsMethodDefinition) {
4148 const char* context_data[][2] = {{"({", "});"},
4149 {"'use strict'; ({", "});"},
4150 {"({*", "});"},
4151 {"'use strict'; ({*", "});"},
4152 {NULL, NULL}};
4153
4154 const char* object_literal_body_data[] = {
4155 "m() {}",
4156 "m(x) { return x; }",
4157 "m(x, y) {}, n() {}",
4158 "set(x, y) {}",
4159 "get(x, y) {}",
4160 NULL
4161 };
4162
4163 RunParserSyncTest(context_data, object_literal_body_data, kSuccess);
4164 }
4165
4166
TEST(MethodDefinitionNames)4167 TEST(MethodDefinitionNames) {
4168 const char* context_data[][2] = {{"({", "(x, y) {}});"},
4169 {"'use strict'; ({", "(x, y) {}});"},
4170 {"({*", "(x, y) {}});"},
4171 {"'use strict'; ({*", "(x, y) {}});"},
4172 {NULL, NULL}};
4173
4174 const char* name_data[] = {
4175 "m",
4176 "'m'",
4177 "\"m\"",
4178 "\"m n\"",
4179 "true",
4180 "false",
4181 "null",
4182 "0",
4183 "1.2",
4184 "1e1",
4185 "1E1",
4186 "1e+1",
4187 "1e-1",
4188
4189 // Keywords
4190 "async",
4191 "await",
4192 "break",
4193 "case",
4194 "catch",
4195 "class",
4196 "const",
4197 "continue",
4198 "debugger",
4199 "default",
4200 "delete",
4201 "do",
4202 "else",
4203 "enum",
4204 "export",
4205 "extends",
4206 "finally",
4207 "for",
4208 "function",
4209 "if",
4210 "implements",
4211 "import",
4212 "in",
4213 "instanceof",
4214 "interface",
4215 "let",
4216 "new",
4217 "package",
4218 "private",
4219 "protected",
4220 "public",
4221 "return",
4222 "static",
4223 "super",
4224 "switch",
4225 "this",
4226 "throw",
4227 "try",
4228 "typeof",
4229 "var",
4230 "void",
4231 "while",
4232 "with",
4233 "yield",
4234 NULL
4235 };
4236
4237 RunParserSyncTest(context_data, name_data, kSuccess);
4238 }
4239
4240
TEST(MethodDefinitionStrictFormalParamereters)4241 TEST(MethodDefinitionStrictFormalParamereters) {
4242 const char* context_data[][2] = {{"({method(", "){}});"},
4243 {"'use strict'; ({method(", "){}});"},
4244 {"({*method(", "){}});"},
4245 {"'use strict'; ({*method(", "){}});"},
4246 {NULL, NULL}};
4247
4248 const char* params_data[] = {
4249 "x, x",
4250 "x, y, x",
4251 "var",
4252 "const",
4253 NULL
4254 };
4255
4256 RunParserSyncTest(context_data, params_data, kError);
4257 }
4258
4259
TEST(MethodDefinitionEvalArguments)4260 TEST(MethodDefinitionEvalArguments) {
4261 const char* strict_context_data[][2] =
4262 {{"'use strict'; ({method(", "){}});"},
4263 {"'use strict'; ({*method(", "){}});"},
4264 {NULL, NULL}};
4265 const char* sloppy_context_data[][2] =
4266 {{"({method(", "){}});"},
4267 {"({*method(", "){}});"},
4268 {NULL, NULL}};
4269
4270 const char* data[] = {
4271 "eval",
4272 "arguments",
4273 NULL};
4274
4275 // Fail in strict mode
4276 RunParserSyncTest(strict_context_data, data, kError);
4277
4278 // OK in sloppy mode
4279 RunParserSyncTest(sloppy_context_data, data, kSuccess);
4280 }
4281
4282
TEST(MethodDefinitionDuplicateEvalArguments)4283 TEST(MethodDefinitionDuplicateEvalArguments) {
4284 const char* context_data[][2] =
4285 {{"'use strict'; ({method(", "){}});"},
4286 {"'use strict'; ({*method(", "){}});"},
4287 {"({method(", "){}});"},
4288 {"({*method(", "){}});"},
4289 {NULL, NULL}};
4290
4291 const char* data[] = {
4292 "eval, eval",
4293 "eval, a, eval",
4294 "arguments, arguments",
4295 "arguments, a, arguments",
4296 NULL};
4297
4298 // In strict mode, the error is using "eval" or "arguments" as parameter names
4299 // In sloppy mode, the error is that eval / arguments are duplicated
4300 RunParserSyncTest(context_data, data, kError);
4301 }
4302
4303
TEST(MethodDefinitionDuplicateProperty)4304 TEST(MethodDefinitionDuplicateProperty) {
4305 const char* context_data[][2] = {{"'use strict'; ({", "});"},
4306 {NULL, NULL}};
4307
4308 const char* params_data[] = {
4309 "x: 1, x() {}",
4310 "x() {}, x: 1",
4311 "x() {}, get x() {}",
4312 "x() {}, set x(_) {}",
4313 "x() {}, x() {}",
4314 "x() {}, y() {}, x() {}",
4315 "x() {}, \"x\"() {}",
4316 "x() {}, 'x'() {}",
4317 "0() {}, '0'() {}",
4318 "1.0() {}, 1: 1",
4319
4320 "x: 1, *x() {}",
4321 "*x() {}, x: 1",
4322 "*x() {}, get x() {}",
4323 "*x() {}, set x(_) {}",
4324 "*x() {}, *x() {}",
4325 "*x() {}, y() {}, *x() {}",
4326 "*x() {}, *\"x\"() {}",
4327 "*x() {}, *'x'() {}",
4328 "*0() {}, *'0'() {}",
4329 "*1.0() {}, 1: 1",
4330
4331 NULL
4332 };
4333
4334 RunParserSyncTest(context_data, params_data, kSuccess);
4335 }
4336
4337
TEST(ClassExpressionNoErrors)4338 TEST(ClassExpressionNoErrors) {
4339 const char* context_data[][2] = {{"(", ");"},
4340 {"var C = ", ";"},
4341 {"bar, ", ";"},
4342 {NULL, NULL}};
4343 const char* class_data[] = {
4344 "class {}",
4345 "class name {}",
4346 "class extends F {}",
4347 "class name extends F {}",
4348 "class extends (F, G) {}",
4349 "class name extends (F, G) {}",
4350 "class extends class {} {}",
4351 "class name extends class {} {}",
4352 "class extends class base {} {}",
4353 "class name extends class base {} {}",
4354 NULL};
4355
4356 RunParserSyncTest(context_data, class_data, kSuccess);
4357 }
4358
4359
TEST(ClassDeclarationNoErrors)4360 TEST(ClassDeclarationNoErrors) {
4361 const char* context_data[][2] = {{"'use strict'; ", ""},
4362 {"'use strict'; {", "}"},
4363 {"'use strict'; if (true) {", "}"},
4364 {NULL, NULL}};
4365 const char* statement_data[] = {
4366 "class name {}",
4367 "class name extends F {}",
4368 "class name extends (F, G) {}",
4369 "class name extends class {} {}",
4370 "class name extends class base {} {}",
4371 NULL};
4372
4373 RunParserSyncTest(context_data, statement_data, kSuccess);
4374 }
4375
4376
TEST(ClassBodyNoErrors)4377 TEST(ClassBodyNoErrors) {
4378 // clang-format off
4379 // Tests that parser and preparser accept valid class syntax.
4380 const char* context_data[][2] = {{"(class {", "});"},
4381 {"(class extends Base {", "});"},
4382 {"class C {", "}"},
4383 {"class C extends Base {", "}"},
4384 {NULL, NULL}};
4385 const char* class_body_data[] = {
4386 ";",
4387 ";;",
4388 "m() {}",
4389 "m() {};",
4390 "; m() {}",
4391 "m() {}; n(x) {}",
4392 "get x() {}",
4393 "set x(v) {}",
4394 "get() {}",
4395 "set() {}",
4396 "*g() {}",
4397 "*g() {};",
4398 "; *g() {}",
4399 "*g() {}; *h(x) {}",
4400 "static() {}",
4401 "get static() {}",
4402 "set static(v) {}",
4403 "static m() {}",
4404 "static get x() {}",
4405 "static set x(v) {}",
4406 "static get() {}",
4407 "static set() {}",
4408 "static static() {}",
4409 "static get static() {}",
4410 "static set static(v) {}",
4411 "*static() {}",
4412 "static *static() {}",
4413 "*get() {}",
4414 "*set() {}",
4415 "static *g() {}",
4416
4417 // Escaped 'static' should be allowed anywhere
4418 // static-as-PropertyName is.
4419 "st\\u0061tic() {}",
4420 "get st\\u0061tic() {}",
4421 "set st\\u0061tic(v) {}",
4422 "static st\\u0061tic() {}",
4423 "static get st\\u0061tic() {}",
4424 "static set st\\u0061tic(v) {}",
4425 "*st\\u0061tic() {}",
4426 "static *st\\u0061tic() {}",
4427 NULL};
4428 // clang-format on
4429
4430 RunParserSyncTest(context_data, class_body_data, kSuccess);
4431 }
4432
4433
TEST(ClassPropertyNameNoErrors)4434 TEST(ClassPropertyNameNoErrors) {
4435 const char* context_data[][2] = {{"(class {", "() {}});"},
4436 {"(class { get ", "() {}});"},
4437 {"(class { set ", "(v) {}});"},
4438 {"(class { static ", "() {}});"},
4439 {"(class { static get ", "() {}});"},
4440 {"(class { static set ", "(v) {}});"},
4441 {"(class { *", "() {}});"},
4442 {"(class { static *", "() {}});"},
4443 {"class C {", "() {}}"},
4444 {"class C { get ", "() {}}"},
4445 {"class C { set ", "(v) {}}"},
4446 {"class C { static ", "() {}}"},
4447 {"class C { static get ", "() {}}"},
4448 {"class C { static set ", "(v) {}}"},
4449 {"class C { *", "() {}}"},
4450 {"class C { static *", "() {}}"},
4451 {NULL, NULL}};
4452 const char* name_data[] = {
4453 "42",
4454 "42.5",
4455 "42e2",
4456 "42e+2",
4457 "42e-2",
4458 "null",
4459 "false",
4460 "true",
4461 "'str'",
4462 "\"str\"",
4463 "static",
4464 "get",
4465 "set",
4466 "var",
4467 "const",
4468 "let",
4469 "this",
4470 "class",
4471 "function",
4472 "yield",
4473 "if",
4474 "else",
4475 "for",
4476 "while",
4477 "do",
4478 "try",
4479 "catch",
4480 "finally",
4481 NULL};
4482
4483 RunParserSyncTest(context_data, name_data, kSuccess);
4484 }
4485
4486
TEST(ClassExpressionErrors)4487 TEST(ClassExpressionErrors) {
4488 const char* context_data[][2] = {{"(", ");"},
4489 {"var C = ", ";"},
4490 {"bar, ", ";"},
4491 {NULL, NULL}};
4492 const char* class_data[] = {
4493 "class",
4494 "class name",
4495 "class name extends",
4496 "class extends",
4497 "class {",
4498 "class { m }",
4499 "class { m; n }",
4500 "class { m: 1 }",
4501 "class { m(); n() }",
4502 "class { get m }",
4503 "class { get m() }",
4504 "class { get m() { }",
4505 "class { set m() {} }", // Missing required parameter.
4506 "class { m() {}, n() {} }", // No commas allowed.
4507 NULL};
4508
4509 RunParserSyncTest(context_data, class_data, kError);
4510 }
4511
4512
TEST(ClassDeclarationErrors)4513 TEST(ClassDeclarationErrors) {
4514 const char* context_data[][2] = {{"", ""},
4515 {"{", "}"},
4516 {"if (true) {", "}"},
4517 {NULL, NULL}};
4518 const char* class_data[] = {
4519 "class",
4520 "class name",
4521 "class name extends",
4522 "class extends",
4523 "class name {",
4524 "class name { m }",
4525 "class name { m; n }",
4526 "class name { m: 1 }",
4527 "class name { m(); n() }",
4528 "class name { get x }",
4529 "class name { get x() }",
4530 "class name { set x() {) }", // missing required param
4531 "class {}", // Name is required for declaration
4532 "class extends base {}",
4533 "class name { *",
4534 "class name { * }",
4535 "class name { *; }",
4536 "class name { *get x() {} }",
4537 "class name { *set x(_) {} }",
4538 "class name { *static m() {} }",
4539 NULL};
4540
4541 RunParserSyncTest(context_data, class_data, kError);
4542 }
4543
4544
TEST(ClassNameErrors)4545 TEST(ClassNameErrors) {
4546 const char* context_data[][2] = {{"class ", "{}"},
4547 {"(class ", "{});"},
4548 {"'use strict'; class ", "{}"},
4549 {"'use strict'; (class ", "{});"},
4550 {NULL, NULL}};
4551 const char* class_name[] = {
4552 "arguments",
4553 "eval",
4554 "implements",
4555 "interface",
4556 "let",
4557 "package",
4558 "private",
4559 "protected",
4560 "public",
4561 "static",
4562 "var",
4563 "yield",
4564 NULL};
4565
4566 RunParserSyncTest(context_data, class_name, kError);
4567 }
4568
4569
TEST(ClassGetterParamNameErrors)4570 TEST(ClassGetterParamNameErrors) {
4571 const char* context_data[][2] = {
4572 {"class C { get name(", ") {} }"},
4573 {"(class { get name(", ") {} });"},
4574 {"'use strict'; class C { get name(", ") {} }"},
4575 {"'use strict'; (class { get name(", ") {} })"},
4576 {NULL, NULL}
4577 };
4578
4579 const char* class_name[] = {
4580 "arguments",
4581 "eval",
4582 "implements",
4583 "interface",
4584 "let",
4585 "package",
4586 "private",
4587 "protected",
4588 "public",
4589 "static",
4590 "var",
4591 "yield",
4592 NULL};
4593
4594 RunParserSyncTest(context_data, class_name, kError);
4595 }
4596
4597
TEST(ClassStaticPrototypeErrors)4598 TEST(ClassStaticPrototypeErrors) {
4599 const char* context_data[][2] = {{"class C {", "}"},
4600 {"(class {", "});"},
4601 {NULL, NULL}};
4602
4603 const char* class_body_data[] = {
4604 "static prototype() {}",
4605 "static get prototype() {}",
4606 "static set prototype(_) {}",
4607 "static *prototype() {}",
4608 "static 'prototype'() {}",
4609 "static *'prototype'() {}",
4610 "static prot\\u006ftype() {}",
4611 "static 'prot\\u006ftype'() {}",
4612 "static get 'prot\\u006ftype'() {}",
4613 "static set 'prot\\u006ftype'(_) {}",
4614 "static *'prot\\u006ftype'() {}",
4615 NULL};
4616
4617 RunParserSyncTest(context_data, class_body_data, kError);
4618 }
4619
4620
TEST(ClassSpecialConstructorErrors)4621 TEST(ClassSpecialConstructorErrors) {
4622 const char* context_data[][2] = {{"class C {", "}"},
4623 {"(class {", "});"},
4624 {NULL, NULL}};
4625
4626 const char* class_body_data[] = {
4627 "get constructor() {}",
4628 "get constructor(_) {}",
4629 "*constructor() {}",
4630 "get 'constructor'() {}",
4631 "*'constructor'() {}",
4632 "get c\\u006fnstructor() {}",
4633 "*c\\u006fnstructor() {}",
4634 "get 'c\\u006fnstructor'() {}",
4635 "get 'c\\u006fnstructor'(_) {}",
4636 "*'c\\u006fnstructor'() {}",
4637 NULL};
4638
4639 RunParserSyncTest(context_data, class_body_data, kError);
4640 }
4641
4642
TEST(ClassConstructorNoErrors)4643 TEST(ClassConstructorNoErrors) {
4644 const char* context_data[][2] = {{"class C {", "}"},
4645 {"(class {", "});"},
4646 {NULL, NULL}};
4647
4648 const char* class_body_data[] = {
4649 "constructor() {}",
4650 "static constructor() {}",
4651 "static get constructor() {}",
4652 "static set constructor(_) {}",
4653 "static *constructor() {}",
4654 NULL};
4655
4656 RunParserSyncTest(context_data, class_body_data, kSuccess);
4657 }
4658
4659
TEST(ClassMultipleConstructorErrors)4660 TEST(ClassMultipleConstructorErrors) {
4661 const char* context_data[][2] = {{"class C {", "}"},
4662 {"(class {", "});"},
4663 {NULL, NULL}};
4664
4665 const char* class_body_data[] = {
4666 "constructor() {}; constructor() {}",
4667 NULL};
4668
4669 RunParserSyncTest(context_data, class_body_data, kError);
4670 }
4671
4672
TEST(ClassMultiplePropertyNamesNoErrors)4673 TEST(ClassMultiplePropertyNamesNoErrors) {
4674 const char* context_data[][2] = {{"class C {", "}"},
4675 {"(class {", "});"},
4676 {NULL, NULL}};
4677
4678 const char* class_body_data[] = {
4679 "constructor() {}; static constructor() {}",
4680 "m() {}; static m() {}",
4681 "m() {}; m() {}",
4682 "static m() {}; static m() {}",
4683 "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
4684 NULL};
4685
4686 RunParserSyncTest(context_data, class_body_data, kSuccess);
4687 }
4688
4689
TEST(ClassesAreStrictErrors)4690 TEST(ClassesAreStrictErrors) {
4691 const char* context_data[][2] = {{"", ""},
4692 {"(", ");"},
4693 {NULL, NULL}};
4694
4695 const char* class_body_data[] = {
4696 "class C { method() { with ({}) {} } }",
4697 "class C extends function() { with ({}) {} } {}",
4698 "class C { *method() { with ({}) {} } }",
4699 NULL};
4700
4701 RunParserSyncTest(context_data, class_body_data, kError);
4702 }
4703
4704
TEST(ObjectLiteralPropertyShorthandKeywordsError)4705 TEST(ObjectLiteralPropertyShorthandKeywordsError) {
4706 const char* context_data[][2] = {{"({", "});"},
4707 {"'use strict'; ({", "});"},
4708 {NULL, NULL}};
4709
4710 const char* name_data[] = {
4711 "break",
4712 "case",
4713 "catch",
4714 "class",
4715 "const",
4716 "continue",
4717 "debugger",
4718 "default",
4719 "delete",
4720 "do",
4721 "else",
4722 "enum",
4723 "export",
4724 "extends",
4725 "false",
4726 "finally",
4727 "for",
4728 "function",
4729 "if",
4730 "import",
4731 "in",
4732 "instanceof",
4733 "new",
4734 "null",
4735 "return",
4736 "super",
4737 "switch",
4738 "this",
4739 "throw",
4740 "true",
4741 "try",
4742 "typeof",
4743 "var",
4744 "void",
4745 "while",
4746 "with",
4747 NULL
4748 };
4749
4750 RunParserSyncTest(context_data, name_data, kError);
4751 }
4752
4753
TEST(ObjectLiteralPropertyShorthandStrictKeywords)4754 TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
4755 const char* context_data[][2] = {{"({", "});"},
4756 {NULL, NULL}};
4757
4758 const char* name_data[] = {
4759 "implements",
4760 "interface",
4761 "let",
4762 "package",
4763 "private",
4764 "protected",
4765 "public",
4766 "static",
4767 "yield",
4768 NULL
4769 };
4770
4771 RunParserSyncTest(context_data, name_data, kSuccess);
4772
4773 const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
4774 {NULL, NULL}};
4775 RunParserSyncTest(context_strict_data, name_data, kError);
4776 }
4777
4778
TEST(ObjectLiteralPropertyShorthandError)4779 TEST(ObjectLiteralPropertyShorthandError) {
4780 const char* context_data[][2] = {{"({", "});"},
4781 {"'use strict'; ({", "});"},
4782 {NULL, NULL}};
4783
4784 const char* name_data[] = {
4785 "1",
4786 "1.2",
4787 "0",
4788 "0.1",
4789 "1.0",
4790 "1e1",
4791 "0x1",
4792 "\"s\"",
4793 "'s'",
4794 NULL
4795 };
4796
4797 RunParserSyncTest(context_data, name_data, kError);
4798 }
4799
4800
TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError)4801 TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
4802 const char* context_data[][2] = {{"", ""},
4803 {NULL, NULL}};
4804
4805 const char* name_data[] = {
4806 "function* g() { ({yield}); }",
4807 NULL
4808 };
4809
4810 RunParserSyncTest(context_data, name_data, kError);
4811 }
4812
4813
TEST(ConstParsingInForIn)4814 TEST(ConstParsingInForIn) {
4815 const char* context_data[][2] = {{"'use strict';", ""},
4816 {"function foo(){ 'use strict';", "}"},
4817 {NULL, NULL}};
4818
4819 const char* data[] = {
4820 "for(const x = 1; ; ) {}",
4821 "for(const x = 1, y = 2;;){}",
4822 "for(const x in [1,2,3]) {}",
4823 "for(const x of [1,2,3]) {}",
4824 NULL};
4825 RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, nullptr, 0);
4826 }
4827
4828
TEST(StatementParsingInForIn)4829 TEST(StatementParsingInForIn) {
4830 const char* context_data[][2] = {{"", ""},
4831 {"'use strict';", ""},
4832 {"function foo(){ 'use strict';", "}"},
4833 {NULL, NULL}};
4834
4835 const char* data[] = {"for(x in {}, {}) {}", "for(var x in {}, {}) {}",
4836 "for(let x in {}, {}) {}", "for(const x in {}, {}) {}",
4837 NULL};
4838
4839 RunParserSyncTest(context_data, data, kSuccess);
4840 }
4841
4842
TEST(ConstParsingInForInError)4843 TEST(ConstParsingInForInError) {
4844 const char* context_data[][2] = {{"'use strict';", ""},
4845 {"function foo(){ 'use strict';", "}"},
4846 {NULL, NULL}};
4847
4848 const char* data[] = {
4849 "for(const x,y = 1; ; ) {}",
4850 "for(const x = 4 in [1,2,3]) {}",
4851 "for(const x = 4, y in [1,2,3]) {}",
4852 "for(const x = 4 of [1,2,3]) {}",
4853 "for(const x = 4, y of [1,2,3]) {}",
4854 "for(const x = 1, y = 2 in []) {}",
4855 "for(const x,y in []) {}",
4856 "for(const x = 1, y = 2 of []) {}",
4857 "for(const x,y of []) {}",
4858 NULL};
4859 RunParserSyncTest(context_data, data, kError, nullptr, 0, nullptr, 0);
4860 }
4861
4862
TEST(InitializedDeclarationsInStrictForInError)4863 TEST(InitializedDeclarationsInStrictForInError) {
4864 const char* context_data[][2] = {{"'use strict';", ""},
4865 {"function foo(){ 'use strict';", "}"},
4866 {NULL, NULL}};
4867
4868 const char* data[] = {
4869 "for (var i = 1 in {}) {}",
4870 "for (var i = void 0 in [1, 2, 3]) {}",
4871 "for (let i = 1 in {}) {}",
4872 "for (let i = void 0 in [1, 2, 3]) {}",
4873 "for (const i = 1 in {}) {}",
4874 "for (const i = void 0 in [1, 2, 3]) {}",
4875 NULL};
4876 RunParserSyncTest(context_data, data, kError);
4877 }
4878
4879
TEST(InitializedDeclarationsInStrictForOfError)4880 TEST(InitializedDeclarationsInStrictForOfError) {
4881 const char* context_data[][2] = {{"'use strict';", ""},
4882 {"function foo(){ 'use strict';", "}"},
4883 {NULL, NULL}};
4884
4885 const char* data[] = {
4886 "for (var i = 1 of {}) {}",
4887 "for (var i = void 0 of [1, 2, 3]) {}",
4888 "for (let i = 1 of {}) {}",
4889 "for (let i = void 0 of [1, 2, 3]) {}",
4890 "for (const i = 1 of {}) {}",
4891 "for (const i = void 0 of [1, 2, 3]) {}",
4892 NULL};
4893 RunParserSyncTest(context_data, data, kError);
4894 }
4895
4896
TEST(InitializedDeclarationsInSloppyForInError)4897 TEST(InitializedDeclarationsInSloppyForInError) {
4898 const char* context_data[][2] = {{"", ""},
4899 {"function foo(){", "}"},
4900 {NULL, NULL}};
4901
4902 const char* data[] = {
4903 "for (var i = 1 in {}) {}",
4904 "for (var i = void 0 in [1, 2, 3]) {}",
4905 NULL};
4906 // TODO(caitp): This should be an error in sloppy mode.
4907 RunParserSyncTest(context_data, data, kSuccess);
4908 }
4909
4910
TEST(InitializedDeclarationsInSloppyForOfError)4911 TEST(InitializedDeclarationsInSloppyForOfError) {
4912 const char* context_data[][2] = {{"", ""},
4913 {"function foo(){", "}"},
4914 {NULL, NULL}};
4915
4916 const char* data[] = {
4917 "for (var i = 1 of {}) {}",
4918 "for (var i = void 0 of [1, 2, 3]) {}",
4919 NULL};
4920 RunParserSyncTest(context_data, data, kError);
4921 }
4922
4923
TEST(ForInMultipleDeclarationsError)4924 TEST(ForInMultipleDeclarationsError) {
4925 const char* context_data[][2] = {{"", ""},
4926 {"function foo(){", "}"},
4927 {"'use strict';", ""},
4928 {"function foo(){ 'use strict';", "}"},
4929 {NULL, NULL}};
4930
4931 const char* data[] = {
4932 "for (var i, j in {}) {}",
4933 "for (var i, j in [1, 2, 3]) {}",
4934 "for (var i, j = 1 in {}) {}",
4935 "for (var i, j = void 0 in [1, 2, 3]) {}",
4936
4937 "for (let i, j in {}) {}",
4938 "for (let i, j in [1, 2, 3]) {}",
4939 "for (let i, j = 1 in {}) {}",
4940 "for (let i, j = void 0 in [1, 2, 3]) {}",
4941
4942 "for (const i, j in {}) {}",
4943 "for (const i, j in [1, 2, 3]) {}",
4944 "for (const i, j = 1 in {}) {}",
4945 "for (const i, j = void 0 in [1, 2, 3]) {}",
4946 NULL};
4947 RunParserSyncTest(context_data, data, kError);
4948 }
4949
4950
TEST(ForOfMultipleDeclarationsError)4951 TEST(ForOfMultipleDeclarationsError) {
4952 const char* context_data[][2] = {{"", ""},
4953 {"function foo(){", "}"},
4954 {"'use strict';", ""},
4955 {"function foo(){ 'use strict';", "}"},
4956 {NULL, NULL}};
4957
4958 const char* data[] = {
4959 "for (var i, j of {}) {}",
4960 "for (var i, j of [1, 2, 3]) {}",
4961 "for (var i, j = 1 of {}) {}",
4962 "for (var i, j = void 0 of [1, 2, 3]) {}",
4963
4964 "for (let i, j of {}) {}",
4965 "for (let i, j of [1, 2, 3]) {}",
4966 "for (let i, j = 1 of {}) {}",
4967 "for (let i, j = void 0 of [1, 2, 3]) {}",
4968
4969 "for (const i, j of {}) {}",
4970 "for (const i, j of [1, 2, 3]) {}",
4971 "for (const i, j = 1 of {}) {}",
4972 "for (const i, j = void 0 of [1, 2, 3]) {}",
4973 NULL};
4974 RunParserSyncTest(context_data, data, kError);
4975 }
4976
4977
TEST(ForInNoDeclarationsError)4978 TEST(ForInNoDeclarationsError) {
4979 const char* context_data[][2] = {{"", ""},
4980 {"function foo(){", "}"},
4981 {"'use strict';", ""},
4982 {"function foo(){ 'use strict';", "}"},
4983 {NULL, NULL}};
4984
4985 const char* data[] = {
4986 "for (var in {}) {}",
4987 "for (const in {}) {}",
4988 NULL};
4989 RunParserSyncTest(context_data, data, kError);
4990 }
4991
4992
TEST(ForOfNoDeclarationsError)4993 TEST(ForOfNoDeclarationsError) {
4994 const char* context_data[][2] = {{"", ""},
4995 {"function foo(){", "}"},
4996 {"'use strict';", ""},
4997 {"function foo(){ 'use strict';", "}"},
4998 {NULL, NULL}};
4999
5000 const char* data[] = {
5001 "for (var of [1, 2, 3]) {}",
5002 "for (const of [1, 2, 3]) {}",
5003 NULL};
5004 RunParserSyncTest(context_data, data, kError);
5005 }
5006
5007
TEST(ForOfInOperator)5008 TEST(ForOfInOperator) {
5009 const char* context_data[][2] = {{"", ""},
5010 {"'use strict';", ""},
5011 {"function foo(){ 'use strict';", "}"},
5012 {NULL, NULL}};
5013
5014 const char* data[] = {
5015 "for(x of 'foo' in {}) {}", "for(var x of 'foo' in {}) {}",
5016 "for(let x of 'foo' in {}) {}", "for(const x of 'foo' in {}) {}", NULL};
5017
5018 RunParserSyncTest(context_data, data, kSuccess);
5019 }
5020
5021
TEST(ForOfYieldIdentifier)5022 TEST(ForOfYieldIdentifier) {
5023 const char* context_data[][2] = {{"", ""}, {NULL, NULL}};
5024
5025 const char* data[] = {"for(x of yield) {}", "for(var x of yield) {}",
5026 "for(let x of yield) {}", "for(const x of yield) {}",
5027 NULL};
5028
5029 RunParserSyncTest(context_data, data, kSuccess);
5030 }
5031
5032
TEST(ForOfYieldExpression)5033 TEST(ForOfYieldExpression) {
5034 const char* context_data[][2] = {{"", ""},
5035 {"'use strict';", ""},
5036 {"function foo(){ 'use strict';", "}"},
5037 {NULL, NULL}};
5038
5039 const char* data[] = {"function* g() { for(x of yield) {} }",
5040 "function* g() { for(var x of yield) {} }",
5041 "function* g() { for(let x of yield) {} }",
5042 "function* g() { for(const x of yield) {} }", NULL};
5043
5044 RunParserSyncTest(context_data, data, kSuccess);
5045 }
5046
5047
TEST(ForOfExpressionError)5048 TEST(ForOfExpressionError) {
5049 const char* context_data[][2] = {{"", ""},
5050 {"'use strict';", ""},
5051 {"function foo(){ 'use strict';", "}"},
5052 {NULL, NULL}};
5053
5054 const char* data[] = {
5055 "for(x of [], []) {}", "for(var x of [], []) {}",
5056 "for(let x of [], []) {}", "for(const x of [], []) {}",
5057
5058 // AssignmentExpression should be validated statically:
5059 "for(x of { y = 23 }) {}", "for(var x of { y = 23 }) {}",
5060 "for(let x of { y = 23 }) {}", "for(const x of { y = 23 }) {}", NULL};
5061
5062 RunParserSyncTest(context_data, data, kError);
5063 }
5064
5065
TEST(InvalidUnicodeEscapes)5066 TEST(InvalidUnicodeEscapes) {
5067 const char* context_data[][2] = {{"", ""},
5068 {"'use strict';", ""},
5069 {NULL, NULL}};
5070 const char* data[] = {
5071 "var foob\\u123r = 0;",
5072 "var \\u123roo = 0;",
5073 "\"foob\\u123rr\"",
5074 // No escapes allowed in regexp flags
5075 "/regex/\\u0069g",
5076 "/regex/\\u006g",
5077 // Braces gone wrong
5078 "var foob\\u{c481r = 0;",
5079 "var foob\\uc481}r = 0;",
5080 "var \\u{0052oo = 0;",
5081 "var \\u0052}oo = 0;",
5082 "\"foob\\u{c481r\"",
5083 "var foob\\u{}ar = 0;",
5084 // Too high value for the unicode escape
5085 "\"\\u{110000}\"",
5086 // Not an unicode escape
5087 "var foob\\v1234r = 0;",
5088 "var foob\\U1234r = 0;",
5089 "var foob\\v{1234}r = 0;",
5090 "var foob\\U{1234}r = 0;",
5091 NULL};
5092 RunParserSyncTest(context_data, data, kError);
5093 }
5094
5095
TEST(UnicodeEscapes)5096 TEST(UnicodeEscapes) {
5097 const char* context_data[][2] = {{"", ""},
5098 {"'use strict';", ""},
5099 {NULL, NULL}};
5100 const char* data[] = {
5101 // Identifier starting with escape
5102 "var \\u0052oo = 0;",
5103 "var \\u{0052}oo = 0;",
5104 "var \\u{52}oo = 0;",
5105 "var \\u{00000000052}oo = 0;",
5106 // Identifier with an escape but not starting with an escape
5107 "var foob\\uc481r = 0;",
5108 "var foob\\u{c481}r = 0;",
5109 // String with an escape
5110 "\"foob\\uc481r\"",
5111 "\"foob\\{uc481}r\"",
5112 // This character is a valid unicode character, representable as a surrogate
5113 // pair, not representable as 4 hex digits.
5114 "\"foo\\u{10e6d}\"",
5115 // Max value for the unicode escape
5116 "\"\\u{10ffff}\"",
5117 NULL};
5118 RunParserSyncTest(context_data, data, kSuccess);
5119 }
5120
5121
TEST(ScanTemplateLiterals)5122 TEST(ScanTemplateLiterals) {
5123 const char* context_data[][2] = {{"'use strict';", ""},
5124 {"function foo(){ 'use strict';"
5125 " var a, b, c; return ", "}"},
5126 {NULL, NULL}};
5127
5128 const char* data[] = {
5129 "``",
5130 "`no-subst-template`",
5131 "`template-head${a}`",
5132 "`${a}`",
5133 "`${a}template-tail`",
5134 "`template-head${a}template-tail`",
5135 "`${a}${b}${c}`",
5136 "`a${a}b${b}c${c}`",
5137 "`${a}a${b}b${c}c`",
5138 "`foo\n\nbar\r\nbaz`",
5139 "`foo\n\n${ bar }\r\nbaz`",
5140 "`foo${a /* comment */}`",
5141 "`foo${a // comment\n}`",
5142 "`foo${a \n}`",
5143 "`foo${a \r\n}`",
5144 "`foo${a \r}`",
5145 "`foo${/* comment */ a}`",
5146 "`foo${// comment\na}`",
5147 "`foo${\n a}`",
5148 "`foo${\r\n a}`",
5149 "`foo${\r a}`",
5150 "`foo${'a' in a}`",
5151 NULL};
5152 RunParserSyncTest(context_data, data, kSuccess);
5153 }
5154
5155
TEST(ScanTaggedTemplateLiterals)5156 TEST(ScanTaggedTemplateLiterals) {
5157 const char* context_data[][2] = {{"'use strict';", ""},
5158 {"function foo(){ 'use strict';"
5159 " function tag() {}"
5160 " var a, b, c; return ", "}"},
5161 {NULL, NULL}};
5162
5163 const char* data[] = {
5164 "tag ``",
5165 "tag `no-subst-template`",
5166 "tag`template-head${a}`",
5167 "tag `${a}`",
5168 "tag `${a}template-tail`",
5169 "tag `template-head${a}template-tail`",
5170 "tag\n`${a}${b}${c}`",
5171 "tag\r\n`a${a}b${b}c${c}`",
5172 "tag `${a}a${b}b${c}c`",
5173 "tag\t`foo\n\nbar\r\nbaz`",
5174 "tag\r`foo\n\n${ bar }\r\nbaz`",
5175 "tag`foo${a /* comment */}`",
5176 "tag`foo${a // comment\n}`",
5177 "tag`foo${a \n}`",
5178 "tag`foo${a \r\n}`",
5179 "tag`foo${a \r}`",
5180 "tag`foo${/* comment */ a}`",
5181 "tag`foo${// comment\na}`",
5182 "tag`foo${\n a}`",
5183 "tag`foo${\r\n a}`",
5184 "tag`foo${\r a}`",
5185 "tag`foo${'a' in a}`",
5186 NULL};
5187 RunParserSyncTest(context_data, data, kSuccess);
5188 }
5189
5190
TEST(TemplateMaterializedLiterals)5191 TEST(TemplateMaterializedLiterals) {
5192 const char* context_data[][2] = {
5193 {
5194 "'use strict';\n"
5195 "function tag() {}\n"
5196 "var a, b, c;\n"
5197 "(", ")"
5198 },
5199 {NULL, NULL}
5200 };
5201
5202 const char* data[] = {
5203 "tag``",
5204 "tag`a`",
5205 "tag`a${1}b`",
5206 "tag`a${1}b${2}c`",
5207 "``",
5208 "`a`",
5209 "`a${1}b`",
5210 "`a${1}b${2}c`",
5211 NULL
5212 };
5213
5214 RunParserSyncTest(context_data, data, kSuccess);
5215 }
5216
5217
TEST(ScanUnterminatedTemplateLiterals)5218 TEST(ScanUnterminatedTemplateLiterals) {
5219 const char* context_data[][2] = {{"'use strict';", ""},
5220 {"function foo(){ 'use strict';"
5221 " var a, b, c; return ", "}"},
5222 {NULL, NULL}};
5223
5224 const char* data[] = {
5225 "`no-subst-template",
5226 "`template-head${a}",
5227 "`${a}template-tail",
5228 "`template-head${a}template-tail",
5229 "`${a}${b}${c}",
5230 "`a${a}b${b}c${c}",
5231 "`${a}a${b}b${c}c",
5232 "`foo\n\nbar\r\nbaz",
5233 "`foo\n\n${ bar }\r\nbaz",
5234 "`foo${a /* comment } */`",
5235 "`foo${a /* comment } `*/",
5236 "`foo${a // comment}`",
5237 "`foo${a \n`",
5238 "`foo${a \r\n`",
5239 "`foo${a \r`",
5240 "`foo${/* comment */ a`",
5241 "`foo${// commenta}`",
5242 "`foo${\n a`",
5243 "`foo${\r\n a`",
5244 "`foo${\r a`",
5245 "`foo${fn(}`",
5246 "`foo${1 if}`",
5247 NULL};
5248 RunParserSyncTest(context_data, data, kError);
5249 }
5250
5251
TEST(TemplateLiteralsIllegalTokens)5252 TEST(TemplateLiteralsIllegalTokens) {
5253 const char* context_data[][2] = {{"'use strict';", ""},
5254 {"function foo(){ 'use strict';"
5255 " var a, b, c; return ", "}"},
5256 {NULL, NULL}};
5257 const char* data[] = {
5258 "`hello\\x`",
5259 "`hello\\x${1}`",
5260 "`hello${1}\\x`",
5261 "`hello${1}\\x${2}`",
5262 "`hello\\x\n`",
5263 "`hello\\x\n${1}`",
5264 "`hello${1}\\x\n`",
5265 "`hello${1}\\x\n${2}`",
5266 NULL};
5267
5268 RunParserSyncTest(context_data, data, kError);
5269 }
5270
5271
TEST(ParseRestParameters)5272 TEST(ParseRestParameters) {
5273 const char* context_data[][2] = {{"'use strict';(function(",
5274 "){ return args;})(1, [], /regexp/, 'str',"
5275 "function(){});"},
5276 {"(function(", "){ return args;})(1, [],"
5277 "/regexp/, 'str', function(){});"},
5278 {NULL, NULL}};
5279
5280 const char* data[] = {"...args",
5281 "a, ...args",
5282 "... args",
5283 "a, ... args",
5284 "...\targs",
5285 "a, ...\targs",
5286 "...\r\nargs",
5287 "a, ...\r\nargs",
5288 "...\rargs",
5289 "a, ...\rargs",
5290 "...\t\n\t\t\n args",
5291 "a, ... \n \n args",
5292 "...{ length, 0: a, 1: b}",
5293 "...{}",
5294 "...[a, b]",
5295 "...[]",
5296 "...[...[a, b, ...c]]",
5297 NULL};
5298 RunParserSyncTest(context_data, data, kSuccess);
5299 }
5300
5301
TEST(ParseRestParametersErrors)5302 TEST(ParseRestParametersErrors) {
5303 const char* context_data[][2] = {{"'use strict';(function(",
5304 "){ return args;}(1, [], /regexp/, 'str',"
5305 "function(){});"},
5306 {"(function(", "){ return args;}(1, [],"
5307 "/regexp/, 'str', function(){});"},
5308 {NULL, NULL}};
5309
5310 const char* data[] = {
5311 "...args, b",
5312 "a, ...args, b",
5313 "...args, b",
5314 "a, ...args, b",
5315 "...args,\tb",
5316 "a,...args\t,b",
5317 "...args\r\n, b",
5318 "a, ... args,\r\nb",
5319 "...args\r,b",
5320 "a, ... args,\rb",
5321 "...args\t\n\t\t\n, b",
5322 "a, ... args, \n \n b",
5323 "a, a, ...args",
5324 "a,\ta, ...args",
5325 "a,\ra, ...args",
5326 "a,\na, ...args",
5327 NULL};
5328 RunParserSyncTest(context_data, data, kError);
5329 }
5330
5331
TEST(RestParameterInSetterMethodError)5332 TEST(RestParameterInSetterMethodError) {
5333 const char* context_data[][2] = {
5334 {"'use strict';({ set prop(", ") {} }).prop = 1;"},
5335 {"'use strict';(class { static set prop(", ") {} }).prop = 1;"},
5336 {"'use strict';(new (class { set prop(", ") {} })).prop = 1;"},
5337 {"({ set prop(", ") {} }).prop = 1;"},
5338 {"(class { static set prop(", ") {} }).prop = 1;"},
5339 {"(new (class { set prop(", ") {} })).prop = 1;"},
5340 {nullptr, nullptr}};
5341 const char* data[] = {"...a", "...arguments", "...eval", nullptr};
5342
5343 RunParserSyncTest(context_data, data, kError);
5344 }
5345
5346
TEST(RestParametersEvalArguments)5347 TEST(RestParametersEvalArguments) {
5348 // clang-format off
5349 const char* strict_context_data[][2] =
5350 {{"'use strict';(function(",
5351 "){ return;})(1, [], /regexp/, 'str',function(){});"},
5352 {NULL, NULL}};
5353 const char* sloppy_context_data[][2] =
5354 {{"(function(",
5355 "){ return;})(1, [],/regexp/, 'str', function(){});"},
5356 {NULL, NULL}};
5357
5358 const char* data[] = {
5359 "...eval",
5360 "eval, ...args",
5361 "...arguments",
5362 // See https://bugs.chromium.org/p/v8/issues/detail?id=4577
5363 // "arguments, ...args",
5364 NULL};
5365 // clang-format on
5366
5367 // Fail in strict mode
5368 RunParserSyncTest(strict_context_data, data, kError);
5369
5370 // OK in sloppy mode
5371 RunParserSyncTest(sloppy_context_data, data, kSuccess);
5372 }
5373
5374
TEST(RestParametersDuplicateEvalArguments)5375 TEST(RestParametersDuplicateEvalArguments) {
5376 const char* context_data[][2] =
5377 {{"'use strict';(function(",
5378 "){ return;})(1, [], /regexp/, 'str',function(){});"},
5379 {"(function(",
5380 "){ return;})(1, [],/regexp/, 'str', function(){});"},
5381 {NULL, NULL}};
5382
5383 const char* data[] = {
5384 "eval, ...eval",
5385 "eval, eval, ...args",
5386 "arguments, ...arguments",
5387 "arguments, arguments, ...args",
5388 NULL};
5389
5390 // In strict mode, the error is using "eval" or "arguments" as parameter names
5391 // In sloppy mode, the error is that eval / arguments are duplicated
5392 RunParserSyncTest(context_data, data, kError);
5393 }
5394
5395
TEST(SpreadCall)5396 TEST(SpreadCall) {
5397 const char* context_data[][2] = {{"function fn() { 'use strict';} fn(", ");"},
5398 {"function fn() {} fn(", ");"},
5399 {NULL, NULL}};
5400
5401 const char* data[] = {
5402 "...([1, 2, 3])", "...'123', ...'456'", "...new Set([1, 2, 3]), 4",
5403 "1, ...[2, 3], 4", "...Array(...[1,2,3,4])", "...NaN",
5404 "0, 1, ...[2, 3, 4], 5, 6, 7, ...'89'",
5405 "0, 1, ...[2, 3, 4], 5, 6, 7, ...'89', 10",
5406 "...[0, 1, 2], 3, 4, 5, 6, ...'7', 8, 9",
5407 "...[0, 1, 2], 3, 4, 5, 6, ...'7', 8, 9, ...[10]", NULL};
5408
5409 RunParserSyncTest(context_data, data, kSuccess);
5410 }
5411
5412
TEST(SpreadCallErrors)5413 TEST(SpreadCallErrors) {
5414 const char* context_data[][2] = {{"function fn() { 'use strict';} fn(", ");"},
5415 {"function fn() {} fn(", ");"},
5416 {NULL, NULL}};
5417
5418 const char* data[] = {"(...[1, 2, 3])", "......[1,2,3]", NULL};
5419
5420 RunParserSyncTest(context_data, data, kError);
5421 }
5422
5423
TEST(BadRestSpread)5424 TEST(BadRestSpread) {
5425 const char* context_data[][2] = {{"function fn() { 'use strict';", "} fn();"},
5426 {"function fn() { ", "} fn();"},
5427 {NULL, NULL}};
5428 const char* data[] = {"return ...[1,2,3];", "var ...x = [1,2,3];",
5429 "var [...x,] = [1,2,3];", "var [...x, y] = [1,2,3];",
5430 "var {...x} = [1,2,3];", "var { x } = {x: ...[1,2,3]}",
5431 NULL};
5432 RunParserSyncTest(context_data, data, kError);
5433 }
5434
5435
TEST(LexicalScopingSloppyMode)5436 TEST(LexicalScopingSloppyMode) {
5437 const char* context_data[][2] = {
5438 {"", ""},
5439 {"function f() {", "}"},
5440 {"{", "}"},
5441 {NULL, NULL}};
5442
5443 const char* good_data[] = {
5444 "let = 1;",
5445 "for(let = 1;;){}",
5446 NULL};
5447 RunParserSyncTest(context_data, good_data, kSuccess);
5448 }
5449
5450
TEST(ComputedPropertyName)5451 TEST(ComputedPropertyName) {
5452 const char* context_data[][2] = {{"({[", "]: 1});"},
5453 {"({get [", "]() {}});"},
5454 {"({set [", "](_) {}});"},
5455 {"({[", "]() {}});"},
5456 {"({*[", "]() {}});"},
5457 {"(class {get [", "]() {}});"},
5458 {"(class {set [", "](_) {}});"},
5459 {"(class {[", "]() {}});"},
5460 {"(class {*[", "]() {}});"},
5461 {NULL, NULL}};
5462 const char* error_data[] = {
5463 "1, 2",
5464 "var name",
5465 NULL};
5466
5467 RunParserSyncTest(context_data, error_data, kError);
5468
5469 const char* name_data[] = {
5470 "1",
5471 "1 + 2",
5472 "'name'",
5473 "\"name\"",
5474 "[]",
5475 "{}",
5476 NULL};
5477
5478 RunParserSyncTest(context_data, name_data, kSuccess);
5479 }
5480
5481
TEST(ComputedPropertyNameShorthandError)5482 TEST(ComputedPropertyNameShorthandError) {
5483 const char* context_data[][2] = {{"({", "});"},
5484 {NULL, NULL}};
5485 const char* error_data[] = {
5486 "a: 1, [2]",
5487 "[1], a: 1",
5488 NULL};
5489
5490 RunParserSyncTest(context_data, error_data, kError);
5491 }
5492
5493
TEST(BasicImportExportParsing)5494 TEST(BasicImportExportParsing) {
5495 // clang-format off
5496 const char* kSources[] = {
5497 "export let x = 0;",
5498 "export var y = 0;",
5499 "export const z = 0;",
5500 "export function func() { };",
5501 "export class C { };",
5502 "export { };",
5503 "function f() {}; f(); export { f };",
5504 "var a, b, c; export { a, b as baz, c };",
5505 "var d, e; export { d as dreary, e, };",
5506 "export default function f() {}",
5507 "export default function() {}",
5508 "export default function*() {}",
5509 "export default class C {}",
5510 "export default class {}"
5511 "export default class extends C {}"
5512 "export default 42",
5513 "var x; export default x = 7",
5514 "export { Q } from 'somemodule.js';",
5515 "export * from 'somemodule.js';",
5516 "var foo; export { foo as for };",
5517 "export { arguments } from 'm.js';",
5518 "export { for } from 'm.js';",
5519 "export { yield } from 'm.js'",
5520 "export { static } from 'm.js'",
5521 "export { let } from 'm.js'",
5522 "var a; export { a as b, a as c };",
5523 "var a; export { a as await };",
5524 "var a; export { a as enum };",
5525
5526 "import 'somemodule.js';",
5527 "import { } from 'm.js';",
5528 "import { a } from 'm.js';",
5529 "import { a, b as d, c, } from 'm.js';",
5530 "import * as thing from 'm.js';",
5531 "import thing from 'm.js';",
5532 "import thing, * as rest from 'm.js';",
5533 "import thing, { a, b, c } from 'm.js';",
5534 "import { arguments as a } from 'm.js';",
5535 "import { for as f } from 'm.js';",
5536 "import { yield as y } from 'm.js';",
5537 "import { static as s } from 'm.js';",
5538 "import { let as l } from 'm.js';",
5539 };
5540 // clang-format on
5541
5542 i::Isolate* isolate = CcTest::i_isolate();
5543 i::Factory* factory = isolate->factory();
5544
5545 v8::HandleScope handles(CcTest::isolate());
5546 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
5547 v8::Context::Scope context_scope(context);
5548
5549 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5550 128 * 1024);
5551
5552 for (unsigned i = 0; i < arraysize(kSources); ++i) {
5553 i::Handle<i::String> source =
5554 factory->NewStringFromAsciiChecked(kSources[i]);
5555
5556 // Show that parsing as a module works
5557 {
5558 i::Handle<i::Script> script = factory->NewScript(source);
5559 i::Zone zone(CcTest::i_isolate()->allocator());
5560 i::ParseInfo info(&zone, script);
5561 i::Parser parser(&info);
5562 info.set_module();
5563 if (!parser.Parse(&info)) {
5564 i::Handle<i::JSObject> exception_handle(
5565 i::JSObject::cast(isolate->pending_exception()));
5566 i::Handle<i::String> message_string = i::Handle<i::String>::cast(
5567 i::JSReceiver::GetProperty(isolate, exception_handle, "message")
5568 .ToHandleChecked());
5569
5570 v8::base::OS::Print(
5571 "Parser failed on:\n"
5572 "\t%s\n"
5573 "with error:\n"
5574 "\t%s\n"
5575 "However, we expected no error.",
5576 source->ToCString().get(), message_string->ToCString().get());
5577 CHECK(false);
5578 }
5579 }
5580
5581 // And that parsing a script does not.
5582 {
5583 i::Handle<i::Script> script = factory->NewScript(source);
5584 i::Zone zone(CcTest::i_isolate()->allocator());
5585 i::ParseInfo info(&zone, script);
5586 i::Parser parser(&info);
5587 info.set_global();
5588 CHECK(!parser.Parse(&info));
5589 }
5590 }
5591 }
5592
5593
TEST(ImportExportParsingErrors)5594 TEST(ImportExportParsingErrors) {
5595 // clang-format off
5596 const char* kErrorSources[] = {
5597 "export {",
5598 "var a; export { a",
5599 "var a; export { a,",
5600 "var a; export { a, ;",
5601 "var a; export { a as };",
5602 "var a, b; export { a as , b};",
5603 "export }",
5604 "var foo, bar; export { foo bar };",
5605 "export { foo };",
5606 "export { , };",
5607 "export default;",
5608 "export default var x = 7;",
5609 "export default let x = 7;",
5610 "export default const x = 7;",
5611 "export *;",
5612 "export * from;",
5613 "export { Q } from;",
5614 "export default from 'module.js';",
5615 "export { for }",
5616 "export { for as foo }",
5617 "export { arguments }",
5618 "export { arguments as foo }",
5619 "var a; export { a, a };",
5620 "var a, b; export { a as b, b };",
5621 "var a, b; export { a as c, b as c };",
5622 "export default function f(){}; export default class C {};",
5623 "export default function f(){}; var a; export { a as default };",
5624 "export function() {}",
5625 "export function*() {}",
5626 "export class {}",
5627 "export class extends C {}",
5628
5629 "import from;",
5630 "import from 'm.js';",
5631 "import { };",
5632 "import {;",
5633 "import };",
5634 "import { , };",
5635 "import { , } from 'm.js';",
5636 "import { a } from;",
5637 "import { a } 'm.js';",
5638 "import , from 'm.js';",
5639 "import a , from 'm.js';",
5640 "import a { b, c } from 'm.js';",
5641 "import arguments from 'm.js';",
5642 "import eval from 'm.js';",
5643 "import { arguments } from 'm.js';",
5644 "import { eval } from 'm.js';",
5645 "import { a as arguments } from 'm.js';",
5646 "import { for } from 'm.js';",
5647 "import { y as yield } from 'm.js'",
5648 "import { s as static } from 'm.js'",
5649 "import { l as let } from 'm.js'",
5650 "import { a as await } from 'm.js';",
5651 "import { a as enum } from 'm.js';",
5652 "import { x }, def from 'm.js';",
5653 "import def, def2 from 'm.js';",
5654 "import * as x, def from 'm.js';",
5655 "import * as x, * as y from 'm.js';",
5656 "import {x}, {y} from 'm.js';",
5657 "import * as x, {y} from 'm.js';",
5658 };
5659 // clang-format on
5660
5661 i::Isolate* isolate = CcTest::i_isolate();
5662 i::Factory* factory = isolate->factory();
5663
5664 v8::HandleScope handles(CcTest::isolate());
5665 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
5666 v8::Context::Scope context_scope(context);
5667
5668 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5669 128 * 1024);
5670
5671 for (unsigned i = 0; i < arraysize(kErrorSources); ++i) {
5672 i::Handle<i::String> source =
5673 factory->NewStringFromAsciiChecked(kErrorSources[i]);
5674
5675 i::Handle<i::Script> script = factory->NewScript(source);
5676 i::Zone zone(CcTest::i_isolate()->allocator());
5677 i::ParseInfo info(&zone, script);
5678 i::Parser parser(&info);
5679 info.set_module();
5680 CHECK(!parser.Parse(&info));
5681 }
5682 }
5683
TEST(ModuleTopLevelFunctionDecl)5684 TEST(ModuleTopLevelFunctionDecl) {
5685 // clang-format off
5686 const char* kErrorSources[] = {
5687 "function f() {} function f() {}",
5688 "var f; function f() {}",
5689 "function f() {} var f;",
5690 "function* f() {} function* f() {}",
5691 "var f; function* f() {}",
5692 "function* f() {} var f;",
5693 "function f() {} function* f() {}",
5694 "function* f() {} function f() {}",
5695 };
5696 // clang-format on
5697
5698 i::Isolate* isolate = CcTest::i_isolate();
5699 i::Factory* factory = isolate->factory();
5700
5701 v8::HandleScope handles(CcTest::isolate());
5702 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
5703 v8::Context::Scope context_scope(context);
5704
5705 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5706 128 * 1024);
5707
5708 for (unsigned i = 0; i < arraysize(kErrorSources); ++i) {
5709 i::Handle<i::String> source =
5710 factory->NewStringFromAsciiChecked(kErrorSources[i]);
5711
5712 i::Handle<i::Script> script = factory->NewScript(source);
5713 i::Zone zone(CcTest::i_isolate()->allocator());
5714 i::ParseInfo info(&zone, script);
5715 i::Parser parser(&info);
5716 info.set_module();
5717 CHECK(!parser.Parse(&info));
5718 }
5719 }
5720
TEST(ModuleAwaitReserved)5721 TEST(ModuleAwaitReserved) {
5722 // clang-format off
5723 const char* kErrorSources[] = {
5724 "await;",
5725 "await: ;",
5726 "var await;",
5727 "var [await] = [];",
5728 "var { await } = {};",
5729 "var { x: await } = {};",
5730 "{ var await; }",
5731 "let await;",
5732 "let [await] = [];",
5733 "let { await } = {};",
5734 "let { x: await } = {};",
5735 "{ let await; }",
5736 "const await = null;",
5737 "const [await] = [];",
5738 "const { await } = {};",
5739 "const { x: await } = {};",
5740 "{ const await = null; }",
5741 "function await() {}",
5742 "function f(await) {}",
5743 "function* await() {}",
5744 "function* g(await) {}",
5745 "(function await() {});",
5746 "(function (await) {});",
5747 "(function* await() {});",
5748 "(function* (await) {});",
5749 "(await) => {};",
5750 "await => {};",
5751 "class await {}",
5752 "class C { constructor(await) {} }",
5753 "class C { m(await) {} }",
5754 "class C { static m(await) {} }",
5755 "class C { *m(await) {} }",
5756 "class C { static *m(await) {} }",
5757 "(class await {})",
5758 "(class { constructor(await) {} });",
5759 "(class { m(await) {} });",
5760 "(class { static m(await) {} });",
5761 "(class { *m(await) {} });",
5762 "(class { static *m(await) {} });",
5763 "({ m(await) {} });",
5764 "({ *m(await) {} });",
5765 "({ set p(await) {} });",
5766 "try {} catch (await) {}",
5767 "try {} catch (await) {} finally {}",
5768 NULL
5769 };
5770 // clang-format on
5771 const char* context_data[][2] = {{"", ""}, {NULL, NULL}};
5772
5773 RunModuleParserSyncTest(context_data, kErrorSources, kError);
5774 }
5775
TEST(ModuleAwaitReservedPreParse)5776 TEST(ModuleAwaitReservedPreParse) {
5777 const char* context_data[][2] = {{"", ""}, {NULL, NULL}};
5778 const char* error_data[] = {"function f() { var await = 0; }", NULL};
5779
5780 RunModuleParserSyncTest(context_data, error_data, kError);
5781 }
5782
TEST(ModuleAwaitPermitted)5783 TEST(ModuleAwaitPermitted) {
5784 // clang-format off
5785 const char* kValidSources[] = {
5786 "({}).await;",
5787 "({ await: null });",
5788 "({ await() {} });",
5789 "({ get await() {} });",
5790 "({ set await(x) {} });",
5791 "(class { await() {} });",
5792 "(class { static await() {} });",
5793 "(class { *await() {} });",
5794 "(class { static *await() {} });",
5795 NULL
5796 };
5797 // clang-format on
5798 const char* context_data[][2] = {{"", ""}, {NULL, NULL}};
5799
5800 RunModuleParserSyncTest(context_data, kValidSources, kSuccess);
5801 }
5802
TEST(EnumReserved)5803 TEST(EnumReserved) {
5804 // clang-format off
5805 const char* kErrorSources[] = {
5806 "enum;",
5807 "enum: ;",
5808 "var enum;",
5809 "var [enum] = [];",
5810 "var { enum } = {};",
5811 "var { x: enum } = {};",
5812 "{ var enum; }",
5813 "let enum;",
5814 "let [enum] = [];",
5815 "let { enum } = {};",
5816 "let { x: enum } = {};",
5817 "{ let enum; }",
5818 "const enum = null;",
5819 "const [enum] = [];",
5820 "const { enum } = {};",
5821 "const { x: enum } = {};",
5822 "{ const enum = null; }",
5823 "function enum() {}",
5824 "function f(enum) {}",
5825 "function* enum() {}",
5826 "function* g(enum) {}",
5827 "(function enum() {});",
5828 "(function (enum) {});",
5829 "(function* enum() {});",
5830 "(function* (enum) {});",
5831 "(enum) => {};",
5832 "enum => {};",
5833 "class enum {}",
5834 "class C { constructor(enum) {} }",
5835 "class C { m(enum) {} }",
5836 "class C { static m(enum) {} }",
5837 "class C { *m(enum) {} }",
5838 "class C { static *m(enum) {} }",
5839 "(class enum {})",
5840 "(class { constructor(enum) {} });",
5841 "(class { m(enum) {} });",
5842 "(class { static m(enum) {} });",
5843 "(class { *m(enum) {} });",
5844 "(class { static *m(enum) {} });",
5845 "({ m(enum) {} });",
5846 "({ *m(enum) {} });",
5847 "({ set p(enum) {} });",
5848 "try {} catch (enum) {}",
5849 "try {} catch (enum) {} finally {}",
5850 NULL
5851 };
5852 // clang-format on
5853 const char* context_data[][2] = {{"", ""}, {NULL, NULL}};
5854
5855 RunModuleParserSyncTest(context_data, kErrorSources, kError);
5856 }
5857
TEST(ModuleParsingInternals)5858 TEST(ModuleParsingInternals) {
5859 i::Isolate* isolate = CcTest::i_isolate();
5860 i::Factory* factory = isolate->factory();
5861 v8::HandleScope handles(CcTest::isolate());
5862 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
5863 v8::Context::Scope context_scope(context);
5864 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5865 128 * 1024);
5866
5867 static const char kSource[] =
5868 "let x = 5;"
5869 "export { x as y };"
5870 "import { q as z } from 'm.js';"
5871 "import n from 'n.js';"
5872 "export { a as b } from 'm.js';"
5873 "export * from 'p.js';"
5874 "import 'q.js'";
5875 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(kSource);
5876 i::Handle<i::Script> script = factory->NewScript(source);
5877 i::Zone zone(CcTest::i_isolate()->allocator());
5878 i::ParseInfo info(&zone, script);
5879 i::Parser parser(&info);
5880 info.set_module();
5881 CHECK(parser.Parse(&info));
5882 CHECK(i::Compiler::Analyze(&info));
5883 i::FunctionLiteral* func = info.literal();
5884 i::Scope* module_scope = func->scope();
5885 i::Scope* outer_scope = module_scope->outer_scope();
5886 CHECK(outer_scope->is_script_scope());
5887 CHECK_NULL(outer_scope->outer_scope());
5888 CHECK(module_scope->is_module_scope());
5889 i::ModuleDescriptor* descriptor = module_scope->module();
5890 CHECK_NOT_NULL(descriptor);
5891 CHECK_EQ(1, descriptor->Length());
5892 const i::AstRawString* export_name =
5893 info.ast_value_factory()->GetOneByteString("y");
5894 const i::AstRawString* local_name =
5895 descriptor->LookupLocalExport(export_name, &zone);
5896 CHECK_NOT_NULL(local_name);
5897 CHECK(local_name->IsOneByteEqualTo("x"));
5898 i::ZoneList<i::Declaration*>* declarations = module_scope->declarations();
5899 CHECK_EQ(3, declarations->length());
5900 CHECK(declarations->at(0)->proxy()->raw_name()->IsOneByteEqualTo("x"));
5901 i::ImportDeclaration* import_decl =
5902 declarations->at(1)->AsImportDeclaration();
5903 CHECK(import_decl->import_name()->IsOneByteEqualTo("q"));
5904 CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("z"));
5905 CHECK(import_decl->module_specifier()->IsOneByteEqualTo("m.js"));
5906 import_decl = declarations->at(2)->AsImportDeclaration();
5907 CHECK(import_decl->import_name()->IsOneByteEqualTo("default"));
5908 CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("n"));
5909 CHECK(import_decl->module_specifier()->IsOneByteEqualTo("n.js"));
5910 // TODO(adamk): Add test for indirect exports once they're fully implemented.
5911 // TODO(adamk): Add test for star exports once they're fully implemented.
5912 const i::ZoneList<const i::AstRawString*>& requested_modules =
5913 descriptor->requested_modules();
5914 CHECK_EQ(4, requested_modules.length());
5915 CHECK(requested_modules[0]->IsOneByteEqualTo("m.js"));
5916 CHECK(requested_modules[1]->IsOneByteEqualTo("n.js"));
5917 CHECK(requested_modules[2]->IsOneByteEqualTo("p.js"));
5918 CHECK(requested_modules[3]->IsOneByteEqualTo("q.js"));
5919 }
5920
5921
TEST(DuplicateProtoError)5922 TEST(DuplicateProtoError) {
5923 const char* context_data[][2] = {
5924 {"({", "});"},
5925 {"'use strict'; ({", "});"},
5926 {NULL, NULL}
5927 };
5928 const char* error_data[] = {
5929 "__proto__: {}, __proto__: {}",
5930 "__proto__: {}, \"__proto__\": {}",
5931 "__proto__: {}, \"__\x70roto__\": {}",
5932 "__proto__: {}, a: 1, __proto__: {}",
5933 NULL
5934 };
5935
5936 RunParserSyncTest(context_data, error_data, kError);
5937 }
5938
5939
TEST(DuplicateProtoNoError)5940 TEST(DuplicateProtoNoError) {
5941 const char* context_data[][2] = {
5942 {"({", "});"},
5943 {"'use strict'; ({", "});"},
5944 {NULL, NULL}
5945 };
5946 const char* error_data[] = {
5947 "__proto__: {}, ['__proto__']: {}",
5948 "__proto__: {}, __proto__() {}",
5949 "__proto__: {}, get __proto__() {}",
5950 "__proto__: {}, set __proto__(v) {}",
5951 "__proto__: {}, __proto__",
5952 NULL
5953 };
5954
5955 RunParserSyncTest(context_data, error_data, kSuccess);
5956 }
5957
5958
TEST(DeclarationsError)5959 TEST(DeclarationsError) {
5960 const char* context_data[][2] = {{"'use strict'; if (true)", ""},
5961 {"'use strict'; if (false) {} else", ""},
5962 {"'use strict'; while (false)", ""},
5963 {"'use strict'; for (;;)", ""},
5964 {"'use strict'; for (x in y)", ""},
5965 {"'use strict'; do ", " while (false)"},
5966 {NULL, NULL}};
5967
5968 const char* statement_data[] = {
5969 "let x = 1;",
5970 "const x = 1;",
5971 "class C {}",
5972 NULL};
5973
5974 RunParserSyncTest(context_data, statement_data, kError);
5975 }
5976
5977
TestLanguageMode(const char * source,i::LanguageMode expected_language_mode)5978 void TestLanguageMode(const char* source,
5979 i::LanguageMode expected_language_mode) {
5980 i::Isolate* isolate = CcTest::i_isolate();
5981 i::Factory* factory = isolate->factory();
5982 v8::HandleScope handles(CcTest::isolate());
5983 v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
5984 v8::Context::Scope context_scope(context);
5985 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5986 128 * 1024);
5987
5988 i::Handle<i::Script> script =
5989 factory->NewScript(factory->NewStringFromAsciiChecked(source));
5990 i::Zone zone(CcTest::i_isolate()->allocator());
5991 i::ParseInfo info(&zone, script);
5992 i::Parser parser(&info);
5993 info.set_global();
5994 parser.Parse(&info);
5995 CHECK(info.literal() != NULL);
5996 CHECK_EQ(expected_language_mode, info.literal()->language_mode());
5997 }
5998
5999
TEST(LanguageModeDirectives)6000 TEST(LanguageModeDirectives) {
6001 TestLanguageMode("\"use nothing\"", i::SLOPPY);
6002 TestLanguageMode("\"use strict\"", i::STRICT);
6003
6004 TestLanguageMode("var x = 1; \"use strict\"", i::SLOPPY);
6005
6006 TestLanguageMode("\"use some future directive\"; \"use strict\";", i::STRICT);
6007 }
6008
6009
TEST(PropertyNameEvalArguments)6010 TEST(PropertyNameEvalArguments) {
6011 const char* context_data[][2] = {{"'use strict';", ""},
6012 {NULL, NULL}};
6013
6014 const char* statement_data[] = {
6015 "({eval: 1})",
6016 "({arguments: 1})",
6017 "({eval() {}})",
6018 "({arguments() {}})",
6019 "({*eval() {}})",
6020 "({*arguments() {}})",
6021 "({get eval() {}})",
6022 "({get arguments() {}})",
6023 "({set eval(_) {}})",
6024 "({set arguments(_) {}})",
6025
6026 "class C {eval() {}}",
6027 "class C {arguments() {}}",
6028 "class C {*eval() {}}",
6029 "class C {*arguments() {}}",
6030 "class C {get eval() {}}",
6031 "class C {get arguments() {}}",
6032 "class C {set eval(_) {}}",
6033 "class C {set arguments(_) {}}",
6034
6035 "class C {static eval() {}}",
6036 "class C {static arguments() {}}",
6037 "class C {static *eval() {}}",
6038 "class C {static *arguments() {}}",
6039 "class C {static get eval() {}}",
6040 "class C {static get arguments() {}}",
6041 "class C {static set eval(_) {}}",
6042 "class C {static set arguments(_) {}}",
6043
6044 NULL};
6045
6046 RunParserSyncTest(context_data, statement_data, kSuccess);
6047 }
6048
6049
TEST(FunctionLiteralDuplicateParameters)6050 TEST(FunctionLiteralDuplicateParameters) {
6051 const char* strict_context_data[][2] =
6052 {{"'use strict';(function(", "){})();"},
6053 {"(function(", ") { 'use strict'; })();"},
6054 {"'use strict'; function fn(", ") {}; fn();"},
6055 {"function fn(", ") { 'use strict'; }; fn();"},
6056 {NULL, NULL}};
6057
6058 const char* sloppy_context_data[][2] =
6059 {{"(function(", "){})();"},
6060 {"(function(", ") {})();"},
6061 {"function fn(", ") {}; fn();"},
6062 {"function fn(", ") {}; fn();"},
6063 {NULL, NULL}};
6064
6065 const char* data[] = {
6066 "a, a",
6067 "a, a, a",
6068 "b, a, a",
6069 "a, b, c, c",
6070 "a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, w",
6071 NULL};
6072
6073 RunParserSyncTest(strict_context_data, data, kError);
6074 RunParserSyncTest(sloppy_context_data, data, kSuccess);
6075 }
6076
6077
TEST(ArrowFunctionASIErrors)6078 TEST(ArrowFunctionASIErrors) {
6079 const char* context_data[][2] = {{"'use strict';", ""}, {"", ""},
6080 {NULL, NULL}};
6081
6082 const char* data[] = {
6083 "(a\n=> a)(1)",
6084 "(a/*\n*/=> a)(1)",
6085 "((a)\n=> a)(1)",
6086 "((a)/*\n*/=> a)(1)",
6087 "((a, b)\n=> a + b)(1, 2)",
6088 "((a, b)/*\n*/=> a + b)(1, 2)",
6089 NULL};
6090 RunParserSyncTest(context_data, data, kError);
6091 }
6092
6093
TEST(DestructuringPositiveTests)6094 TEST(DestructuringPositiveTests) {
6095 const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
6096 {"var ", " = {};"},
6097 {"'use strict'; const ", " = {};"},
6098 {"function f(", ") {}"},
6099 {"function f(argument1, ", ") {}"},
6100 {"var f = (", ") => {};"},
6101 {"var f = (argument1,", ") => {};"},
6102 {"try {} catch(", ") {}"},
6103 {NULL, NULL}};
6104
6105 // clang-format off
6106 const char* data[] = {
6107 "a",
6108 "{ x : y }",
6109 "{ x : y = 1 }",
6110 "{ get, set }",
6111 "{ get = 1, set = 2 }",
6112 "[a]",
6113 "[a = 1]",
6114 "[a,b,c]",
6115 "[a, b = 42, c]",
6116 "{ x : x, y : y }",
6117 "{ x : x = 1, y : y }",
6118 "{ x : x, y : y = 42 }",
6119 "[]",
6120 "{}",
6121 "[{x:x, y:y}, [a,b,c]]",
6122 "[{x:x = 1, y:y = 2}, [a = 3, b = 4, c = 5]]",
6123 "{x}",
6124 "{x, y}",
6125 "{x = 42, y = 15}",
6126 "[a,,b]",
6127 "{42 : x}",
6128 "{42 : x = 42}",
6129 "{42e-2 : x}",
6130 "{42e-2 : x = 42}",
6131 "{x : y, x : z}",
6132 "{'hi' : x}",
6133 "{'hi' : x = 42}",
6134 "{var: x}",
6135 "{var: x = 42}",
6136 "{[x] : z}",
6137 "{[1+1] : z}",
6138 "{[foo()] : z}",
6139 "{}",
6140 "[...rest]",
6141 "[a,b,...rest]",
6142 "[a,,...rest]",
6143 NULL};
6144 // clang-format on
6145 RunParserSyncTest(context_data, data, kSuccess);
6146 }
6147
6148
TEST(DestructuringNegativeTests)6149 TEST(DestructuringNegativeTests) {
6150 { // All modes.
6151 const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
6152 {"var ", " = {};"},
6153 {"'use strict'; const ", " = {};"},
6154 {"function f(", ") {}"},
6155 {"function f(argument1, ", ") {}"},
6156 {"var f = (", ") => {};"},
6157 {"var f = ", " => {};"},
6158 {"var f = (argument1,", ") => {};"},
6159 {"try {} catch(", ") {}"},
6160 {NULL, NULL}};
6161
6162 // clang-format off
6163 const char* data[] = {
6164 "a++",
6165 "++a",
6166 "delete a",
6167 "void a",
6168 "typeof a",
6169 "--a",
6170 "+a",
6171 "-a",
6172 "~a",
6173 "!a",
6174 "{ x : y++ }",
6175 "[a++]",
6176 "(x => y)",
6177 "a[i]", "a()",
6178 "a.b",
6179 "new a",
6180 "a + a",
6181 "a - a",
6182 "a * a",
6183 "a / a",
6184 "a == a",
6185 "a != a",
6186 "a > a",
6187 "a < a",
6188 "a <<< a",
6189 "a >>> a",
6190 "function a() {}",
6191 "a`bcd`",
6192 "this",
6193 "null",
6194 "true",
6195 "false",
6196 "1",
6197 "'abc'",
6198 "/abc/",
6199 "`abc`",
6200 "class {}",
6201 "{+2 : x}",
6202 "{-2 : x}",
6203 "var",
6204 "[var]",
6205 "{x : {y : var}}",
6206 "{x : x = a+}",
6207 "{x : x = (a+)}",
6208 "{x : x += a}",
6209 "{m() {} = 0}",
6210 "{[1+1]}",
6211 "[...rest, x]",
6212 "[a,b,...rest, x]",
6213 "[a,,...rest, x]",
6214 "[...rest,]",
6215 "[a,b,...rest,]",
6216 "[a,,...rest,]",
6217 "[...rest,...rest1]",
6218 "[a,b,...rest,...rest1]",
6219 "[a,,..rest,...rest1]",
6220 "[x, y, ...z = 1]",
6221 "[...z = 1]",
6222 "[x, y, ...[z] = [1]]",
6223 "[...[z] = [1]]",
6224 "{ x : 3 }",
6225 "{ x : 'foo' }",
6226 "{ x : /foo/ }",
6227 "{ x : `foo` }",
6228 "{ get a() {} }",
6229 "{ set a() {} }",
6230 "{ method() {} }",
6231 "{ *method() {} }",
6232 NULL};
6233 // clang-format on
6234 RunParserSyncTest(context_data, data, kError);
6235 }
6236
6237 { // All modes.
6238 const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
6239 {"var ", " = {};"},
6240 {"'use strict'; const ", " = {};"},
6241 {"function f(", ") {}"},
6242 {"function f(argument1, ", ") {}"},
6243 {"var f = (", ") => {};"},
6244 {"var f = (argument1,", ") => {};"},
6245 {NULL, NULL}};
6246
6247 // clang-format off
6248 const char* data[] = {
6249 "x => x",
6250 "() => x",
6251 NULL};
6252 // clang-format on
6253 RunParserSyncTest(context_data, data, kError);
6254 }
6255
6256 { // Strict mode.
6257 const char* context_data[][2] = {
6258 {"'use strict'; let ", " = {};"},
6259 {"'use strict'; const ", " = {};"},
6260 {"'use strict'; function f(", ") {}"},
6261 {"'use strict'; function f(argument1, ", ") {}"},
6262 {NULL, NULL}};
6263
6264 // clang-format off
6265 const char* data[] = {
6266 "[eval]",
6267 "{ a : arguments }",
6268 "[public]",
6269 "{ x : private }",
6270 NULL};
6271 // clang-format on
6272 RunParserSyncTest(context_data, data, kError);
6273 }
6274
6275 { // 'yield' in generators.
6276 const char* context_data[][2] = {
6277 {"function*() { var ", " = {};"},
6278 {"function*() { 'use strict'; let ", " = {};"},
6279 {"function*() { 'use strict'; const ", " = {};"},
6280 {NULL, NULL}};
6281
6282 // clang-format off
6283 const char* data[] = {
6284 "yield",
6285 "[yield]",
6286 "{ x : yield }",
6287 NULL};
6288 // clang-format on
6289 RunParserSyncTest(context_data, data, kError);
6290 }
6291
6292 { // Declaration-specific errors
6293 const char* context_data[][2] = {{"'use strict'; var ", ""},
6294 {"'use strict'; let ", ""},
6295 {"'use strict'; const ", ""},
6296 {"'use strict'; for (var ", ";;) {}"},
6297 {"'use strict'; for (let ", ";;) {}"},
6298 {"'use strict'; for (const ", ";;) {}"},
6299 {"var ", ""},
6300 {"let ", ""},
6301 {"const ", ""},
6302 {"for (var ", ";;) {}"},
6303 {"for (let ", ";;) {}"},
6304 {"for (const ", ";;) {}"},
6305 {NULL, NULL}};
6306
6307 // clang-format off
6308 const char* data[] = {
6309 "{ a }",
6310 "[ a ]",
6311 NULL};
6312 // clang-format on
6313 RunParserSyncTest(context_data, data, kError);
6314 }
6315 }
6316
6317
TEST(DestructuringAssignmentPositiveTests)6318 TEST(DestructuringAssignmentPositiveTests) {
6319 const char* context_data[][2] = {
6320 {"'use strict'; let x, y, z; (", " = {});"},
6321 {"var x, y, z; (", " = {});"},
6322 {"'use strict'; let x, y, z; for (x in ", " = {});"},
6323 {"'use strict'; let x, y, z; for (x of ", " = {});"},
6324 {"var x, y, z; for (x in ", " = {});"},
6325 {"var x, y, z; for (x of ", " = {});"},
6326 {"var x, y, z; for (", " in {});"},
6327 {"var x, y, z; for (", " of {});"},
6328 {"'use strict'; var x, y, z; for (", " in {});"},
6329 {"'use strict'; var x, y, z; for (", " of {});"},
6330 {NULL, NULL}};
6331
6332 const char* mixed_assignments_context_data[][2] = {
6333 {"'use strict'; let x, y, z; (", " = z = {});"},
6334 {"var x, y, z; (", " = z = {});"},
6335 {"'use strict'; let x, y, z; (x = ", " = z = {});"},
6336 {"var x, y, z; (x = ", " = z = {});"},
6337 {"'use strict'; let x, y, z; for (x in ", " = z = {});"},
6338 {"'use strict'; let x, y, z; for (x in x = ", " = z = {});"},
6339 {"'use strict'; let x, y, z; for (x of ", " = z = {});"},
6340 {"'use strict'; let x, y, z; for (x of x = ", " = z = {});"},
6341 {"var x, y, z; for (x in ", " = z = {});"},
6342 {"var x, y, z; for (x in x = ", " = z = {});"},
6343 {"var x, y, z; for (x of ", " = z = {});"},
6344 {"var x, y, z; for (x of x = ", " = z = {});"},
6345 {NULL, NULL}};
6346
6347 // clang-format off
6348 const char* data[] = {
6349 "x",
6350
6351 "{ x : y }",
6352 "{ x : foo().y }",
6353 "{ x : foo()[y] }",
6354 "{ x : y.z }",
6355 "{ x : y[z] }",
6356 "{ x : { y } }",
6357 "{ x : { foo: y } }",
6358 "{ x : { foo: foo().y } }",
6359 "{ x : { foo: foo()[y] } }",
6360 "{ x : { foo: y.z } }",
6361 "{ x : { foo: y[z] } }",
6362 "{ x : [ y ] }",
6363 "{ x : [ foo().y ] }",
6364 "{ x : [ foo()[y] ] }",
6365 "{ x : [ y.z ] }",
6366 "{ x : [ y[z] ] }",
6367
6368 "{ x : y = 10 }",
6369 "{ x : foo().y = 10 }",
6370 "{ x : foo()[y] = 10 }",
6371 "{ x : y.z = 10 }",
6372 "{ x : y[z] = 10 }",
6373 "{ x : { y = 10 } = {} }",
6374 "{ x : { foo: y = 10 } = {} }",
6375 "{ x : { foo: foo().y = 10 } = {} }",
6376 "{ x : { foo: foo()[y] = 10 } = {} }",
6377 "{ x : { foo: y.z = 10 } = {} }",
6378 "{ x : { foo: y[z] = 10 } = {} }",
6379 "{ x : [ y = 10 ] = {} }",
6380 "{ x : [ foo().y = 10 ] = {} }",
6381 "{ x : [ foo()[y] = 10 ] = {} }",
6382 "{ x : [ y.z = 10 ] = {} }",
6383 "{ x : [ y[z] = 10 ] = {} }",
6384
6385 "[ x ]",
6386 "[ foo().x ]",
6387 "[ foo()[x] ]",
6388 "[ x.y ]",
6389 "[ x[y] ]",
6390 "[ { x } ]",
6391 "[ { x : y } ]",
6392 "[ { x : foo().y } ]",
6393 "[ { x : foo()[y] } ]",
6394 "[ { x : x.y } ]",
6395 "[ { x : x[y] } ]",
6396 "[ [ x ] ]",
6397 "[ [ foo().x ] ]",
6398 "[ [ foo()[x] ] ]",
6399 "[ [ x.y ] ]",
6400 "[ [ x[y] ] ]",
6401
6402 "[ x = 10 ]",
6403 "[ foo().x = 10 ]",
6404 "[ foo()[x] = 10 ]",
6405 "[ x.y = 10 ]",
6406 "[ x[y] = 10 ]",
6407 "[ { x = 10 } = {} ]",
6408 "[ { x : y = 10 } = {} ]",
6409 "[ { x : foo().y = 10 } = {} ]",
6410 "[ { x : foo()[y] = 10 } = {} ]",
6411 "[ { x : x.y = 10 } = {} ]",
6412 "[ { x : x[y] = 10 } = {} ]",
6413 "[ [ x = 10 ] = {} ]",
6414 "[ [ foo().x = 10 ] = {} ]",
6415 "[ [ foo()[x] = 10 ] = {} ]",
6416 "[ [ x.y = 10 ] = {} ]",
6417 "[ [ x[y] = 10 ] = {} ]",
6418 "{ x : y = 1 }",
6419 "{ x }",
6420 "{ x, y, z }",
6421 "{ x = 1, y: z, z: y }",
6422 "{x = 42, y = 15}",
6423 "[x]",
6424 "[x = 1]",
6425 "[x,y,z]",
6426 "[x, y = 42, z]",
6427 "{ x : x, y : y }",
6428 "{ x : x = 1, y : y }",
6429 "{ x : x, y : y = 42 }",
6430 "[]",
6431 "{}",
6432 "[{x:x, y:y}, [,x,z,]]",
6433 "[{x:x = 1, y:y = 2}, [z = 3, z = 4, z = 5]]",
6434 "[x,,y]",
6435 "[(x),,(y)]",
6436 "[(x)]",
6437 "{42 : x}",
6438 "{42 : x = 42}",
6439 "{42e-2 : x}",
6440 "{42e-2 : x = 42}",
6441 "{'hi' : x}",
6442 "{'hi' : x = 42}",
6443 "{var: x}",
6444 "{var: x = 42}",
6445 "{var: (x) = 42}",
6446 "{[x] : z}",
6447 "{[1+1] : z}",
6448 "{[1+1] : (z)}",
6449 "{[foo()] : z}",
6450 "{[foo()] : (z)}",
6451 "{[foo()] : foo().bar}",
6452 "{[foo()] : foo()['bar']}",
6453 "{[foo()] : this.bar}",
6454 "{[foo()] : this['bar']}",
6455 "{[foo()] : 'foo'.bar}",
6456 "{[foo()] : 'foo'['bar']}",
6457 "[...x]",
6458 "[x,y,...z]",
6459 "[x,,...z]",
6460 "{ x: y }",
6461 "[x, y]",
6462 "[((x, y) => z).x]",
6463 "{x: ((y, z) => z).x}",
6464 "[((x, y) => z)['x']]",
6465 "{x: ((y, z) => z)['x']}",
6466
6467 "{x: { y = 10 } }",
6468 "[(({ x } = { x: 1 }) => x).a]",
6469
6470 // v8:4662
6471 "{ x: (y) }",
6472 "{ x: (y) = [] }",
6473 "{ x: (foo.bar) }",
6474 "{ x: (foo['bar']) }",
6475 "[ ...(a) ]",
6476 "[ ...(foo['bar']) ]",
6477 "[ ...(foo.bar) ]",
6478 "[ (y) ]",
6479 "[ (foo.bar) ]",
6480 "[ (foo['bar']) ]",
6481
6482 NULL};
6483 // clang-format on
6484 RunParserSyncTest(context_data, data, kSuccess);
6485
6486 RunParserSyncTest(mixed_assignments_context_data, data, kSuccess);
6487
6488 const char* empty_context_data[][2] = {
6489 {"'use strict';", ""}, {"", ""}, {NULL, NULL}};
6490
6491 // CoverInitializedName ambiguity handling in various contexts
6492 const char* ambiguity_data[] = {
6493 "var foo = { x = 10 } = {};",
6494 "var foo = { q } = { x = 10 } = {};",
6495 "var foo; foo = { x = 10 } = {};",
6496 "var foo; foo = { q } = { x = 10 } = {};",
6497 "var x; ({ x = 10 } = {});",
6498 "var q, x; ({ q } = { x = 10 } = {});",
6499 "var x; [{ x = 10 } = {}]",
6500 "var x; (true ? { x = true } = {} : { x = false } = {})",
6501 "var q, x; (q, { x = 10 } = {});",
6502 "var { x = 10 } = { x = 20 } = {};",
6503 "var { x = 10 } = (o = { x = 20 } = {});",
6504 "var x; (({ x = 10 } = { x = 20 } = {}) => x)({})",
6505 NULL,
6506 };
6507 RunParserSyncTest(empty_context_data, ambiguity_data, kSuccess);
6508 }
6509
6510
TEST(DestructuringAssignmentNegativeTests)6511 TEST(DestructuringAssignmentNegativeTests) {
6512 const char* context_data[][2] = {
6513 {"'use strict'; let x, y, z; (", " = {});"},
6514 {"var x, y, z; (", " = {});"},
6515 {"'use strict'; let x, y, z; for (x in ", " = {});"},
6516 {"'use strict'; let x, y, z; for (x of ", " = {});"},
6517 {"var x, y, z; for (x in ", " = {});"},
6518 {"var x, y, z; for (x of ", " = {});"},
6519 {NULL, NULL}};
6520
6521 // clang-format off
6522 const char* data[] = {
6523 "{ x : ++y }",
6524 "{ x : y * 2 }",
6525 "{ ...x }",
6526 "{ get x() {} }",
6527 "{ set x() {} }",
6528 "{ x: y() }",
6529 "{ this }",
6530 "{ x: this }",
6531 "{ x: this = 1 }",
6532 "{ super }",
6533 "{ x: super }",
6534 "{ x: super = 1 }",
6535 "{ new.target }",
6536 "{ x: new.target }",
6537 "{ x: new.target = 1 }",
6538 "[x--]",
6539 "[--x = 1]",
6540 "[x()]",
6541 "[this]",
6542 "[this = 1]",
6543 "[new.target]",
6544 "[new.target = 1]",
6545 "[super]",
6546 "[super = 1]",
6547 "[function f() {}]",
6548 "[50]",
6549 "[(50)]",
6550 "[(function() {})]",
6551 "[(foo())]",
6552 "{ x: 50 }",
6553 "{ x: (50) }",
6554 "['str']",
6555 "{ x: 'str' }",
6556 "{ x: ('str') }",
6557 "{ x: (foo()) }",
6558 "{ x: (function() {}) }",
6559 "{ x: y } = 'str'",
6560 "[x, y] = 'str'",
6561 "[(x,y) => z]",
6562 "{x: (y) => z}",
6563 "[x, ...y, z]",
6564 "[...x,]",
6565 "[x, y, ...z = 1]",
6566 "[...z = 1]",
6567 "[x, y, ...[z] = [1]]",
6568 "[...[z] = [1]]",
6569
6570 // v8:4657
6571 "({ x: x4, x: (x+=1e4) })",
6572 "(({ x: x4, x: (x+=1e4) }))",
6573 "({ x: x4, x: (x+=1e4) } = {})",
6574 "(({ x: x4, x: (x+=1e4) } = {}))",
6575 "(({ x: x4, x: (x+=1e4) }) = {})",
6576 "({ x: y } = {})",
6577 "(({ x: y } = {}))",
6578 "(({ x: y }) = {})",
6579 "([a])",
6580 "(([a]))",
6581 "([a] = [])",
6582 "(([a] = []))",
6583 "(([a]) = [])",
6584
6585 // v8:4662
6586 "{ x: ([y]) }",
6587 "{ x: ([y] = []) }",
6588 "{ x: ({y}) }",
6589 "{ x: ({y} = {}) }",
6590 "{ x: (++y) }",
6591 "[ (...[a]) ]",
6592 "[ ...([a]) ]",
6593 "[ ...([a] = [])",
6594 "[ ...[ ( [ a ] ) ] ]",
6595 "[ ([a]) ]",
6596 "[ (...[a]) ]",
6597 "[ ([a] = []) ]",
6598 "[ (++y) ]",
6599 "[ ...(++y) ]",
6600
6601 "[ x += x ]",
6602 "{ foo: x += x }",
6603
6604 NULL};
6605 // clang-format on
6606 RunParserSyncTest(context_data, data, kError);
6607
6608 const char* empty_context_data[][2] = {
6609 {"'use strict';", ""}, {"", ""}, {NULL, NULL}};
6610
6611 // CoverInitializedName ambiguity handling in various contexts
6612 const char* ambiguity_data[] = {
6613 "var foo = { x = 10 };",
6614 "var foo = { q } = { x = 10 };",
6615 "var foo; foo = { x = 10 };",
6616 "var foo; foo = { q } = { x = 10 };",
6617 "var x; ({ x = 10 });",
6618 "var q, x; ({ q } = { x = 10 });",
6619 "var x; [{ x = 10 }]",
6620 "var x; (true ? { x = true } : { x = false })",
6621 "var q, x; (q, { x = 10 });",
6622 "var { x = 10 } = { x = 20 };",
6623 "var { x = 10 } = (o = { x = 20 });",
6624 "var x; (({ x = 10 } = { x = 20 }) => x)({})",
6625
6626 // Not ambiguous, but uses same context data
6627 "switch([window %= []] = []) { default: }",
6628
6629 NULL,
6630 };
6631 RunParserSyncTest(empty_context_data, ambiguity_data, kError);
6632
6633 // Strict mode errors
6634 const char* strict_context_data[][2] = {{"'use strict'; (", " = {})"},
6635 {"'use strict'; for (", " of {}) {}"},
6636 {"'use strict'; for (", " in {}) {}"},
6637 {NULL, NULL}};
6638 const char* strict_data[] = {"{ eval }",
6639 "{ arguments }",
6640 "{ foo: eval }",
6641 "{ foo: arguments }",
6642 "{ eval = 0 }",
6643 "{ arguments = 0 }",
6644 "{ foo: eval = 0 }",
6645 "{ foo: arguments = 0 }",
6646 "[ eval ]",
6647 "[ arguments ]",
6648 "[ eval = 0 ]",
6649 "[ arguments = 0 ]",
6650
6651 // v8:4662
6652 "{ x: (eval) }",
6653 "{ x: (arguments) }",
6654 "{ x: (eval = 0) }",
6655 "{ x: (arguments = 0) }",
6656 "{ x: (eval) = 0 }",
6657 "{ x: (arguments) = 0 }",
6658 "[ (eval) ]",
6659 "[ (arguments) ]",
6660 "[ (eval = 0) ]",
6661 "[ (arguments = 0) ]",
6662 "[ (eval) = 0 ]",
6663 "[ (arguments) = 0 ]",
6664 "[ ...(eval) ]",
6665 "[ ...(arguments) ]",
6666 "[ ...(eval = 0) ]",
6667 "[ ...(arguments = 0) ]",
6668 "[ ...(eval) = 0 ]",
6669 "[ ...(arguments) = 0 ]",
6670
6671 NULL};
6672 RunParserSyncTest(strict_context_data, strict_data, kError);
6673 }
6674
6675
TEST(DestructuringDisallowPatternsInForVarIn)6676 TEST(DestructuringDisallowPatternsInForVarIn) {
6677 const char* context_data[][2] = {
6678 {"", ""}, {"function f() {", "}"}, {NULL, NULL}};
6679 // clang-format off
6680 const char* error_data[] = {
6681 "for (let x = {} in null);",
6682 "for (let x = {} of null);",
6683 NULL};
6684 // clang-format on
6685 RunParserSyncTest(context_data, error_data, kError);
6686
6687 // clang-format off
6688 const char* success_data[] = {
6689 "for (var x = {} in null);",
6690 NULL};
6691 // clang-format on
6692 RunParserSyncTest(context_data, success_data, kSuccess);
6693 }
6694
6695
TEST(DestructuringDuplicateParams)6696 TEST(DestructuringDuplicateParams) {
6697 const char* context_data[][2] = {{"'use strict';", ""},
6698 {"function outer() { 'use strict';", "}"},
6699 {nullptr, nullptr}};
6700
6701
6702 // clang-format off
6703 const char* error_data[] = {
6704 "function f(x,x){}",
6705 "function f(x, {x : x}){}",
6706 "function f(x, {x}){}",
6707 "function f({x,x}) {}",
6708 "function f([x,x]) {}",
6709 "function f(x, [y,{z:x}]) {}",
6710 "function f([x,{y:x}]) {}",
6711 // non-simple parameter list causes duplicates to be errors in sloppy mode.
6712 "function f(x, x, {a}) {}",
6713 nullptr};
6714 // clang-format on
6715 RunParserSyncTest(context_data, error_data, kError);
6716 }
6717
6718
TEST(DestructuringDuplicateParamsSloppy)6719 TEST(DestructuringDuplicateParamsSloppy) {
6720 const char* context_data[][2] = {
6721 {"", ""}, {"function outer() {", "}"}, {nullptr, nullptr}};
6722
6723
6724 // clang-format off
6725 const char* error_data[] = {
6726 // non-simple parameter list causes duplicates to be errors in sloppy mode.
6727 "function f(x, {x : x}){}",
6728 "function f(x, {x}){}",
6729 "function f({x,x}) {}",
6730 "function f(x, x, {a}) {}",
6731 nullptr};
6732 // clang-format on
6733 RunParserSyncTest(context_data, error_data, kError);
6734 }
6735
6736
TEST(DestructuringDisallowPatternsInSingleParamArrows)6737 TEST(DestructuringDisallowPatternsInSingleParamArrows) {
6738 const char* context_data[][2] = {{"'use strict';", ""},
6739 {"function outer() { 'use strict';", "}"},
6740 {"", ""},
6741 {"function outer() { ", "}"},
6742 {nullptr, nullptr}};
6743
6744 // clang-format off
6745 const char* error_data[] = {
6746 "var f = {x} => {};",
6747 "var f = {x,y} => {};",
6748 nullptr};
6749 // clang-format on
6750 RunParserSyncTest(context_data, error_data, kError);
6751 }
6752
6753
TEST(DefaultParametersYieldInInitializers)6754 TEST(DefaultParametersYieldInInitializers) {
6755 // clang-format off
6756 const char* sloppy_function_context_data[][2] = {
6757 {"(function f(", ") { });"},
6758 {NULL, NULL}
6759 };
6760
6761 const char* strict_function_context_data[][2] = {
6762 {"'use strict'; (function f(", ") { });"},
6763 {NULL, NULL}
6764 };
6765
6766 const char* sloppy_arrow_context_data[][2] = {
6767 {"((", ")=>{});"},
6768 {NULL, NULL}
6769 };
6770
6771 const char* strict_arrow_context_data[][2] = {
6772 {"'use strict'; ((", ")=>{});"},
6773 {NULL, NULL}
6774 };
6775
6776 const char* generator_context_data[][2] = {
6777 {"'use strict'; (function *g(", ") { });"},
6778 {"(function *g(", ") { });"},
6779 // Arrow function within generator has the same rules.
6780 {"'use strict'; (function *g() { (", ") => {} });"},
6781 {"(function *g() { (", ") => {} });"},
6782 // And similarly for arrow functions in the parameter list.
6783 {"'use strict'; (function *g(z = (", ") => {}) { });"},
6784 {"(function *g(z = (", ") => {}) { });"},
6785 {NULL, NULL}
6786 };
6787
6788 const char* parameter_data[] = {
6789 "x=yield",
6790 "x, y=yield",
6791 "{x=yield}",
6792 "[x=yield]",
6793
6794 "x=(yield)",
6795 "x, y=(yield)",
6796 "{x=(yield)}",
6797 "[x=(yield)]",
6798
6799 "x=f(yield)",
6800 "x, y=f(yield)",
6801 "{x=f(yield)}",
6802 "[x=f(yield)]",
6803
6804 "{x}=yield",
6805 "[x]=yield",
6806
6807 "{x}=(yield)",
6808 "[x]=(yield)",
6809
6810 "{x}=f(yield)",
6811 "[x]=f(yield)",
6812 NULL
6813 };
6814
6815 // Because classes are always in strict mode, these are always errors.
6816 const char* always_error_param_data[] = {
6817 "x = class extends (yield) { }",
6818 "x = class extends f(yield) { }",
6819 "x = class extends (null, yield) { }",
6820 "x = class extends (a ? null : yield) { }",
6821 "[x] = [class extends (a ? null : yield) { }]",
6822 "[x = class extends (a ? null : yield) { }]",
6823 "[x = class extends (a ? null : yield) { }] = [null]",
6824 "x = class { [yield]() { } }",
6825 "x = class { static [yield]() { } }",
6826 "x = class { [(yield, 1)]() { } }",
6827 "x = class { [y = (yield, 1)]() { } }",
6828 NULL
6829 };
6830 // clang-format on
6831
6832 RunParserSyncTest(sloppy_function_context_data, parameter_data, kSuccess);
6833 RunParserSyncTest(sloppy_arrow_context_data, parameter_data, kSuccess);
6834
6835 RunParserSyncTest(strict_function_context_data, parameter_data, kError);
6836 RunParserSyncTest(strict_arrow_context_data, parameter_data, kError);
6837
6838 RunParserSyncTest(generator_context_data, parameter_data, kError);
6839 RunParserSyncTest(generator_context_data, always_error_param_data, kError);
6840 }
6841
TEST(SpreadArray)6842 TEST(SpreadArray) {
6843 const char* context_data[][2] = {
6844 {"'use strict';", ""}, {"", ""}, {NULL, NULL}};
6845
6846 // clang-format off
6847 const char* data[] = {
6848 "[...a]",
6849 "[a, ...b]",
6850 "[...a,]",
6851 "[...a, ,]",
6852 "[, ...a]",
6853 "[...a, ...b]",
6854 "[...a, , ...b]",
6855 "[...[...a]]",
6856 "[, ...a]",
6857 "[, , ...a]",
6858 NULL};
6859 // clang-format on
6860 RunParserSyncTest(context_data, data, kSuccess);
6861 }
6862
6863
TEST(SpreadArrayError)6864 TEST(SpreadArrayError) {
6865 const char* context_data[][2] = {
6866 {"'use strict';", ""}, {"", ""}, {NULL, NULL}};
6867
6868 // clang-format off
6869 const char* data[] = {
6870 "[...]",
6871 "[a, ...]",
6872 "[..., ]",
6873 "[..., ...]",
6874 "[ (...a)]",
6875 NULL};
6876 // clang-format on
6877 RunParserSyncTest(context_data, data, kError);
6878 }
6879
6880
TEST(NewTarget)6881 TEST(NewTarget) {
6882 // clang-format off
6883 const char* good_context_data[][2] = {
6884 {"function f() {", "}"},
6885 {"'use strict'; function f() {", "}"},
6886 {"var f = function() {", "}"},
6887 {"'use strict'; var f = function() {", "}"},
6888 {"({m: function() {", "}})"},
6889 {"'use strict'; ({m: function() {", "}})"},
6890 {"({m() {", "}})"},
6891 {"'use strict'; ({m() {", "}})"},
6892 {"({get x() {", "}})"},
6893 {"'use strict'; ({get x() {", "}})"},
6894 {"({set x(_) {", "}})"},
6895 {"'use strict'; ({set x(_) {", "}})"},
6896 {"class C {m() {", "}}"},
6897 {"class C {get x() {", "}}"},
6898 {"class C {set x(_) {", "}}"},
6899 {NULL}
6900 };
6901
6902 const char* bad_context_data[][2] = {
6903 {"", ""},
6904 {"'use strict';", ""},
6905 {NULL}
6906 };
6907
6908 const char* data[] = {
6909 "new.target",
6910 "{ new.target }",
6911 "() => { new.target }",
6912 "() => new.target",
6913 "if (1) { new.target }",
6914 "if (1) {} else { new.target }",
6915 "while (0) { new.target }",
6916 "do { new.target } while (0)",
6917 NULL
6918 };
6919
6920 // clang-format on
6921
6922 RunParserSyncTest(good_context_data, data, kSuccess);
6923 RunParserSyncTest(bad_context_data, data, kError);
6924 }
6925
6926
TEST(ConstSloppy)6927 TEST(ConstSloppy) {
6928 // clang-format off
6929 const char* context_data[][2] = {
6930 {"", ""},
6931 {"{", "}"},
6932 {NULL, NULL}
6933 };
6934
6935 const char* data[] = {
6936 "const x = 1",
6937 "for (const x = 1; x < 1; x++) {}",
6938 "for (const x in {}) {}",
6939 "for (const x of []) {}",
6940 NULL
6941 };
6942 // clang-format on
6943 RunParserSyncTest(context_data, data, kSuccess);
6944 }
6945
6946
TEST(LetSloppy)6947 TEST(LetSloppy) {
6948 // clang-format off
6949 const char* context_data[][2] = {
6950 {"", ""},
6951 {"'use strict';", ""},
6952 {"{", "}"},
6953 {NULL, NULL}
6954 };
6955
6956 const char* data[] = {
6957 "let x",
6958 "let x = 1",
6959 "for (let x = 1; x < 1; x++) {}",
6960 "for (let x in {}) {}",
6961 "for (let x of []) {}",
6962 NULL
6963 };
6964 // clang-format on
6965
6966 RunParserSyncTest(context_data, data, kSuccess);
6967 }
6968
6969
TEST(LanguageModeDirectivesNonSimpleParameterListErrors)6970 TEST(LanguageModeDirectivesNonSimpleParameterListErrors) {
6971 // TC39 deemed "use strict" directives to be an error when occurring in the
6972 // body of a function with non-simple parameter list, on 29/7/2015.
6973 // https://goo.gl/ueA7Ln
6974 const char* context_data[][2] = {
6975 {"function f(", ") { 'use strict'; }"},
6976 {"function* g(", ") { 'use strict'; }"},
6977 {"class c { foo(", ") { 'use strict' }"},
6978 {"var a = (", ") => { 'use strict'; }"},
6979 {"var o = { m(", ") { 'use strict'; }"},
6980 {"var o = { *gm(", ") { 'use strict'; }"},
6981 {"var c = { m(", ") { 'use strict'; }"},
6982 {"var c = { *gm(", ") { 'use strict'; }"},
6983
6984 {"'use strict'; function f(", ") { 'use strict'; }"},
6985 {"'use strict'; function* g(", ") { 'use strict'; }"},
6986 {"'use strict'; class c { foo(", ") { 'use strict' }"},
6987 {"'use strict'; var a = (", ") => { 'use strict'; }"},
6988 {"'use strict'; var o = { m(", ") { 'use strict'; }"},
6989 {"'use strict'; var o = { *gm(", ") { 'use strict'; }"},
6990 {"'use strict'; var c = { m(", ") { 'use strict'; }"},
6991 {"'use strict'; var c = { *gm(", ") { 'use strict'; }"},
6992
6993 {NULL, NULL}};
6994
6995 const char* data[] = {
6996 // TODO(@caitp): support formal parameter initializers
6997 "{}",
6998 "[]",
6999 "[{}]",
7000 "{a}",
7001 "a, {b}",
7002 "a, b, {c, d, e}",
7003 "initializer = true",
7004 "a, b, c = 1",
7005 "...args",
7006 "a, b, ...rest",
7007 "[a, b, ...rest]",
7008 "{ bindingPattern = {} }",
7009 "{ initializedBindingPattern } = { initializedBindingPattern: true }",
7010 NULL};
7011
7012 RunParserSyncTest(context_data, data, kError);
7013 }
7014
7015
TEST(LetSloppyOnly)7016 TEST(LetSloppyOnly) {
7017 // clang-format off
7018 const char* context_data[][2] = {
7019 {"", ""},
7020 {"{", "}"},
7021 {"(function() {", "})()"},
7022 {NULL, NULL}
7023 };
7024
7025 const char* data[] = {
7026 "let",
7027 "let = 1",
7028 "for (let = 1; let < 1; let++) {}",
7029 "for (let in {}) {}",
7030 "for (var let = 1; let < 1; let++) {}",
7031 "for (var let in {}) {}",
7032 "for (var [let] = 1; let < 1; let++) {}",
7033 "for (var [let] in {}) {}",
7034 "var let",
7035 "var [let] = []",
7036 NULL
7037 };
7038 // clang-format on
7039
7040 RunParserSyncTest(context_data, data, kSuccess);
7041
7042 // Some things should be rejected even in sloppy mode
7043 // This addresses BUG(v8:4403).
7044
7045 // clang-format off
7046 const char* fail_data[] = {
7047 "let let = 1",
7048 "for (let let = 1; let < 1; let++) {}",
7049 "for (let let in {}) {}",
7050 "for (let let of []) {}",
7051 "const let = 1",
7052 "for (const let = 1; let < 1; let++) {}",
7053 "for (const let in {}) {}",
7054 "for (const let of []) {}",
7055 "let [let] = 1",
7056 "for (let [let] = 1; let < 1; let++) {}",
7057 "for (let [let] in {}) {}",
7058 "for (let [let] of []) {}",
7059 "const [let] = 1",
7060 "for (const [let] = 1; let < 1; let++) {}",
7061 "for (const [let] in {}) {}",
7062 "for (const [let] of []) {}",
7063
7064 // Sprinkle in the escaped version too.
7065 "let l\\u0065t = 1",
7066 "const l\\u0065t = 1",
7067 "let [l\\u0065t] = 1",
7068 "const [l\\u0065t] = 1",
7069 "for (let l\\u0065t in {}) {}",
7070 NULL
7071 };
7072 // clang-format on
7073
7074 RunParserSyncTest(context_data, fail_data, kError);
7075 }
7076
7077
TEST(EscapedKeywords)7078 TEST(EscapedKeywords) {
7079 // clang-format off
7080 const char* sloppy_context_data[][2] = {
7081 {"", ""},
7082 {NULL, NULL}
7083 };
7084
7085 const char* strict_context_data[][2] = {
7086 {"'use strict';", ""},
7087 {NULL, NULL}
7088 };
7089
7090 const char* fail_data[] = {
7091 "for (var i = 0; i < 100; ++i) { br\\u0065ak; }",
7092 "cl\\u0061ss Foo {}",
7093 "var x = cl\\u0061ss {}",
7094 "\\u0063onst foo = 1;",
7095 "while (i < 10) { if (i++ & 1) c\\u006fntinue; this.x++; }",
7096 "d\\u0065bugger;",
7097 "d\\u0065lete this.a;",
7098 "\\u0063o { } while(0)",
7099 "if (d\\u006f { true }) {}",
7100 "if (false) { this.a = 1; } \\u0065lse { this.b = 1; }",
7101 "e\\u0078port var foo;",
7102 "try { } catch (e) {} f\\u0069nally { }",
7103 "f\\u006fr (var i = 0; i < 10; ++i);",
7104 "f\\u0075nction fn() {}",
7105 "var f = f\\u0075nction() {}",
7106 "\\u0069f (true) { }",
7107 "\\u0069mport blah from './foo.js';",
7108 "n\\u0065w function f() {}",
7109 "(function() { r\\u0065turn; })()",
7110 "class C extends function() {} { constructor() { sup\\u0065r() } }",
7111 "class C extends function() {} { constructor() { sup\\u0065r.a = 1 } }",
7112 "sw\\u0069tch (this.a) {}",
7113 "var x = th\\u0069s;",
7114 "th\\u0069s.a = 1;",
7115 "thr\\u006fw 'boo';",
7116 "t\\u0072y { true } catch (e) {}",
7117 "var x = typ\\u0065of 'blah'",
7118 "v\\u0061r a = true",
7119 "var v\\u0061r = true",
7120 "(function() { return v\\u006fid 0; })()",
7121 "wh\\u0069le (true) { }",
7122 "w\\u0069th (this.scope) { }",
7123 "(function*() { y\\u0069eld 1; })()",
7124 "(function*() { var y\\u0069eld = 1; })()",
7125
7126 "var \\u0065num = 1;",
7127 "var { \\u0065num } = {}",
7128 "(\\u0065num = 1);",
7129
7130 // Null / Boolean literals
7131 "(x === n\\u0075ll);",
7132 "var x = n\\u0075ll;",
7133 "var n\\u0075ll = 1;",
7134 "var { n\\u0075ll } = { 1 };",
7135 "n\\u0075ll = 1;",
7136 "(x === tr\\u0075e);",
7137 "var x = tr\\u0075e;",
7138 "var tr\\u0075e = 1;",
7139 "var { tr\\u0075e } = {};",
7140 "tr\\u0075e = 1;",
7141 "(x === f\\u0061lse);",
7142 "var x = f\\u0061lse;",
7143 "var f\\u0061lse = 1;",
7144 "var { f\\u0061lse } = {};",
7145 "f\\u0061lse = 1;",
7146
7147 // TODO(caitp): consistent error messages for labeled statements and
7148 // expressions
7149 "switch (this.a) { c\\u0061se 6: break; }",
7150 "try { } c\\u0061tch (e) {}",
7151 "switch (this.a) { d\\u0065fault: break; }",
7152 "class C \\u0065xtends function B() {} {}",
7153 "for (var a i\\u006e this) {}",
7154 "if ('foo' \\u0069n this) {}",
7155 "if (this \\u0069nstanceof Array) {}",
7156 "(n\\u0065w function f() {})",
7157 "(typ\\u0065of 123)",
7158 "(v\\u006fid 0)",
7159 "do { ; } wh\\u0069le (true) { }",
7160 "(function*() { return (n++, y\\u0069eld 1); })()",
7161 "class C { st\\u0061tic bar() {} }",
7162 "class C { st\\u0061tic *bar() {} }",
7163 "class C { st\\u0061tic get bar() {} }",
7164 "class C { st\\u0061tic set bar() {} }",
7165
7166 // TODO(adamk): These should not be errors in sloppy mode.
7167 "(y\\u0069eld);",
7168 "var y\\u0069eld = 1;",
7169 "var { y\\u0069eld } = {};",
7170 NULL
7171 };
7172 // clang-format on
7173
7174 RunParserSyncTest(sloppy_context_data, fail_data, kError);
7175 RunParserSyncTest(strict_context_data, fail_data, kError);
7176 RunModuleParserSyncTest(sloppy_context_data, fail_data, kError);
7177
7178 // clang-format off
7179 const char* let_data[] = {
7180 "var l\\u0065t = 1;",
7181 "l\\u0065t = 1;",
7182 "(l\\u0065t === 1);",
7183 NULL
7184 };
7185 // clang-format on
7186
7187 RunParserSyncTest(sloppy_context_data, let_data, kSuccess);
7188 RunParserSyncTest(strict_context_data, let_data, kError);
7189
7190 // Non-errors in sloppy mode
7191 const char* valid_data[] = {"(\\u0069mplements = 1);",
7192 "var impl\\u0065ments = 1;",
7193 "var { impl\\u0065ments } = {};",
7194 "(\\u0069nterface = 1);",
7195 "var int\\u0065rface = 1;",
7196 "var { int\\u0065rface } = {};",
7197 "(p\\u0061ckage = 1);",
7198 "var packa\\u0067e = 1;",
7199 "var { packa\\u0067e } = {};",
7200 "(p\\u0072ivate = 1);",
7201 "var p\\u0072ivate;",
7202 "var { p\\u0072ivate } = {};",
7203 "(prot\\u0065cted);",
7204 "var prot\\u0065cted = 1;",
7205 "var { prot\\u0065cted } = {};",
7206 "(publ\\u0069c);",
7207 "var publ\\u0069c = 1;",
7208 "var { publ\\u0069c } = {};",
7209 "(st\\u0061tic);",
7210 "var st\\u0061tic = 1;",
7211 "var { st\\u0061tic } = {};",
7212 NULL};
7213 RunParserSyncTest(sloppy_context_data, valid_data, kSuccess);
7214 RunParserSyncTest(strict_context_data, valid_data, kError);
7215 RunModuleParserSyncTest(strict_context_data, valid_data, kError);
7216 }
7217
7218
TEST(MiscSyntaxErrors)7219 TEST(MiscSyntaxErrors) {
7220 // clang-format off
7221 const char* context_data[][2] = {
7222 { "'use strict'", "" },
7223 { "", "" },
7224 { NULL, NULL }
7225 };
7226 const char* error_data[] = {
7227 "for (();;) {}",
7228
7229 // crbug.com/582626
7230 "{ NaN ,chA((evarA=new t ( l = !.0[((... co -a0([1]))=> greturnkf",
7231 NULL
7232 };
7233 // clang-format on
7234
7235 RunParserSyncTest(context_data, error_data, kError);
7236 }
7237
7238
TEST(EscapeSequenceErrors)7239 TEST(EscapeSequenceErrors) {
7240 // clang-format off
7241 const char* context_data[][2] = {
7242 { "'", "'" },
7243 { "\"", "\"" },
7244 { "`", "`" },
7245 { "`${'", "'}`" },
7246 { "`${\"", "\"}`" },
7247 { "`${`", "`}`" },
7248 { "f(tag`", "`);" },
7249 { NULL, NULL }
7250 };
7251 const char* error_data[] = {
7252 "\\uABCG",
7253 "\\u{ZZ}",
7254 "\\u{FFZ}",
7255 "\\u{FFFFFFFFFF }",
7256 "\\u{110000}",
7257 "\\u{110000",
7258 "\\u{FFFD }",
7259 "\\xZF",
7260 NULL
7261 };
7262 // clang-format on
7263
7264 RunParserSyncTest(context_data, error_data, kError);
7265 }
7266
7267
TEST(FunctionSentErrors)7268 TEST(FunctionSentErrors) {
7269 // clang-format off
7270 const char* context_data[][2] = {
7271 { "'use strict'", "" },
7272 { "", "" },
7273 { NULL, NULL }
7274 };
7275 const char* error_data[] = {
7276 "var x = function.sent",
7277 "function* g() { yield function.s\\u0065nt; }",
7278 NULL
7279 };
7280 // clang-format on
7281
7282 static const ParserFlag always_flags[] = {kAllowHarmonyFunctionSent};
7283 RunParserSyncTest(context_data, error_data, kError, always_flags,
7284 arraysize(always_flags));
7285 }
7286
TEST(NewTargetErrors)7287 TEST(NewTargetErrors) {
7288 // clang-format off
7289 const char* context_data[][2] = {
7290 { "'use strict'", "" },
7291 { "", "" },
7292 { NULL, NULL }
7293 };
7294 const char* error_data[] = {
7295 "var x = new.target",
7296 "function f() { return new.t\\u0061rget; }",
7297 NULL
7298 };
7299 // clang-format on
7300 RunParserSyncTest(context_data, error_data, kError);
7301 }
7302
TEST(FunctionDeclarationError)7303 TEST(FunctionDeclarationError) {
7304 // clang-format off
7305 const char* strict_context[][2] = {
7306 { "'use strict';", "" },
7307 { "'use strict'; { ", "}" },
7308 {"(function() { 'use strict';", "})()"},
7309 {"(function() { 'use strict'; {", "} })()"},
7310 { NULL, NULL }
7311 };
7312 const char* sloppy_context[][2] = {
7313 { "", "" },
7314 { "{", "}" },
7315 {"(function() {", "})()"},
7316 {"(function() { {", "} })()"},
7317 { NULL, NULL }
7318 };
7319 // Invalid in all contexts
7320 const char* error_data[] = {
7321 "try function foo() {} catch (e) {}",
7322 NULL
7323 };
7324 // Valid in sloppy mode only, and only when the
7325 // --harmony-restrictive-declarations flag is off
7326 const char* unrestricted_data[] = {
7327 "do function foo() {} while (0);",
7328 "for (;false;) function foo() {}",
7329 "for (var i = 0; i < 1; i++) function f() { };",
7330 "for (var x in {a: 1}) function f() { };",
7331 "for (var x in {}) function f() { };",
7332 "for (var x in {}) function foo() {}",
7333 "for (x in {a: 1}) function f() { };",
7334 "for (x in {}) function f() { };",
7335 "var x; for (x in {}) function foo() {}",
7336 "with ({}) function f() { };",
7337 "do label: function foo() {} while (0);",
7338 "for (;false;) label: function foo() {}",
7339 "for (var i = 0; i < 1; i++) label: function f() { };",
7340 "for (var x in {a: 1}) label: function f() { };",
7341 "for (var x in {}) label: function f() { };",
7342 "for (var x in {}) label: function foo() {}",
7343 "for (x in {a: 1}) label: function f() { };",
7344 "for (x in {}) label: function f() { };",
7345 "var x; for (x in {}) label: function foo() {}",
7346 "with ({}) label: function f() { };",
7347 "if (true) label: function f() {}",
7348 "if (true) {} else label: function f() {}",
7349 "if (true) function* f() { }",
7350 "label: function* f() { }",
7351 // TODO(littledan, v8:4806): Ban duplicate generator declarations in
7352 // a block, maybe by tracking whether a Variable is a generator declaration
7353 // "{ function* f() {} function* f() {} }",
7354 // "{ function f() {} function* f() {} }",
7355 // "{ function* f() {} function f() {} }",
7356 NULL
7357 };
7358 // Valid only in sloppy mode, with or without
7359 // --harmony-restrictive-declarations
7360 const char* sloppy_data[] = {
7361 "if (true) function foo() {}",
7362 "if (false) {} else function f() { };",
7363 "label: function f() { }",
7364 "label: if (true) function f() { }",
7365 "label: if (true) {} else function f() { }",
7366 NULL
7367 };
7368 // clang-format on
7369
7370 static const ParserFlag restrictive_flags[] = {
7371 kAllowHarmonyRestrictiveDeclarations};
7372
7373 // Nothing parses in strict mode without a SyntaxError
7374 RunParserSyncTest(strict_context, error_data, kError);
7375 RunParserSyncTest(strict_context, error_data, kError, NULL, 0,
7376 restrictive_flags, arraysize(restrictive_flags));
7377 RunParserSyncTest(strict_context, unrestricted_data, kError);
7378 RunParserSyncTest(strict_context, unrestricted_data, kError, NULL, 0,
7379 restrictive_flags, arraysize(restrictive_flags));
7380 RunParserSyncTest(strict_context, sloppy_data, kError);
7381 RunParserSyncTest(strict_context, sloppy_data, kError, NULL, 0,
7382 restrictive_flags, arraysize(restrictive_flags));
7383
7384 // In sloppy mode, some things are successful, depending on the flag
7385 RunParserSyncTest(sloppy_context, error_data, kError);
7386 RunParserSyncTest(sloppy_context, error_data, kError, NULL, 0,
7387 restrictive_flags, arraysize(restrictive_flags));
7388 RunParserSyncTest(sloppy_context, unrestricted_data, kSuccess);
7389 RunParserSyncTest(sloppy_context, unrestricted_data, kError, NULL, 0,
7390 restrictive_flags, arraysize(restrictive_flags));
7391 RunParserSyncTest(sloppy_context, sloppy_data, kSuccess);
7392 RunParserSyncTest(sloppy_context, sloppy_data, kSuccess, restrictive_flags,
7393 arraysize(restrictive_flags));
7394 }
7395
TEST(ExponentiationOperator)7396 TEST(ExponentiationOperator) {
7397 // clang-format off
7398 const char* context_data[][2] = {
7399 { "var O = { p: 1 }, x = 10; ; if (", ") { foo(); }" },
7400 { "var O = { p: 1 }, x = 10; ; (", ")" },
7401 { "var O = { p: 1 }, x = 10; foo(", ")" },
7402 { NULL, NULL }
7403 };
7404 const char* data[] = {
7405 "(delete O.p) ** 10",
7406 "(delete x) ** 10",
7407 "(~O.p) ** 10",
7408 "(~x) ** 10",
7409 "(!O.p) ** 10",
7410 "(!x) ** 10",
7411 "(+O.p) ** 10",
7412 "(+x) ** 10",
7413 "(-O.p) ** 10",
7414 "(-x) ** 10",
7415 "(typeof O.p) ** 10",
7416 "(typeof x) ** 10",
7417 "(void 0) ** 10",
7418 "(void O.p) ** 10",
7419 "(void x) ** 10",
7420 "++O.p ** 10",
7421 "++x ** 10",
7422 "--O.p ** 10",
7423 "--x ** 10",
7424 "O.p++ ** 10",
7425 "x++ ** 10",
7426 "O.p-- ** 10",
7427 "x-- ** 10",
7428 NULL
7429 };
7430 // clang-format on
7431
7432 static const ParserFlag always_flags[] = {
7433 kAllowHarmonyExponentiationOperator};
7434 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
7435 arraysize(always_flags));
7436 }
7437
TEST(ExponentiationOperatorErrors)7438 TEST(ExponentiationOperatorErrors) {
7439 // clang-format off
7440 const char* context_data[][2] = {
7441 { "var O = { p: 1 }, x = 10; ; if (", ") { foo(); }" },
7442 { "var O = { p: 1 }, x = 10; ; (", ")" },
7443 { "var O = { p: 1 }, x = 10; foo(", ")" },
7444 { NULL, NULL }
7445 };
7446 const char* error_data[] = {
7447 "delete O.p ** 10",
7448 "delete x ** 10",
7449 "~O.p ** 10",
7450 "~x ** 10",
7451 "!O.p ** 10",
7452 "!x ** 10",
7453 "+O.p ** 10",
7454 "+x ** 10",
7455 "-O.p ** 10",
7456 "-x ** 10",
7457 "typeof O.p ** 10",
7458 "typeof x ** 10",
7459 "void ** 10",
7460 "void O.p ** 10",
7461 "void x ** 10",
7462 "++delete O.p ** 10",
7463 "--delete O.p ** 10",
7464 "++~O.p ** 10",
7465 "++~x ** 10",
7466 "--!O.p ** 10",
7467 "--!x ** 10",
7468 "++-O.p ** 10",
7469 "++-x ** 10",
7470 "--+O.p ** 10",
7471 "--+x ** 10",
7472 "[ x ] **= [ 2 ]",
7473 "[ x **= 2 ] = [ 2 ]",
7474 "{ x } **= { x: 2 }",
7475 "{ x: x **= 2 ] = { x: 2 }",
7476 // TODO(caitp): a Call expression as LHS should be an early ReferenceError!
7477 // "Array() **= 10",
7478 NULL
7479 };
7480 // clang-format on
7481
7482 static const ParserFlag always_flags[] = {
7483 kAllowHarmonyExponentiationOperator};
7484 RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
7485 arraysize(always_flags));
7486 }
7487
TEST(AsyncAwait)7488 TEST(AsyncAwait) {
7489 // clang-format off
7490 const char* context_data[][2] = {
7491 { "'use strict';", "" },
7492 { "", "" },
7493 { NULL, NULL }
7494 };
7495
7496 const char* data[] = {
7497 "var asyncFn = async function() { await 1; };",
7498 "var asyncFn = async function withName() { await 1; };",
7499 "var asyncFn = async () => await 'test';",
7500 "var asyncFn = async x => await x + 'test';",
7501 "async function asyncFn() { await 1; }",
7502 "var O = { async method() { await 1; } }",
7503 "var O = { async ['meth' + 'od']() { await 1; } }",
7504 "var O = { async 'method'() { await 1; } }",
7505 "var O = { async 0() { await 1; } }",
7506 "async function await() {}",
7507
7508 "var asyncFn = async({ foo = 1 }) => foo;",
7509 "var asyncFn = async({ foo = 1 } = {}) => foo;",
7510 NULL
7511 };
7512 // clang-format on
7513
7514 static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
7515 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
7516 arraysize(always_flags));
7517
7518 // clang-format off
7519 const char* async_body_context_data[][2] = {
7520 { "async function f() {", "}" },
7521 { "var f = async function() {", "}" },
7522 { "var f = async() => {", "}" },
7523 { "var O = { async method() {", "} }" },
7524 { "'use strict'; async function f() {", "}" },
7525 { "'use strict'; var f = async function() {", "}" },
7526 { "'use strict'; var f = async() => {", "}" },
7527 { "'use strict'; var O = { async method() {", "} }" },
7528 { NULL, NULL }
7529 };
7530
7531 const char* body_context_data[][2] = {
7532 { "function f() {", "}" },
7533 { "function* g() {", "}" },
7534 { "var f = function() {", "}" },
7535 { "var g = function*() {", "}" },
7536 { "var O = { method() {", "} }" },
7537 { "var O = { *method() {", "} }" },
7538 { "var f = () => {", "}" },
7539 { "'use strict'; function f() {", "}" },
7540 { "'use strict'; function* g() {", "}" },
7541 { "'use strict'; var f = function() {", "}" },
7542 { "'use strict'; var g = function*() {", "}" },
7543 { "'use strict'; var O = { method() {", "} }" },
7544 { "'use strict'; var O = { *method() {", "} }" },
7545 { "'use strict'; var f = () => {", "}" },
7546 { NULL, NULL }
7547 };
7548
7549 const char* body_data[] = {
7550 "var async = 1; return async;",
7551 "let async = 1; return async;",
7552 "const async = 1; return async;",
7553 "function async() {} return async();",
7554 "var async = async => async; return async();",
7555 "function foo() { var await = 1; return await; }",
7556 "function foo(await) { return await; }",
7557 "function* foo() { var await = 1; return await; }",
7558 "function* foo(await) { return await; }",
7559 "var f = (await) => await;",
7560 "var f = () => { var await = 1; return await; }",
7561 "var O = { method() { var await = 1; return await; } };",
7562 "var O = { method(await) { return await; } };",
7563 "var O = { *method() { var await = 1; return await; } };",
7564 "var O = { *method(await) { return await; } };",
7565
7566 "(function await() {})",
7567 NULL
7568 };
7569 // clang-format on
7570
7571 RunParserSyncTest(async_body_context_data, body_data, kSuccess, NULL, 0,
7572 always_flags, arraysize(always_flags));
7573 RunParserSyncTest(body_context_data, body_data, kSuccess, NULL, 0,
7574 always_flags, arraysize(always_flags));
7575 }
7576
TEST(AsyncAwaitErrors)7577 TEST(AsyncAwaitErrors) {
7578 // clang-format off
7579 const char* context_data[][2] = {
7580 { "'use strict';", "" },
7581 { "", "" },
7582 { NULL, NULL }
7583 };
7584
7585 const char* strict_context_data[][2] = {
7586 { "'use strict';", "" },
7587 { NULL, NULL }
7588 };
7589
7590 const char* error_data[] = {
7591 "var asyncFn = async function() { var await = 1; };",
7592 "var asyncFn = async function() { var { await } = 1; };",
7593 "var asyncFn = async function() { var [ await ] = 1; };",
7594 "var asyncFn = async function await() {};",
7595 "var asyncFn = async () => var await = 'test';",
7596 "var asyncFn = async await => await + 'test';",
7597 "var asyncFn = async function(await) {};",
7598 "var asyncFn = async function() { return async (await) => {}; }",
7599 "var asyncFn = async (await) => 'test';",
7600 "var asyncFn = async x => { var await = 1; }",
7601 "var asyncFn = async x => { var { await } = 1; }",
7602 "var asyncFn = async x => { var [ await ] = 1; }",
7603 "async function f(await) {}",
7604 "async function f() { var await = 1; }",
7605 "async function f() { var { await } = 1; }",
7606 "async function f() { var [ await ] = 1; }",
7607
7608 "var O = { async method(a, a) {} }",
7609 "var O = { async ['meth' + 'od'](a, a) {} }",
7610 "var O = { async 'method'(a, a) {} }",
7611 "var O = { async 0(a, a) {} }",
7612
7613 "async function f() { var O = { async [await](a, a) {} } }",
7614
7615 "var asyncFn = async function() { await; }",
7616 "async function f() { await; }",
7617 "var O = { async method() { await; } };",
7618 "var f = async() => await;",
7619 "var f = async() => { await; };",
7620
7621 "var asyncFn = async function*() {}",
7622 "async function* f() {}",
7623 "var O = { *async method() {} };",
7624 "var O = { async *method() {} };",
7625 "var O = { async method*() {} };",
7626
7627 "var asyncFn = async function(x = await 1) { return x; }",
7628 "async function f(x = await 1) { return x; }",
7629 "var f = async(x = await 1) => x;",
7630 "var O = { async method(x = await 1) { return x; } };",
7631
7632 "var f = async(x = await) => 1;",
7633
7634 "class C { async constructor() {} }",
7635 "class C {}; class C2 extends C { async constructor() {} }",
7636 "class C { static async prototype() {} }",
7637 "class C {}; class C2 extends C { static async prototype() {} }",
7638
7639 "var f = async() => ((async(x = await 1) => x)();",
7640
7641 "var asyncFn = async function() { function await() {} }",
7642 "var asyncFn = async() => { function await() {} }",
7643 "var O = { async method() { function await() {} } }",
7644 "async function foo() { function await() {} }",
7645
7646 // Henrique Ferreiro's bug (tm)
7647 "(async function foo() { } foo => 1)",
7648 "(async function foo() { } () => 1)",
7649 "(async function foo() { } => 1)",
7650 "(async function() { } foo => 1)",
7651 "(async function() { } () => 1)",
7652 "(async function() { } => 1)",
7653 "(async.foo => 1)",
7654 "(async.foo foo => 1)",
7655 "(async.foo () => 1)",
7656 "(async().foo => 1)",
7657 "(async().foo foo => 1)",
7658 "(async().foo () => 1)",
7659 "(async['foo'] => 1)",
7660 "(async['foo'] foo => 1)",
7661 "(async['foo'] () => 1)",
7662 "(async()['foo'] => 1)",
7663 "(async()['foo'] foo => 1)",
7664 "(async()['foo'] () => 1)",
7665 "(async`foo` => 1)",
7666 "(async`foo` foo => 1)",
7667 "(async`foo` () => 1)",
7668 "(async`foo`.bar => 1)",
7669 "(async`foo`.bar foo => 1)",
7670 "(async`foo`.bar () => 1)",
7671
7672 // v8:5148 assert that errors are still thrown for calls that may have been
7673 // async functions
7674 "async({ foo = 1 })",
7675 NULL
7676 };
7677
7678 const char* strict_error_data[] = {
7679 "var O = { async method(eval) {} }",
7680 "var O = { async ['meth' + 'od'](eval) {} }",
7681 "var O = { async 'method'(eval) {} }",
7682 "var O = { async 0(eval) {} }",
7683
7684 "var O = { async method(arguments) {} }",
7685 "var O = { async ['meth' + 'od'](arguments) {} }",
7686 "var O = { async 'method'(arguments) {} }",
7687 "var O = { async 0(arguments) {} }",
7688
7689 "var O = { async method(dupe, dupe) {} }",
7690
7691 // TODO(caitp): preparser needs to report duplicate parameter errors, too.
7692 // "var f = async(dupe, dupe) => {}",
7693
7694 NULL
7695 };
7696
7697 const char* formal_parameters_data[] = {
7698 "var f = async({ await }) => 1;",
7699 "var f = async({ await = 1 }) => 1;",
7700 "var f = async({ await } = {}) => 1;",
7701 "var f = async({ await = 1 } = {}) => 1;",
7702 "var f = async([await]) => 1;",
7703 "var f = async([await] = []) => 1;",
7704 "var f = async([await = 1]) => 1;",
7705 "var f = async([await = 1] = []) => 1;",
7706 "var f = async(...await) => 1;",
7707 "var f = async(await) => 1;",
7708 "var f = async(await = 1) => 1;",
7709 "var f = async(...[await]) => 1;",
7710 NULL
7711 };
7712 // clang-format on
7713
7714 static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
7715 RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
7716 arraysize(always_flags));
7717 RunParserSyncTest(strict_context_data, strict_error_data, kError, NULL, 0,
7718 always_flags, arraysize(always_flags));
7719
7720 RunParserSyncTest(context_data, formal_parameters_data, kError, NULL, 0,
7721 always_flags, arraysize(always_flags));
7722 }
7723
TEST(AsyncAwaitModule)7724 TEST(AsyncAwaitModule) {
7725 // clang-format off
7726 const char* context_data[][2] = {
7727 { "", "" },
7728 { NULL, NULL }
7729 };
7730
7731 const char* data[] = {
7732 "export default async function() { await 1; }",
7733 "export default async function async() { await 1; }",
7734 "export async function async() { await 1; }",
7735 NULL
7736 };
7737 // clang-format on
7738
7739 static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
7740 RunModuleParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
7741 arraysize(always_flags), NULL, 0, false);
7742 }
7743
TEST(AsyncAwaitModuleErrors)7744 TEST(AsyncAwaitModuleErrors) {
7745 // clang-format off
7746 const char* context_data[][2] = {
7747 { "", "" },
7748 { NULL, NULL }
7749 };
7750
7751 const char* error_data[] = {
7752 "export default (async function await() {})",
7753 "export default async function await() {}",
7754 "export async function await() {}",
7755 "export async function() {}",
7756 "export async",
7757 NULL
7758 };
7759 // clang-format on
7760
7761 static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
7762 RunModuleParserSyncTest(context_data, error_data, kError, NULL, 0,
7763 always_flags, arraysize(always_flags), NULL, 0,
7764 false);
7765 }
7766
TEST(RestrictiveForInErrors)7767 TEST(RestrictiveForInErrors) {
7768 // clang-format off
7769 const char* context_data[][2] = {
7770 { "'use strict'", "" },
7771 { "", "" },
7772 { NULL, NULL }
7773 };
7774 const char* error_data[] = {
7775 "for (var x = 0 in {});",
7776 "for (const x = 0 in {});",
7777 "for (let x = 0 in {});",
7778 NULL
7779 };
7780 // clang-format on
7781
7782 static const ParserFlag always_flags[] = {kAllowHarmonyForIn};
7783 RunParserSyncTest(context_data, error_data, kError, nullptr, 0, always_flags,
7784 arraysize(always_flags));
7785 }
7786
TEST(NoDuplicateGeneratorsInBlock)7787 TEST(NoDuplicateGeneratorsInBlock) {
7788 const char* block_context_data[][2] = {
7789 {"'use strict'; {", "}"},
7790 {"{", "}"},
7791 {"(function() { {", "} })()"},
7792 {"(function() {'use strict'; {", "} })()"},
7793 {NULL, NULL}};
7794 const char* top_level_context_data[][2] = {
7795 {"'use strict';", ""},
7796 {"", ""},
7797 {"(function() {", "})()"},
7798 {"(function() {'use strict';", "})()"},
7799 {NULL, NULL}};
7800 const char* error_data[] = {"function* x() {} function* x() {}",
7801 "function x() {} function* x() {}",
7802 "function* x() {} function x() {}", NULL};
7803 static const ParserFlag always_flags[] = {kAllowHarmonyRestrictiveGenerators};
7804 // The preparser doesn't enforce the restriction, so turn it off.
7805 bool test_preparser = false;
7806 RunParserSyncTest(block_context_data, error_data, kError, NULL, 0,
7807 always_flags, arraysize(always_flags), NULL, 0, false,
7808 test_preparser);
7809 RunParserSyncTest(top_level_context_data, error_data, kSuccess, NULL, 0,
7810 always_flags, arraysize(always_flags));
7811 }
7812
TEST(NoDuplicateAsyncFunctionInBlock)7813 TEST(NoDuplicateAsyncFunctionInBlock) {
7814 const char* block_context_data[][2] = {
7815 {"'use strict'; {", "}"},
7816 {"{", "}"},
7817 {"(function() { {", "} })()"},
7818 {"(function() {'use strict'; {", "} })()"},
7819 {NULL, NULL}};
7820 const char* top_level_context_data[][2] = {
7821 {"'use strict';", ""},
7822 {"", ""},
7823 {"(function() {", "})()"},
7824 {"(function() {'use strict';", "})()"},
7825 {NULL, NULL}};
7826 const char* error_data[] = {"async function x() {} async function x() {}",
7827 "function x() {} async function x() {}",
7828 "async function x() {} function x() {}",
7829 "function* x() {} async function x() {}",
7830 "function* x() {} async function x() {}",
7831 "async function x() {} function* x() {}",
7832 "function* x() {} async function x() {}",
7833 NULL};
7834 static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
7835 // The preparser doesn't enforce the restriction, so turn it off.
7836 bool test_preparser = false;
7837 RunParserSyncTest(block_context_data, error_data, kError, NULL, 0,
7838 always_flags, arraysize(always_flags), NULL, 0, false,
7839 test_preparser);
7840 RunParserSyncTest(top_level_context_data, error_data, kSuccess, NULL, 0,
7841 always_flags, arraysize(always_flags));
7842 }
7843