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