1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "src/ast-numbering.h"
36 #include "src/ast-value-factory.h"
37 #include "src/compiler.h"
38 #include "src/execution.h"
39 #include "src/isolate.h"
40 #include "src/objects.h"
41 #include "src/parser.h"
42 #include "src/preparser.h"
43 #include "src/rewriter.h"
44 #include "src/scanner-character-streams.h"
45 #include "src/token.h"
46 #include "src/utils.h"
48 #include "test/cctest/cctest.h"
53 i::Token::Value token;
56 static const KeywordToken keywords[] = {
57 #define KEYWORD(t, s, d) { s, i::Token::t },
58 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
60 { NULL, i::Token::IDENTIFIER }
63 KeywordToken key_token;
64 i::UnicodeCache unicode_cache;
66 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
67 const i::byte* keyword =
68 reinterpret_cast<const i::byte*>(key_token.keyword);
69 int length = i::StrLength(key_token.keyword);
70 CHECK(static_cast<int>(sizeof(buffer)) >= length);
72 i::Utf8ToUtf16CharacterStream stream(keyword, length);
73 i::Scanner scanner(&unicode_cache);
74 // The scanner should parse Harmony keywords for this test.
75 scanner.SetHarmonyModules(true);
76 scanner.SetHarmonyClasses(true);
77 scanner.Initialize(&stream);
78 CHECK_EQ(key_token.token, scanner.Next());
79 CHECK_EQ(i::Token::EOS, scanner.Next());
81 // Removing characters will make keyword matching fail.
83 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
84 i::Scanner scanner(&unicode_cache);
85 scanner.Initialize(&stream);
86 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
87 CHECK_EQ(i::Token::EOS, scanner.Next());
89 // Adding characters will make keyword matching fail.
90 static const char chars_to_append[] = { 'z', '0', '_' };
91 for (int j = 0; j < static_cast<int>(arraysize(chars_to_append)); ++j) {
92 i::MemMove(buffer, keyword, length);
93 buffer[length] = chars_to_append[j];
94 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
95 i::Scanner scanner(&unicode_cache);
96 scanner.Initialize(&stream);
97 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
98 CHECK_EQ(i::Token::EOS, scanner.Next());
100 // Replacing characters will make keyword matching fail.
102 i::MemMove(buffer, keyword, length);
103 buffer[length - 1] = '_';
104 i::Utf8ToUtf16CharacterStream stream(buffer, length);
105 i::Scanner scanner(&unicode_cache);
106 scanner.Initialize(&stream);
107 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
108 CHECK_EQ(i::Token::EOS, scanner.Next());
114 TEST(ScanHTMLEndComments) {
115 v8::V8::Initialize();
116 v8::Isolate* isolate = CcTest::isolate();
117 v8::HandleScope handles(isolate);
119 // Regression test. See:
120 // http://code.google.com/p/chromium/issues/detail?id=53548
121 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
122 // is only whitespace before it on the line (with comments considered as
123 // whitespace, even a multiline-comment containing a newline).
124 // This was not the case if it occurred before the first real token
126 const char* tests[] = {
127 // Before first real token.
128 "--> is eol-comment\nvar y = 37;\n",
129 "\n --> is eol-comment\nvar y = 37;\n",
130 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
131 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
132 // After first real token.
133 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
134 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
138 const char* fail_tests[] = {
139 "x --> is eol-comment\nvar y = 37;\n",
140 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
141 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
142 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
143 "var x = 42; --> is eol-comment\nvar y = 37;\n",
144 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
148 // Parser/Scanner needs a stack limit.
149 CcTest::i_isolate()->stack_guard()->SetStackLimit(
150 i::GetCurrentStackPosition() - 128 * 1024);
151 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
152 for (int i = 0; tests[i]; i++) {
153 const i::byte* source =
154 reinterpret_cast<const i::byte*>(tests[i]);
155 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i]));
156 i::CompleteParserRecorder log;
157 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
158 scanner.Initialize(&stream);
160 i::AstValueFactory ast_value_factory(
161 &zone, CcTest::i_isolate()->heap()->HashSeed());
162 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
164 preparser.set_allow_lazy(true);
165 i::PreParser::PreParseResult result = preparser.PreParseProgram();
166 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
167 CHECK(!log.HasError());
170 for (int i = 0; fail_tests[i]; i++) {
171 const i::byte* source =
172 reinterpret_cast<const i::byte*>(fail_tests[i]);
173 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i]));
174 i::CompleteParserRecorder log;
175 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
176 scanner.Initialize(&stream);
178 i::AstValueFactory ast_value_factory(
179 &zone, CcTest::i_isolate()->heap()->HashSeed());
180 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
182 preparser.set_allow_lazy(true);
183 i::PreParser::PreParseResult result = preparser.PreParseProgram();
184 // Even in the case of a syntax error, kPreParseSuccess is returned.
185 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
186 CHECK(log.HasError());
191 class ScriptResource : public v8::String::ExternalOneByteStringResource {
193 ScriptResource(const char* data, size_t length)
194 : data_(data), length_(length) { }
196 const char* data() const { return data_; }
197 size_t length() const { return length_; }
205 TEST(UsingCachedData) {
206 v8::Isolate* isolate = CcTest::isolate();
207 v8::HandleScope handles(isolate);
208 v8::Local<v8::Context> context = v8::Context::New(isolate);
209 v8::Context::Scope context_scope(context);
210 CcTest::i_isolate()->stack_guard()->SetStackLimit(
211 i::GetCurrentStackPosition() - 128 * 1024);
213 // Source containing functions that might be lazily compiled and all types
214 // of symbols (string, propertyName, regexp).
217 "function foo(a) { return function nolazy(b) { return a + b; } }"
218 "function bar(a) { if (a) return function lazy(b) { return b; } }"
219 "var z = {'string': 'string literal', bareword: 'propertyName', "
220 " 42: 'number literal', for: 'keyword as propertyName', "
221 " f\\u006fr: 'keyword propertyname with escape'};"
222 "var v = /RegExp Literal/;"
223 "var w = /RegExp Literal\\u0020With Escape/gin;"
224 "var y = { get getter() { return 42; }, "
225 " set setter(v) { this.value = v; }};"
226 "var f = a => function (b) { return a + b; };"
227 "var g = a => b => a + b;";
228 int source_length = i::StrLength(source);
230 // ScriptResource will be deleted when the corresponding String is GCd.
231 v8::ScriptCompiler::Source script_source(v8::String::NewExternal(
232 isolate, new ScriptResource(source, source_length)));
233 i::FLAG_harmony_arrow_functions = true;
234 i::FLAG_min_preparse_length = 0;
235 v8::ScriptCompiler::Compile(isolate, &script_source,
236 v8::ScriptCompiler::kProduceParserCache);
237 CHECK(script_source.GetCachedData());
239 // Compile the script again, using the cached data.
240 bool lazy_flag = i::FLAG_lazy;
242 v8::ScriptCompiler::Compile(isolate, &script_source,
243 v8::ScriptCompiler::kConsumeParserCache);
244 i::FLAG_lazy = false;
245 v8::ScriptCompiler::CompileUnbound(isolate, &script_source,
246 v8::ScriptCompiler::kConsumeParserCache);
247 i::FLAG_lazy = lazy_flag;
251 TEST(PreparseFunctionDataIsUsed) {
252 // This tests that we actually do use the function data generated by the
255 // Make preparsing work for short scripts.
256 i::FLAG_min_preparse_length = 0;
257 i::FLAG_harmony_arrow_functions = true;
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);
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();",
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();",
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, &good_source,
280 v8::ScriptCompiler::kProduceDataToCache);
282 const v8::ScriptCompiler::CachedData* cached_data =
283 good_source.GetCachedData();
284 CHECK(cached_data->data != NULL);
285 CHECK_GT(cached_data->length, 0);
287 // Now compile the erroneous code with the good preparse data. If the
288 // preparse data is used, the lazy function is skipped and it should
290 v8::ScriptCompiler::Source bad_source(
291 v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData(
292 cached_data->data, cached_data->length));
293 v8::Local<v8::Value> result =
294 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
295 CHECK(result->IsInt32());
296 CHECK_EQ(25, result->Int32Value());
301 TEST(StandAlonePreParser) {
302 v8::V8::Initialize();
304 CcTest::i_isolate()->stack_guard()->SetStackLimit(
305 i::GetCurrentStackPosition() - 128 * 1024);
307 const char* programs[] = {
310 "function foo(x, y) { return x + y; }",
311 "%ArgleBargle(glop);",
312 "var x = new new Function('this.x = 42');",
313 "var f = (x, y) => x + y;",
317 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
318 for (int i = 0; programs[i]; i++) {
319 const char* program = programs[i];
320 i::Utf8ToUtf16CharacterStream stream(
321 reinterpret_cast<const i::byte*>(program),
322 static_cast<unsigned>(strlen(program)));
323 i::CompleteParserRecorder log;
324 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
325 scanner.Initialize(&stream);
328 i::AstValueFactory ast_value_factory(
329 &zone, CcTest::i_isolate()->heap()->HashSeed());
330 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
332 preparser.set_allow_lazy(true);
333 preparser.set_allow_natives(true);
334 preparser.set_allow_harmony_arrow_functions(true);
335 i::PreParser::PreParseResult result = preparser.PreParseProgram();
336 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
337 CHECK(!log.HasError());
342 TEST(StandAlonePreParserNoNatives) {
343 v8::V8::Initialize();
345 CcTest::i_isolate()->stack_guard()->SetStackLimit(
346 i::GetCurrentStackPosition() - 128 * 1024);
348 const char* programs[] = {
349 "%ArgleBargle(glop);",
350 "var x = %_IsSmi(42);",
354 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
355 for (int i = 0; programs[i]; i++) {
356 const char* program = programs[i];
357 i::Utf8ToUtf16CharacterStream stream(
358 reinterpret_cast<const i::byte*>(program),
359 static_cast<unsigned>(strlen(program)));
360 i::CompleteParserRecorder log;
361 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
362 scanner.Initialize(&stream);
364 // Preparser defaults to disallowing natives syntax.
366 i::AstValueFactory ast_value_factory(
367 &zone, CcTest::i_isolate()->heap()->HashSeed());
368 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
370 preparser.set_allow_lazy(true);
371 i::PreParser::PreParseResult result = preparser.PreParseProgram();
372 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
373 CHECK(log.HasError());
378 TEST(PreparsingObjectLiterals) {
379 // Regression test for a bug where the symbol stream produced by PreParser
380 // didn't match what Parser wanted to consume.
381 v8::Isolate* isolate = CcTest::isolate();
382 v8::HandleScope handles(isolate);
383 v8::Local<v8::Context> context = v8::Context::New(isolate);
384 v8::Context::Scope context_scope(context);
385 CcTest::i_isolate()->stack_guard()->SetStackLimit(
386 i::GetCurrentStackPosition() - 128 * 1024);
389 const char* source = "var myo = {if: \"foo\"}; myo.if;";
390 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
391 CHECK(result->IsString());
392 v8::String::Utf8Value utf8(result);
393 CHECK_EQ(0, strcmp("foo", *utf8));
397 const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
398 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
399 CHECK(result->IsString());
400 v8::String::Utf8Value utf8(result);
401 CHECK_EQ(0, strcmp("foo", *utf8));
405 const char* source = "var myo = {1: \"foo\"}; myo[1];";
406 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
407 CHECK(result->IsString());
408 v8::String::Utf8Value utf8(result);
409 CHECK_EQ(0, strcmp("foo", *utf8));
414 TEST(RegressChromium62639) {
415 v8::V8::Initialize();
416 i::Isolate* isolate = CcTest::i_isolate();
418 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
421 const char* program = "var x = 'something';\n"
422 "escape: function() {}";
423 // Fails parsing expecting an identifier after "function".
424 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
425 // and then used the invalid currently scanned literal. This always
426 // failed in debug mode, and sometimes crashed in release mode.
428 i::Utf8ToUtf16CharacterStream stream(
429 reinterpret_cast<const i::byte*>(program),
430 static_cast<unsigned>(strlen(program)));
431 i::CompleteParserRecorder log;
432 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
433 scanner.Initialize(&stream);
435 i::AstValueFactory ast_value_factory(&zone,
436 CcTest::i_isolate()->heap()->HashSeed());
437 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
438 CcTest::i_isolate()->stack_guard()->real_climit());
439 preparser.set_allow_lazy(true);
440 i::PreParser::PreParseResult result = preparser.PreParseProgram();
441 // Even in the case of a syntax error, kPreParseSuccess is returned.
442 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
443 CHECK(log.HasError());
448 v8::V8::Initialize();
449 i::Isolate* isolate = CcTest::i_isolate();
450 i::Factory* factory = isolate->factory();
452 // Preparsing didn't consider the catch clause of a try statement
453 // as with-content, which made it assume that a function inside
454 // the block could be lazily compiled, and an extra, unexpected,
455 // entry was added to the data.
456 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
459 const char* program =
460 "try { } catch (e) { var foo = function () { /* first */ } }"
461 "var bar = function () { /* second */ }";
463 v8::HandleScope handles(CcTest::isolate());
464 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program);
465 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
466 i::CompleteParserRecorder log;
467 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
468 scanner.Initialize(&stream);
470 i::AstValueFactory ast_value_factory(&zone,
471 CcTest::i_isolate()->heap()->HashSeed());
472 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
473 CcTest::i_isolate()->stack_guard()->real_climit());
474 preparser.set_allow_lazy(true);
475 i::PreParser::PreParseResult result = preparser.PreParseProgram();
476 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
477 i::ScriptData* sd = log.GetScriptData();
478 i::ParseData* pd = i::ParseData::FromCachedData(sd);
482 static_cast<int>(strstr(program, "function") - program);
483 int first_lbrace = first_function + i::StrLength("function () ");
484 CHECK_EQ('{', program[first_lbrace]);
485 i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
486 CHECK(!entry1.is_valid());
488 int second_function =
489 static_cast<int>(strstr(program + first_lbrace, "function") - program);
491 second_function + i::StrLength("function () ");
492 CHECK_EQ('{', program[second_lbrace]);
493 i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
494 CHECK(entry2.is_valid());
495 CHECK_EQ('}', program[entry2.end_pos() - 1]);
501 TEST(PreParseOverflow) {
502 v8::V8::Initialize();
504 CcTest::i_isolate()->stack_guard()->SetStackLimit(
505 i::GetCurrentStackPosition() - 128 * 1024);
507 size_t kProgramSize = 1024 * 1024;
508 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
509 memset(program.get(), '(', kProgramSize);
510 program[kProgramSize] = '\0';
512 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
514 i::Utf8ToUtf16CharacterStream stream(
515 reinterpret_cast<const i::byte*>(program.get()),
516 static_cast<unsigned>(kProgramSize));
517 i::CompleteParserRecorder log;
518 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
519 scanner.Initialize(&stream);
522 i::AstValueFactory ast_value_factory(&zone,
523 CcTest::i_isolate()->heap()->HashSeed());
524 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
526 preparser.set_allow_lazy(true);
527 preparser.set_allow_harmony_arrow_functions(true);
528 i::PreParser::PreParseResult result = preparser.PreParseProgram();
529 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
533 class TestExternalResource: public v8::String::ExternalStringResource {
535 explicit TestExternalResource(uint16_t* data, int length)
536 : data_(data), length_(static_cast<size_t>(length)) { }
538 ~TestExternalResource() { }
540 const uint16_t* data() const {
544 size_t length() const {
553 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
555 void TestCharacterStream(const char* one_byte_source, unsigned length,
556 unsigned start = 0, unsigned end = 0) {
557 if (end == 0) end = length;
558 unsigned sub_length = end - start;
559 i::Isolate* isolate = CcTest::i_isolate();
560 i::Factory* factory = isolate->factory();
561 i::HandleScope test_scope(isolate);
562 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
563 for (unsigned i = 0; i < length; i++) {
564 uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]);
566 i::Vector<const char> one_byte_vector(one_byte_source,
567 static_cast<int>(length));
568 i::Handle<i::String> one_byte_string =
569 factory->NewStringFromAscii(one_byte_vector).ToHandleChecked();
570 TestExternalResource resource(uc16_buffer.get(), length);
571 i::Handle<i::String> uc16_string(
572 factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked());
574 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
575 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
576 i::GenericStringUtf16CharacterStream string_stream(one_byte_string, start,
578 i::Utf8ToUtf16CharacterStream utf8_stream(
579 reinterpret_cast<const i::byte*>(one_byte_source), end);
580 utf8_stream.SeekForward(start);
584 // Read streams one char at a time
585 CHECK_EQU(i, uc16_stream.pos());
586 CHECK_EQU(i, string_stream.pos());
587 CHECK_EQU(i, utf8_stream.pos());
588 int32_t c0 = one_byte_source[i];
589 int32_t c1 = uc16_stream.Advance();
590 int32_t c2 = string_stream.Advance();
591 int32_t c3 = utf8_stream.Advance();
596 CHECK_EQU(i, uc16_stream.pos());
597 CHECK_EQU(i, string_stream.pos());
598 CHECK_EQU(i, utf8_stream.pos());
600 while (i > start + sub_length / 4) {
601 // Pushback, re-read, pushback again.
602 int32_t c0 = one_byte_source[i - 1];
603 CHECK_EQU(i, uc16_stream.pos());
604 CHECK_EQU(i, string_stream.pos());
605 CHECK_EQU(i, utf8_stream.pos());
606 uc16_stream.PushBack(c0);
607 string_stream.PushBack(c0);
608 utf8_stream.PushBack(c0);
610 CHECK_EQU(i, uc16_stream.pos());
611 CHECK_EQU(i, string_stream.pos());
612 CHECK_EQU(i, utf8_stream.pos());
613 int32_t c1 = uc16_stream.Advance();
614 int32_t c2 = string_stream.Advance();
615 int32_t c3 = utf8_stream.Advance();
617 CHECK_EQU(i, uc16_stream.pos());
618 CHECK_EQU(i, string_stream.pos());
619 CHECK_EQU(i, utf8_stream.pos());
623 uc16_stream.PushBack(c0);
624 string_stream.PushBack(c0);
625 utf8_stream.PushBack(c0);
627 CHECK_EQU(i, uc16_stream.pos());
628 CHECK_EQU(i, string_stream.pos());
629 CHECK_EQU(i, utf8_stream.pos());
631 unsigned halfway = start + sub_length / 2;
632 uc16_stream.SeekForward(halfway - i);
633 string_stream.SeekForward(halfway - i);
634 utf8_stream.SeekForward(halfway - i);
636 CHECK_EQU(i, uc16_stream.pos());
637 CHECK_EQU(i, string_stream.pos());
638 CHECK_EQU(i, utf8_stream.pos());
641 // Read streams one char at a time
642 CHECK_EQU(i, uc16_stream.pos());
643 CHECK_EQU(i, string_stream.pos());
644 CHECK_EQU(i, utf8_stream.pos());
645 int32_t c0 = one_byte_source[i];
646 int32_t c1 = uc16_stream.Advance();
647 int32_t c2 = string_stream.Advance();
648 int32_t c3 = utf8_stream.Advance();
653 CHECK_EQU(i, uc16_stream.pos());
654 CHECK_EQU(i, string_stream.pos());
655 CHECK_EQU(i, utf8_stream.pos());
658 int32_t c1 = uc16_stream.Advance();
659 int32_t c2 = string_stream.Advance();
660 int32_t c3 = utf8_stream.Advance();
667 TEST(CharacterStreams) {
668 v8::Isolate* isolate = CcTest::isolate();
669 v8::HandleScope handles(isolate);
670 v8::Local<v8::Context> context = v8::Context::New(isolate);
671 v8::Context::Scope context_scope(context);
673 TestCharacterStream("abc\0\n\r\x7f", 7);
674 static const unsigned kBigStringSize = 4096;
675 char buffer[kBigStringSize + 1];
676 for (unsigned i = 0; i < kBigStringSize; i++) {
677 buffer[i] = static_cast<char>(i & 0x7f);
679 TestCharacterStream(buffer, kBigStringSize);
681 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
683 TestCharacterStream("\0", 1);
684 TestCharacterStream("", 0);
688 TEST(Utf8CharacterStream) {
689 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
690 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
692 static const int kAllUtf8CharsSize =
693 (unibrow::Utf8::kMaxOneByteChar + 1) +
694 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
695 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
696 static const unsigned kAllUtf8CharsSizeU =
697 static_cast<unsigned>(kAllUtf8CharsSize);
699 char buffer[kAllUtf8CharsSizeU];
701 for (int i = 0; i <= kMaxUC16Char; i++) {
702 cursor += unibrow::Utf8::Encode(buffer + cursor,
704 unibrow::Utf16::kNoPreviousCharacter);
706 DCHECK(cursor == kAllUtf8CharsSizeU);
708 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
710 for (int i = 0; i <= kMaxUC16Char; i++) {
711 CHECK_EQU(i, stream.pos());
712 int32_t c = stream.Advance();
714 CHECK_EQU(i + 1, stream.pos());
716 for (int i = kMaxUC16Char; i >= 0; i--) {
717 CHECK_EQU(i + 1, stream.pos());
719 CHECK_EQU(i, stream.pos());
722 while (stream.pos() < kMaxUC16CharU) {
723 CHECK_EQU(i, stream.pos());
724 int progress = static_cast<int>(stream.SeekForward(12));
726 int32_t c = stream.Advance();
727 if (i <= kMaxUC16Char) {
733 CHECK_EQU(i, stream.pos());
739 void TestStreamScanner(i::Utf16CharacterStream* stream,
740 i::Token::Value* expected_tokens,
741 int skip_pos = 0, // Zero means not skipping.
743 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
744 scanner.Initialize(stream);
748 i::Token::Value expected = expected_tokens[i];
749 i::Token::Value actual = scanner.Next();
750 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
751 if (scanner.location().end_pos == skip_pos) {
752 scanner.SeekForward(skip_to);
755 } while (expected_tokens[i] != i::Token::ILLEGAL);
759 TEST(StreamScanner) {
760 v8::V8::Initialize();
762 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
763 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
764 static_cast<unsigned>(strlen(str1)));
765 i::Token::Value expectations1[] = {
767 i::Token::IDENTIFIER,
768 i::Token::IDENTIFIER,
775 i::Token::IDENTIFIER,
779 TestStreamScanner(&stream1, expectations1, 0, 0);
781 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
782 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
783 static_cast<unsigned>(strlen(str2)));
784 i::Token::Value expectations2[] = {
795 DCHECK_EQ('{', str2[19]);
796 DCHECK_EQ('}', str2[37]);
797 TestStreamScanner(&stream2, expectations2, 20, 37);
799 const char* str3 = "{}}}}";
800 i::Token::Value expectations3[] = {
809 // Skip zero-four RBRACEs.
810 for (int i = 0; i <= 4; i++) {
811 expectations3[6 - i] = i::Token::ILLEGAL;
812 expectations3[5 - i] = i::Token::EOS;
813 i::Utf8ToUtf16CharacterStream stream3(
814 reinterpret_cast<const i::byte*>(str3),
815 static_cast<unsigned>(strlen(str3)));
816 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
821 void TestScanRegExp(const char* re_source, const char* expected) {
822 i::Utf8ToUtf16CharacterStream stream(
823 reinterpret_cast<const i::byte*>(re_source),
824 static_cast<unsigned>(strlen(re_source)));
825 i::HandleScope scope(CcTest::i_isolate());
826 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
827 scanner.Initialize(&stream);
829 i::Token::Value start = scanner.peek();
830 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
831 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
832 scanner.Next(); // Current token is now the regexp literal.
834 i::AstValueFactory ast_value_factory(&zone,
835 CcTest::i_isolate()->heap()->HashSeed());
836 ast_value_factory.Internalize(CcTest::i_isolate());
837 i::Handle<i::String> val =
838 scanner.CurrentSymbol(&ast_value_factory)->string();
839 i::DisallowHeapAllocation no_alloc;
840 i::String::FlatContent content = val->GetFlatContent();
841 CHECK(content.IsOneByte());
842 i::Vector<const uint8_t> actual = content.ToOneByteVector();
843 for (int i = 0; i < actual.length(); i++) {
844 CHECK_NE('\0', expected[i]);
845 CHECK_EQ(expected[i], actual[i]);
850 TEST(RegExpScanning) {
851 v8::V8::Initialize();
853 // RegExp token with added garbage at the end. The scanner should only
854 // scan the RegExp until the terminating slash just before "flipperwald".
855 TestScanRegExp("/b/flipperwald", "b");
856 // Incomplete escape sequences doesn't hide the terminating slash.
857 TestScanRegExp("/\\x/flipperwald", "\\x");
858 TestScanRegExp("/\\u/flipperwald", "\\u");
859 TestScanRegExp("/\\u1/flipperwald", "\\u1");
860 TestScanRegExp("/\\u12/flipperwald", "\\u12");
861 TestScanRegExp("/\\u123/flipperwald", "\\u123");
862 TestScanRegExp("/\\c/flipperwald", "\\c");
863 TestScanRegExp("/\\c//flipperwald", "\\c");
864 // Slashes inside character classes are not terminating.
865 TestScanRegExp("/[/]/flipperwald", "[/]");
866 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
867 // Incomplete escape sequences inside a character class doesn't hide
868 // the end of the character class.
869 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
870 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
871 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
872 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
873 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
874 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
875 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
876 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
877 // Escaped ']'s wont end the character class.
878 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
879 // Escaped slashes are not terminating.
880 TestScanRegExp("/\\//flipperwald", "\\/");
881 // Starting with '=' works too.
882 TestScanRegExp("/=/", "=");
883 TestScanRegExp("/=?/", "=?");
887 static int Utf8LengthHelper(const char* s) {
888 int len = i::StrLength(s);
889 int character_length = len;
890 for (int i = 0; i < len; i++) {
891 unsigned char c = s[i];
892 int input_offset = 0;
893 int output_adjust = 0;
895 if (c < 0xc0) continue;
898 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
900 continue; // Handle first UTF-8 byte.
902 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
903 // This 4 byte sequence could have been coded as a 3 byte sequence.
904 // Record a single kBadChar for the first byte and continue.
908 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
909 character_length -= 2;
910 } else if (c >= 0xe0) {
911 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
912 // This 3 byte sequence could have been coded as a 2 byte sequence.
913 // Record a single kBadChar for the first byte and continue.
917 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
920 if ((c & 0x1e) == 0) {
921 // This 2 byte sequence could have been coded as a 1 byte sequence.
922 // Record a single kBadChar for the first byte and continue.
926 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
930 for (int j = 1; j <= input_offset; j++) {
931 if ((s[i + j] & 0xc0) != 0x80) {
932 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
933 // which is a single UTF-16 code unit.
940 character_length -= output_adjust;
944 return character_length;
948 TEST(ScopeUsesArgumentsSuperThis) {
949 static const struct {
953 { "function f() {", "}" },
954 { "var f = () => {", "};" },
955 { "class C { constructor() {", "} }" },
961 SUPER_PROPERTY = 1 << 1,
963 INNER_ARGUMENTS = 1 << 3,
964 INNER_SUPER_PROPERTY = 1 << 4,
968 static const struct {
973 {"return this", THIS},
974 {"return arguments", ARGUMENTS},
975 {"return super.x", SUPER_PROPERTY},
976 {"return arguments[0]", ARGUMENTS},
977 {"return this + arguments[0]", ARGUMENTS | THIS},
978 {"return this + arguments[0] + super.x",
979 ARGUMENTS | SUPER_PROPERTY | THIS},
980 {"return x => this + x", INNER_THIS},
981 {"return x => super.f() + x", INNER_SUPER_PROPERTY},
982 {"this.foo = 42;", THIS},
983 {"this.foo();", THIS},
984 {"if (foo()) { this.f() }", THIS},
985 {"if (foo()) { super.f() }", SUPER_PROPERTY},
986 {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
987 {"while (true) { this.f() }", THIS},
988 {"while (true) { super.f() }", SUPER_PROPERTY},
989 {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
990 // Multiple nesting levels must work as well.
991 {"while (true) { while (true) { while (true) return this } }", THIS},
992 {"while (true) { while (true) { while (true) return super.f() } }",
994 {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
995 // Note that propagation of the inner_uses_this() value does not
996 // cross boundaries of normal functions onto parent scopes.
997 {"return function (x) { return this + x }", NONE},
998 {"return { m(x) { return super.m() + x } }", NONE},
999 {"var x = function () { this.foo = 42 };", NONE},
1000 {"var x = { m() { super.foo = 42 } };", NONE},
1001 {"if (1) { return function () { while (true) new this() } }", NONE},
1002 {"if (1) { return { m() { while (true) super.m() } } }", NONE},
1003 {"return function (x) { return () => this }", NONE},
1004 {"return { m(x) { return () => super.m() } }", NONE},
1005 // Flags must be correctly set when using block scoping.
1006 {"\"use strict\"; while (true) { let x; this, arguments; }",
1007 INNER_ARGUMENTS | INNER_THIS},
1008 {"\"use strict\"; while (true) { let x; this, super.f(), arguments; }",
1009 INNER_ARGUMENTS | INNER_SUPER_PROPERTY | INNER_THIS},
1010 {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
1011 {"\"use strict\"; if (foo()) { let x; super.f() }",
1012 INNER_SUPER_PROPERTY},
1013 {"\"use strict\"; if (1) {"
1014 " let x; return { m() { return this + super.m() + arguments } }"
1019 i::Isolate* isolate = CcTest::i_isolate();
1020 i::Factory* factory = isolate->factory();
1022 v8::HandleScope handles(CcTest::isolate());
1023 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1024 v8::Context::Scope context_scope(context);
1026 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1029 for (unsigned j = 0; j < arraysize(surroundings); ++j) {
1030 for (unsigned i = 0; i < arraysize(source_data); ++i) {
1031 // Super property is only allowed in constructor and method.
1032 if (((source_data[i].expected & SUPER_PROPERTY) ||
1033 (source_data[i].expected & INNER_SUPER_PROPERTY) ||
1034 (source_data[i].expected == NONE)) && j != 2) {
1037 int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
1038 i::StrLength(surroundings[j].suffix) +
1039 i::StrLength(source_data[i].body);
1040 i::ScopedVector<char> program(kProgramByteSize + 1);
1041 i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
1042 source_data[i].body, surroundings[j].suffix);
1043 i::Handle<i::String> source =
1044 factory->NewStringFromUtf8(i::CStrVector(program.start()))
1046 i::Handle<i::Script> script = factory->NewScript(source);
1048 i::ParseInfo info(&zone, script);
1049 i::Parser parser(&info);
1050 parser.set_allow_harmony_arrow_functions(true);
1051 parser.set_allow_harmony_classes(true);
1052 parser.set_allow_harmony_object_literals(true);
1053 parser.set_allow_harmony_sloppy(true);
1055 CHECK(parser.Parse(&info));
1056 CHECK(i::Rewriter::Rewrite(&info));
1057 CHECK(i::Scope::Analyze(&info));
1058 CHECK(info.function() != NULL);
1060 i::Scope* script_scope = info.function()->scope();
1061 CHECK(script_scope->is_script_scope());
1062 CHECK_EQ(1, script_scope->inner_scopes()->length());
1064 i::Scope* scope = script_scope->inner_scopes()->at(0);
1065 // Adjust for constructor scope.
1067 CHECK_EQ(1, scope->inner_scopes()->length());
1068 scope = scope->inner_scopes()->at(0);
1070 CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
1071 scope->uses_arguments());
1072 CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
1073 scope->uses_super_property());
1074 CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
1075 CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
1076 scope->inner_uses_arguments());
1077 CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
1078 scope->inner_uses_super_property());
1079 CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
1080 scope->inner_uses_this());
1086 TEST(ScopePositions) {
1087 // Test the parser for correctly setting the start and end positions
1088 // of a scope. We check the scope positions of exactly one scope
1089 // nested in the global scope of a program. 'inner source' is the
1090 // source code that determines the part of the source belonging
1091 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
1092 // parts of the source that belong to the global scope.
1094 const char* outer_prefix;
1095 const char* inner_source;
1096 const char* outer_suffix;
1097 i::ScopeType scope_type;
1098 i::LanguageMode language_mode;
1101 const SourceData source_data[] = {
1102 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
1103 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
1104 { " with ({}) ", "{\n"
1107 " more;", i::WITH_SCOPE, i::SLOPPY },
1108 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
1109 { " with ({}) ", "statement", "\n"
1110 " more;", i::WITH_SCOPE, i::SLOPPY },
1112 " ", "statement;", "\n"
1113 " more;", i::WITH_SCOPE, i::SLOPPY },
1114 { " try {} catch ", "(e) { block; }", " more;",
1115 i::CATCH_SCOPE, i::SLOPPY },
1116 { " try {} catch ", "(e) { block; }", "; more;",
1117 i::CATCH_SCOPE, i::SLOPPY },
1118 { " try {} catch ", "(e) {\n"
1121 " more;", i::CATCH_SCOPE, i::SLOPPY },
1122 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
1123 i::CATCH_SCOPE, i::SLOPPY },
1125 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
1127 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
1132 " more;", i::BLOCK_SCOPE, i::STRICT },
1134 " function fun", "(a,b) { infunction; }", " more;",
1135 i::FUNCTION_SCOPE, i::SLOPPY },
1137 " function fun", "(a,b) {\n"
1140 " more;", i::FUNCTION_SCOPE, i::SLOPPY },
1141 { " start;\n", "(a,b) => a + b", "; more;",
1142 i::ARROW_SCOPE, i::SLOPPY },
1143 { " start;\n", "(a,b) => { return a+b; }", "\nmore;",
1144 i::ARROW_SCOPE, i::SLOPPY },
1146 " (function fun", "(a,b) { infunction; }", ")();",
1147 i::FUNCTION_SCOPE, i::SLOPPY },
1148 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
1149 i::BLOCK_SCOPE, i::STRICT },
1150 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
1151 i::BLOCK_SCOPE, i::STRICT },
1152 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
1155 " more;", i::BLOCK_SCOPE, i::STRICT },
1156 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
1157 i::BLOCK_SCOPE, i::STRICT },
1158 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
1159 " more;", i::BLOCK_SCOPE, i::STRICT },
1160 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
1162 " more;", i::BLOCK_SCOPE, i::STRICT },
1163 { " for ", "(let x in {}) { block; }", " more;",
1164 i::BLOCK_SCOPE, i::STRICT },
1165 { " for ", "(let x in {}) { block; }", "; more;",
1166 i::BLOCK_SCOPE, i::STRICT },
1167 { " for ", "(let x in {}) {\n"
1170 " more;", i::BLOCK_SCOPE, i::STRICT },
1171 { " for ", "(let x in {}) statement;", " more;",
1172 i::BLOCK_SCOPE, i::STRICT },
1173 { " for ", "(let x in {}) statement", "\n"
1174 " more;", i::BLOCK_SCOPE, i::STRICT },
1175 { " for ", "(let x in {})\n"
1177 " more;", i::BLOCK_SCOPE, i::STRICT },
1178 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
1179 // the preparser off in terms of byte offsets.
1181 { " 'foo\355\240\201\355\260\211';\n"
1182 " (function fun", "(a,b) { infunction; }", ")();",
1183 i::FUNCTION_SCOPE, i::SLOPPY },
1185 { " 'foo\360\220\220\212';\n"
1186 " (function fun", "(a,b) { infunction; }", ")();",
1187 i::FUNCTION_SCOPE, i::SLOPPY },
1188 // 3 byte encoding of \u0fff.
1189 { " 'foo\340\277\277';\n"
1190 " (function fun", "(a,b) { infunction; }", ")();",
1191 i::FUNCTION_SCOPE, i::SLOPPY },
1192 // Broken 6 byte encoding with missing last byte.
1193 { " 'foo\355\240\201\355\211';\n"
1194 " (function fun", "(a,b) { infunction; }", ")();",
1195 i::FUNCTION_SCOPE, i::SLOPPY },
1196 // Broken 3 byte encoding of \u0fff with missing last byte.
1197 { " 'foo\340\277';\n"
1198 " (function fun", "(a,b) { infunction; }", ")();",
1199 i::FUNCTION_SCOPE, i::SLOPPY },
1200 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
1202 " (function fun", "(a,b) { infunction; }", ")();",
1203 i::FUNCTION_SCOPE, i::SLOPPY },
1204 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
1205 { " 'foo\340\203\277';\n"
1206 " (function fun", "(a,b) { infunction; }", ")();",
1207 i::FUNCTION_SCOPE, i::SLOPPY },
1208 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
1209 { " 'foo\340\201\277';\n"
1210 " (function fun", "(a,b) { infunction; }", ")();",
1211 i::FUNCTION_SCOPE, i::SLOPPY },
1212 // Unpaired lead surrogate.
1213 { " 'foo\355\240\201';\n"
1214 " (function fun", "(a,b) { infunction; }", ")();",
1215 i::FUNCTION_SCOPE, i::SLOPPY },
1216 // Unpaired lead surrogate where following code point is a 3 byte sequence.
1217 { " 'foo\355\240\201\340\277\277';\n"
1218 " (function fun", "(a,b) { infunction; }", ")();",
1219 i::FUNCTION_SCOPE, i::SLOPPY },
1220 // Unpaired lead surrogate where following code point is a 4 byte encoding
1221 // of a trail surrogate.
1222 { " 'foo\355\240\201\360\215\260\211';\n"
1223 " (function fun", "(a,b) { infunction; }", ")();",
1224 i::FUNCTION_SCOPE, i::SLOPPY },
1225 // Unpaired trail surrogate.
1226 { " 'foo\355\260\211';\n"
1227 " (function fun", "(a,b) { infunction; }", ")();",
1228 i::FUNCTION_SCOPE, i::SLOPPY },
1229 // 2 byte encoding of \u00ff.
1230 { " 'foo\303\277';\n"
1231 " (function fun", "(a,b) { infunction; }", ")();",
1232 i::FUNCTION_SCOPE, i::SLOPPY },
1233 // Broken 2 byte encoding of \u00ff with missing last byte.
1235 " (function fun", "(a,b) { infunction; }", ")();",
1236 i::FUNCTION_SCOPE, i::SLOPPY },
1237 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
1238 { " 'foo\301\277';\n"
1239 " (function fun", "(a,b) { infunction; }", ")();",
1240 i::FUNCTION_SCOPE, i::SLOPPY },
1241 // Illegal 5 byte encoding.
1242 { " 'foo\370\277\277\277\277';\n"
1243 " (function fun", "(a,b) { infunction; }", ")();",
1244 i::FUNCTION_SCOPE, i::SLOPPY },
1245 // Illegal 6 byte encoding.
1246 { " 'foo\374\277\277\277\277\277';\n"
1247 " (function fun", "(a,b) { infunction; }", ")();",
1248 i::FUNCTION_SCOPE, i::SLOPPY },
1249 // Illegal 0xfe byte
1250 { " 'foo\376\277\277\277\277\277\277';\n"
1251 " (function fun", "(a,b) { infunction; }", ")();",
1252 i::FUNCTION_SCOPE, i::SLOPPY },
1253 // Illegal 0xff byte
1254 { " 'foo\377\277\277\277\277\277\277\277';\n"
1255 " (function fun", "(a,b) { infunction; }", ")();",
1256 i::FUNCTION_SCOPE, i::SLOPPY },
1258 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
1259 i::FUNCTION_SCOPE, i::SLOPPY },
1261 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
1262 i::FUNCTION_SCOPE, i::SLOPPY },
1263 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
1266 i::Isolate* isolate = CcTest::i_isolate();
1267 i::Factory* factory = isolate->factory();
1269 v8::HandleScope handles(CcTest::isolate());
1270 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1271 v8::Context::Scope context_scope(context);
1273 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1276 for (int i = 0; source_data[i].outer_prefix; i++) {
1277 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1278 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1279 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1280 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1281 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1282 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1283 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1284 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1285 i::ScopedVector<char> program(kProgramByteSize + 1);
1286 i::SNPrintF(program, "%s%s%s",
1287 source_data[i].outer_prefix,
1288 source_data[i].inner_source,
1289 source_data[i].outer_suffix);
1291 // Parse program source.
1292 i::Handle<i::String> source = factory->NewStringFromUtf8(
1293 i::CStrVector(program.start())).ToHandleChecked();
1294 CHECK_EQ(source->length(), kProgramSize);
1295 i::Handle<i::Script> script = factory->NewScript(source);
1297 i::ParseInfo info(&zone, script);
1298 i::Parser parser(&info);
1299 parser.set_allow_lazy(true);
1300 parser.set_allow_harmony_arrow_functions(true);
1302 info.set_language_mode(source_data[i].language_mode);
1303 parser.Parse(&info);
1304 CHECK(info.function() != NULL);
1306 // Check scope types and positions.
1307 i::Scope* scope = info.function()->scope();
1308 CHECK(scope->is_script_scope());
1309 CHECK_EQ(scope->start_position(), 0);
1310 CHECK_EQ(scope->end_position(), kProgramSize);
1311 CHECK_EQ(scope->inner_scopes()->length(), 1);
1313 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1314 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
1315 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1316 // The end position of a token is one position after the last
1317 // character belonging to that token.
1318 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1323 const char* ReadString(unsigned* start) {
1324 int length = start[0];
1325 char* result = i::NewArray<char>(length + 1);
1326 for (int i = 0; i < length; i++) {
1327 result[i] = start[i + 1];
1329 result[length] = '\0';
1334 i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
1335 i::Isolate* isolate = CcTest::i_isolate();
1336 i::Factory* factory = isolate->factory();
1337 const char* message =
1338 ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
1339 i::Handle<i::String> format = v8::Utils::OpenHandle(
1340 *v8::String::NewFromUtf8(CcTest::isolate(), message));
1341 int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
1342 const char* arg = NULL;
1343 i::Handle<i::JSArray> args_array;
1344 if (arg_count == 1) {
1345 // Position after text found by skipping past length field and
1346 // length field content words.
1347 int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
1348 data[i::PreparseDataConstants::kMessageTextPos];
1349 arg = ReadString(&data[pos]);
1350 args_array = factory->NewJSArray(1);
1351 i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
1352 NONE, i::SLOPPY).Check();
1354 CHECK_EQ(0, arg_count);
1355 args_array = factory->NewJSArray(0);
1358 i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
1359 i::Handle<i::Object> format_fun = i::Object::GetProperty(
1360 isolate, builtins, "FormatMessage").ToHandleChecked();
1361 i::Handle<i::Object> arg_handles[] = { format, args_array };
1362 i::Handle<i::Object> result = i::Execution::Call(
1363 isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked();
1364 CHECK(result->IsString());
1365 i::DeleteArray(message);
1366 i::DeleteArray(arg);
1368 return i::Handle<i::String>::cast(result);
1375 kAllowHarmonyModules,
1376 kAllowHarmonyNumericLiterals,
1377 kAllowHarmonyArrowFunctions,
1378 kAllowHarmonyClasses,
1379 kAllowHarmonyObjectLiterals,
1380 kAllowHarmonyRestParameters,
1381 kAllowHarmonySloppy,
1382 kAllowHarmonyUnicode,
1383 kAllowHarmonyComputedPropertyNames,
1388 enum ParserSyncTestResult {
1394 template <typename Traits>
1395 void SetParserFlags(i::ParserBase<Traits>* parser,
1396 i::EnumSet<ParserFlag> flags) {
1397 parser->set_allow_lazy(flags.Contains(kAllowLazy));
1398 parser->set_allow_natives(flags.Contains(kAllowNatives));
1399 parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
1400 parser->set_allow_harmony_numeric_literals(
1401 flags.Contains(kAllowHarmonyNumericLiterals));
1402 parser->set_allow_harmony_object_literals(
1403 flags.Contains(kAllowHarmonyObjectLiterals));
1404 parser->set_allow_harmony_arrow_functions(
1405 flags.Contains(kAllowHarmonyArrowFunctions));
1406 parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
1407 parser->set_allow_harmony_rest_params(
1408 flags.Contains(kAllowHarmonyRestParameters));
1409 parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
1410 parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
1411 parser->set_allow_harmony_computed_property_names(
1412 flags.Contains(kAllowHarmonyComputedPropertyNames));
1413 parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode));
1417 void TestParserSyncWithFlags(i::Handle<i::String> source,
1418 i::EnumSet<ParserFlag> flags,
1419 ParserSyncTestResult result) {
1420 i::Isolate* isolate = CcTest::i_isolate();
1421 i::Factory* factory = isolate->factory();
1423 uintptr_t stack_limit = isolate->stack_guard()->real_climit();
1424 int preparser_materialized_literals = -1;
1425 int parser_materialized_literals = -2;
1427 // Preparse the data.
1428 i::CompleteParserRecorder log;
1430 i::Scanner scanner(isolate->unicode_cache());
1431 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1433 i::AstValueFactory ast_value_factory(
1434 &zone, CcTest::i_isolate()->heap()->HashSeed());
1435 i::PreParser preparser(&zone, &scanner, &ast_value_factory, &log,
1437 SetParserFlags(&preparser, flags);
1438 scanner.Initialize(&stream);
1439 i::PreParser::PreParseResult result = preparser.PreParseProgram(
1440 &preparser_materialized_literals);
1441 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1444 bool preparse_error = log.HasError();
1447 i::FunctionLiteral* function;
1449 i::Handle<i::Script> script = factory->NewScript(source);
1451 i::ParseInfo info(&zone, script);
1452 i::Parser parser(&info);
1453 SetParserFlags(&parser, flags);
1455 parser.Parse(&info);
1456 function = info.function();
1458 parser_materialized_literals = function->materialized_literal_count();
1462 // Check that preparsing fails iff parsing fails.
1463 if (function == NULL) {
1464 // Extract exception from the parser.
1465 CHECK(isolate->has_pending_exception());
1466 i::Handle<i::JSObject> exception_handle(
1467 i::JSObject::cast(isolate->pending_exception()));
1468 i::Handle<i::String> message_string =
1469 i::Handle<i::String>::cast(i::Object::GetProperty(
1470 isolate, exception_handle, "message").ToHandleChecked());
1472 if (result == kSuccess) {
1473 v8::base::OS::Print(
1474 "Parser failed on:\n"
1478 "However, we expected no error.",
1479 source->ToCString().get(), message_string->ToCString().get());
1483 if (!preparse_error) {
1484 v8::base::OS::Print(
1485 "Parser failed on:\n"
1489 "However, the preparser succeeded",
1490 source->ToCString().get(), message_string->ToCString().get());
1493 // Check that preparser and parser produce the same error.
1494 i::Handle<i::String> preparser_message =
1495 FormatMessage(log.ErrorMessageData());
1496 if (!i::String::Equals(message_string, preparser_message)) {
1497 v8::base::OS::Print(
1498 "Expected parser and preparser to produce the same error on:\n"
1500 "However, found the following error messages\n"
1502 "\tpreparser: %s\n",
1503 source->ToCString().get(),
1504 message_string->ToCString().get(),
1505 preparser_message->ToCString().get());
1508 } else if (preparse_error) {
1509 v8::base::OS::Print(
1510 "Preparser failed on:\n"
1514 "However, the parser succeeded",
1515 source->ToCString().get(),
1516 FormatMessage(log.ErrorMessageData())->ToCString().get());
1518 } else if (result == kError) {
1519 v8::base::OS::Print(
1520 "Expected error on:\n"
1522 "However, parser and preparser succeeded",
1523 source->ToCString().get());
1525 } else if (preparser_materialized_literals != parser_materialized_literals) {
1526 v8::base::OS::Print(
1527 "Preparser materialized literals (%d) differ from Parser materialized "
1528 "literals (%d) on:\n"
1530 "However, parser and preparser succeeded",
1531 preparser_materialized_literals, parser_materialized_literals,
1532 source->ToCString().get());
1538 void TestParserSync(const char* source,
1539 const ParserFlag* varying_flags,
1540 size_t varying_flags_length,
1541 ParserSyncTestResult result = kSuccessOrError,
1542 const ParserFlag* always_true_flags = NULL,
1543 size_t always_true_flags_length = 0,
1544 const ParserFlag* always_false_flags = NULL,
1545 size_t always_false_flags_length = 0) {
1546 i::Handle<i::String> str =
1547 CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
1548 for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
1549 i::EnumSet<ParserFlag> flags;
1550 for (size_t flag_index = 0; flag_index < varying_flags_length;
1552 if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]);
1554 for (size_t flag_index = 0; flag_index < always_true_flags_length;
1556 flags.Add(always_true_flags[flag_index]);
1558 for (size_t flag_index = 0; flag_index < always_false_flags_length;
1560 flags.Remove(always_false_flags[flag_index]);
1562 TestParserSyncWithFlags(str, flags, result);
1568 const char* context_data[][2] = {
1571 { "if (true) ", " else {}" },
1572 { "if (true) {} else ", "" },
1573 { "if (true) ", "" },
1574 { "do ", " while (false)" },
1575 { "while (false) ", "" },
1576 { "for (;;) ", "" },
1577 { "with ({})", "" },
1578 { "switch (12) { case 12: ", "}" },
1579 { "switch (12) { default: ", "}" },
1580 { "switch (12) { ", "case 12: }" },
1585 const char* statement_data[] = {
1593 "if (false) {} else ;",
1594 "if (false) {} else {}",
1595 "if (false) {} else 12",
1599 "do {} while (false)",
1609 // TODO(marja): activate once parsing 'return' is merged into ParserBase.
1616 "switch ({}) { default: }",
1621 "try {} catch(e) {}",
1622 "try {} finally {}",
1623 "try {} catch(e) {} finally {}",
1628 const char* termination_data[] = {
1637 v8::HandleScope handles(CcTest::isolate());
1638 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1639 v8::Context::Scope context_scope(context);
1641 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1642 i::GetCurrentStackPosition() - 128 * 1024);
1644 for (int i = 0; context_data[i][0] != NULL; ++i) {
1645 for (int j = 0; statement_data[j] != NULL; ++j) {
1646 for (int k = 0; termination_data[k] != NULL; ++k) {
1647 int kPrefixLen = i::StrLength(context_data[i][0]);
1648 int kStatementLen = i::StrLength(statement_data[j]);
1649 int kTerminationLen = i::StrLength(termination_data[k]);
1650 int kSuffixLen = i::StrLength(context_data[i][1]);
1651 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1652 + kSuffixLen + i::StrLength("label: for (;;) { }");
1654 // Plug the source code pieces together.
1655 i::ScopedVector<char> program(kProgramSize + 1);
1656 int length = i::SNPrintF(program,
1657 "label: for (;;) { %s%s%s%s }",
1660 termination_data[k],
1661 context_data[i][1]);
1662 CHECK(length == kProgramSize);
1663 TestParserSync(program.start(), NULL, 0);
1668 // Neither Harmony numeric literals nor our natives syntax have any
1669 // interaction with the flags above, so test these separately to reduce
1670 // the combinatorial explosion.
1671 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
1672 TestParserSync("0o1234", flags2, arraysize(flags2));
1673 TestParserSync("0b1011", flags2, arraysize(flags2));
1675 static const ParserFlag flags3[] = { kAllowNatives };
1676 TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
1681 // Test that syntax error caused by octal literal is reported correctly as
1682 // such (issue 2220).
1683 v8::V8::Initialize();
1684 v8::HandleScope scope(CcTest::isolate());
1685 v8::Context::Scope context_scope(
1686 v8::Context::New(CcTest::isolate()));
1687 v8::TryCatch try_catch;
1688 const char* script =
1689 "\"use strict\"; \n"
1690 "a = function() { \n"
1691 " b = function() { \n"
1695 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
1696 CHECK(try_catch.HasCaught());
1697 v8::String::Utf8Value exception(try_catch.Exception());
1699 strcmp("SyntaxError: Octal literals are not allowed in strict mode.",
1704 void RunParserSyncTest(const char* context_data[][2],
1705 const char* statement_data[],
1706 ParserSyncTestResult result,
1707 const ParserFlag* flags = NULL,
1709 const ParserFlag* always_true_flags = NULL,
1710 int always_true_len = 0,
1711 const ParserFlag* always_false_flags = NULL,
1712 int always_false_len = 0) {
1713 v8::HandleScope handles(CcTest::isolate());
1714 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1715 v8::Context::Scope context_scope(context);
1717 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1718 i::GetCurrentStackPosition() - 128 * 1024);
1720 // Experimental feature flags should not go here; pass the flags as
1721 // always_true_flags if the test needs them.
1722 static const ParserFlag default_flags[] = {
1726 ParserFlag* generated_flags = NULL;
1727 if (flags == NULL) {
1728 flags = default_flags;
1729 flags_len = arraysize(default_flags);
1730 if (always_true_flags != NULL || always_false_flags != NULL) {
1731 // Remove always_true/false_flags from default_flags (if present).
1732 CHECK((always_true_flags != NULL) == (always_true_len > 0));
1733 CHECK((always_false_flags != NULL) == (always_false_len > 0));
1734 generated_flags = new ParserFlag[flags_len + always_true_len];
1736 for (int i = 0; i < flags_len; ++i) {
1737 bool use_flag = true;
1738 for (int j = 0; use_flag && j < always_true_len; ++j) {
1739 if (flags[i] == always_true_flags[j]) use_flag = false;
1741 for (int j = 0; use_flag && j < always_false_len; ++j) {
1742 if (flags[i] == always_false_flags[j]) use_flag = false;
1744 if (use_flag) generated_flags[flag_index++] = flags[i];
1746 flags_len = flag_index;
1747 flags = generated_flags;
1750 for (int i = 0; context_data[i][0] != NULL; ++i) {
1751 for (int j = 0; statement_data[j] != NULL; ++j) {
1752 int kPrefixLen = i::StrLength(context_data[i][0]);
1753 int kStatementLen = i::StrLength(statement_data[j]);
1754 int kSuffixLen = i::StrLength(context_data[i][1]);
1755 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
1757 // Plug the source code pieces together.
1758 i::ScopedVector<char> program(kProgramSize + 1);
1759 int length = i::SNPrintF(program,
1763 context_data[i][1]);
1764 CHECK(length == kProgramSize);
1765 TestParserSync(program.start(),
1775 delete[] generated_flags;
1779 TEST(ErrorsEvalAndArguments) {
1780 // Tests that both preparsing and parsing produce the right kind of errors for
1781 // using "eval" and "arguments" as identifiers. Without the strict mode, it's
1782 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it
1784 const char* context_data[][2] = {
1785 {"\"use strict\";", ""},
1786 {"\"use strong\";", ""},
1787 {"var eval; function test_func() {\"use strict\"; ", "}"},
1788 {"var eval; function test_func() {\"use strong\"; ", "}"},
1791 const char* statement_data[] = {
1795 "var foo, arguments;",
1796 "try { } catch (eval) { }",
1797 "try { } catch (arguments) { }",
1798 "function eval() { }",
1799 "function arguments() { }",
1800 "function foo(eval) { }",
1801 "function foo(arguments) { }",
1802 "function foo(bar, eval) { }",
1803 "function foo(bar, arguments) { }",
1805 "(arguments) => { }",
1806 "(foo, eval) => { }",
1807 "(foo, arguments) => { }",
1810 "var foo = eval = 1;",
1811 "var foo = arguments = 1;",
1819 static const ParserFlag always_flags[] = {kAllowStrongMode};
1820 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
1821 arraysize(always_flags));
1825 TEST(NoErrorsEvalAndArgumentsSloppy) {
1826 // Tests that both preparsing and parsing accept "eval" and "arguments" as
1827 // identifiers when needed.
1828 const char* context_data[][2] = {
1830 { "function test_func() {", "}"},
1834 const char* statement_data[] = {
1838 "var foo, arguments;",
1839 "try { } catch (eval) { }",
1840 "try { } catch (arguments) { }",
1841 "function eval() { }",
1842 "function arguments() { }",
1843 "function foo(eval) { }",
1844 "function foo(arguments) { }",
1845 "function foo(bar, eval) { }",
1846 "function foo(bar, arguments) { }",
1849 "var foo = eval = 1;",
1850 "var foo = arguments = 1;",
1858 RunParserSyncTest(context_data, statement_data, kSuccess);
1862 TEST(NoErrorsEvalAndArgumentsStrict) {
1863 const char* context_data[][2] = {
1864 { "\"use strict\";", "" },
1865 { "function test_func() { \"use strict\";", "}" },
1866 { "() => { \"use strict\"; ", "}" },
1870 const char* statement_data[] = {
1874 "var foo = arguments;",
1875 "var foo = { eval: 1 };",
1876 "var foo = { arguments: 1 };",
1877 "var foo = { }; foo.eval = {};",
1878 "var foo = { }; foo.arguments = {};",
1882 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
1883 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1884 always_flags, arraysize(always_flags));
1888 #define FUTURE_STRICT_RESERVED_WORDS(V) \
1900 #define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
1907 #define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
1909 "var foo, " #NAME ";", \
1910 "try { } catch (" #NAME ") { }", \
1911 "function " #NAME "() { }", \
1912 "(function " #NAME "() { })", \
1913 "function foo(" #NAME ") { }", \
1914 "function foo(bar, " #NAME ") { }", \
1917 "var foo = " #NAME " = 1;", \
1922 TEST(ErrorsFutureStrictReservedWords) {
1923 // Tests that both preparsing and parsing produce the right kind of errors for
1924 // using future strict reserved words as identifiers. Without the strict mode,
1925 // it's ok to use future strict reserved words as identifiers. With the strict
1927 const char* context_data[][2] = {
1928 {"function test_func() {\"use strict\"; ", "}"},
1929 {"() => { \"use strict\"; ", "}"},
1930 {"function test_func() {\"use strong\"; ", "}"},
1931 {"() => { \"use strong\"; ", "}"},
1934 const char* statement_data[] {
1935 LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
1939 static const ParserFlag always_flags[] = {kAllowStrongMode};
1940 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
1941 arraysize(always_flags));
1942 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
1943 arraysize(always_flags));
1947 #undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
1950 TEST(NoErrorsFutureStrictReservedWords) {
1951 const char* context_data[][2] = {
1953 { "function test_func() {", "}"},
1958 const char* statement_data[] = {
1959 FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
1963 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
1964 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1965 always_flags, arraysize(always_flags));
1967 static const ParserFlag classes_flags[] = {kAllowHarmonyArrowFunctions,
1968 kAllowHarmonyClasses};
1969 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1970 classes_flags, arraysize(classes_flags));
1974 TEST(ErrorsReservedWords) {
1975 // Tests that both preparsing and parsing produce the right kind of errors for
1976 // using future reserved words as identifiers. These tests don't depend on the
1978 const char* context_data[][2] = {
1980 { "\"use strict\";", "" },
1981 { "var eval; function test_func() {", "}"},
1982 { "var eval; function test_func() {\"use strict\"; ", "}"},
1983 { "var eval; () => {", "}"},
1984 { "var eval; () => {\"use strict\"; ", "}"},
1988 const char* statement_data[] = {
1991 "try { } catch (super) { }",
1992 "function super() { }",
1993 "function foo(super) { }",
1994 "function foo(bar, super) { }",
1996 "(bar, super) => { }",
1998 "var foo = super = 1;",
2001 "function foo super",
2005 RunParserSyncTest(context_data, statement_data, kError);
2009 TEST(NoErrorsLetSloppyAllModes) {
2010 // In sloppy mode, it's okay to use "let" as identifier.
2011 const char* context_data[][2] = {
2013 { "function f() {", "}" },
2014 { "(function f() {", "})" },
2018 const char* statement_data[] = {
2021 "try { } catch (let) { }",
2022 "function let() { }",
2023 "(function let() { })",
2024 "function foo(let) { }",
2025 "function foo(bar, let) { }",
2027 "var foo = let = 1;",
2032 "function let(let) { let: let(let + let(0)); }",
2034 "({ get let() { 1 } })",
2039 RunParserSyncTest(context_data, statement_data, kSuccess);
2043 TEST(NoErrorsYieldSloppyAllModes) {
2044 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2045 // generator (see other test).
2046 const char* context_data[][2] = {
2048 { "function not_gen() {", "}" },
2049 { "(function not_gen() {", "})" },
2053 const char* statement_data[] = {
2056 "try { } catch (yield) { }",
2057 "function yield() { }",
2058 "(function yield() { })",
2059 "function foo(yield) { }",
2060 "function foo(bar, yield) { }",
2062 "var foo = yield = 1;",
2067 "function yield(yield) { yield: yield (yield + yield(0)); }",
2069 "({ get yield() { 1 } })",
2075 RunParserSyncTest(context_data, statement_data, kSuccess);
2079 TEST(NoErrorsYieldSloppyGeneratorsEnabled) {
2080 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2081 // generator (see next test).
2082 const char* context_data[][2] = {
2084 { "function not_gen() {", "}" },
2085 { "function * gen() { function not_gen() {", "} }" },
2086 { "(function not_gen() {", "})" },
2087 { "(function * gen() { (function not_gen() {", "}) })" },
2091 const char* statement_data[] = {
2094 "try { } catch (yield) { }",
2095 "function yield() { }",
2096 "(function yield() { })",
2097 "function foo(yield) { }",
2098 "function foo(bar, yield) { }",
2099 "function * yield() { }",
2100 "(function * yield() { })",
2102 "var foo = yield = 1;",
2107 "function yield(yield) { yield: yield (yield + yield(0)); }",
2109 "({ get yield() { 1 } })",
2115 RunParserSyncTest(context_data, statement_data, kSuccess);
2119 TEST(ErrorsYieldStrict) {
2120 const char* context_data[][2] = {
2121 {"\"use strict\";", ""},
2122 {"\"use strict\"; function not_gen() {", "}"},
2123 {"function test_func() {\"use strict\"; ", "}"},
2124 {"\"use strict\"; function * gen() { function not_gen() {", "} }"},
2125 {"\"use strict\"; (function not_gen() {", "})"},
2126 {"\"use strict\"; (function * gen() { (function not_gen() {", "}) })"},
2127 {"() => {\"use strict\"; ", "}"},
2128 {"\"use strong\";", ""},
2129 {"\"use strong\"; function not_gen() {", "}"},
2130 {"function test_func() {\"use strong\"; ", "}"},
2131 {"\"use strong\"; function * gen() { function not_gen() {", "} }"},
2132 {"\"use strong\"; (function not_gen() {", "})"},
2133 {"\"use strong\"; (function * gen() { (function not_gen() {", "}) })"},
2134 {"() => {\"use strong\"; ", "}"},
2137 const char* statement_data[] = {
2140 "try { } catch (yield) { }",
2141 "function yield() { }",
2142 "(function yield() { })",
2143 "function foo(yield) { }",
2144 "function foo(bar, yield) { }",
2145 "function * yield() { }",
2146 "(function * yield() { })",
2148 "var foo = yield = 1;",
2155 static const ParserFlag always_flags[] = {kAllowStrongMode};
2156 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
2157 arraysize(always_flags));
2161 TEST(NoErrorsGenerator) {
2162 const char* context_data[][2] = {
2163 { "function * gen() {", "}" },
2164 { "(function * gen() {", "})" },
2165 { "(function * () {", "})" },
2169 const char* statement_data[] = {
2170 // A generator without a body is valid.
2172 // Valid yield expressions inside generators.
2177 "yield * yield * 1;",
2178 "yield 3 + (yield 4);",
2179 "yield * 3 + (yield * 4);",
2180 "(yield * 3) + (yield * 4);",
2181 "yield 3; yield 4;",
2182 "yield * 3; yield * 4;",
2183 "(function (yield) { })",
2184 "yield { yield: 12 }",
2185 "yield /* comment */ { yield: 12 }",
2186 "yield * \n { yield: 12 }",
2187 "yield /* comment */ * \n { yield: 12 }",
2188 // You can return in a generator.
2190 "yield * 1; return",
2191 "yield 1; return 37",
2192 "yield * 1; return 37",
2193 "yield 1; return 37; yield 'dead';",
2194 "yield * 1; return 37; yield * 'dead';",
2195 // Yield is still a valid key in object literals.
2197 "({ get yield() { } })",
2198 // Yield without RHS.
2202 "yield /* comment */"
2203 "yield // comment\n"
2209 "(yield) ? yield : yield",
2210 "(yield) \n ? yield : yield",
2211 // If there is a newline before the next token, we don't look for RHS.
2212 "yield\nfor (;;) {}",
2216 RunParserSyncTest(context_data, statement_data, kSuccess);
2220 TEST(ErrorsYieldGenerator) {
2221 const char* context_data[][2] = {
2222 { "function * gen() {", "}" },
2223 { "\"use strict\"; function * gen() {", "}" },
2227 const char* statement_data[] = {
2228 // Invalid yield expressions inside generators.
2231 "try { } catch (yield) { }",
2232 "function yield() { }",
2233 // The name of the NFE is let-bound in the generator, which does not permit
2234 // yield to be an identifier.
2235 "(function yield() { })",
2236 "(function * yield() { })",
2237 // Yield isn't valid as a formal parameter for generators.
2238 "function * foo(yield) { }",
2239 "(function * foo(yield) { })",
2241 "var foo = yield = 1;",
2246 // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which
2248 "yield 3 + yield 4;",
2251 // Parses as yield (/ yield): invalid.
2255 // Invalid (no newline allowed between yield and *).
2257 // Invalid (we see a newline, so we parse {yield:42} as a statement, not an
2258 // object literal, and yield is not a valid label).
2259 "yield\n{yield: 42}",
2260 "yield /* comment */\n {yield: 42}",
2261 "yield //comment\n {yield: 42}",
2265 RunParserSyncTest(context_data, statement_data, kError);
2269 TEST(ErrorsNameOfStrictFunction) {
2270 // Tests that illegal tokens as names of a strict function produce the correct
2272 const char* context_data[][2] = {
2274 { "\"use strict\"; function", ""},
2275 { "\"use strong\"; function", ""},
2276 { "function * ", ""},
2277 { "\"use strict\"; function * ", ""},
2278 { "\"use strong\"; function * ", ""},
2282 const char* statement_data[] = {
2283 "eval() {\"use strict\";}",
2284 "arguments() {\"use strict\";}",
2285 "interface() {\"use strict\";}",
2286 "yield() {\"use strict\";}",
2287 // Future reserved words are always illegal
2289 "super() {\"use strict\";}",
2293 static const ParserFlag always_flags[] = {kAllowStrongMode};
2294 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
2295 arraysize(always_flags));
2299 TEST(NoErrorsNameOfStrictFunction) {
2300 const char* context_data[][2] = {
2305 const char* statement_data[] = {
2313 RunParserSyncTest(context_data, statement_data, kSuccess);
2317 TEST(NoErrorsNameOfStrictGenerator) {
2318 const char* context_data[][2] = {
2319 { "function * ", ""},
2323 const char* statement_data[] = {
2331 RunParserSyncTest(context_data, statement_data, kSuccess);
2335 TEST(ErrorsIllegalWordsAsLabelsSloppy) {
2336 // Using future reserved words as labels is always an error.
2337 const char* context_data[][2] = {
2339 { "function test_func() {", "}" },
2344 const char* statement_data[] = {
2345 "super: while(true) { break super; }",
2349 RunParserSyncTest(context_data, statement_data, kError);
2353 TEST(ErrorsIllegalWordsAsLabelsStrict) {
2354 // Tests that illegal tokens as labels produce the correct errors.
2355 const char* context_data[][2] = {
2356 {"\"use strict\";", ""},
2357 {"function test_func() {\"use strict\"; ", "}"},
2358 {"() => {\"use strict\"; ", "}"},
2359 {"\"use strong\";", ""},
2360 {"function test_func() {\"use strong\"; ", "}"},
2361 {"() => {\"use strong\"; ", "}"},
2364 #define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
2365 const char* statement_data[] = {
2366 "super: while(true) { break super; }",
2367 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
2370 #undef LABELLED_WHILE
2372 static const ParserFlag always_flags[] = {kAllowStrongMode};
2373 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
2374 arraysize(always_flags));
2378 TEST(NoErrorsIllegalWordsAsLabels) {
2379 // Using eval and arguments as labels is legal even in strict mode.
2380 const char* context_data[][2] = {
2382 { "function test_func() {", "}" },
2384 { "\"use strict\";", "" },
2385 { "\"use strict\"; function test_func() {", "}" },
2386 { "\"use strict\"; () => {", "}" },
2390 const char* statement_data[] = {
2391 "mylabel: while(true) { break mylabel; }",
2392 "eval: while(true) { break eval; }",
2393 "arguments: while(true) { break arguments; }",
2397 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
2398 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2399 always_flags, arraysize(always_flags));
2403 TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
2404 const char* context_data[][2] = {
2406 { "function test_func() {", "}" },
2411 #define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
2412 const char* statement_data[] {
2413 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
2416 #undef LABELLED_WHILE
2418 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
2419 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2420 always_flags, arraysize(always_flags));
2424 TEST(ErrorsParenthesizedLabels) {
2425 // Parenthesized identifiers shouldn't be recognized as labels.
2426 const char* context_data[][2] = {
2428 { "function test_func() {", "}" },
2433 const char* statement_data[] = {
2434 "(mylabel): while(true) { break mylabel; }",
2438 RunParserSyncTest(context_data, statement_data, kError);
2442 TEST(NoErrorsParenthesizedDirectivePrologue) {
2443 // Parenthesized directive prologue shouldn't be recognized.
2444 const char* context_data[][2] = {
2449 const char* statement_data[] = {
2450 "(\"use strict\"); var eval;",
2451 "(\"use strong\"); var eval;",
2455 static const ParserFlag always_flags[] = {kAllowStrongMode};
2456 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2457 always_flags, arraysize(always_flags));
2461 TEST(ErrorsNotAnIdentifierName) {
2462 const char* context_data[][2] = {
2464 { "\"use strict\";", ""},
2468 const char* statement_data[] = {
2469 "var foo = {}; foo.{;",
2470 "var foo = {}; foo.};",
2471 "var foo = {}; foo.=;",
2472 "var foo = {}; foo.888;",
2473 "var foo = {}; foo.-;",
2474 "var foo = {}; foo.--;",
2478 RunParserSyncTest(context_data, statement_data, kError);
2482 TEST(NoErrorsIdentifierNames) {
2483 // Keywords etc. are valid as property names.
2484 const char* context_data[][2] = {
2486 { "\"use strict\";", ""},
2490 const char* statement_data[] = {
2491 "var foo = {}; foo.if;",
2492 "var foo = {}; foo.yield;",
2493 "var foo = {}; foo.super;",
2494 "var foo = {}; foo.interface;",
2495 "var foo = {}; foo.eval;",
2496 "var foo = {}; foo.arguments;",
2500 RunParserSyncTest(context_data, statement_data, kSuccess);
2504 TEST(DontRegressPreParserDataSizes) {
2505 // These tests make sure that Parser doesn't start producing less "preparse
2506 // data" (data which the embedder can cache).
2507 v8::V8::Initialize();
2508 v8::Isolate* isolate = CcTest::isolate();
2509 v8::HandleScope handles(isolate);
2511 CcTest::i_isolate()->stack_guard()->SetStackLimit(
2512 i::GetCurrentStackPosition() - 128 * 1024);
2515 const char* program;
2521 {"function foo() {}", 1},
2522 {"function foo() {} function bar() {}", 2},
2523 // Getter / setter functions are recorded as functions if they're on the top
2525 {"var x = {get foo(){} };", 1},
2526 // Functions insize lazy functions are not recorded.
2527 {"function lazy() { function a() {} function b() {} function c() {} }", 1},
2528 {"function lazy() { var x = {get foo(){} } }", 1},
2532 for (int i = 0; test_cases[i].program; i++) {
2533 const char* program = test_cases[i].program;
2534 i::Factory* factory = CcTest::i_isolate()->factory();
2535 i::Handle<i::String> source =
2536 factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
2537 i::Handle<i::Script> script = factory->NewScript(source);
2539 i::ParseInfo info(&zone, script);
2540 i::ScriptData* sd = NULL;
2541 info.set_cached_data(&sd);
2542 info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
2543 info.set_allow_lazy_parsing();
2544 i::Parser::ParseStatic(&info);
2545 i::ParseData* pd = i::ParseData::FromCachedData(sd);
2547 if (pd->FunctionCount() != test_cases[i].functions) {
2548 v8::base::OS::Print(
2549 "Expected preparse data for program:\n"
2551 "to contain %d functions, however, received %d functions.\n",
2552 program, test_cases[i].functions, pd->FunctionCount());
2561 TEST(FunctionDeclaresItselfStrict) {
2562 // Tests that we produce the right kinds of errors when a function declares
2563 // itself strict (we cannot produce there errors as soon as we see the
2564 // offending identifiers, because we don't know at that point whether the
2565 // function is strict or not).
2566 const char* context_data[][2] = {
2567 {"function eval() {", "}"},
2568 {"function arguments() {", "}"},
2569 {"function yield() {", "}"},
2570 {"function interface() {", "}"},
2571 {"function foo(eval) {", "}"},
2572 {"function foo(arguments) {", "}"},
2573 {"function foo(yield) {", "}"},
2574 {"function foo(interface) {", "}"},
2575 {"function foo(bar, eval) {", "}"},
2576 {"function foo(bar, arguments) {", "}"},
2577 {"function foo(bar, yield) {", "}"},
2578 {"function foo(bar, interface) {", "}"},
2579 {"function foo(bar, bar) {", "}"},
2583 const char* strict_statement_data[] = {
2589 const char* non_strict_statement_data[] = {
2594 static const ParserFlag always_flags[] = {kAllowStrongMode};
2595 RunParserSyncTest(context_data, strict_statement_data, kError, NULL, 0,
2596 always_flags, arraysize(always_flags));
2597 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess, NULL, 0,
2598 always_flags, arraysize(always_flags));
2602 TEST(ErrorsTryWithoutCatchOrFinally) {
2603 const char* context_data[][2] = {
2608 const char* statement_data[] = {
2611 "try { } catch (e) foo();",
2612 "try { } catch { }",
2613 "try { } finally foo();",
2617 RunParserSyncTest(context_data, statement_data, kError);
2621 TEST(NoErrorsTryCatchFinally) {
2622 const char* context_data[][2] = {
2627 const char* statement_data[] = {
2628 "try { } catch (e) { }",
2629 "try { } catch (e) { } finally { }",
2630 "try { } finally { }",
2634 RunParserSyncTest(context_data, statement_data, kSuccess);
2638 TEST(ErrorsRegexpLiteral) {
2639 const char* context_data[][2] = {
2644 const char* statement_data[] = {
2649 RunParserSyncTest(context_data, statement_data, kError);
2653 TEST(NoErrorsRegexpLiteral) {
2654 const char* context_data[][2] = {
2659 const char* statement_data[] = {
2662 "/foo/whatever", // This is an error but not detected by the parser.
2666 RunParserSyncTest(context_data, statement_data, kSuccess);
2671 const char* context_data[][2] = {
2676 const char* statement_data[] = {
2677 "%someintrinsic(arg)",
2681 // This test requires kAllowNatives to succeed.
2682 static const ParserFlag always_true_flags[] = {
2686 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2687 always_true_flags, 1);
2691 TEST(NoErrorsNewExpression) {
2692 const char* context_data[][2] = {
2698 const char* statement_data[] = {
2703 // The first () will be processed as a part of the NewExpression and the
2704 // second () will be processed as part of LeftHandSideExpression.
2706 // The first () will be processed as a part of the inner NewExpression and
2707 // the second () will be processed as a part of the outer NewExpression.
2712 "new foo.bar().baz;",
2715 "new foo[bar][baz];",
2716 "new foo[bar]()[baz];",
2717 "new foo[bar].baz(baz)()[bar].baz;",
2718 "new \"foo\"", // Runtime error
2719 "new 1", // Runtime error
2721 "(new new Function(\"this.x = 1\")).x;",
2722 "new new Test_Two(String, 2).v(0123).length;",
2726 RunParserSyncTest(context_data, statement_data, kSuccess);
2730 TEST(ErrorsNewExpression) {
2731 const char* context_data[][2] = {
2737 const char* statement_data[] = {
2745 RunParserSyncTest(context_data, statement_data, kError);
2749 TEST(StrictObjectLiteralChecking) {
2750 const char* context_data[][2] = {
2751 {"\"use strict\"; var myobject = {", "};"},
2752 {"\"use strict\"; var myobject = {", ",};"},
2753 {"var myobject = {", "};"},
2754 {"var myobject = {", ",};"},
2758 // These are only errors in strict mode.
2759 const char* statement_data[] = {
2761 "\"foo\": 1, \"foo\": 2",
2762 "foo: 1, \"foo\": 2",
2765 "get: 1, get: 2", // Not a getter for real, just a property called get.
2766 "set: 1, set: 2", // Not a setter for real, just a property called set.
2770 RunParserSyncTest(context_data, statement_data, kSuccess);
2774 TEST(ErrorsObjectLiteralChecking) {
2775 const char* context_data[][2] = {
2776 {"\"use strict\"; var myobject = {", "};"},
2777 {"var myobject = {", "};"},
2781 const char* statement_data[] = {
2783 // Wrong number of parameters
2788 // Parsing FunctionLiteral for getter or setter fails
2790 "get foo() \"error\"",
2794 RunParserSyncTest(context_data, statement_data, kError);
2798 TEST(NoErrorsObjectLiteralChecking) {
2799 const char* context_data[][2] = {
2800 {"var myobject = {", "};"},
2801 {"var myobject = {", ",};"},
2802 {"\"use strict\"; var myobject = {", "};"},
2803 {"\"use strict\"; var myobject = {", ",};"},
2807 const char* statement_data[] = {
2808 "foo: 1, get foo() {}",
2809 "foo: 1, set foo(v) {}",
2810 "\"foo\": 1, get \"foo\"() {}",
2811 "\"foo\": 1, set \"foo\"(v) {}",
2813 "1: 1, set 1(v) {}",
2814 "get foo() {}, get foo() {}",
2815 "set foo(_) {}, set foo(v) {}",
2816 "foo: 1, get \"foo\"() {}",
2817 "foo: 1, set \"foo\"(v) {}",
2818 "\"foo\": 1, get foo() {}",
2819 "\"foo\": 1, set foo(v) {}",
2820 "1: 1, get \"1\"() {}",
2821 "1: 1, set \"1\"(v) {}",
2822 "\"1\": 1, get 1() {}",
2823 "\"1\": 1, set 1(v) {}",
2825 "\"foo\": 1, \"bar\": 2",
2827 // Syntax: IdentifierName ':' AssignmentExpression
2828 "foo: bar = 5 + baz",
2829 // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}'
2833 // Syntax: 'set' PropertyName '(' PropertySetParameterList ')'
2834 // '{' FunctionBody '}'
2836 "set \"foo\"(v) {}",
2838 // Non-colliding getters and setters -> no errors
2839 "foo: 1, get bar() {}",
2840 "foo: 1, set bar(v) {}",
2841 "\"foo\": 1, get \"bar\"() {}",
2842 "\"foo\": 1, set \"bar\"(v) {}",
2844 "1: 1, set 2(v) {}",
2845 "get: 1, get foo() {}",
2846 "set: 1, set foo(_) {}",
2847 // Keywords, future reserved and strict future reserved are also allowed as
2857 RunParserSyncTest(context_data, statement_data, kSuccess);
2861 TEST(TooManyArguments) {
2862 const char* context_data[][2] = {
2867 using v8::internal::Code;
2868 char statement[Code::kMaxArguments * 2 + 1];
2869 for (int i = 0; i < Code::kMaxArguments; ++i) {
2870 statement[2 * i] = '0';
2871 statement[2 * i + 1] = ',';
2873 statement[Code::kMaxArguments * 2] = 0;
2875 const char* statement_data[] = {
2880 // The test is quite slow, so run it with a reduced set of flags.
2881 static const ParserFlag empty_flags[] = {kAllowLazy};
2882 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
2886 TEST(StrictDelete) {
2887 // "delete <Identifier>" is not allowed in strict mode.
2888 const char* strong_context_data[][2] = {
2889 {"\"use strong\"; ", ""},
2893 const char* strict_context_data[][2] = {
2894 {"\"use strict\"; ", ""},
2898 const char* sloppy_context_data[][2] = {
2903 // These are errors in the strict mode.
2904 const char* sloppy_statement_data[] = {
2909 "delete interface;",
2913 // These are always OK
2914 const char* good_statement_data[] = {
2923 "delete new foo();",
2924 "delete new foo(bar);",
2928 // These are always errors
2929 const char* bad_statement_data[] = {
2934 static const ParserFlag always_flags[] = {kAllowStrongMode};
2935 RunParserSyncTest(strong_context_data, sloppy_statement_data, kError, NULL, 0,
2936 always_flags, arraysize(always_flags));
2937 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError, NULL, 0,
2938 always_flags, arraysize(always_flags));
2939 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess, NULL,
2940 0, always_flags, arraysize(always_flags));
2942 RunParserSyncTest(strong_context_data, good_statement_data, kError, NULL, 0,
2943 always_flags, arraysize(always_flags));
2944 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess, NULL, 0,
2945 always_flags, arraysize(always_flags));
2946 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess, NULL, 0,
2947 always_flags, arraysize(always_flags));
2949 RunParserSyncTest(strong_context_data, bad_statement_data, kError, NULL, 0,
2950 always_flags, arraysize(always_flags));
2951 RunParserSyncTest(strict_context_data, bad_statement_data, kError, NULL, 0,
2952 always_flags, arraysize(always_flags));
2953 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError, NULL, 0,
2954 always_flags, arraysize(always_flags));
2958 TEST(NoErrorsDeclsInCase) {
2959 const char* context_data[][2] = {
2960 {"'use strict'; switch(x) { case 1:", "}"},
2961 {"function foo() {'use strict'; switch(x) { case 1:", "}}"},
2962 {"'use strict'; switch(x) { case 1: case 2:", "}"},
2963 {"function foo() {'use strict'; switch(x) { case 1: case 2:", "}}"},
2964 {"'use strict'; switch(x) { default:", "}"},
2965 {"function foo() {'use strict'; switch(x) { default:", "}}"},
2966 {"'use strict'; switch(x) { case 1: default:", "}"},
2967 {"function foo() {'use strict'; switch(x) { case 1: default:", "}}"},
2968 { nullptr, nullptr }
2971 const char* statement_data[] = {
2974 "class C extends Q {}",
2975 "function f() { } class C {}",
2976 "function f() { }; class C {}",
2977 "class C {}; function f() {}",
2981 static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
2983 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2984 always_flags, arraysize(always_flags));
2988 TEST(InvalidLeftHandSide) {
2989 const char* assignment_context_data[][2] = {
2991 {"\"use strict\"; ", " = 1;"},
2995 const char* prefix_context_data[][2] = {
2997 {"\"use strict\"; ++", ";"},
3001 const char* postfix_context_data[][2] = {
3003 {"\"use strict\"; ", "++;"},
3007 // Good left hand sides for assigment or prefix / postfix operations.
3008 const char* good_statement_data[] = {
3025 "this.foo[foo].bar(this)(bar)[foo]()",
3029 // Bad left hand sides for assigment or prefix / postfix operations.
3030 const char* bad_statement_data_common[] = {
3035 "if", // Unexpected token
3036 "{x: 1}", // Unexpected token
3040 "new new foo()[bar]", // means: new (new foo()[bar])
3041 "new new foo().bar", // means: new (new foo()[bar])
3045 // These are not okay for assignment, but okay for prefix / postix.
3046 const char* bad_statement_data_for_assignment[] = {
3053 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
3054 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
3055 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
3058 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
3059 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
3061 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
3062 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);
3066 TEST(FuncNameInferrerBasic) {
3067 // Tests that function names are inferred properly.
3068 i::FLAG_allow_natives_syntax = true;
3069 v8::Isolate* isolate = CcTest::isolate();
3070 v8::HandleScope scope(isolate);
3072 CompileRun("var foo1 = function() {}; "
3073 "var foo2 = function foo3() {}; "
3074 "function not_ctor() { "
3075 " var foo4 = function() {}; "
3076 " return %FunctionGetInferredName(foo4); "
3078 "function Ctor() { "
3079 " var foo5 = function() {}; "
3080 " return %FunctionGetInferredName(foo5); "
3082 "var obj1 = { foo6: function() {} }; "
3083 "var obj2 = { 'foo7': function() {} }; "
3085 "obj3[1] = function() {}; "
3087 "obj4[1] = function foo8() {}; "
3089 "obj5['foo9'] = function() {}; "
3090 "var obj6 = { obj7 : { foo10: function() {} } };");
3091 ExpectString("%FunctionGetInferredName(foo1)", "foo1");
3092 // foo2 is not unnamed -> its name is not inferred.
3093 ExpectString("%FunctionGetInferredName(foo2)", "");
3094 ExpectString("not_ctor()", "foo4");
3095 ExpectString("Ctor()", "Ctor.foo5");
3096 ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6");
3097 ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7");
3098 ExpectString("%FunctionGetInferredName(obj3[1])",
3099 "obj3.(anonymous function)");
3100 ExpectString("%FunctionGetInferredName(obj4[1])", "");
3101 ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9");
3102 ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10");
3106 TEST(FuncNameInferrerTwoByte) {
3107 // Tests function name inferring in cases where some parts of the inferred
3108 // function name are two-byte strings.
3109 i::FLAG_allow_natives_syntax = true;
3110 v8::Isolate* isolate = CcTest::isolate();
3111 v8::HandleScope scope(isolate);
3113 uint16_t* two_byte_source = AsciiToTwoByteString(
3114 "var obj1 = { oXj2 : { foo1: function() {} } }; "
3115 "%FunctionGetInferredName(obj1.oXj2.foo1)");
3116 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3117 // Make it really non-Latin1 (replace the Xs with a non-Latin1 character).
3118 two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d;
3119 v8::Local<v8::String> source =
3120 v8::String::NewFromTwoByte(isolate, two_byte_source);
3121 v8::Local<v8::Value> result = CompileRun(source);
3122 CHECK(result->IsString());
3123 v8::Local<v8::String> expected_name =
3124 v8::String::NewFromTwoByte(isolate, two_byte_name);
3125 CHECK(result->Equals(expected_name));
3126 i::DeleteArray(two_byte_source);
3127 i::DeleteArray(two_byte_name);
3131 TEST(FuncNameInferrerEscaped) {
3132 // The same as FuncNameInferrerTwoByte, except that we express the two-byte
3133 // character as a unicode escape.
3134 i::FLAG_allow_natives_syntax = true;
3135 v8::Isolate* isolate = CcTest::isolate();
3136 v8::HandleScope scope(isolate);
3138 uint16_t* two_byte_source = AsciiToTwoByteString(
3139 "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; "
3140 "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)");
3141 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3142 // Fix to correspond to the non-ASCII name in two_byte_source.
3143 two_byte_name[6] = 0x010d;
3144 v8::Local<v8::String> source =
3145 v8::String::NewFromTwoByte(isolate, two_byte_source);
3146 v8::Local<v8::Value> result = CompileRun(source);
3147 CHECK(result->IsString());
3148 v8::Local<v8::String> expected_name =
3149 v8::String::NewFromTwoByte(isolate, two_byte_name);
3150 CHECK(result->Equals(expected_name));
3151 i::DeleteArray(two_byte_source);
3152 i::DeleteArray(two_byte_name);
3156 TEST(RegressionLazyFunctionWithErrorWithArg) {
3157 // The bug occurred when a lazy function had an error which requires a
3158 // parameter (such as "unknown label" here). The error message was processed
3159 // before the AstValueFactory containing the error message string was
3161 v8::Isolate* isolate = CcTest::isolate();
3162 v8::HandleScope scope(isolate);
3164 i::FLAG_lazy = true;
3165 i::FLAG_min_preparse_length = 0;
3166 CompileRun("function this_is_lazy() {\n"
3169 "this_is_lazy();\n");
3173 TEST(SerializationOfMaybeAssignmentFlag) {
3174 i::Isolate* isolate = CcTest::i_isolate();
3175 i::Factory* factory = isolate->factory();
3176 i::HandleScope scope(isolate);
3185 " function assertResult(r) {"
3189 " assertResult([2]);"
3190 " assertResult([2]);"
3195 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3196 i::SNPrintF(program, "%s", src);
3197 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3198 source->PrintOn(stdout);
3201 v8::Local<v8::Value> v = CompileRun(src);
3202 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3203 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3204 i::Context* context = f->context();
3205 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3206 avf.Internalize(isolate);
3207 const i::AstRawString* name = avf.GetOneByteString("result");
3208 i::Handle<i::String> str = name->string();
3209 CHECK(str->IsInternalizedString());
3210 i::Scope* script_scope =
3211 new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
3212 script_scope->Initialize();
3214 i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
3215 DCHECK(s != script_scope);
3216 DCHECK(name != NULL);
3218 // Get result from h's function context (that is f's context)
3219 i::Variable* var = s->Lookup(name);
3222 // Maybe assigned should survive deserialization
3223 CHECK(var->maybe_assigned() == i::kMaybeAssigned);
3224 // TODO(sigurds) Figure out if is_used should survive context serialization.
3228 TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
3229 i::Isolate* isolate = CcTest::i_isolate();
3230 i::Factory* factory = isolate->factory();
3231 i::HandleScope scope(isolate);
3237 " var a = arguments;"
3245 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3246 i::SNPrintF(program, "%s", src);
3247 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3248 source->PrintOn(stdout);
3251 v8::Local<v8::Value> v = CompileRun(src);
3252 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3253 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3254 i::Context* context = f->context();
3255 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3256 avf.Internalize(isolate);
3258 i::Scope* script_scope =
3259 new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf);
3260 script_scope->Initialize();
3262 i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope);
3263 DCHECK(s != script_scope);
3264 const i::AstRawString* name_x = avf.GetOneByteString("x");
3266 // Get result from f's function context (that is g's outer context)
3267 i::Variable* var_x = s->Lookup(name_x);
3268 CHECK(var_x != NULL);
3269 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
3273 TEST(InnerAssignment) {
3274 i::Isolate* isolate = CcTest::i_isolate();
3275 i::Factory* factory = isolate->factory();
3276 i::HandleScope scope(isolate);
3279 const char* prefix = "function f() {";
3280 const char* midfix = " function g() {";
3281 const char* suffix = "}}";
3282 struct { const char* source; bool assigned; bool strict; } outers[] = {
3283 // Actual assignments.
3284 { "var x; var x = 5;", true, false },
3285 { "var x; { var x = 5; }", true, false },
3286 { "'use strict'; let x; x = 6;", true, true },
3287 { "var x = 5; function x() {}", true, false },
3288 // Actual non-assignments.
3289 { "var x;", false, false },
3290 { "var x = 5;", false, false },
3291 { "'use strict'; let x;", false, true },
3292 { "'use strict'; let x = 6;", false, true },
3293 { "'use strict'; var x = 0; { let x = 6; }", false, true },
3294 { "'use strict'; var x = 0; { let x; x = 6; }", false, true },
3295 { "'use strict'; let x = 0; { let x = 6; }", false, true },
3296 { "'use strict'; let x = 0; { let x; x = 6; }", false, true },
3297 { "var x; try {} catch (x) { x = 5; }", false, false },
3298 { "function x() {}", false, false },
3299 // Eval approximation.
3300 { "var x; eval('');", true, false },
3301 { "eval(''); var x;", true, false },
3302 { "'use strict'; let x; eval('');", true, true },
3303 { "'use strict'; eval(''); let x;", true, true },
3304 // Non-assignments not recognized, because the analysis is approximative.
3305 { "var x; var x;", true, false },
3306 { "var x = 5; var x;", true, false },
3307 { "var x; { var x; }", true, false },
3308 { "var x; function x() {}", true, false },
3309 { "function x() {}; var x;", true, false },
3310 { "var x; try {} catch (x) { var x = 5; }", true, false },
3312 struct { const char* source; bool assigned; bool with; } inners[] = {
3313 // Actual assignments.
3314 { "x = 1;", true, false },
3315 { "x++;", true, false },
3316 { "++x;", true, false },
3317 { "x--;", true, false },
3318 { "--x;", true, false },
3319 { "{ x = 1; }", true, false },
3320 { "'use strict'; { let x; }; x = 0;", true, false },
3321 { "'use strict'; { const x = 1; }; x = 0;", true, false },
3322 { "'use strict'; { function x() {} }; x = 0;", true, false },
3323 { "with ({}) { x = 1; }", true, true },
3324 { "eval('');", true, false },
3325 { "'use strict'; { let y; eval('') }", true, false },
3326 { "function h() { x = 0; }", true, false },
3327 { "(function() { x = 0; })", true, false },
3328 { "(function() { x = 0; })", true, false },
3329 { "with ({}) (function() { x = 0; })", true, true },
3330 // Actual non-assignments.
3331 { "", false, false },
3332 { "x;", false, false },
3333 { "var x;", false, false },
3334 { "var x = 8;", false, false },
3335 { "var x; x = 8;", false, false },
3336 { "'use strict'; let x;", false, false },
3337 { "'use strict'; let x = 8;", false, false },
3338 { "'use strict'; let x; x = 8;", false, false },
3339 { "'use strict'; const x = 8;", false, false },
3340 { "function x() {}", false, false },
3341 { "function x() { x = 0; }", false, false },
3342 { "function h(x) { x = 0; }", false, false },
3343 { "'use strict'; { let x; x = 0; }", false, false },
3344 { "{ var x; }; x = 0;", false, false },
3345 { "with ({}) {}", false, true },
3346 { "var x; { with ({}) { x = 1; } }", false, true },
3347 { "try {} catch(x) { x = 0; }", false, false },
3348 { "try {} catch(x) { with ({}) { x = 1; } }", false, true },
3349 // Eval approximation.
3350 { "eval('');", true, false },
3351 { "function h() { eval(''); }", true, false },
3352 { "(function() { eval(''); })", true, false },
3353 // Shadowing not recognized because of eval approximation.
3354 { "var x; eval('');", true, false },
3355 { "'use strict'; let x; eval('');", true, false },
3356 { "try {} catch(x) { eval(''); }", true, false },
3357 { "function x() { eval(''); }", true, false },
3358 { "(function(x) { eval(''); })", true, false },
3361 // Used to trigger lazy compilation of function
3362 int comment_len = 2048;
3363 i::ScopedVector<char> comment(comment_len + 1);
3364 i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0);
3365 int prefix_len = Utf8LengthHelper(prefix);
3366 int midfix_len = Utf8LengthHelper(midfix);
3367 int suffix_len = Utf8LengthHelper(suffix);
3368 for (unsigned i = 0; i < arraysize(outers); ++i) {
3369 const char* outer = outers[i].source;
3370 int outer_len = Utf8LengthHelper(outer);
3371 for (unsigned j = 0; j < arraysize(inners); ++j) {
3372 for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) {
3373 for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) {
3374 if (outers[i].strict && inners[j].with) continue;
3375 const char* inner = inners[j].source;
3376 int inner_len = Utf8LengthHelper(inner);
3378 int outer_comment_len = outer_lazy ? comment_len : 0;
3379 int inner_comment_len = inner_lazy ? comment_len : 0;
3380 const char* outer_comment = outer_lazy ? comment.start() : "";
3381 const char* inner_comment = inner_lazy ? comment.start() : "";
3382 int len = prefix_len + outer_comment_len + outer_len + midfix_len +
3383 inner_comment_len + inner_len + suffix_len;
3384 i::ScopedVector<char> program(len + 1);
3386 i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer,
3387 midfix, inner_comment, inner, suffix);
3388 i::Handle<i::String> source =
3389 factory->InternalizeUtf8String(program.start());
3390 source->PrintOn(stdout);
3393 i::Handle<i::Script> script = factory->NewScript(source);
3395 i::ParseInfo info(&zone, script);
3396 i::Parser parser(&info);
3397 CHECK(parser.Parse(&info));
3398 CHECK(i::Compiler::Analyze(&info));
3399 CHECK(info.function() != NULL);
3401 i::Scope* scope = info.function()->scope();
3402 CHECK_EQ(scope->inner_scopes()->length(), 1);
3403 i::Scope* inner_scope = scope->inner_scopes()->at(0);
3404 const i::AstRawString* var_name =
3405 info.ast_value_factory()->GetOneByteString("x");
3406 i::Variable* var = inner_scope->Lookup(var_name);
3407 bool expected = outers[i].assigned || inners[j].assigned;
3409 CHECK(var->is_used() || !expected);
3410 CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected);
3419 int* global_use_counts = NULL;
3421 void MockUseCounterCallback(v8::Isolate* isolate,
3422 v8::Isolate::UseCounterFeature feature) {
3423 ++global_use_counts[feature];
3429 TEST(UseAsmUseCount) {
3430 i::Isolate* isolate = CcTest::i_isolate();
3431 i::HandleScope scope(isolate);
3433 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3434 global_use_counts = use_counts;
3435 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3436 CompileRun("\"use asm\";\n"
3438 "\"use asm\";\n" // Only the first one counts.
3439 "function bar() { \"use asm\"; var baz = 1; }");
3440 CHECK_EQ(2, use_counts[v8::Isolate::kUseAsm]);
3444 TEST(ErrorsArrowFunctions) {
3445 // Tests that parser and preparser generate the same kind of errors
3446 // on invalid arrow function syntax.
3447 const char* context_data[][2] = {
3450 {"bar ? (", ") : baz;"},
3451 {"bar ? baz : (", ");"},
3458 const char* statement_data[] = {
3467 "() => {'value': 42}",
3469 // Check that the early return introduced in ParsePrimaryExpression
3470 // does not accept stray closing parentheses.
3476 // Parameter lists with extra parens should be recognized as errors.
3485 // Parameter lists are always validated as strict, so those are errors.
3491 "(arguments) => {}",
3493 "(interface) => {}",
3494 "(eval, bar) => {}",
3495 "(bar, eval) => {}",
3496 "(bar, arguments) => {}",
3497 "(bar, yield) => {}",
3498 "(bar, interface) => {}",
3499 // TODO(aperez): Detecting duplicates does not work in PreParser.
3500 // "(bar, bar) => {}",
3502 // The parameter list is parsed as an expression, but only
3503 // a comma-separated list of identifier is valid.
3537 "(foo ? bar : baz) => {}",
3538 "(a, foo ? bar : baz) => {}",
3539 "(foo ? bar : baz, a) => {}",
3543 // The test is quite slow, so run it with a reduced set of flags.
3544 static const ParserFlag flags[] = {kAllowLazy};
3545 static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
3546 RunParserSyncTest(context_data, statement_data, kError, flags,
3547 arraysize(flags), always_flags, arraysize(always_flags));
3551 TEST(NoErrorsArrowFunctions) {
3552 // Tests that parser and preparser accept valid arrow functions syntax.
3553 const char* context_data[][2] = {
3555 {"bar ? (", ") : baz;"},
3556 {"bar ? baz : (", ");"},
3562 const char* statement_data[] = {
3564 "() => { return 42 }",
3565 "x => { return x; }",
3566 "(x) => { return x; }",
3567 "(x, y) => { return x + y; }",
3568 "(x, y, z) => { return x + y + z; }",
3569 "(x, y) => { x.a = y; }",
3576 "(x, y, z) => x, y, z",
3577 "(x, y) => x.a = y",
3578 "() => ({'value': 42})",
3580 "(x, y) => (u, v) => x*u + y*v",
3581 "(x, y) => z => z * (x + y)",
3582 "x => (y, z) => z * (x + y)",
3584 // Those are comma-separated expressions, with arrow functions as items.
3585 // They stress the code for validating arrow function parameter lists.
3587 "a, b, (c, d) => 0",
3588 "(a, b, (c, d) => 0)",
3589 "(a, b) => 0, (c, d) => 1",
3590 "(a, b => {}, a => a + 1)",
3591 "((a, b) => {}, (a => a + 1))",
3592 "(a, (a, (b, c) => 0))",
3594 // Arrow has more precedence, this is the same as: foo ? bar : (baz = {})
3595 "foo ? bar : baz => {}",
3599 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
3600 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3601 always_flags, arraysize(always_flags));
3605 TEST(SuperNoErrors) {
3606 // Tests that parser and preparser accept 'super' keyword in right places.
3607 const char* context_data[][2] = {
3608 {"class C { m() { ", "; } }"},
3609 {"class C { m() { k = ", "; } }"},
3610 {"class C { m() { foo(", "); } }"},
3611 {"class C { m() { () => ", "; } }"},
3615 const char* statement_data[] = {
3622 "z.super", // Ok, property lookup.
3626 static const ParserFlag always_flags[] = {
3627 kAllowHarmonyArrowFunctions,
3628 kAllowHarmonyClasses,
3629 kAllowHarmonyObjectLiterals,
3632 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3633 always_flags, arraysize(always_flags));
3638 const char* context_data[][2] = {
3639 {"class C { m() { ", "; } }"},
3640 {"class C { m() { k = ", "; } }"},
3641 {"class C { m() { foo(", "); } }"},
3642 {"class C { m() { () => ", "; } }"},
3646 const char* expression_data[] = {
3653 "new super(12, 45)",
3656 "new new super()()",
3660 static const ParserFlag always_flags[] = {
3661 kAllowHarmonyClasses,
3662 kAllowHarmonyObjectLiterals,
3665 RunParserSyncTest(context_data, expression_data, kError, NULL, 0,
3666 always_flags, arraysize(always_flags));
3671 const char* context_data[][2] = {{"", ""},
3674 const char* success_data[] = {
3675 "class C extends B { constructor() { super(); } }",
3676 "class C extends B { constructor() { () => super(); } }",
3680 static const ParserFlag always_flags[] = {
3681 kAllowHarmonyArrowFunctions,
3682 kAllowHarmonyClasses,
3683 kAllowHarmonyObjectLiterals,
3686 RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0,
3687 always_flags, arraysize(always_flags));
3689 const char* error_data[] = {
3690 "class C { constructor() { super(); } }",
3691 "class C { method() { super(); } }",
3692 "class C { method() { () => super(); } }",
3693 "class C { *method() { super(); } }",
3694 "class C { get x() { super(); } }",
3695 "class C { set x(_) { super(); } }",
3696 "({ method() { super(); } })",
3697 "({ *method() { super(); } })",
3698 "({ get x() { super(); } })",
3699 "({ set x(_) { super(); } })",
3700 "({ f: function() { super(); } })",
3701 "(function() { super(); })",
3702 "var f = function() { super(); }",
3703 "({ f: function*() { super(); } })",
3704 "(function*() { super(); })",
3705 "var f = function*() { super(); }",
3709 RunParserSyncTest(context_data, error_data, kError, NULL, 0,
3710 always_flags, arraysize(always_flags));
3714 TEST(SuperNewNoErrors) {
3715 const char* context_data[][2] = {
3716 {"class C { constructor() { ", " } }"},
3717 {"class C { *method() { ", " } }"},
3718 {"class C { get x() { ", " } }"},
3719 {"class C { set x(_) { ", " } }"},
3720 {"({ method() { ", " } })"},
3721 {"({ *method() { ", " } })"},
3722 {"({ get x() { ", " } })"},
3723 {"({ set x(_) { ", " } })"},
3727 const char* expression_data[] = {
3730 "() => new super.x;",
3731 "() => new super.x();",
3735 static const ParserFlag always_flags[] = {
3736 kAllowHarmonyArrowFunctions,
3737 kAllowHarmonyClasses,
3738 kAllowHarmonyObjectLiterals,
3741 RunParserSyncTest(context_data, expression_data, kSuccess, NULL, 0,
3742 always_flags, arraysize(always_flags));
3746 TEST(SuperNewErrors) {
3747 const char* context_data[][2] = {
3748 {"class C { method() { ", " } }"},
3749 {"class C { *method() { ", " } }"},
3750 {"class C { get x() { ", " } }"},
3751 {"class C { set x(_) { ", " } }"},
3752 {"({ method() { ", " } })"},
3753 {"({ *method() { ", " } })"},
3754 {"({ get x() { ", " } })"},
3755 {"({ set x(_) { ", " } })"},
3756 {"({ f: function() { ", " } })"},
3757 {"(function() { ", " })"},
3758 {"var f = function() { ", " }"},
3759 {"({ f: function*() { ", " } })"},
3760 {"(function*() { ", " })"},
3761 {"var f = function*() { ", " }"},
3765 const char* statement_data[] = {
3769 "() => new super();",
3773 static const ParserFlag always_flags[] = {
3774 kAllowHarmonyArrowFunctions,
3775 kAllowHarmonyClasses,
3776 kAllowHarmonyObjectLiterals,
3779 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
3780 always_flags, arraysize(always_flags));
3784 TEST(SuperErrorsNonMethods) {
3785 // super is only allowed in methods, accessors and constructors.
3786 const char* context_data[][2] = {
3791 {"if (true) {", "}"},
3792 {"if (false) {} else {", "}"},
3793 {"while (true) {", "}"},
3794 {"function f() {", "}"},
3795 {"class C extends (", ") {}"},
3796 {"class C { m() { function f() {", "} } }"},
3797 {"({ m() { function f() {", "} } })"},
3801 const char* statement_data[] = {
3818 static const ParserFlag always_flags[] = {
3819 kAllowHarmonyClasses,
3820 kAllowHarmonyObjectLiterals,
3823 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
3824 always_flags, arraysize(always_flags));
3828 TEST(NoErrorsMethodDefinition) {
3829 const char* context_data[][2] = {{"({", "});"},
3830 {"'use strict'; ({", "});"},
3832 {"'use strict'; ({*", "});"},
3835 const char* object_literal_body_data[] = {
3837 "m(x) { return x; }",
3838 "m(x, y) {}, n() {}",
3844 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3845 RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0,
3846 always_flags, arraysize(always_flags));
3850 TEST(MethodDefinitionNames) {
3851 const char* context_data[][2] = {{"({", "(x, y) {}});"},
3852 {"'use strict'; ({", "(x, y) {}});"},
3853 {"({*", "(x, y) {}});"},
3854 {"'use strict'; ({*", "(x, y) {}});"},
3857 const char* name_data[] = {
3920 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3921 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
3922 always_flags, arraysize(always_flags));
3926 TEST(MethodDefinitionStrictFormalParamereters) {
3927 const char* context_data[][2] = {{"({method(", "){}});"},
3928 {"'use strict'; ({method(", "){}});"},
3929 {"({*method(", "){}});"},
3930 {"'use strict'; ({*method(", "){}});"},
3933 const char* params_data[] = {
3941 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3942 RunParserSyncTest(context_data, params_data, kError, NULL, 0,
3943 always_flags, arraysize(always_flags));
3947 TEST(MethodDefinitionEvalArguments) {
3948 const char* strict_context_data[][2] =
3949 {{"'use strict'; ({method(", "){}});"},
3950 {"'use strict'; ({*method(", "){}});"},
3952 const char* sloppy_context_data[][2] =
3953 {{"({method(", "){}});"},
3954 {"({*method(", "){}});"},
3957 const char* data[] = {
3962 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3964 // Fail in strict mode
3965 RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
3966 arraysize(always_flags));
3968 // OK in sloppy mode
3969 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
3970 arraysize(always_flags));
3974 TEST(MethodDefinitionDuplicateEvalArguments) {
3975 const char* context_data[][2] =
3976 {{"'use strict'; ({method(", "){}});"},
3977 {"'use strict'; ({*method(", "){}});"},
3978 {"({method(", "){}});"},
3979 {"({*method(", "){}});"},
3982 const char* data[] = {
3985 "arguments, arguments",
3986 "arguments, a, arguments",
3989 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3991 // In strict mode, the error is using "eval" or "arguments" as parameter names
3992 // In sloppy mode, the error is that eval / arguments are duplicated
3993 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
3994 arraysize(always_flags));
3998 TEST(MethodDefinitionDuplicateProperty) {
3999 const char* context_data[][2] = {{"'use strict'; ({", "});"},
4002 const char* params_data[] = {
4005 "x() {}, get x() {}",
4006 "x() {}, set x(_) {}",
4008 "x() {}, y() {}, x() {}",
4009 "x() {}, \"x\"() {}",
4016 "*x() {}, get x() {}",
4017 "*x() {}, set x(_) {}",
4019 "*x() {}, y() {}, *x() {}",
4020 "*x() {}, *\"x\"() {}",
4021 "*x() {}, *'x'() {}",
4022 "*0() {}, *'0'() {}",
4028 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4029 RunParserSyncTest(context_data, params_data, kSuccess, NULL, 0,
4030 always_flags, arraysize(always_flags));
4034 TEST(ClassExpressionNoErrors) {
4035 const char* context_data[][2] = {{"(", ");"},
4039 const char* class_data[] = {
4042 "class extends F {}",
4043 "class name extends F {}",
4044 "class extends (F, G) {}",
4045 "class name extends (F, G) {}",
4046 "class extends class {} {}",
4047 "class name extends class {} {}",
4048 "class extends class base {} {}",
4049 "class name extends class base {} {}",
4052 static const ParserFlag always_flags[] = {
4053 kAllowHarmonyClasses, kAllowHarmonySloppy};
4054 RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
4055 always_flags, arraysize(always_flags));
4059 TEST(ClassDeclarationNoErrors) {
4060 const char* context_data[][2] = {{"'use strict'; ", ""},
4061 {"'use strict'; {", "}"},
4062 {"'use strict'; if (true) {", "}"},
4064 const char* statement_data[] = {
4066 "class name extends F {}",
4067 "class name extends (F, G) {}",
4068 "class name extends class {} {}",
4069 "class name extends class base {} {}",
4072 static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
4073 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
4074 always_flags, arraysize(always_flags));
4078 TEST(ClassBodyNoErrors) {
4079 // Tests that parser and preparser accept valid class syntax.
4080 const char* context_data[][2] = {{"(class {", "});"},
4081 {"(class extends Base {", "});"},
4083 {"class C extends Base {", "}"},
4085 const char* class_body_data[] = {
4099 "*g() {}; *h(x) {}",
4102 "static get x() {}",
4103 "static set x(v) {}",
4106 "static static() {}",
4107 "static get static() {}",
4108 "static set static(v) {}",
4115 static const ParserFlag always_flags[] = {
4116 kAllowHarmonyClasses,
4117 kAllowHarmonyObjectLiterals,
4120 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4121 always_flags, arraysize(always_flags));
4125 TEST(ClassPropertyNameNoErrors) {
4126 const char* context_data[][2] = {{"(class {", "() {}});"},
4127 {"(class { get ", "() {}});"},
4128 {"(class { set ", "(v) {}});"},
4129 {"(class { static ", "() {}});"},
4130 {"(class { static get ", "() {}});"},
4131 {"(class { static set ", "(v) {}});"},
4132 {"(class { *", "() {}});"},
4133 {"(class { static *", "() {}});"},
4134 {"class C {", "() {}}"},
4135 {"class C { get ", "() {}}"},
4136 {"class C { set ", "(v) {}}"},
4137 {"class C { static ", "() {}}"},
4138 {"class C { static get ", "() {}}"},
4139 {"class C { static set ", "(v) {}}"},
4140 {"class C { *", "() {}}"},
4141 {"class C { static *", "() {}}"},
4143 const char* name_data[] = {
4174 static const ParserFlag always_flags[] = {
4175 kAllowHarmonyClasses,
4176 kAllowHarmonyObjectLiterals,
4179 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
4180 always_flags, arraysize(always_flags));
4184 TEST(ClassExpressionErrors) {
4185 const char* context_data[][2] = {{"(", ");"},
4189 const char* class_data[] = {
4192 "class name extends",
4198 "class { m(); n() }",
4200 "class { get m() }",
4201 "class { get m() { }",
4202 "class { set m() {} }", // Missing required parameter.
4203 "class { m() {}, n() {} }", // No commas allowed.
4206 static const ParserFlag always_flags[] = {
4207 kAllowHarmonyClasses,
4208 kAllowHarmonyObjectLiterals,
4211 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
4212 always_flags, arraysize(always_flags));
4216 TEST(ClassDeclarationErrors) {
4217 const char* context_data[][2] = {{"", ""},
4219 {"if (true) {", "}"},
4221 const char* class_data[] = {
4224 "class name extends",
4228 "class name { m; n }",
4229 "class name { m: 1 }",
4230 "class name { m(); n() }",
4231 "class name { get x }",
4232 "class name { get x() }",
4233 "class name { set x() {) }", // missing required param
4234 "class {}", // Name is required for declaration
4235 "class extends base {}",
4238 "class name { *; }",
4239 "class name { *get x() {} }",
4240 "class name { *set x(_) {} }",
4241 "class name { *static m() {} }",
4244 static const ParserFlag always_flags[] = {
4245 kAllowHarmonyClasses,
4246 kAllowHarmonyNumericLiterals,
4249 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
4250 always_flags, arraysize(always_flags));
4254 TEST(ClassNameErrors) {
4255 const char* context_data[][2] = {{"class ", "{}"},
4256 {"(class ", "{});"},
4257 {"'use strict'; class ", "{}"},
4258 {"'use strict'; (class ", "{});"},
4260 const char* class_name[] = {
4275 static const ParserFlag always_flags[] = {
4276 kAllowHarmonyClasses,
4277 kAllowHarmonyObjectLiterals,
4280 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
4281 always_flags, arraysize(always_flags));
4285 TEST(ClassGetterParamNameErrors) {
4286 const char* context_data[][2] = {
4287 {"class C { get name(", ") {} }"},
4288 {"(class { get name(", ") {} });"},
4289 {"'use strict'; class C { get name(", ") {} }"},
4290 {"'use strict'; (class { get name(", ") {} })"},
4294 const char* class_name[] = {
4309 static const ParserFlag always_flags[] = {
4310 kAllowHarmonyClasses,
4311 kAllowHarmonyObjectLiterals,
4314 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
4315 always_flags, arraysize(always_flags));
4319 TEST(ClassStaticPrototypeErrors) {
4320 const char* context_data[][2] = {{"class C {", "}"},
4321 {"(class {", "});"},
4324 const char* class_body_data[] = {
4325 "static prototype() {}",
4326 "static get prototype() {}",
4327 "static set prototype(_) {}",
4328 "static *prototype() {}",
4329 "static 'prototype'() {}",
4330 "static *'prototype'() {}",
4331 "static prot\\u006ftype() {}",
4332 "static 'prot\\u006ftype'() {}",
4333 "static get 'prot\\u006ftype'() {}",
4334 "static set 'prot\\u006ftype'(_) {}",
4335 "static *'prot\\u006ftype'() {}",
4338 static const ParserFlag always_flags[] = {
4339 kAllowHarmonyClasses,
4340 kAllowHarmonyObjectLiterals,
4343 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4344 always_flags, arraysize(always_flags));
4348 TEST(ClassSpecialConstructorErrors) {
4349 const char* context_data[][2] = {{"class C {", "}"},
4350 {"(class {", "});"},
4353 const char* class_body_data[] = {
4354 "get constructor() {}",
4355 "get constructor(_) {}",
4356 "*constructor() {}",
4357 "get 'constructor'() {}",
4358 "*'constructor'() {}",
4359 "get c\\u006fnstructor() {}",
4360 "*c\\u006fnstructor() {}",
4361 "get 'c\\u006fnstructor'() {}",
4362 "get 'c\\u006fnstructor'(_) {}",
4363 "*'c\\u006fnstructor'() {}",
4366 static const ParserFlag always_flags[] = {
4367 kAllowHarmonyClasses,
4368 kAllowHarmonyObjectLiterals,
4371 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4372 always_flags, arraysize(always_flags));
4376 TEST(ClassConstructorNoErrors) {
4377 const char* context_data[][2] = {{"class C {", "}"},
4378 {"(class {", "});"},
4381 const char* class_body_data[] = {
4383 "static constructor() {}",
4384 "static get constructor() {}",
4385 "static set constructor(_) {}",
4386 "static *constructor() {}",
4389 static const ParserFlag always_flags[] = {
4390 kAllowHarmonyClasses,
4391 kAllowHarmonyObjectLiterals,
4394 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4395 always_flags, arraysize(always_flags));
4399 TEST(ClassMultipleConstructorErrors) {
4400 const char* context_data[][2] = {{"class C {", "}"},
4401 {"(class {", "});"},
4404 const char* class_body_data[] = {
4405 "constructor() {}; constructor() {}",
4408 static const ParserFlag always_flags[] = {
4409 kAllowHarmonyClasses,
4410 kAllowHarmonyObjectLiterals,
4413 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4414 always_flags, arraysize(always_flags));
4418 TEST(ClassMultiplePropertyNamesNoErrors) {
4419 const char* context_data[][2] = {{"class C {", "}"},
4420 {"(class {", "});"},
4423 const char* class_body_data[] = {
4424 "constructor() {}; static constructor() {}",
4425 "m() {}; static m() {}",
4427 "static m() {}; static m() {}",
4428 "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
4431 static const ParserFlag always_flags[] = {
4432 kAllowHarmonyClasses,
4433 kAllowHarmonyObjectLiterals,
4436 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4437 always_flags, arraysize(always_flags));
4441 TEST(ClassesAreStrictErrors) {
4442 const char* context_data[][2] = {{"", ""},
4446 const char* class_body_data[] = {
4447 "class C { method() { with ({}) {} } }",
4448 "class C extends function() { with ({}) {} } {}",
4449 "class C { *method() { with ({}) {} } }",
4452 static const ParserFlag always_flags[] = {
4453 kAllowHarmonyClasses,
4454 kAllowHarmonyObjectLiterals,
4457 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4458 always_flags, arraysize(always_flags));
4462 TEST(ObjectLiteralPropertyShorthandKeywordsError) {
4463 const char* context_data[][2] = {{"({", "});"},
4464 {"'use strict'; ({", "});"},
4467 const char* name_data[] = {
4507 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4508 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4509 always_flags, arraysize(always_flags));
4513 TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
4514 const char* context_data[][2] = {{"({", "});"},
4517 const char* name_data[] = {
4530 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4531 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
4532 always_flags, arraysize(always_flags));
4534 const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
4536 RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0,
4537 always_flags, arraysize(always_flags));
4541 TEST(ObjectLiteralPropertyShorthandError) {
4542 const char* context_data[][2] = {{"({", "});"},
4543 {"'use strict'; ({", "});"},
4546 const char* name_data[] = {
4559 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4560 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4561 always_flags, arraysize(always_flags));
4565 TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
4566 const char* context_data[][2] = {{"", ""},
4569 const char* name_data[] = {
4570 "function* g() { ({yield}); }",
4574 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4575 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4576 always_flags, arraysize(always_flags));
4580 TEST(ConstParsingInForIn) {
4581 const char* context_data[][2] = {{"'use strict';", ""},
4582 {"function foo(){ 'use strict';", "}"},
4585 const char* data[] = {
4586 "for(const x = 1; ; ) {}",
4587 "for(const x = 1, y = 2;;){}",
4588 "for(const x in [1,2,3]) {}",
4589 "for(const x of [1,2,3]) {}",
4591 RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, nullptr, 0);
4595 TEST(ConstParsingInForInError) {
4596 const char* context_data[][2] = {{"'use strict';", ""},
4597 {"function foo(){ 'use strict';", "}"},
4600 const char* data[] = {
4601 "for(const x,y = 1; ; ) {}",
4602 "for(const x = 4 in [1,2,3]) {}",
4603 "for(const x = 4, y in [1,2,3]) {}",
4604 "for(const x = 4 of [1,2,3]) {}",
4605 "for(const x = 4, y of [1,2,3]) {}",
4606 "for(const x = 1, y = 2 in []) {}",
4607 "for(const x,y in []) {}",
4608 "for(const x = 1, y = 2 of []) {}",
4609 "for(const x,y of []) {}",
4611 RunParserSyncTest(context_data, data, kError, nullptr, 0, nullptr, 0);
4615 TEST(InvalidUnicodeEscapes) {
4616 const char* context_data[][2] = {{"", ""},
4617 {"'use strict';", ""},
4619 const char* data[] = {
4620 "var foob\\u123r = 0;",
4621 "var \\u123roo = 0;",
4623 // No escapes allowed in regexp flags
4626 // Braces gone wrong
4627 "var foob\\u{c481r = 0;",
4628 "var foob\\uc481}r = 0;",
4629 "var \\u{0052oo = 0;",
4630 "var \\u0052}oo = 0;",
4631 "\"foob\\u{c481r\"",
4632 "var foob\\u{}ar = 0;",
4633 // Too high value for the unicode escape
4635 // Not an unicode escape
4636 "var foob\\v1234r = 0;",
4637 "var foob\\U1234r = 0;",
4638 "var foob\\v{1234}r = 0;",
4639 "var foob\\U{1234}r = 0;",
4641 static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
4642 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4643 arraysize(always_flags));
4647 TEST(UnicodeEscapes) {
4648 const char* context_data[][2] = {{"", ""},
4649 {"'use strict';", ""},
4651 const char* data[] = {
4652 // Identifier starting with escape
4653 "var \\u0052oo = 0;",
4654 "var \\u{0052}oo = 0;",
4655 "var \\u{52}oo = 0;",
4656 "var \\u{00000000052}oo = 0;",
4657 // Identifier with an escape but not starting with an escape
4658 "var foob\\uc481r = 0;",
4659 "var foob\\u{c481}r = 0;",
4660 // String with an escape
4662 "\"foob\\{uc481}r\"",
4663 // This character is a valid unicode character, representable as a surrogate
4664 // pair, not representable as 4 hex digits.
4665 "\"foo\\u{10e6d}\"",
4666 // Max value for the unicode escape
4669 static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
4670 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4671 arraysize(always_flags));
4675 TEST(ScanTemplateLiterals) {
4676 const char* context_data[][2] = {{"'use strict';", ""},
4677 {"function foo(){ 'use strict';"
4678 " var a, b, c; return ", "}"},
4681 const char* data[] = {
4683 "`no-subst-template`",
4684 "`template-head${a}`",
4686 "`${a}template-tail`",
4687 "`template-head${a}template-tail`",
4689 "`a${a}b${b}c${c}`",
4690 "`${a}a${b}b${c}c`",
4691 "`foo\n\nbar\r\nbaz`",
4692 "`foo\n\n${ bar }\r\nbaz`",
4693 "`foo${a /* comment */}`",
4694 "`foo${a // comment\n}`",
4698 "`foo${/* comment */ a}`",
4699 "`foo${// comment\na}`",
4705 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0);
4709 TEST(ScanTaggedTemplateLiterals) {
4710 const char* context_data[][2] = {{"'use strict';", ""},
4711 {"function foo(){ 'use strict';"
4712 " function tag() {}"
4713 " var a, b, c; return ", "}"},
4716 const char* data[] = {
4718 "tag `no-subst-template`",
4719 "tag`template-head${a}`",
4721 "tag `${a}template-tail`",
4722 "tag `template-head${a}template-tail`",
4723 "tag\n`${a}${b}${c}`",
4724 "tag\r\n`a${a}b${b}c${c}`",
4725 "tag `${a}a${b}b${c}c`",
4726 "tag\t`foo\n\nbar\r\nbaz`",
4727 "tag\r`foo\n\n${ bar }\r\nbaz`",
4728 "tag`foo${a /* comment */}`",
4729 "tag`foo${a // comment\n}`",
4731 "tag`foo${a \r\n}`",
4733 "tag`foo${/* comment */ a}`",
4734 "tag`foo${// comment\na}`",
4736 "tag`foo${\r\n a}`",
4738 "tag`foo${'a' in a}`",
4740 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0);
4744 TEST(TemplateMaterializedLiterals) {
4745 const char* context_data[][2] = {
4748 "function tag() {}\n"
4755 const char* data[] = {
4767 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0);
4771 TEST(ScanUnterminatedTemplateLiterals) {
4772 const char* context_data[][2] = {{"'use strict';", ""},
4773 {"function foo(){ 'use strict';"
4774 " var a, b, c; return ", "}"},
4777 const char* data[] = {
4778 "`no-subst-template",
4779 "`template-head${a}",
4780 "`${a}template-tail",
4781 "`template-head${a}template-tail",
4785 "`foo\n\nbar\r\nbaz",
4786 "`foo\n\n${ bar }\r\nbaz",
4787 "`foo${a /* comment } */`",
4788 "`foo${a /* comment } `*/",
4789 "`foo${a // comment}`",
4793 "`foo${/* comment */ a`",
4794 "`foo${// commenta}`",
4801 RunParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0);
4805 TEST(TemplateLiteralsIllegalTokens) {
4806 const char* context_data[][2] = {{"'use strict';", ""},
4807 {"function foo(){ 'use strict';"
4808 " var a, b, c; return ", "}"},
4810 const char* data[] = {
4814 "`hello${1}\\x${2}`",
4818 "`hello${1}\\x\n${2}`",
4821 RunParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0);
4825 TEST(ParseRestParameters) {
4826 const char* context_data[][2] = {{"'use strict';(function(",
4827 "){ return args;})(1, [], /regexp/, 'str',"
4829 {"(function(", "){ return args;})(1, [],"
4830 "/regexp/, 'str', function(){});"},
4833 const char* data[] = {
4844 "...\t\n\t\t\n args",
4845 "a, ... \n \n args",
4847 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4848 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4849 arraysize(always_flags));
4853 TEST(ParseRestParametersErrors) {
4854 const char* context_data[][2] = {{"'use strict';(function(",
4855 "){ return args;}(1, [], /regexp/, 'str',"
4857 {"(function(", "){ return args;}(1, [],"
4858 "/regexp/, 'str', function(){});"},
4861 const char* data[] = {
4869 "a, ... args,\r\nb",
4872 "...args\t\n\t\t\n, b",
4873 "a, ... args, \n \n b",
4879 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4880 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4881 arraysize(always_flags));
4885 TEST(RestParametersEvalArguments) {
4886 const char* strict_context_data[][2] =
4887 {{"'use strict';(function(",
4888 "){ return;})(1, [], /regexp/, 'str',function(){});"},
4890 const char* sloppy_context_data[][2] =
4892 "){ return;})(1, [],/regexp/, 'str', function(){});"},
4895 const char* data[] = {
4899 "arguments, ...args",
4902 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4904 // Fail in strict mode
4905 RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
4906 arraysize(always_flags));
4908 // OK in sloppy mode
4909 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
4910 arraysize(always_flags));
4914 TEST(RestParametersDuplicateEvalArguments) {
4915 const char* context_data[][2] =
4916 {{"'use strict';(function(",
4917 "){ return;})(1, [], /regexp/, 'str',function(){});"},
4919 "){ return;})(1, [],/regexp/, 'str', function(){});"},
4922 const char* data[] = {
4924 "eval, eval, ...args",
4925 "arguments, ...arguments",
4926 "arguments, arguments, ...args",
4929 static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
4931 // In strict mode, the error is using "eval" or "arguments" as parameter names
4932 // In sloppy mode, the error is that eval / arguments are duplicated
4933 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4934 arraysize(always_flags));
4938 TEST(LexicalScopingSloppyMode) {
4939 const char* context_data[][2] = {
4941 {"function f() {", "}"},
4944 const char* bad_data[] = {
4946 "for(let x = 1;;){}",
4947 "for(let x of []){}",
4948 "for(let x in []){}",
4950 "class C extends D {}",
4952 "(class extends D {})",
4954 "(class C extends D {})",
4956 static const ParserFlag always_true_flags[] = {kAllowHarmonyClasses};
4957 static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
4958 RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
4959 always_true_flags, arraysize(always_true_flags),
4960 always_false_flags, arraysize(always_false_flags));
4962 const char* good_data[] = {
4966 RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0,
4967 always_true_flags, arraysize(always_true_flags),
4968 always_false_flags, arraysize(always_false_flags));
4972 TEST(ComputedPropertyName) {
4973 const char* context_data[][2] = {{"({[", "]: 1});"},
4974 {"({get [", "]() {}});"},
4975 {"({set [", "](_) {}});"},
4976 {"({[", "]() {}});"},
4977 {"({*[", "]() {}});"},
4978 {"(class {get [", "]() {}});"},
4979 {"(class {set [", "](_) {}});"},
4980 {"(class {[", "]() {}});"},
4981 {"(class {*[", "]() {}});"},
4983 const char* error_data[] = {
4988 static const ParserFlag always_flags[] = {
4989 kAllowHarmonyClasses,
4990 kAllowHarmonyComputedPropertyNames,
4991 kAllowHarmonyObjectLiterals,
4992 kAllowHarmonySloppy,
4994 RunParserSyncTest(context_data, error_data, kError, NULL, 0,
4995 always_flags, arraysize(always_flags));
4997 const char* name_data[] = {
5006 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
5007 always_flags, arraysize(always_flags));
5011 TEST(ComputedPropertyNameShorthandError) {
5012 const char* context_data[][2] = {{"({", "});"},
5014 const char* error_data[] = {
5019 static const ParserFlag always_flags[] = {
5020 kAllowHarmonyClasses,
5021 kAllowHarmonyComputedPropertyNames,
5022 kAllowHarmonyObjectLiterals,
5023 kAllowHarmonySloppy,
5025 RunParserSyncTest(context_data, error_data, kError, NULL, 0,
5026 always_flags, arraysize(always_flags));
5030 TEST(BasicImportExportParsing) {
5031 const char* kSources[] = {
5032 "export let x = 0;",
5033 "export var y = 0;",
5034 "export const z = 0;",
5035 "export function func() { };",
5036 "export class C { };",
5038 "function f() {}; f(); export { f };",
5039 "var a, b, c; export { a, b as baz, c };",
5040 "var d, e; export { d as dreary, e, };",
5041 "export default function f() {}",
5042 "export default class C {}",
5043 "export default 42",
5044 "var x; export default x = 7",
5045 "export { Q } from 'somemodule.js';",
5046 "export * from 'somemodule.js';",
5047 "var foo; export { foo as for };",
5048 "export { arguments } from 'm.js';",
5049 "export { for } from 'm.js';",
5050 "export { yield } from 'm.js'",
5051 "export { static } from 'm.js'",
5052 "export { let } from 'm.js'",
5053 "var a; export { a as b, a as c };",
5055 "import 'somemodule.js';",
5056 "import { } from 'm.js';",
5057 "import { a } from 'm.js';",
5058 "import { a, b as d, c, } from 'm.js';",
5059 "import * as thing from 'm.js';",
5060 "import thing from 'm.js';",
5061 "import thing, * as rest from 'm.js';",
5062 "import thing, { a, b, c } from 'm.js';",
5063 "import { arguments as a } from 'm.js';",
5064 "import { for as f } from 'm.js';",
5065 "import { yield as y } from 'm.js';",
5066 "import { static as s } from 'm.js';",
5067 "import { let as l } from 'm.js';",
5070 i::Isolate* isolate = CcTest::i_isolate();
5071 i::Factory* factory = isolate->factory();
5073 v8::HandleScope handles(CcTest::isolate());
5074 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
5075 v8::Context::Scope context_scope(context);
5077 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5080 for (unsigned i = 0; i < arraysize(kSources); ++i) {
5081 i::Handle<i::String> source =
5082 factory->NewStringFromAsciiChecked(kSources[i]);
5084 // Show that parsing as a module works
5086 i::Handle<i::Script> script = factory->NewScript(source);
5088 i::ParseInfo info(&zone, script);
5089 i::Parser parser(&info);
5090 parser.set_allow_harmony_classes(true);
5091 parser.set_allow_harmony_modules(true);
5093 if (!parser.Parse(&info)) {
5094 i::Handle<i::JSObject> exception_handle(
5095 i::JSObject::cast(isolate->pending_exception()));
5096 i::Handle<i::String> message_string =
5097 i::Handle<i::String>::cast(i::Object::GetProperty(
5098 isolate, exception_handle, "message").ToHandleChecked());
5100 v8::base::OS::Print(
5101 "Parser failed on:\n"
5105 "However, we expected no error.",
5106 source->ToCString().get(), message_string->ToCString().get());
5111 // And that parsing a script does not.
5113 i::Handle<i::Script> script = factory->NewScript(source);
5115 i::ParseInfo info(&zone, script);
5116 i::Parser parser(&info);
5117 parser.set_allow_harmony_classes(true);
5118 parser.set_allow_harmony_modules(true);
5120 CHECK(!parser.Parse(&info));
5126 TEST(ImportExportParsingErrors) {
5127 const char* kErrorSources[] = {
5129 "var a; export { a",
5130 "var a; export { a,",
5131 "var a; export { a, ;",
5132 "var a; export { a as };",
5133 "var a, b; export { a as , b};",
5135 "var foo, bar; export { foo bar };",
5139 "export default var x = 7;",
5140 "export default let x = 7;",
5141 "export default const x = 7;",
5144 "export { Q } from;",
5145 "export default from 'module.js';",
5147 "export { for as foo }",
5148 "export { arguments }",
5149 "export { arguments as foo }",
5150 "var a; export { a, a };",
5151 "var a, b; export { a as b, b };",
5152 "var a, b; export { a as c, b as c };",
5153 "export default function f(){}; export default class C {};",
5154 "export default function f(){}; var a; export { a as default };",
5157 "import from 'm.js';",
5162 "import { , } from 'm.js';",
5163 "import { a } from;",
5164 "import { a } 'm.js';",
5165 "import , from 'm.js';",
5166 "import a , from 'm.js';",
5167 "import a { b, c } from 'm.js';",
5168 "import arguments from 'm.js';",
5169 "import eval from 'm.js';",
5170 "import { arguments } from 'm.js';",
5171 "import { eval } from 'm.js';",
5172 "import { a as arguments } from 'm.js';",
5173 "import { for } from 'm.js';",
5174 "import { y as yield } from 'm.js'",
5175 "import { s as static } from 'm.js'",
5176 "import { l as let } from 'm.js'",
5177 "import { x }, def from 'm.js';",
5178 "import def, def2 from 'm.js';",
5179 "import * as x, def from 'm.js';",
5180 "import * as x, * as y from 'm.js';",
5181 "import {x}, {y} from 'm.js';",
5182 "import * as x, {y} from 'm.js';",
5184 // TODO(ES6): These two forms should be supported
5185 "export default function() {};",
5186 "export default class {};"
5189 i::Isolate* isolate = CcTest::i_isolate();
5190 i::Factory* factory = isolate->factory();
5192 v8::HandleScope handles(CcTest::isolate());
5193 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
5194 v8::Context::Scope context_scope(context);
5196 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5199 for (unsigned i = 0; i < arraysize(kErrorSources); ++i) {
5200 i::Handle<i::String> source =
5201 factory->NewStringFromAsciiChecked(kErrorSources[i]);
5203 i::Handle<i::Script> script = factory->NewScript(source);
5205 i::ParseInfo info(&zone, script);
5206 i::Parser parser(&info);
5207 parser.set_allow_harmony_classes(true);
5208 parser.set_allow_harmony_modules(true);
5210 CHECK(!parser.Parse(&info));
5215 TEST(ModuleParsingInternals) {
5216 i::FLAG_harmony_modules = true;
5218 i::Isolate* isolate = CcTest::i_isolate();
5219 i::Factory* factory = isolate->factory();
5220 v8::HandleScope handles(CcTest::isolate());
5221 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
5222 v8::Context::Scope context_scope(context);
5223 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5226 static const char kSource[] =
5228 "export { x as y };"
5229 "import { q as z } from 'm.js';"
5230 "import n from 'n.js'";
5231 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(kSource);
5232 i::Handle<i::Script> script = factory->NewScript(source);
5234 i::ParseInfo info(&zone, script);
5235 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
5236 i::Parser parser(&info);
5237 parser.set_allow_harmony_modules(true);
5239 CHECK(parser.Parse(&info));
5240 CHECK(i::Compiler::Analyze(&info));
5242 i::FunctionLiteral* func = info.function();
5243 i::Scope* module_scope = func->scope();
5244 i::Scope* outer_scope = module_scope->outer_scope();
5245 CHECK(outer_scope->is_script_scope());
5246 CHECK_NULL(outer_scope->outer_scope());
5247 CHECK_EQ(1, outer_scope->num_modules());
5248 CHECK(module_scope->is_module_scope());
5249 CHECK_NOT_NULL(module_scope->module_var());
5250 CHECK_EQ(i::INTERNAL, module_scope->module_var()->mode());
5252 i::ModuleDescriptor* descriptor = module_scope->module();
5253 CHECK_NOT_NULL(descriptor);
5254 CHECK_EQ(1, descriptor->Length());
5255 const i::AstRawString* export_name = avf.GetOneByteString("y");
5256 const i::AstRawString* local_name =
5257 descriptor->LookupLocalExport(export_name, &zone);
5258 CHECK_NOT_NULL(local_name);
5259 CHECK(local_name->IsOneByteEqualTo("x"));
5260 i::ZoneList<i::Declaration*>* declarations = module_scope->declarations();
5261 CHECK_EQ(3, declarations->length());
5262 CHECK(declarations->at(0)->proxy()->raw_name()->IsOneByteEqualTo("x"));
5263 i::ImportDeclaration* import_decl =
5264 declarations->at(1)->AsImportDeclaration();
5265 CHECK(import_decl->import_name()->IsOneByteEqualTo("q"));
5266 CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("z"));
5267 CHECK(import_decl->module_specifier()->IsOneByteEqualTo("m.js"));
5268 import_decl = declarations->at(2)->AsImportDeclaration();
5269 CHECK(import_decl->import_name()->IsOneByteEqualTo("default"));
5270 CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("n"));
5271 CHECK(import_decl->module_specifier()->IsOneByteEqualTo("n.js"));
5275 TEST(DuplicateProtoError) {
5276 const char* context_data[][2] = {
5278 {"'use strict'; ({", "});"},
5281 const char* error_data[] = {
5282 "__proto__: {}, __proto__: {}",
5283 "__proto__: {}, \"__proto__\": {}",
5284 "__proto__: {}, \"__\x70roto__\": {}",
5285 "__proto__: {}, a: 1, __proto__: {}",
5289 RunParserSyncTest(context_data, error_data, kError);
5293 TEST(DuplicateProtoNoError) {
5294 const char* context_data[][2] = {
5296 {"'use strict'; ({", "});"},
5299 const char* error_data[] = {
5300 "__proto__: {}, ['__proto__']: {}",
5301 "__proto__: {}, __proto__() {}",
5302 "__proto__: {}, get __proto__() {}",
5303 "__proto__: {}, set __proto__(v) {}",
5304 "__proto__: {}, __proto__",
5308 static const ParserFlag always_flags[] = {
5309 kAllowHarmonyComputedPropertyNames,
5310 kAllowHarmonyObjectLiterals,
5312 RunParserSyncTest(context_data, error_data, kSuccess, NULL, 0,
5313 always_flags, arraysize(always_flags));
5317 TEST(DeclarationsError) {
5318 const char* context_data[][2] = {{"'use strict'; if (true)", ""},
5319 {"'use strict'; if (false) {} else", ""},
5320 {"'use strict'; while (false)", ""},
5321 {"'use strict'; for (;;)", ""},
5322 {"'use strict'; for (x in y)", ""},
5323 {"'use strict'; do ", " while (false)"},
5324 {"'use strong'; if (true)", ""},
5325 {"'use strong'; if (false) {} else", ""},
5326 {"'use strong'; while (false)", ""},
5327 {"'use strong'; for (;;)", ""},
5328 {"'use strong'; for (x in y)", ""},
5329 {"'use strong'; do ", " while (false)"},
5332 const char* statement_data[] = {
5338 static const ParserFlag always_flags[] = {kAllowHarmonyClasses,
5340 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
5341 always_flags, arraysize(always_flags));
5345 void TestLanguageMode(const char* source,
5346 i::LanguageMode expected_language_mode) {
5347 i::Isolate* isolate = CcTest::i_isolate();
5348 i::Factory* factory = isolate->factory();
5349 v8::HandleScope handles(CcTest::isolate());
5350 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
5351 v8::Context::Scope context_scope(context);
5352 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
5355 i::Handle<i::Script> script =
5356 factory->NewScript(factory->NewStringFromAsciiChecked(source));
5358 i::ParseInfo info(&zone, script);
5359 i::Parser parser(&info);
5360 parser.set_allow_strong_mode(true);
5362 parser.Parse(&info);
5363 CHECK(info.function() != NULL);
5364 CHECK_EQ(expected_language_mode, info.function()->language_mode());
5368 TEST(LanguageModeDirectives) {
5369 TestLanguageMode("\"use nothing\"", i::SLOPPY);
5370 TestLanguageMode("\"use strict\"", i::STRICT);
5371 TestLanguageMode("\"use strong\"", i::STRONG);
5373 TestLanguageMode("var x = 1; \"use strict\"", i::SLOPPY);
5374 TestLanguageMode("var x = 1; \"use strong\"", i::SLOPPY);
5376 // Test that multiple directives ("use strict" / "use strong") put the parser
5377 // into the correct mode.
5378 TestLanguageMode("\"use strict\"; \"use strong\";", i::STRONG);
5379 TestLanguageMode("\"use strong\"; \"use strict\";", i::STRONG);
5381 TestLanguageMode("\"use some future directive\"; \"use strict\";", i::STRICT);
5382 TestLanguageMode("\"use some future directive\"; \"use strong\";", i::STRONG);
5386 TEST(PropertyNameEvalArguments) {
5387 const char* context_data[][2] = {{"'use strict';", ""},
5388 {"'use strong';", ""},
5391 const char* statement_data[] = {
5395 "({arguments() {}})",
5397 "({*arguments() {}})",
5398 "({get eval() {}})",
5399 "({get arguments() {}})",
5400 "({set eval(_) {}})",
5401 "({set arguments(_) {}})",
5403 "class C {eval() {}}",
5404 "class C {arguments() {}}",
5405 "class C {*eval() {}}",
5406 "class C {*arguments() {}}",
5407 "class C {get eval() {}}",
5408 "class C {get arguments() {}}",
5409 "class C {set eval(_) {}}",
5410 "class C {set arguments(_) {}}",
5412 "class C {static eval() {}}",
5413 "class C {static arguments() {}}",
5414 "class C {static *eval() {}}",
5415 "class C {static *arguments() {}}",
5416 "class C {static get eval() {}}",
5417 "class C {static get arguments() {}}",
5418 "class C {static set eval(_) {}}",
5419 "class C {static set arguments(_) {}}",
5423 static const ParserFlag always_flags[] = {
5424 kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowStrongMode};
5425 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
5426 always_flags, arraysize(always_flags));
5430 TEST(FunctionLiteralDuplicateParameters) {
5431 const char* strict_context_data[][2] =
5432 {{"'use strict';(function(", "){})();"},
5433 {"(function(", ") { 'use strict'; })();"},
5434 {"'use strict'; function fn(", ") {}; fn();"},
5435 {"function fn(", ") { 'use strict'; }; fn();"},
5436 {"'use strong';(function(", "){})();"},
5437 {"(function(", ") { 'use strong'; })();"},
5438 {"'use strong'; function fn(", ") {}; fn();"},
5439 {"function fn(", ") { 'use strong'; }; fn();"},
5442 const char* sloppy_context_data[][2] =
5443 {{"(function(", "){})();"},
5444 {"(function(", ") {})();"},
5445 {"function fn(", ") {}; fn();"},
5446 {"function fn(", ") {}; fn();"},
5449 const char* data[] = {
5454 "a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, w",
5457 static const ParserFlag always_flags[] = { kAllowStrongMode };
5458 RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags,
5459 arraysize(always_flags));
5460 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, NULL, 0);
5464 TEST(VarForbiddenInStrongMode) {
5465 const char* strong_context_data[][2] =
5466 {{"'use strong'; ", ""},
5467 {"function f() {'use strong'; ", "}"},
5468 {"function f() {'use strong'; while (true) { ", "} }"},
5471 const char* strict_context_data[][2] =
5472 {{"'use strict'; ", ""},
5473 {"function f() {'use strict'; ", "}"},
5474 {"function f() {'use strict'; while (true) { ", "} }"},
5477 const char* sloppy_context_data[][2] =
5479 {"function f() { ", "}"},
5482 const char* var_declarations[] = {
5484 "for (var i = 0; i < 10; i++) { }",
5487 const char* let_declarations[] = {
5489 "for (let i = 0; i < 10; i++) { }",
5492 const char* const_declarations[] = {
5496 static const ParserFlag always_flags[] = {kAllowStrongMode};
5497 RunParserSyncTest(strong_context_data, var_declarations, kError, NULL, 0,
5498 always_flags, arraysize(always_flags));
5499 RunParserSyncTest(strong_context_data, let_declarations, kSuccess, NULL, 0,
5500 always_flags, arraysize(always_flags));
5501 RunParserSyncTest(strong_context_data, const_declarations, kSuccess, NULL, 0,
5502 always_flags, arraysize(always_flags));
5504 RunParserSyncTest(strict_context_data, var_declarations, kSuccess, NULL, 0,
5505 always_flags, arraysize(always_flags));
5506 RunParserSyncTest(strict_context_data, let_declarations, kSuccess, NULL, 0,
5507 always_flags, arraysize(always_flags));
5509 RunParserSyncTest(sloppy_context_data, var_declarations, kSuccess, NULL, 0,
5510 always_flags, arraysize(always_flags));
5511 // At the moment, let declarations are only available in strict mode.
5512 RunParserSyncTest(sloppy_context_data, let_declarations, kError, NULL, 0,
5513 always_flags, arraysize(always_flags));
5517 TEST(StrongEmptySubStatements) {
5518 const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
5519 const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
5520 const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
5522 const char* data[] = {
5530 "for (const x = 0;;);",
5531 "for (const x in []);",
5532 "for (const x of []);",
5535 static const ParserFlag always_flags[] = {
5538 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
5539 arraysize(always_flags));
5540 RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
5541 arraysize(always_flags));
5542 RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
5543 arraysize(always_flags));
5548 const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
5549 const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
5550 const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
5552 const char* data[] = {
5554 "for (const x in []) {}",
5557 static const ParserFlag always_flags[] = {
5560 RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags,
5561 arraysize(always_flags));
5562 RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
5563 arraysize(always_flags));
5564 RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
5565 arraysize(always_flags));
5569 TEST(StrongSuperCalls) {
5570 const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
5571 const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
5572 const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
5574 const char* data[] = {
5575 "class C extends Object { constructor() {} }",
5576 "class C extends Object { constructor() { (super()); } }",
5577 "class C extends Object { constructor() { (() => super())(); } }",
5578 "class C extends Object { constructor() { { super(); } } }",
5579 "class C extends Object { constructor() { if (1) super(); } }",
5580 "class C extends Object { constructor() { super(), super(); } }",
5581 "class C extends Object { constructor() { super(); super(); } }",
5582 "class C extends Object { constructor() { super(); (super()); } }",
5583 "class C extends Object { constructor() { super(); { super() } } }",
5586 static const ParserFlag always_flags[] = {
5587 kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals,
5588 kAllowHarmonyArrowFunctions
5590 RunParserSyncTest(sloppy_context_data, data, kError, NULL, 0, always_flags,
5591 arraysize(always_flags));
5592 RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
5593 arraysize(always_flags));
5594 RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
5595 arraysize(always_flags));
5599 TEST(StrongConstructorReturns) {
5600 const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
5601 const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
5602 const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
5604 const char* data[] = {
5605 "class C extends Object { constructor() { super(); return {}; } }",
5606 "class C extends Object { constructor() { super(); { return {}; } } }",
5607 "class C extends Object { constructor() { super(); if (1) return {}; } }",
5608 "class C extends Object { constructor() { return; super(); } }",
5609 "class C extends Object { constructor() { { return; } super(); } }",
5610 "class C extends Object { constructor() { if (0) return; super(); } }",
5613 static const ParserFlag always_flags[] = {
5614 kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals
5616 RunParserSyncTest(sloppy_context_data, data, kError, NULL, 0, always_flags,
5617 arraysize(always_flags));
5618 RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
5619 arraysize(always_flags));
5620 RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
5621 arraysize(always_flags));
5625 TEST(ArrowFunctionASIErrors) {
5626 const char* context_data[][2] = {{"'use strict';", ""}, {"", ""},
5629 const char* data[] = {
5633 "((a)/*\n*/=> a)(1)",
5634 "((a, b)\n=> a + b)(1, 2)",
5635 "((a, b)/*\n*/=> a + b)(1, 2)",
5637 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
5638 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
5639 arraysize(always_flags));
5643 TEST(StrongModeFreeVariablesDeclaredByPreviousScript) {
5644 i::FLAG_strong_mode = true;
5645 v8::V8::Initialize();
5646 v8::HandleScope scope(CcTest::isolate());
5647 v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
5648 v8::TryCatch try_catch;
5650 // Introduce a bunch of variables, in all language modes.
5651 const char* script1 =
5652 "var my_var1 = 0; \n"
5653 "function my_func1() { } \n"
5654 "const my_const1 = 0; \n";
5655 CompileRun(v8_str(script1));
5656 CHECK(!try_catch.HasCaught());
5658 const char* script2 =
5659 "\"use strict\"; \n"
5660 "let my_var2 = 0; \n"
5661 "function my_func2() { } \n"
5662 "const my_const2 = 0 \n";
5663 CompileRun(v8_str(script2));
5664 CHECK(!try_catch.HasCaught());
5666 const char* script3 =
5667 "\"use strong\"; \n"
5668 "let my_var3 = 0; \n"
5669 "function my_func3() { } \n"
5670 "const my_const3 = 0; \n";
5671 CompileRun(v8_str(script3));
5672 CHECK(!try_catch.HasCaught());
5674 // Sloppy eval introduces variables in the surrounding scope.
5675 const char* script4 =
5676 "eval('var my_var4 = 0;') \n"
5677 "eval('function my_func4() { }') \n"
5678 "eval('const my_const4 = 0;') \n";
5679 CompileRun(v8_str(script4));
5680 CHECK(!try_catch.HasCaught());
5682 // Test that referencing these variables work.
5683 const char* script5 =
5684 "\"use strong\"; \n"
5697 CompileRun(v8_str(script5));
5698 CHECK(!try_catch.HasCaught());
5702 TEST(StrongModeFreeVariablesDeclaredByLanguage) {
5703 i::FLAG_strong_mode = true;
5704 v8::V8::Initialize();
5705 v8::HandleScope scope(CcTest::isolate());
5706 v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
5707 v8::TryCatch try_catch;
5709 const char* script1 =
5710 "\"use strong\"; \n"
5713 CompileRun(v8_str(script1));
5714 CHECK(!try_catch.HasCaught());
5718 TEST(StrongModeFreeVariablesDeclaredInGlobalPrototype) {
5719 i::FLAG_strong_mode = true;
5720 v8::V8::Initialize();
5721 v8::HandleScope scope(CcTest::isolate());
5722 v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
5723 v8::TryCatch try_catch;
5725 const char* script1 = "this.__proto__.my_var = 0;\n";
5726 CompileRun(v8_str(script1));
5727 CHECK(!try_catch.HasCaught());
5729 const char* script2 =
5730 "\"use strong\"; \n"
5732 CompileRun(v8_str(script2));
5733 CHECK(!try_catch.HasCaught());
5737 TEST(StrongModeFreeVariablesNotDeclared) {
5738 i::FLAG_strong_mode = true;
5739 v8::V8::Initialize();
5740 v8::HandleScope scope(CcTest::isolate());
5741 v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate()));
5742 v8::TryCatch try_catch;
5744 // Test that referencing unintroduced variables in sloppy mode is ok.
5745 const char* script1 =
5749 CompileRun(v8_str(script1));
5750 CHECK(!try_catch.HasCaught());
5752 // But not in strong mode.
5754 const char* script2 =
5755 "\"use strong\"; \n"
5759 v8::TryCatch try_catch2;
5760 v8::Script::Compile(v8_str(script2));
5761 CHECK(try_catch2.HasCaught());
5762 v8::String::Utf8Value exception(try_catch2.Exception());
5765 "ReferenceError: In strong mode, using an undeclared global "
5766 "variable 'not_there2' is not allowed",
5770 // Check that the variable reference is detected inside a strong function too,
5771 // even if the script scope is not strong.
5773 const char* script3 =
5774 "(function not_lazy() { \n"
5775 " \"use strong\"; \n"
5780 v8::TryCatch try_catch2;
5781 v8::Script::Compile(v8_str(script3));
5782 CHECK(try_catch2.HasCaught());
5783 v8::String::Utf8Value exception(try_catch2.Exception());
5786 "ReferenceError: In strong mode, using an undeclared global "
5787 "variable 'not_there3' is not allowed",