blob: 08caeab55f502954277b53376a08ab8a885f5170 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blockd0582a62009-12-15 09:54:21 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080028#include <stdio.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029#include <stdlib.h>
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080030#include <string.h>
Steve Blockd0582a62009-12-15 09:54:21 +000031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/v8.h"
Steve Blockd0582a62009-12-15 09:54:21 +000033
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034#include "src/ast.h"
35#include "src/ast-numbering.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036#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"
47
48#include "test/cctest/cctest.h"
Steve Blockd0582a62009-12-15 09:54:21 +000049
Ben Murdoch69a99ed2011-11-30 16:03:39 +000050TEST(ScanKeywords) {
Steve Blockd0582a62009-12-15 09:54:21 +000051 struct KeywordToken {
52 const char* keyword;
53 i::Token::Value token;
54 };
55
56 static const KeywordToken keywords[] = {
57#define KEYWORD(t, s, d) { s, i::Token::t },
Ben Murdoch69a99ed2011-11-30 16:03:39 +000058 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
Steve Blockd0582a62009-12-15 09:54:21 +000059#undef KEYWORD
60 { NULL, i::Token::IDENTIFIER }
61 };
62
Steve Blockd0582a62009-12-15 09:54:21 +000063 KeywordToken key_token;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000064 i::UnicodeCache unicode_cache;
65 i::byte buffer[32];
Steve Blockd0582a62009-12-15 09:54:21 +000066 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000067 const i::byte* keyword =
68 reinterpret_cast<const i::byte*>(key_token.keyword);
69 int length = i::StrLength(key_token.keyword);
70 CHECK(static_cast<int>(sizeof(buffer)) >= length);
71 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010072 i::Utf8ToUtf16CharacterStream stream(keyword, length);
73 i::Scanner scanner(&unicode_cache);
74 // The scanner should parse Harmony keywords for this test.
75 scanner.SetHarmonyScoping(true);
76 scanner.SetHarmonyModules(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 scanner.SetHarmonyClasses(true);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000078 scanner.Initialize(&stream);
79 CHECK_EQ(key_token.token, scanner.Next());
80 CHECK_EQ(i::Token::EOS, scanner.Next());
Steve Blockd0582a62009-12-15 09:54:21 +000081 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000082 // Removing characters will make keyword matching fail.
83 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010084 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
85 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000086 scanner.Initialize(&stream);
87 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
88 CHECK_EQ(i::Token::EOS, scanner.Next());
Steve Blockd0582a62009-12-15 09:54:21 +000089 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000090 // Adding characters will make keyword matching fail.
91 static const char chars_to_append[] = { 'z', '0', '_' };
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092 for (int j = 0; j < static_cast<int>(arraysize(chars_to_append)); ++j) {
93 i::MemMove(buffer, keyword, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000094 buffer[length] = chars_to_append[j];
Ben Murdoch3ef787d2012-04-12 10:51:47 +010095 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
96 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000097 scanner.Initialize(&stream);
98 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
99 CHECK_EQ(i::Token::EOS, scanner.Next());
100 }
101 // Replacing characters will make keyword matching fail.
102 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 i::MemMove(buffer, keyword, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000104 buffer[length - 1] = '_';
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100105 i::Utf8ToUtf16CharacterStream stream(buffer, length);
106 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000107 scanner.Initialize(&stream);
108 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
109 CHECK_EQ(i::Token::EOS, scanner.Next());
110 }
Steve Blockd0582a62009-12-15 09:54:21 +0000111 }
Steve Blockd0582a62009-12-15 09:54:21 +0000112}
113
Iain Merrick9ac36c92010-09-13 15:29:50 +0100114
115TEST(ScanHTMLEndComments) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000116 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 v8::Isolate* isolate = CcTest::isolate();
118 v8::HandleScope handles(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000119
Iain Merrick9ac36c92010-09-13 15:29:50 +0100120 // Regression test. See:
121 // http://code.google.com/p/chromium/issues/detail?id=53548
122 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000123 // is only whitespace before it on the line (with comments considered as
124 // whitespace, even a multiline-comment containing a newline).
125 // This was not the case if it occurred before the first real token
Iain Merrick9ac36c92010-09-13 15:29:50 +0100126 // in the input.
127 const char* tests[] = {
128 // Before first real token.
129 "--> is eol-comment\nvar y = 37;\n",
130 "\n --> is eol-comment\nvar y = 37;\n",
131 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
132 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
133 // After first real token.
134 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
135 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
136 NULL
137 };
138
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000139 const char* fail_tests[] = {
140 "x --> is eol-comment\nvar y = 37;\n",
141 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
142 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
143 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
144 "var x = 42; --> is eol-comment\nvar y = 37;\n",
145 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
146 NULL
147 };
148
Iain Merrick9ac36c92010-09-13 15:29:50 +0100149 // Parser/Scanner needs a stack limit.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 CcTest::i_isolate()->stack_guard()->SetStackLimit(
151 i::GetCurrentStackPosition() - 128 * 1024);
152 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Iain Merrick9ac36c92010-09-13 15:29:50 +0100153 for (int i = 0; tests[i]; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 const i::byte* source =
155 reinterpret_cast<const i::byte*>(tests[i]);
156 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i]));
157 i::CompleteParserRecorder log;
158 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
159 scanner.Initialize(&stream);
160 i::PreParser preparser(&scanner, &log, stack_limit);
161 preparser.set_allow_lazy(true);
162 i::PreParser::PreParseResult result = preparser.PreParseProgram();
163 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
164 CHECK(!log.HasError());
Iain Merrick9ac36c92010-09-13 15:29:50 +0100165 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000166
167 for (int i = 0; fail_tests[i]; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168 const i::byte* source =
169 reinterpret_cast<const i::byte*>(fail_tests[i]);
170 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i]));
171 i::CompleteParserRecorder log;
172 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
173 scanner.Initialize(&stream);
174 i::PreParser preparser(&scanner, &log, stack_limit);
175 preparser.set_allow_lazy(true);
176 i::PreParser::PreParseResult result = preparser.PreParseProgram();
177 // Even in the case of a syntax error, kPreParseSuccess is returned.
178 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
179 CHECK(log.HasError());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000180 }
Iain Merrick9ac36c92010-09-13 15:29:50 +0100181}
182
183
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184class ScriptResource : public v8::String::ExternalOneByteStringResource {
Iain Merrick9ac36c92010-09-13 15:29:50 +0100185 public:
186 ScriptResource(const char* data, size_t length)
187 : data_(data), length_(length) { }
188
189 const char* data() const { return data_; }
190 size_t length() const { return length_; }
191
192 private:
193 const char* data_;
194 size_t length_;
195};
196
197
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198TEST(UsingCachedData) {
199 v8::Isolate* isolate = CcTest::isolate();
200 v8::HandleScope handles(isolate);
201 v8::Local<v8::Context> context = v8::Context::New(isolate);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100202 v8::Context::Scope context_scope(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 CcTest::i_isolate()->stack_guard()->SetStackLimit(
204 i::GetCurrentStackPosition() - 128 * 1024);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100205
206 // Source containing functions that might be lazily compiled and all types
207 // of symbols (string, propertyName, regexp).
208 const char* source =
209 "var x = 42;"
210 "function foo(a) { return function nolazy(b) { return a + b; } }"
211 "function bar(a) { if (a) return function lazy(b) { return b; } }"
212 "var z = {'string': 'string literal', bareword: 'propertyName', "
213 " 42: 'number literal', for: 'keyword as propertyName', "
214 " f\\u006fr: 'keyword propertyname with escape'};"
215 "var v = /RegExp Literal/;"
216 "var w = /RegExp Literal\\u0020With Escape/gin;"
217 "var y = { get getter() { return 42; }, "
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 " set setter(v) { this.value = v; }};"
219 "var f = a => function (b) { return a + b; };"
220 "var g = a => b => a + b;";
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100221 int source_length = i::StrLength(source);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100222
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 // ScriptResource will be deleted when the corresponding String is GCd.
224 v8::ScriptCompiler::Source script_source(v8::String::NewExternal(
225 isolate, new ScriptResource(source, source_length)));
226 i::FLAG_harmony_arrow_functions = true;
227 i::FLAG_min_preparse_length = 0;
228 v8::ScriptCompiler::Compile(isolate, &script_source,
229 v8::ScriptCompiler::kProduceParserCache);
230 CHECK(script_source.GetCachedData());
231
232 // Compile the script again, using the cached data.
Iain Merrick9ac36c92010-09-13 15:29:50 +0100233 bool lazy_flag = i::FLAG_lazy;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 i::FLAG_lazy = true;
235 v8::ScriptCompiler::Compile(isolate, &script_source,
236 v8::ScriptCompiler::kConsumeParserCache);
237 i::FLAG_lazy = false;
238 v8::ScriptCompiler::CompileUnbound(isolate, &script_source,
239 v8::ScriptCompiler::kConsumeParserCache);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100240 i::FLAG_lazy = lazy_flag;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241}
Iain Merrick9ac36c92010-09-13 15:29:50 +0100242
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243
244TEST(PreparseFunctionDataIsUsed) {
245 // This tests that we actually do use the function data generated by the
246 // preparser.
247
248 // Make preparsing work for short scripts.
249 i::FLAG_min_preparse_length = 0;
250 i::FLAG_harmony_arrow_functions = true;
251
252 v8::Isolate* isolate = CcTest::isolate();
253 v8::HandleScope handles(isolate);
254 v8::Local<v8::Context> context = v8::Context::New(isolate);
255 v8::Context::Scope context_scope(context);
256 CcTest::i_isolate()->stack_guard()->SetStackLimit(
257 i::GetCurrentStackPosition() - 128 * 1024);
258
259 const char* good_code[] = {
260 "function this_is_lazy() { var a; } function foo() { return 25; } foo();",
261 "var this_is_lazy = () => { var a; }; var foo = () => 25; foo();",
262 };
263
264 // Insert a syntax error inside the lazy function.
265 const char* bad_code[] = {
266 "function this_is_lazy() { if ( } function foo() { return 25; } foo();",
267 "var this_is_lazy = () => { if ( }; var foo = () => 25; foo();",
268 };
269
270 for (unsigned i = 0; i < arraysize(good_code); i++) {
271 v8::ScriptCompiler::Source good_source(v8_str(good_code[i]));
272 v8::ScriptCompiler::Compile(isolate, &good_source,
273 v8::ScriptCompiler::kProduceDataToCache);
274
275 const v8::ScriptCompiler::CachedData* cached_data =
276 good_source.GetCachedData();
277 CHECK(cached_data->data != NULL);
278 CHECK_GT(cached_data->length, 0);
279
280 // Now compile the erroneous code with the good preparse data. If the
281 // preparse data is used, the lazy function is skipped and it should
282 // compile fine.
283 v8::ScriptCompiler::Source bad_source(
284 v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData(
285 cached_data->data, cached_data->length));
286 v8::Local<v8::Value> result =
287 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
288 CHECK(result->IsInt32());
289 CHECK_EQ(25, result->Int32Value());
290 }
Iain Merrick9ac36c92010-09-13 15:29:50 +0100291}
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800292
293
294TEST(StandAlonePreParser) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000295 v8::V8::Initialize();
296
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 CcTest::i_isolate()->stack_guard()->SetStackLimit(
298 i::GetCurrentStackPosition() - 128 * 1024);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800299
300 const char* programs[] = {
301 "{label: 42}",
302 "var x = 42;",
303 "function foo(x, y) { return x + y; }",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000304 "%ArgleBargle(glop);",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800305 "var x = new new Function('this.x = 42');",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 "var f = (x, y) => x + y;",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800307 NULL
308 };
309
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800311 for (int i = 0; programs[i]; i++) {
312 const char* program = programs[i];
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100313 i::Utf8ToUtf16CharacterStream stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100314 reinterpret_cast<const i::byte*>(program),
315 static_cast<unsigned>(strlen(program)));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800316 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100318 scanner.Initialize(&stream);
319
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 i::PreParser preparser(&scanner, &log, stack_limit);
321 preparser.set_allow_lazy(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400322 preparser.set_allow_natives(true);
323 preparser.set_allow_harmony_arrow_functions(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324 i::PreParser::PreParseResult result = preparser.PreParseProgram();
325 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
326 CHECK(!log.HasError());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800327 }
328}
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800329
330
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100331TEST(StandAlonePreParserNoNatives) {
332 v8::V8::Initialize();
333
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334 CcTest::i_isolate()->stack_guard()->SetStackLimit(
335 i::GetCurrentStackPosition() - 128 * 1024);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100336
337 const char* programs[] = {
338 "%ArgleBargle(glop);",
339 "var x = %_IsSmi(42);",
340 NULL
341 };
342
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000343 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100344 for (int i = 0; programs[i]; i++) {
345 const char* program = programs[i];
346 i::Utf8ToUtf16CharacterStream stream(
347 reinterpret_cast<const i::byte*>(program),
348 static_cast<unsigned>(strlen(program)));
349 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100351 scanner.Initialize(&stream);
352
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353 // Preparser defaults to disallowing natives syntax.
354 i::PreParser preparser(&scanner, &log, stack_limit);
355 preparser.set_allow_lazy(true);
356 i::PreParser::PreParseResult result = preparser.PreParseProgram();
357 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
358 CHECK(log.HasError());
359 }
360}
361
362
363TEST(PreparsingObjectLiterals) {
364 // Regression test for a bug where the symbol stream produced by PreParser
365 // didn't match what Parser wanted to consume.
366 v8::Isolate* isolate = CcTest::isolate();
367 v8::HandleScope handles(isolate);
368 v8::Local<v8::Context> context = v8::Context::New(isolate);
369 v8::Context::Scope context_scope(context);
370 CcTest::i_isolate()->stack_guard()->SetStackLimit(
371 i::GetCurrentStackPosition() - 128 * 1024);
372
373 {
374 const char* source = "var myo = {if: \"foo\"}; myo.if;";
375 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
376 CHECK(result->IsString());
377 v8::String::Utf8Value utf8(result);
378 CHECK_EQ("foo", *utf8);
379 }
380
381 {
382 const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
383 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
384 CHECK(result->IsString());
385 v8::String::Utf8Value utf8(result);
386 CHECK_EQ("foo", *utf8);
387 }
388
389 {
390 const char* source = "var myo = {1: \"foo\"}; myo[1];";
391 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
392 CHECK(result->IsString());
393 v8::String::Utf8Value utf8(result);
394 CHECK_EQ("foo", *utf8);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100395 }
396}
397
398
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800399TEST(RegressChromium62639) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000400 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 i::Isolate* isolate = CcTest::i_isolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000402
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000403 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
404 128 * 1024);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800405
406 const char* program = "var x = 'something';\n"
407 "escape: function() {}";
408 // Fails parsing expecting an identifier after "function".
409 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
410 // and then used the invalid currently scanned literal. This always
411 // failed in debug mode, and sometimes crashed in release mode.
412
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100413 i::Utf8ToUtf16CharacterStream stream(
414 reinterpret_cast<const i::byte*>(program),
415 static_cast<unsigned>(strlen(program)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000416 i::CompleteParserRecorder log;
417 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
418 scanner.Initialize(&stream);
419 i::PreParser preparser(&scanner, &log,
420 CcTest::i_isolate()->stack_guard()->real_climit());
421 preparser.set_allow_lazy(true);
422 i::PreParser::PreParseResult result = preparser.PreParseProgram();
423 // Even in the case of a syntax error, kPreParseSuccess is returned.
424 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
425 CHECK(log.HasError());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800426}
427
428
429TEST(Regress928) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000430 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431 i::Isolate* isolate = CcTest::i_isolate();
432 i::Factory* factory = isolate->factory();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000433
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800434 // Preparsing didn't consider the catch clause of a try statement
435 // as with-content, which made it assume that a function inside
436 // the block could be lazily compiled, and an extra, unexpected,
437 // entry was added to the data.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
439 128 * 1024);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800440
441 const char* program =
442 "try { } catch (e) { var foo = function () { /* first */ } }"
443 "var bar = function () { /* second */ }";
444
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000445 v8::HandleScope handles(CcTest::isolate());
446 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program);
447 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
448 i::CompleteParserRecorder log;
449 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
450 scanner.Initialize(&stream);
451 i::PreParser preparser(&scanner, &log,
452 CcTest::i_isolate()->stack_guard()->real_climit());
453 preparser.set_allow_lazy(true);
454 i::PreParser::PreParseResult result = preparser.PreParseProgram();
455 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
456 i::ScriptData* sd = log.GetScriptData();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400457 i::ParseData* pd = i::ParseData::FromCachedData(sd);
458 pd->Initialize();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800459
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100460 int first_function =
461 static_cast<int>(strstr(program, "function") - program);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100462 int first_lbrace = first_function + i::StrLength("function () ");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800463 CHECK_EQ('{', program[first_lbrace]);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400464 i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800465 CHECK(!entry1.is_valid());
466
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100467 int second_function =
468 static_cast<int>(strstr(program + first_lbrace, "function") - program);
469 int second_lbrace =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100470 second_function + i::StrLength("function () ");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800471 CHECK_EQ('{', program[second_lbrace]);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400472 i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800473 CHECK(entry2.is_valid());
474 CHECK_EQ('}', program[entry2.end_pos() - 1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475 delete sd;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400476 delete pd;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800477}
Ben Murdochb0fe1622011-05-05 13:52:32 +0100478
479
480TEST(PreParseOverflow) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000481 v8::V8::Initialize();
482
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 CcTest::i_isolate()->stack_guard()->SetStackLimit(
484 i::GetCurrentStackPosition() - 128 * 1024);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100485
486 size_t kProgramSize = 1024 * 1024;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
488 memset(program.get(), '(', kProgramSize);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100489 program[kProgramSize] = '\0';
490
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100492
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100493 i::Utf8ToUtf16CharacterStream stream(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 reinterpret_cast<const i::byte*>(program.get()),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100495 static_cast<unsigned>(kProgramSize));
496 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100498 scanner.Initialize(&stream);
499
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 i::PreParser preparser(&scanner, &log, stack_limit);
501 preparser.set_allow_lazy(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400502 preparser.set_allow_harmony_arrow_functions(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 i::PreParser::PreParseResult result = preparser.PreParseProgram();
504 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100505}
506
507
508class TestExternalResource: public v8::String::ExternalStringResource {
509 public:
510 explicit TestExternalResource(uint16_t* data, int length)
511 : data_(data), length_(static_cast<size_t>(length)) { }
512
513 ~TestExternalResource() { }
514
515 const uint16_t* data() const {
516 return data_;
517 }
518
519 size_t length() const {
520 return length_;
521 }
522 private:
523 uint16_t* data_;
524 size_t length_;
525};
526
527
528#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
529
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000530void TestCharacterStream(const char* one_byte_source, unsigned length,
531 unsigned start = 0, unsigned end = 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100532 if (end == 0) end = length;
533 unsigned sub_length = end - start;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 i::Isolate* isolate = CcTest::i_isolate();
535 i::Factory* factory = isolate->factory();
536 i::HandleScope test_scope(isolate);
Ben Murdoch589d6972011-11-30 16:04:58 +0000537 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100538 for (unsigned i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000539 uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100540 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000541 i::Vector<const char> one_byte_vector(one_byte_source,
542 static_cast<int>(length));
543 i::Handle<i::String> one_byte_string =
544 factory->NewStringFromAscii(one_byte_vector).ToHandleChecked();
545 TestExternalResource resource(uc16_buffer.get(), length);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100546 i::Handle<i::String> uc16_string(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547 factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100548
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100549 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100550 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 i::GenericStringUtf16CharacterStream string_stream(one_byte_string, start,
552 end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100553 i::Utf8ToUtf16CharacterStream utf8_stream(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 reinterpret_cast<const i::byte*>(one_byte_source), end);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100555 utf8_stream.SeekForward(start);
556
557 unsigned i = start;
558 while (i < end) {
559 // Read streams one char at a time
560 CHECK_EQU(i, uc16_stream.pos());
561 CHECK_EQU(i, string_stream.pos());
562 CHECK_EQU(i, utf8_stream.pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000563 int32_t c0 = one_byte_source[i];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100564 int32_t c1 = uc16_stream.Advance();
565 int32_t c2 = string_stream.Advance();
566 int32_t c3 = utf8_stream.Advance();
567 i++;
568 CHECK_EQ(c0, c1);
569 CHECK_EQ(c0, c2);
570 CHECK_EQ(c0, c3);
571 CHECK_EQU(i, uc16_stream.pos());
572 CHECK_EQU(i, string_stream.pos());
573 CHECK_EQU(i, utf8_stream.pos());
574 }
575 while (i > start + sub_length / 4) {
576 // Pushback, re-read, pushback again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 int32_t c0 = one_byte_source[i - 1];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100578 CHECK_EQU(i, uc16_stream.pos());
579 CHECK_EQU(i, string_stream.pos());
580 CHECK_EQU(i, utf8_stream.pos());
581 uc16_stream.PushBack(c0);
582 string_stream.PushBack(c0);
583 utf8_stream.PushBack(c0);
584 i--;
585 CHECK_EQU(i, uc16_stream.pos());
586 CHECK_EQU(i, string_stream.pos());
587 CHECK_EQU(i, utf8_stream.pos());
588 int32_t c1 = uc16_stream.Advance();
589 int32_t c2 = string_stream.Advance();
590 int32_t c3 = utf8_stream.Advance();
591 i++;
592 CHECK_EQU(i, uc16_stream.pos());
593 CHECK_EQU(i, string_stream.pos());
594 CHECK_EQU(i, utf8_stream.pos());
595 CHECK_EQ(c0, c1);
596 CHECK_EQ(c0, c2);
597 CHECK_EQ(c0, c3);
598 uc16_stream.PushBack(c0);
599 string_stream.PushBack(c0);
600 utf8_stream.PushBack(c0);
601 i--;
602 CHECK_EQU(i, uc16_stream.pos());
603 CHECK_EQU(i, string_stream.pos());
604 CHECK_EQU(i, utf8_stream.pos());
605 }
606 unsigned halfway = start + sub_length / 2;
607 uc16_stream.SeekForward(halfway - i);
608 string_stream.SeekForward(halfway - i);
609 utf8_stream.SeekForward(halfway - i);
610 i = halfway;
611 CHECK_EQU(i, uc16_stream.pos());
612 CHECK_EQU(i, string_stream.pos());
613 CHECK_EQU(i, utf8_stream.pos());
614
615 while (i < end) {
616 // Read streams one char at a time
617 CHECK_EQU(i, uc16_stream.pos());
618 CHECK_EQU(i, string_stream.pos());
619 CHECK_EQU(i, utf8_stream.pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620 int32_t c0 = one_byte_source[i];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100621 int32_t c1 = uc16_stream.Advance();
622 int32_t c2 = string_stream.Advance();
623 int32_t c3 = utf8_stream.Advance();
624 i++;
625 CHECK_EQ(c0, c1);
626 CHECK_EQ(c0, c2);
627 CHECK_EQ(c0, c3);
628 CHECK_EQU(i, uc16_stream.pos());
629 CHECK_EQU(i, string_stream.pos());
630 CHECK_EQU(i, utf8_stream.pos());
631 }
632
633 int32_t c1 = uc16_stream.Advance();
634 int32_t c2 = string_stream.Advance();
635 int32_t c3 = utf8_stream.Advance();
636 CHECK_LT(c1, 0);
637 CHECK_LT(c2, 0);
638 CHECK_LT(c3, 0);
639}
640
641
642TEST(CharacterStreams) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643 v8::Isolate* isolate = CcTest::isolate();
644 v8::HandleScope handles(isolate);
645 v8::Local<v8::Context> context = v8::Context::New(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100646 v8::Context::Scope context_scope(context);
647
648 TestCharacterStream("abc\0\n\r\x7f", 7);
649 static const unsigned kBigStringSize = 4096;
650 char buffer[kBigStringSize + 1];
651 for (unsigned i = 0; i < kBigStringSize; i++) {
652 buffer[i] = static_cast<char>(i & 0x7f);
653 }
654 TestCharacterStream(buffer, kBigStringSize);
655
656 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
657
658 TestCharacterStream("\0", 1);
659 TestCharacterStream("", 0);
660}
661
662
663TEST(Utf8CharacterStream) {
664 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
665 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
666
667 static const int kAllUtf8CharsSize =
668 (unibrow::Utf8::kMaxOneByteChar + 1) +
669 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
670 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
671 static const unsigned kAllUtf8CharsSizeU =
672 static_cast<unsigned>(kAllUtf8CharsSize);
673
674 char buffer[kAllUtf8CharsSizeU];
675 unsigned cursor = 0;
676 for (int i = 0; i <= kMaxUC16Char; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100677 cursor += unibrow::Utf8::Encode(buffer + cursor,
678 i,
679 unibrow::Utf16::kNoPreviousCharacter);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100680 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 DCHECK(cursor == kAllUtf8CharsSizeU);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100682
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100683 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
684 kAllUtf8CharsSizeU);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100685 for (int i = 0; i <= kMaxUC16Char; i++) {
686 CHECK_EQU(i, stream.pos());
687 int32_t c = stream.Advance();
688 CHECK_EQ(i, c);
689 CHECK_EQU(i + 1, stream.pos());
690 }
691 for (int i = kMaxUC16Char; i >= 0; i--) {
692 CHECK_EQU(i + 1, stream.pos());
693 stream.PushBack(i);
694 CHECK_EQU(i, stream.pos());
695 }
696 int i = 0;
697 while (stream.pos() < kMaxUC16CharU) {
698 CHECK_EQU(i, stream.pos());
699 unsigned progress = stream.SeekForward(12);
700 i += progress;
701 int32_t c = stream.Advance();
702 if (i <= kMaxUC16Char) {
703 CHECK_EQ(i, c);
704 } else {
705 CHECK_EQ(-1, c);
706 }
707 i += 1;
708 CHECK_EQU(i, stream.pos());
709 }
710}
711
712#undef CHECK_EQU
713
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100714void TestStreamScanner(i::Utf16CharacterStream* stream,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715 i::Token::Value* expected_tokens,
716 int skip_pos = 0, // Zero means not skipping.
717 int skip_to = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Steve Block9fac8402011-05-12 15:51:54 +0100719 scanner.Initialize(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100720
721 int i = 0;
722 do {
723 i::Token::Value expected = expected_tokens[i];
724 i::Token::Value actual = scanner.Next();
725 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
726 if (scanner.location().end_pos == skip_pos) {
727 scanner.SeekForward(skip_to);
728 }
729 i++;
730 } while (expected_tokens[i] != i::Token::ILLEGAL);
731}
732
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000733
Ben Murdochb0fe1622011-05-05 13:52:32 +0100734TEST(StreamScanner) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000735 v8::V8::Initialize();
736
Ben Murdochb0fe1622011-05-05 13:52:32 +0100737 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100738 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
739 static_cast<unsigned>(strlen(str1)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100740 i::Token::Value expectations1[] = {
741 i::Token::LBRACE,
742 i::Token::IDENTIFIER,
743 i::Token::IDENTIFIER,
744 i::Token::FOR,
745 i::Token::COLON,
746 i::Token::MUL,
747 i::Token::DIV,
748 i::Token::LT,
749 i::Token::SUB,
750 i::Token::IDENTIFIER,
751 i::Token::EOS,
752 i::Token::ILLEGAL
753 };
754 TestStreamScanner(&stream1, expectations1, 0, 0);
755
756 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100757 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
758 static_cast<unsigned>(strlen(str2)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100759 i::Token::Value expectations2[] = {
760 i::Token::CASE,
761 i::Token::DEFAULT,
762 i::Token::CONST,
763 i::Token::LBRACE,
764 // Skipped part here
765 i::Token::RBRACE,
766 i::Token::DO,
767 i::Token::EOS,
768 i::Token::ILLEGAL
769 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000770 DCHECK_EQ('{', str2[19]);
771 DCHECK_EQ('}', str2[37]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100772 TestStreamScanner(&stream2, expectations2, 20, 37);
773
774 const char* str3 = "{}}}}";
775 i::Token::Value expectations3[] = {
776 i::Token::LBRACE,
777 i::Token::RBRACE,
778 i::Token::RBRACE,
779 i::Token::RBRACE,
780 i::Token::RBRACE,
781 i::Token::EOS,
782 i::Token::ILLEGAL
783 };
784 // Skip zero-four RBRACEs.
785 for (int i = 0; i <= 4; i++) {
786 expectations3[6 - i] = i::Token::ILLEGAL;
787 expectations3[5 - i] = i::Token::EOS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100788 i::Utf8ToUtf16CharacterStream stream3(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100789 reinterpret_cast<const i::byte*>(str3),
790 static_cast<unsigned>(strlen(str3)));
791 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
792 }
793}
Ben Murdoch086aeea2011-05-13 15:57:08 +0100794
795
796void TestScanRegExp(const char* re_source, const char* expected) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100797 i::Utf8ToUtf16CharacterStream stream(
Ben Murdoch086aeea2011-05-13 15:57:08 +0100798 reinterpret_cast<const i::byte*>(re_source),
799 static_cast<unsigned>(strlen(re_source)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000800 i::HandleScope scope(CcTest::i_isolate());
801 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdoch086aeea2011-05-13 15:57:08 +0100802 scanner.Initialize(&stream);
803
804 i::Token::Value start = scanner.peek();
805 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
806 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
807 scanner.Next(); // Current token is now the regexp literal.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808 i::Zone zone(CcTest::i_isolate());
809 i::AstValueFactory ast_value_factory(&zone,
810 CcTest::i_isolate()->heap()->HashSeed());
811 ast_value_factory.Internalize(CcTest::i_isolate());
812 i::Handle<i::String> val =
813 scanner.CurrentSymbol(&ast_value_factory)->string();
814 i::DisallowHeapAllocation no_alloc;
815 i::String::FlatContent content = val->GetFlatContent();
816 CHECK(content.IsOneByte());
817 i::Vector<const uint8_t> actual = content.ToOneByteVector();
Ben Murdoch086aeea2011-05-13 15:57:08 +0100818 for (int i = 0; i < actual.length(); i++) {
819 CHECK_NE('\0', expected[i]);
820 CHECK_EQ(expected[i], actual[i]);
821 }
822}
823
824
825TEST(RegExpScanning) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000826 v8::V8::Initialize();
827
Ben Murdoch086aeea2011-05-13 15:57:08 +0100828 // RegExp token with added garbage at the end. The scanner should only
829 // scan the RegExp until the terminating slash just before "flipperwald".
830 TestScanRegExp("/b/flipperwald", "b");
831 // Incomplete escape sequences doesn't hide the terminating slash.
832 TestScanRegExp("/\\x/flipperwald", "\\x");
833 TestScanRegExp("/\\u/flipperwald", "\\u");
834 TestScanRegExp("/\\u1/flipperwald", "\\u1");
835 TestScanRegExp("/\\u12/flipperwald", "\\u12");
836 TestScanRegExp("/\\u123/flipperwald", "\\u123");
837 TestScanRegExp("/\\c/flipperwald", "\\c");
838 TestScanRegExp("/\\c//flipperwald", "\\c");
839 // Slashes inside character classes are not terminating.
840 TestScanRegExp("/[/]/flipperwald", "[/]");
841 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
842 // Incomplete escape sequences inside a character class doesn't hide
843 // the end of the character class.
844 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
845 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
846 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
847 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
848 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
849 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
850 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
851 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
852 // Escaped ']'s wont end the character class.
853 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
854 // Escaped slashes are not terminating.
855 TestScanRegExp("/\\//flipperwald", "\\/");
856 // Starting with '=' works too.
857 TestScanRegExp("/=/", "=");
858 TestScanRegExp("/=?/", "=?");
859}
Ben Murdoch692be652012-01-10 18:47:50 +0000860
861
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100862static int Utf8LengthHelper(const char* s) {
863 int len = i::StrLength(s);
864 int character_length = len;
865 for (int i = 0; i < len; i++) {
866 unsigned char c = s[i];
867 int input_offset = 0;
868 int output_adjust = 0;
869 if (c > 0x7f) {
870 if (c < 0xc0) continue;
871 if (c >= 0xf0) {
872 if (c >= 0xf8) {
873 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
874 // byte.
875 continue; // Handle first UTF-8 byte.
876 }
877 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
878 // This 4 byte sequence could have been coded as a 3 byte sequence.
879 // Record a single kBadChar for the first byte and continue.
880 continue;
881 }
882 input_offset = 3;
883 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
884 character_length -= 2;
885 } else if (c >= 0xe0) {
886 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
887 // This 3 byte sequence could have been coded as a 2 byte sequence.
888 // Record a single kBadChar for the first byte and continue.
889 continue;
890 }
891 input_offset = 2;
892 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
893 output_adjust = 2;
894 } else {
895 if ((c & 0x1e) == 0) {
896 // This 2 byte sequence could have been coded as a 1 byte sequence.
897 // Record a single kBadChar for the first byte and continue.
898 continue;
899 }
900 input_offset = 1;
901 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
902 output_adjust = 1;
903 }
904 bool bad = false;
905 for (int j = 1; j <= input_offset; j++) {
906 if ((s[i + j] & 0xc0) != 0x80) {
907 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
908 // which is a single UTF-16 code unit.
909 bad = true;
910 break;
911 }
912 }
913 if (!bad) {
914 i += input_offset;
915 character_length -= output_adjust;
916 }
917 }
918 }
919 return character_length;
920}
921
922
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400923TEST(ScopeUsesArgumentsSuperThis) {
924 static const struct {
925 const char* prefix;
926 const char* suffix;
927 } surroundings[] = {
928 { "function f() {", "}" },
929 { "var f = () => {", "}" },
930 };
931
932 enum Expected {
933 NONE = 0,
934 ARGUMENTS = 1,
935 SUPER_PROPERTY = 2,
936 SUPER_CONSTRUCTOR_CALL = 4,
937 THIS = 8,
938 INNER_ARGUMENTS = 16,
939 INNER_SUPER_PROPERTY = 32,
940 INNER_SUPER_CONSTRUCTOR_CALL = 64,
941 INNER_THIS = 128
942 };
943
944 static const struct {
945 const char* body;
946 int expected;
947 } source_data[] = {
948 {"", NONE},
949 {"return this", THIS},
950 {"return arguments", ARGUMENTS},
951 {"return super()", SUPER_CONSTRUCTOR_CALL},
952 {"return super.x", SUPER_PROPERTY},
953 {"return arguments[0]", ARGUMENTS},
954 {"return this + arguments[0]", ARGUMENTS | THIS},
955 {"return this + arguments[0] + super.x",
956 ARGUMENTS | SUPER_PROPERTY | THIS},
957 {"return x => this + x", INNER_THIS},
958 {"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
959 {"this.foo = 42;", THIS},
960 {"this.foo();", THIS},
961 {"if (foo()) { this.f() }", THIS},
962 {"if (foo()) { super.f() }", SUPER_PROPERTY},
963 {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
964 {"while (true) { this.f() }", THIS},
965 {"while (true) { super.f() }", SUPER_PROPERTY},
966 {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
967 // Multiple nesting levels must work as well.
968 {"while (true) { while (true) { while (true) return this } }", THIS},
969 {"while (true) { while (true) { while (true) return super() } }",
970 SUPER_CONSTRUCTOR_CALL},
971 {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
972 {"if (1) { return () => { while (true) new super() } }", NONE},
973 {"if (1) { return () => { while (true) new new super() } }", NONE},
974 // Note that propagation of the inner_uses_this() value does not
975 // cross boundaries of normal functions onto parent scopes.
976 {"return function (x) { return this + x }", NONE},
977 {"return function (x) { return super() + x }", NONE},
978 {"var x = function () { this.foo = 42 };", NONE},
979 {"var x = function () { super.foo = 42 };", NONE},
980 {"if (1) { return function () { while (true) new this() } }", NONE},
981 {"if (1) { return function () { while (true) new super() } }", NONE},
982 {"return function (x) { return () => this }", NONE},
983 {"return function (x) { return () => super() }", NONE},
984 // Flags must be correctly set when using block scoping.
985 {"\"use strict\"; while (true) { let x; this, arguments; }",
986 INNER_ARGUMENTS | INNER_THIS},
987 {"\"use strict\"; while (true) { let x; this, super(), arguments; }",
988 INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
989 {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
990 {"\"use strict\"; if (foo()) { let x; super.f() }",
991 INNER_SUPER_PROPERTY},
992 {"\"use strict\"; if (1) {"
993 " let x; return function () { return this + super() + arguments }"
994 "}",
995 NONE},
996 };
997
998 i::Isolate* isolate = CcTest::i_isolate();
999 i::Factory* factory = isolate->factory();
1000
1001 v8::HandleScope handles(CcTest::isolate());
1002 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1003 v8::Context::Scope context_scope(context);
1004
1005 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1006 128 * 1024);
1007
1008 for (unsigned j = 0; j < arraysize(surroundings); ++j) {
1009 for (unsigned i = 0; i < arraysize(source_data); ++i) {
1010 int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
1011 i::StrLength(surroundings[j].suffix) +
1012 i::StrLength(source_data[i].body);
1013 i::ScopedVector<char> program(kProgramByteSize + 1);
1014 i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
1015 source_data[i].body, surroundings[j].suffix);
1016 i::Handle<i::String> source =
1017 factory->NewStringFromUtf8(i::CStrVector(program.start()))
1018 .ToHandleChecked();
1019 i::Handle<i::Script> script = factory->NewScript(source);
1020 i::CompilationInfoWithZone info(script);
1021 i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
1022 isolate->heap()->HashSeed(),
1023 isolate->unicode_cache()};
1024 i::Parser parser(&info, &parse_info);
1025 parser.set_allow_harmony_arrow_functions(true);
1026 parser.set_allow_harmony_classes(true);
1027 parser.set_allow_harmony_scoping(true);
1028 info.MarkAsGlobal();
1029 parser.Parse();
1030 CHECK(i::Rewriter::Rewrite(&info));
1031 CHECK(i::Scope::Analyze(&info));
1032 CHECK(info.function() != NULL);
1033
1034 i::Scope* script_scope = info.function()->scope();
1035 CHECK(script_scope->is_script_scope());
1036 CHECK_EQ(1, script_scope->inner_scopes()->length());
1037
1038 i::Scope* scope = script_scope->inner_scopes()->at(0);
1039 CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
1040 scope->uses_arguments());
1041 CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
1042 scope->uses_super_property());
1043 CHECK_EQ((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) != 0,
1044 scope->uses_super_constructor_call());
1045 CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
1046 CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
1047 scope->inner_uses_arguments());
1048 CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
1049 scope->inner_uses_super_property());
1050 CHECK_EQ((source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) != 0,
1051 scope->inner_uses_super_constructor_call());
1052 CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
1053 scope->inner_uses_this());
1054 }
1055 }
1056}
1057
1058
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001059TEST(ScopePositions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001060 v8::internal::FLAG_harmony_scoping = true;
1061
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001062 // Test the parser for correctly setting the start and end positions
1063 // of a scope. We check the scope positions of exactly one scope
1064 // nested in the global scope of a program. 'inner source' is the
1065 // source code that determines the part of the source belonging
1066 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
1067 // parts of the source that belong to the global scope.
1068 struct SourceData {
1069 const char* outer_prefix;
1070 const char* inner_source;
1071 const char* outer_suffix;
1072 i::ScopeType scope_type;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001073 i::StrictMode strict_mode;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001074 };
1075
1076 const SourceData source_data[] = {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
1078 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001079 { " with ({}) ", "{\n"
1080 " block;\n"
1081 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001082 " more;", i::WITH_SCOPE, i::SLOPPY },
1083 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001084 { " with ({}) ", "statement", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001085 " more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001086 { " with ({})\n"
1087 " ", "statement;", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001088 " more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001089 { " try {} catch ", "(e) { block; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001090 i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001091 { " try {} catch ", "(e) { block; }", "; more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001092 i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001093 { " try {} catch ", "(e) {\n"
1094 " block;\n"
1095 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001096 " more;", i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001097 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001098 i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001099 { " start;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001100 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001101 { " start;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001102 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001103 { " start;\n"
1104 " ", "{\n"
1105 " let block;\n"
1106 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001108 { " start;\n"
1109 " function fun", "(a,b) { infunction; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001110 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001111 { " start;\n"
1112 " function fun", "(a,b) {\n"
1113 " infunction;\n"
1114 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001115 " more;", i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001116 { " start;\n", "(a,b) => a + b", "; more;",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001117 i::ARROW_SCOPE, i::SLOPPY },
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001118 { " start;\n", "(a,b) => { return a+b; }", "\nmore;",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001119 i::ARROW_SCOPE, i::SLOPPY },
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001120 { " start;\n"
1121 " (function fun", "(a,b) { infunction; }", ")();",
1122 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001123 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001124 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001125 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001126 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001127 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
1128 " block;\n"
1129 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001130 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001131 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001132 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001133 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001134 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001135 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
1136 " statement;", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001137 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001138 { " for ", "(let x in {}) { block; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001139 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001140 { " for ", "(let x in {}) { block; }", "; more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001141 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001142 { " for ", "(let x in {}) {\n"
1143 " block;\n"
1144 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001145 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001146 { " for ", "(let x in {}) statement;", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001148 { " for ", "(let x in {}) statement", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001149 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001150 { " for ", "(let x in {})\n"
1151 " statement;", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001152 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001153 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
1154 // the preparser off in terms of byte offsets.
1155 // 6 byte encoding.
1156 { " 'foo\355\240\201\355\260\211';\n"
1157 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001159 // 4 byte encoding.
1160 { " 'foo\360\220\220\212';\n"
1161 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001163 // 3 byte encoding of \u0fff.
1164 { " 'foo\340\277\277';\n"
1165 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001166 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001167 // Broken 6 byte encoding with missing last byte.
1168 { " 'foo\355\240\201\355\211';\n"
1169 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001170 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001171 // Broken 3 byte encoding of \u0fff with missing last byte.
1172 { " 'foo\340\277';\n"
1173 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001174 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001175 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
1176 { " 'foo\340';\n"
1177 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001178 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001179 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
1180 { " 'foo\340\203\277';\n"
1181 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001182 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001183 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
1184 { " 'foo\340\201\277';\n"
1185 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001186 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001187 // Unpaired lead surrogate.
1188 { " 'foo\355\240\201';\n"
1189 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001190 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001191 // Unpaired lead surrogate where following code point is a 3 byte sequence.
1192 { " 'foo\355\240\201\340\277\277';\n"
1193 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001194 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001195 // Unpaired lead surrogate where following code point is a 4 byte encoding
1196 // of a trail surrogate.
1197 { " 'foo\355\240\201\360\215\260\211';\n"
1198 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001200 // Unpaired trail surrogate.
1201 { " 'foo\355\260\211';\n"
1202 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001203 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001204 // 2 byte encoding of \u00ff.
1205 { " 'foo\303\277';\n"
1206 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001207 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001208 // Broken 2 byte encoding of \u00ff with missing last byte.
1209 { " 'foo\303';\n"
1210 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001211 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001212 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
1213 { " 'foo\301\277';\n"
1214 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001215 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001216 // Illegal 5 byte encoding.
1217 { " 'foo\370\277\277\277\277';\n"
1218 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001220 // Illegal 6 byte encoding.
1221 { " 'foo\374\277\277\277\277\277';\n"
1222 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001224 // Illegal 0xfe byte
1225 { " 'foo\376\277\277\277\277\277\277';\n"
1226 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001228 // Illegal 0xff byte
1229 { " 'foo\377\277\277\277\277\277\277\277';\n"
1230 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001231 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001232 { " 'foo';\n"
1233 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001234 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001235 { " 'foo';\n"
1236 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001237 i::FUNCTION_SCOPE, i::SLOPPY },
1238 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001239 };
1240
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241 i::Isolate* isolate = CcTest::i_isolate();
1242 i::Factory* factory = isolate->factory();
1243
1244 v8::HandleScope handles(CcTest::isolate());
1245 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001246 v8::Context::Scope context_scope(context);
1247
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001248 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1249 128 * 1024);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001250
1251 for (int i = 0; source_data[i].outer_prefix; i++) {
1252 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1253 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1254 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1255 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1256 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1257 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1258 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1259 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260 i::ScopedVector<char> program(kProgramByteSize + 1);
1261 i::SNPrintF(program, "%s%s%s",
1262 source_data[i].outer_prefix,
1263 source_data[i].inner_source,
1264 source_data[i].outer_suffix);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001265
1266 // Parse program source.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001267 i::Handle<i::String> source = factory->NewStringFromUtf8(
1268 i::CStrVector(program.start())).ToHandleChecked();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001269 CHECK_EQ(source->length(), kProgramSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001270 i::Handle<i::Script> script = factory->NewScript(source);
1271 i::CompilationInfoWithZone info(script);
1272 i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
1273 isolate->heap()->HashSeed(),
1274 isolate->unicode_cache()};
1275 i::Parser parser(&info, &parse_info);
1276 parser.set_allow_lazy(true);
1277 parser.set_allow_harmony_scoping(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001278 parser.set_allow_harmony_arrow_functions(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001279 info.MarkAsGlobal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001280 info.SetStrictMode(source_data[i].strict_mode);
1281 parser.Parse();
1282 CHECK(info.function() != NULL);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001283
1284 // Check scope types and positions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001285 i::Scope* scope = info.function()->scope();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001286 CHECK(scope->is_script_scope());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001287 CHECK_EQ(scope->start_position(), 0);
1288 CHECK_EQ(scope->end_position(), kProgramSize);
1289 CHECK_EQ(scope->inner_scopes()->length(), 1);
1290
1291 i::Scope* inner_scope = scope->inner_scopes()->at(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001292 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001293 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1294 // The end position of a token is one position after the last
1295 // character belonging to that token.
1296 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1297 }
1298}
1299
1300
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001301const char* ReadString(unsigned* start) {
1302 int length = start[0];
1303 char* result = i::NewArray<char>(length + 1);
1304 for (int i = 0; i < length; i++) {
1305 result[i] = start[i + 1];
1306 }
1307 result[length] = '\0';
1308 return result;
1309}
1310
1311
1312i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
1313 i::Isolate* isolate = CcTest::i_isolate();
1314 i::Factory* factory = isolate->factory();
1315 const char* message =
1316 ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
1317 i::Handle<i::String> format = v8::Utils::OpenHandle(
1318 *v8::String::NewFromUtf8(CcTest::isolate(), message));
1319 int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
1320 const char* arg = NULL;
1321 i::Handle<i::JSArray> args_array;
1322 if (arg_count == 1) {
1323 // Position after text found by skipping past length field and
1324 // length field content words.
1325 int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
1326 data[i::PreparseDataConstants::kMessageTextPos];
1327 arg = ReadString(&data[pos]);
1328 args_array = factory->NewJSArray(1);
1329 i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
1330 NONE, i::SLOPPY).Check();
1331 } else {
1332 CHECK_EQ(0, arg_count);
1333 args_array = factory->NewJSArray(0);
1334 }
1335
1336 i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
1337 i::Handle<i::Object> format_fun = i::Object::GetProperty(
1338 isolate, builtins, "FormatMessage").ToHandleChecked();
1339 i::Handle<i::Object> arg_handles[] = { format, args_array };
1340 i::Handle<i::Object> result = i::Execution::Call(
1341 isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked();
1342 CHECK(result->IsString());
1343 i::DeleteArray(message);
1344 i::DeleteArray(arg);
1345 data.Dispose();
1346 return i::Handle<i::String>::cast(result);
1347}
1348
1349
1350enum ParserFlag {
1351 kAllowLazy,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001352 kAllowNatives,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353 kAllowHarmonyScoping,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001354 kAllowHarmonyModules,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001355 kAllowHarmonyNumericLiterals,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001356 kAllowHarmonyArrowFunctions,
1357 kAllowHarmonyClasses,
1358 kAllowHarmonyObjectLiterals,
1359 kAllowHarmonyTemplates,
1360 kAllowHarmonySloppy,
1361 kAllowHarmonyUnicode
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001362};
1363
1364
1365enum ParserSyncTestResult {
1366 kSuccessOrError,
1367 kSuccess,
1368 kError
1369};
1370
1371template <typename Traits>
1372void SetParserFlags(i::ParserBase<Traits>* parser,
1373 i::EnumSet<ParserFlag> flags) {
1374 parser->set_allow_lazy(flags.Contains(kAllowLazy));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001375 parser->set_allow_natives(flags.Contains(kAllowNatives));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001376 parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001377 parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378 parser->set_allow_harmony_numeric_literals(
1379 flags.Contains(kAllowHarmonyNumericLiterals));
1380 parser->set_allow_harmony_object_literals(
1381 flags.Contains(kAllowHarmonyObjectLiterals));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001382 parser->set_allow_harmony_arrow_functions(
1383 flags.Contains(kAllowHarmonyArrowFunctions));
1384 parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
1385 parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
1386 parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
1387 parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001388}
1389
1390
1391void TestParserSyncWithFlags(i::Handle<i::String> source,
1392 i::EnumSet<ParserFlag> flags,
1393 ParserSyncTestResult result) {
1394 i::Isolate* isolate = CcTest::i_isolate();
1395 i::Factory* factory = isolate->factory();
1396
1397 uintptr_t stack_limit = isolate->stack_guard()->real_climit();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001398 int preparser_materialized_literals = -1;
1399 int parser_materialized_literals = -2;
Ben Murdoch692be652012-01-10 18:47:50 +00001400
1401 // Preparse the data.
1402 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403 {
1404 i::Scanner scanner(isolate->unicode_cache());
1405 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1406 i::PreParser preparser(&scanner, &log, stack_limit);
1407 SetParserFlags(&preparser, flags);
1408 scanner.Initialize(&stream);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001409 i::PreParser::PreParseResult result = preparser.PreParseProgram(
1410 &preparser_materialized_literals);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001411 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1412 }
1413
1414 bool preparse_error = log.HasError();
Ben Murdoch692be652012-01-10 18:47:50 +00001415
1416 // Parse the data
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001417 i::FunctionLiteral* function;
1418 {
1419 i::Handle<i::Script> script = factory->NewScript(source);
1420 i::CompilationInfoWithZone info(script);
1421 i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
1422 isolate->heap()->HashSeed(),
1423 isolate->unicode_cache()};
1424 i::Parser parser(&info, &parse_info);
1425 SetParserFlags(&parser, flags);
1426 info.MarkAsGlobal();
1427 parser.Parse();
1428 function = info.function();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001429 if (function) {
1430 parser_materialized_literals = function->materialized_literal_count();
1431 }
Ben Murdoch692be652012-01-10 18:47:50 +00001432 }
1433
1434 // Check that preparsing fails iff parsing fails.
Ben Murdoch692be652012-01-10 18:47:50 +00001435 if (function == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001436 // Extract exception from the parser.
1437 CHECK(isolate->has_pending_exception());
1438 i::Handle<i::JSObject> exception_handle(
1439 i::JSObject::cast(isolate->pending_exception()));
1440 i::Handle<i::String> message_string =
1441 i::Handle<i::String>::cast(i::Object::GetProperty(
1442 isolate, exception_handle, "message").ToHandleChecked());
1443
1444 if (result == kSuccess) {
1445 v8::base::OS::Print(
1446 "Parser failed on:\n"
1447 "\t%s\n"
1448 "with error:\n"
1449 "\t%s\n"
1450 "However, we expected no error.",
1451 source->ToCString().get(), message_string->ToCString().get());
1452 CHECK(false);
1453 }
1454
1455 if (!preparse_error) {
1456 v8::base::OS::Print(
1457 "Parser failed on:\n"
1458 "\t%s\n"
1459 "with error:\n"
1460 "\t%s\n"
1461 "However, the preparser succeeded",
1462 source->ToCString().get(), message_string->ToCString().get());
1463 CHECK(false);
1464 }
1465 // Check that preparser and parser produce the same error.
1466 i::Handle<i::String> preparser_message =
1467 FormatMessage(log.ErrorMessageData());
1468 if (!i::String::Equals(message_string, preparser_message)) {
1469 v8::base::OS::Print(
Ben Murdoch692be652012-01-10 18:47:50 +00001470 "Expected parser and preparser to produce the same error on:\n"
1471 "\t%s\n"
1472 "However, found the following error messages\n"
1473 "\tparser: %s\n"
1474 "\tpreparser: %s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001475 source->ToCString().get(),
1476 message_string->ToCString().get(),
1477 preparser_message->ToCString().get());
Ben Murdoch692be652012-01-10 18:47:50 +00001478 CHECK(false);
1479 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 } else if (preparse_error) {
1481 v8::base::OS::Print(
1482 "Preparser failed on:\n"
1483 "\t%s\n"
1484 "with error:\n"
1485 "\t%s\n"
1486 "However, the parser succeeded",
1487 source->ToCString().get(),
1488 FormatMessage(log.ErrorMessageData())->ToCString().get());
1489 CHECK(false);
1490 } else if (result == kError) {
1491 v8::base::OS::Print(
1492 "Expected error on:\n"
1493 "\t%s\n"
1494 "However, parser and preparser succeeded",
1495 source->ToCString().get());
1496 CHECK(false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001497 } else if (preparser_materialized_literals != parser_materialized_literals) {
1498 v8::base::OS::Print(
1499 "Preparser materialized literals (%d) differ from Parser materialized "
1500 "literals (%d) on:\n"
1501 "\t%s\n"
1502 "However, parser and preparser succeeded",
1503 preparser_materialized_literals, parser_materialized_literals,
1504 source->ToCString().get());
1505 CHECK(false);
Ben Murdoch692be652012-01-10 18:47:50 +00001506 }
1507}
1508
1509
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001510void TestParserSync(const char* source,
1511 const ParserFlag* varying_flags,
1512 size_t varying_flags_length,
1513 ParserSyncTestResult result = kSuccessOrError,
1514 const ParserFlag* always_true_flags = NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001515 size_t always_true_flags_length = 0,
1516 const ParserFlag* always_false_flags = NULL,
1517 size_t always_false_flags_length = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001518 i::Handle<i::String> str =
1519 CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
1520 for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
1521 i::EnumSet<ParserFlag> flags;
1522 for (size_t flag_index = 0; flag_index < varying_flags_length;
1523 ++flag_index) {
1524 if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]);
1525 }
1526 for (size_t flag_index = 0; flag_index < always_true_flags_length;
1527 ++flag_index) {
1528 flags.Add(always_true_flags[flag_index]);
1529 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001530 for (size_t flag_index = 0; flag_index < always_false_flags_length;
1531 ++flag_index) {
1532 flags.Remove(always_false_flags[flag_index]);
1533 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534 TestParserSyncWithFlags(str, flags, result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001535 }
1536}
1537
1538
Ben Murdoch692be652012-01-10 18:47:50 +00001539TEST(ParserSync) {
1540 const char* context_data[][2] = {
1541 { "", "" },
1542 { "{", "}" },
1543 { "if (true) ", " else {}" },
1544 { "if (true) {} else ", "" },
1545 { "if (true) ", "" },
1546 { "do ", " while (false)" },
1547 { "while (false) ", "" },
1548 { "for (;;) ", "" },
1549 { "with ({})", "" },
1550 { "switch (12) { case 12: ", "}" },
1551 { "switch (12) { default: ", "}" },
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001552 { "switch (12) { ", "case 12: }" },
Ben Murdoch692be652012-01-10 18:47:50 +00001553 { "label2: ", "" },
1554 { NULL, NULL }
1555 };
1556
1557 const char* statement_data[] = {
1558 "{}",
1559 "var x",
1560 "var x = 1",
1561 "const x",
1562 "const x = 1",
1563 ";",
1564 "12",
1565 "if (false) {} else ;",
1566 "if (false) {} else {}",
1567 "if (false) {} else 12",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001568 "if (false) ;",
Ben Murdoch692be652012-01-10 18:47:50 +00001569 "if (false) {}",
1570 "if (false) 12",
1571 "do {} while (false)",
1572 "for (;;) ;",
1573 "for (;;) {}",
1574 "for (;;) 12",
1575 "continue",
1576 "continue label",
1577 "continue\nlabel",
1578 "break",
1579 "break label",
1580 "break\nlabel",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581 // TODO(marja): activate once parsing 'return' is merged into ParserBase.
1582 // "return",
1583 // "return 12",
1584 // "return\n12",
Ben Murdoch692be652012-01-10 18:47:50 +00001585 "with ({}) ;",
1586 "with ({}) {}",
1587 "with ({}) 12",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001588 "switch ({}) { default: }",
1589 "label3: ",
Ben Murdoch692be652012-01-10 18:47:50 +00001590 "throw",
1591 "throw 12",
1592 "throw\n12",
1593 "try {} catch(e) {}",
1594 "try {} finally {}",
1595 "try {} catch(e) {} finally {}",
1596 "debugger",
1597 NULL
1598 };
1599
1600 const char* termination_data[] = {
1601 "",
1602 ";",
1603 "\n",
1604 ";\n",
1605 "\n;",
1606 NULL
1607 };
1608
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001609 v8::HandleScope handles(CcTest::isolate());
1610 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
Ben Murdoch692be652012-01-10 18:47:50 +00001611 v8::Context::Scope context_scope(context);
1612
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001613 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1614 i::GetCurrentStackPosition() - 128 * 1024);
1615
Ben Murdoch692be652012-01-10 18:47:50 +00001616 for (int i = 0; context_data[i][0] != NULL; ++i) {
1617 for (int j = 0; statement_data[j] != NULL; ++j) {
1618 for (int k = 0; termination_data[k] != NULL; ++k) {
1619 int kPrefixLen = i::StrLength(context_data[i][0]);
1620 int kStatementLen = i::StrLength(statement_data[j]);
1621 int kTerminationLen = i::StrLength(termination_data[k]);
1622 int kSuffixLen = i::StrLength(context_data[i][1]);
1623 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1624 + kSuffixLen + i::StrLength("label: for (;;) { }");
1625
1626 // Plug the source code pieces together.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627 i::ScopedVector<char> program(kProgramSize + 1);
1628 int length = i::SNPrintF(program,
Ben Murdoch692be652012-01-10 18:47:50 +00001629 "label: for (;;) { %s%s%s%s }",
1630 context_data[i][0],
1631 statement_data[j],
1632 termination_data[k],
1633 context_data[i][1]);
1634 CHECK(length == kProgramSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001635 TestParserSync(program.start(), NULL, 0);
Ben Murdoch692be652012-01-10 18:47:50 +00001636 }
1637 }
1638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639
1640 // Neither Harmony numeric literals nor our natives syntax have any
1641 // interaction with the flags above, so test these separately to reduce
1642 // the combinatorial explosion.
1643 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
1644 TestParserSync("0o1234", flags2, arraysize(flags2));
1645 TestParserSync("0b1011", flags2, arraysize(flags2));
1646
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001647 static const ParserFlag flags3[] = { kAllowNatives };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001648 TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
1649}
1650
1651
1652TEST(StrictOctal) {
1653 // Test that syntax error caused by octal literal is reported correctly as
1654 // such (issue 2220).
1655 v8::V8::Initialize();
1656 v8::HandleScope scope(CcTest::isolate());
1657 v8::Context::Scope context_scope(
1658 v8::Context::New(CcTest::isolate()));
1659 v8::TryCatch try_catch;
1660 const char* script =
1661 "\"use strict\"; \n"
1662 "a = function() { \n"
1663 " b = function() { \n"
1664 " 01; \n"
1665 " }; \n"
1666 "}; \n";
1667 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
1668 CHECK(try_catch.HasCaught());
1669 v8::String::Utf8Value exception(try_catch.Exception());
1670 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
1671 *exception);
1672}
1673
1674
1675void RunParserSyncTest(const char* context_data[][2],
1676 const char* statement_data[],
1677 ParserSyncTestResult result,
1678 const ParserFlag* flags = NULL,
1679 int flags_len = 0,
1680 const ParserFlag* always_true_flags = NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001681 int always_true_len = 0,
1682 const ParserFlag* always_false_flags = NULL,
1683 int always_false_len = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001684 v8::HandleScope handles(CcTest::isolate());
1685 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1686 v8::Context::Scope context_scope(context);
1687
1688 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1689 i::GetCurrentStackPosition() - 128 * 1024);
1690
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001691 // Experimental feature flags should not go here; pass the flags as
1692 // always_true_flags if the test needs them.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001693 static const ParserFlag default_flags[] = {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001694 kAllowLazy,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001695 kAllowNatives,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001696 };
1697 ParserFlag* generated_flags = NULL;
1698 if (flags == NULL) {
1699 flags = default_flags;
1700 flags_len = arraysize(default_flags);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001701 if (always_true_flags != NULL || always_false_flags != NULL) {
1702 // Remove always_true/false_flags from default_flags (if present).
1703 CHECK((always_true_flags != NULL) == (always_true_len > 0));
1704 CHECK((always_false_flags != NULL) == (always_false_len > 0));
1705 generated_flags = new ParserFlag[flags_len + always_true_len];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001706 int flag_index = 0;
1707 for (int i = 0; i < flags_len; ++i) {
1708 bool use_flag = true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001709 for (int j = 0; use_flag && j < always_true_len; ++j) {
1710 if (flags[i] == always_true_flags[j]) use_flag = false;
1711 }
1712 for (int j = 0; use_flag && j < always_false_len; ++j) {
1713 if (flags[i] == always_false_flags[j]) use_flag = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001714 }
1715 if (use_flag) generated_flags[flag_index++] = flags[i];
1716 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001717 flags_len = flag_index;
1718 flags = generated_flags;
1719 }
1720 }
1721 for (int i = 0; context_data[i][0] != NULL; ++i) {
1722 for (int j = 0; statement_data[j] != NULL; ++j) {
1723 int kPrefixLen = i::StrLength(context_data[i][0]);
1724 int kStatementLen = i::StrLength(statement_data[j]);
1725 int kSuffixLen = i::StrLength(context_data[i][1]);
1726 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
1727
1728 // Plug the source code pieces together.
1729 i::ScopedVector<char> program(kProgramSize + 1);
1730 int length = i::SNPrintF(program,
1731 "%s%s%s",
1732 context_data[i][0],
1733 statement_data[j],
1734 context_data[i][1]);
1735 CHECK(length == kProgramSize);
1736 TestParserSync(program.start(),
1737 flags,
1738 flags_len,
1739 result,
1740 always_true_flags,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001741 always_true_len,
1742 always_false_flags,
1743 always_false_len);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001744 }
1745 }
1746 delete[] generated_flags;
1747}
1748
1749
1750TEST(ErrorsEvalAndArguments) {
1751 // Tests that both preparsing and parsing produce the right kind of errors for
1752 // using "eval" and "arguments" as identifiers. Without the strict mode, it's
1753 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it
1754 // isn't.
1755 const char* context_data[][2] = {
1756 { "\"use strict\";", "" },
1757 { "var eval; function test_func() {\"use strict\"; ", "}"},
1758 { NULL, NULL }
1759 };
1760
1761 const char* statement_data[] = {
1762 "var eval;",
1763 "var arguments",
1764 "var foo, eval;",
1765 "var foo, arguments;",
1766 "try { } catch (eval) { }",
1767 "try { } catch (arguments) { }",
1768 "function eval() { }",
1769 "function arguments() { }",
1770 "function foo(eval) { }",
1771 "function foo(arguments) { }",
1772 "function foo(bar, eval) { }",
1773 "function foo(bar, arguments) { }",
1774 "(eval) => { }",
1775 "(arguments) => { }",
1776 "(foo, eval) => { }",
1777 "(foo, arguments) => { }",
1778 "eval = 1;",
1779 "arguments = 1;",
1780 "var foo = eval = 1;",
1781 "var foo = arguments = 1;",
1782 "++eval;",
1783 "++arguments;",
1784 "eval++;",
1785 "arguments++;",
1786 NULL
1787 };
1788
1789 RunParserSyncTest(context_data, statement_data, kError);
1790}
1791
1792
1793TEST(NoErrorsEvalAndArgumentsSloppy) {
1794 // Tests that both preparsing and parsing accept "eval" and "arguments" as
1795 // identifiers when needed.
1796 const char* context_data[][2] = {
1797 { "", "" },
1798 { "function test_func() {", "}"},
1799 { NULL, NULL }
1800 };
1801
1802 const char* statement_data[] = {
1803 "var eval;",
1804 "var arguments",
1805 "var foo, eval;",
1806 "var foo, arguments;",
1807 "try { } catch (eval) { }",
1808 "try { } catch (arguments) { }",
1809 "function eval() { }",
1810 "function arguments() { }",
1811 "function foo(eval) { }",
1812 "function foo(arguments) { }",
1813 "function foo(bar, eval) { }",
1814 "function foo(bar, arguments) { }",
1815 "eval = 1;",
1816 "arguments = 1;",
1817 "var foo = eval = 1;",
1818 "var foo = arguments = 1;",
1819 "++eval;",
1820 "++arguments;",
1821 "eval++;",
1822 "arguments++;",
1823 NULL
1824 };
1825
1826 RunParserSyncTest(context_data, statement_data, kSuccess);
1827}
1828
1829
1830TEST(NoErrorsEvalAndArgumentsStrict) {
1831 const char* context_data[][2] = {
1832 { "\"use strict\";", "" },
1833 { "function test_func() { \"use strict\";", "}" },
1834 { "() => { \"use strict\"; ", "}" },
1835 { NULL, NULL }
1836 };
1837
1838 const char* statement_data[] = {
1839 "eval;",
1840 "arguments;",
1841 "var foo = eval;",
1842 "var foo = arguments;",
1843 "var foo = { eval: 1 };",
1844 "var foo = { arguments: 1 };",
1845 "var foo = { }; foo.eval = {};",
1846 "var foo = { }; foo.arguments = {};",
1847 NULL
1848 };
1849
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001850 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001851 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1852 always_flags, arraysize(always_flags));
1853}
1854
1855
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001856#define FUTURE_STRICT_RESERVED_WORDS(V) \
1857 V(implements) \
1858 V(interface) \
1859 V(let) \
1860 V(package) \
1861 V(private) \
1862 V(protected) \
1863 V(public) \
1864 V(static) \
1865 V(yield)
1866
1867
1868#define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
1869 V(implements) \
1870 V(let) \
1871 V(static) \
1872 V(yield)
1873
1874
1875#define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
1876 "var " #NAME ";", \
1877 "var foo, " #NAME ";", \
1878 "try { } catch (" #NAME ") { }", \
1879 "function " #NAME "() { }", \
1880 "(function " #NAME "() { })", \
1881 "function foo(" #NAME ") { }", \
1882 "function foo(bar, " #NAME ") { }", \
1883 #NAME " = 1;", \
1884 #NAME " += 1;", \
1885 "var foo = " #NAME " = 1;", \
1886 "++" #NAME ";", \
1887 #NAME " ++;",
1888
1889
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001890TEST(ErrorsFutureStrictReservedWords) {
1891 // Tests that both preparsing and parsing produce the right kind of errors for
1892 // using future strict reserved words as identifiers. Without the strict mode,
1893 // it's ok to use future strict reserved words as identifiers. With the strict
1894 // mode, it isn't.
1895 const char* context_data[][2] = {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001896 { "function test_func() {\"use strict\"; ", "}"},
1897 { "() => { \"use strict\"; ", "}" },
1898 { NULL, NULL }
1899 };
1900
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001901 const char* statement_data[] {
1902 LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001903 NULL
1904 };
1905
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001906 RunParserSyncTest(context_data, statement_data, kError);
1907 RunParserSyncTest(context_data, statement_data, kError);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001908}
1909
1910
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001911#undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
1912
1913
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001914TEST(NoErrorsFutureStrictReservedWords) {
1915 const char* context_data[][2] = {
1916 { "", "" },
1917 { "function test_func() {", "}"},
1918 { "() => {", "}" },
1919 { NULL, NULL }
1920 };
1921
1922 const char* statement_data[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001923 FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001924 NULL
1925 };
1926
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001927 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001928 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1929 always_flags, arraysize(always_flags));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001930
1931 static const ParserFlag classes_flags[] = {
1932 kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
1933 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1934 classes_flags, arraysize(classes_flags));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001935}
1936
1937
1938TEST(ErrorsReservedWords) {
1939 // Tests that both preparsing and parsing produce the right kind of errors for
1940 // using future reserved words as identifiers. These tests don't depend on the
1941 // strict mode.
1942 const char* context_data[][2] = {
1943 { "", "" },
1944 { "\"use strict\";", "" },
1945 { "var eval; function test_func() {", "}"},
1946 { "var eval; function test_func() {\"use strict\"; ", "}"},
1947 { "var eval; () => {", "}"},
1948 { "var eval; () => {\"use strict\"; ", "}"},
1949 { NULL, NULL }
1950 };
1951
1952 const char* statement_data[] = {
1953 "var super;",
1954 "var foo, super;",
1955 "try { } catch (super) { }",
1956 "function super() { }",
1957 "function foo(super) { }",
1958 "function foo(bar, super) { }",
1959 "(super) => { }",
1960 "(bar, super) => { }",
1961 "super = 1;",
1962 "var foo = super = 1;",
1963 "++super;",
1964 "super++;",
1965 "function foo super",
1966 NULL
1967 };
1968
1969 RunParserSyncTest(context_data, statement_data, kError);
1970}
1971
1972
1973TEST(NoErrorsLetSloppyAllModes) {
1974 // In sloppy mode, it's okay to use "let" as identifier.
1975 const char* context_data[][2] = {
1976 { "", "" },
1977 { "function f() {", "}" },
1978 { "(function f() {", "})" },
1979 { NULL, NULL }
1980 };
1981
1982 const char* statement_data[] = {
1983 "var let;",
1984 "var foo, let;",
1985 "try { } catch (let) { }",
1986 "function let() { }",
1987 "(function let() { })",
1988 "function foo(let) { }",
1989 "function foo(bar, let) { }",
1990 "let = 1;",
1991 "var foo = let = 1;",
1992 "let * 2;",
1993 "++let;",
1994 "let++;",
1995 "let: 34",
1996 "function let(let) { let: let(let + let(0)); }",
1997 "({ let: 1 })",
1998 "({ get let() { 1 } })",
1999 "let(100)",
2000 NULL
2001 };
2002
2003 RunParserSyncTest(context_data, statement_data, kSuccess);
2004}
2005
2006
2007TEST(NoErrorsYieldSloppyAllModes) {
2008 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2009 // generator (see other test).
2010 const char* context_data[][2] = {
2011 { "", "" },
2012 { "function not_gen() {", "}" },
2013 { "(function not_gen() {", "})" },
2014 { NULL, NULL }
2015 };
2016
2017 const char* statement_data[] = {
2018 "var yield;",
2019 "var foo, yield;",
2020 "try { } catch (yield) { }",
2021 "function yield() { }",
2022 "(function yield() { })",
2023 "function foo(yield) { }",
2024 "function foo(bar, yield) { }",
2025 "yield = 1;",
2026 "var foo = yield = 1;",
2027 "yield * 2;",
2028 "++yield;",
2029 "yield++;",
2030 "yield: 34",
2031 "function yield(yield) { yield: yield (yield + yield(0)); }",
2032 "({ yield: 1 })",
2033 "({ get yield() { 1 } })",
2034 "yield(100)",
2035 "yield[100]",
2036 NULL
2037 };
2038
2039 RunParserSyncTest(context_data, statement_data, kSuccess);
2040}
2041
2042
2043TEST(NoErrorsYieldSloppyGeneratorsEnabled) {
2044 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
2045 // generator (see next test).
2046 const char* context_data[][2] = {
2047 { "", "" },
2048 { "function not_gen() {", "}" },
2049 { "function * gen() { function not_gen() {", "} }" },
2050 { "(function not_gen() {", "})" },
2051 { "(function * gen() { (function not_gen() {", "}) })" },
2052 { NULL, NULL }
2053 };
2054
2055 const char* statement_data[] = {
2056 "var yield;",
2057 "var foo, yield;",
2058 "try { } catch (yield) { }",
2059 "function yield() { }",
2060 "(function yield() { })",
2061 "function foo(yield) { }",
2062 "function foo(bar, yield) { }",
2063 "function * yield() { }",
2064 "(function * yield() { })",
2065 "yield = 1;",
2066 "var foo = yield = 1;",
2067 "yield * 2;",
2068 "++yield;",
2069 "yield++;",
2070 "yield: 34",
2071 "function yield(yield) { yield: yield (yield + yield(0)); }",
2072 "({ yield: 1 })",
2073 "({ get yield() { 1 } })",
2074 "yield(100)",
2075 "yield[100]",
2076 NULL
2077 };
2078
2079 RunParserSyncTest(context_data, statement_data, kSuccess);
2080}
2081
2082
2083TEST(ErrorsYieldStrict) {
2084 const char* context_data[][2] = {
2085 { "\"use strict\";", "" },
2086 { "\"use strict\"; function not_gen() {", "}" },
2087 { "function test_func() {\"use strict\"; ", "}"},
2088 { "\"use strict\"; function * gen() { function not_gen() {", "} }" },
2089 { "\"use strict\"; (function not_gen() {", "})" },
2090 { "\"use strict\"; (function * gen() { (function not_gen() {", "}) })" },
2091 { "() => {\"use strict\"; ", "}" },
2092 { NULL, NULL }
2093 };
2094
2095 const char* statement_data[] = {
2096 "var yield;",
2097 "var foo, yield;",
2098 "try { } catch (yield) { }",
2099 "function yield() { }",
2100 "(function yield() { })",
2101 "function foo(yield) { }",
2102 "function foo(bar, yield) { }",
2103 "function * yield() { }",
2104 "(function * yield() { })",
2105 "yield = 1;",
2106 "var foo = yield = 1;",
2107 "++yield;",
2108 "yield++;",
2109 "yield: 34;",
2110 NULL
2111 };
2112
2113 RunParserSyncTest(context_data, statement_data, kError);
2114}
2115
2116
2117TEST(NoErrorsGenerator) {
2118 const char* context_data[][2] = {
2119 { "function * gen() {", "}" },
2120 { "(function * gen() {", "})" },
2121 { "(function * () {", "})" },
2122 { NULL, NULL }
2123 };
2124
2125 const char* statement_data[] = {
2126 // A generator without a body is valid.
2127 ""
2128 // Valid yield expressions inside generators.
2129 "yield 2;",
2130 "yield * 2;",
2131 "yield * \n 2;",
2132 "yield yield 1;",
2133 "yield * yield * 1;",
2134 "yield 3 + (yield 4);",
2135 "yield * 3 + (yield * 4);",
2136 "(yield * 3) + (yield * 4);",
2137 "yield 3; yield 4;",
2138 "yield * 3; yield * 4;",
2139 "(function (yield) { })",
2140 "yield { yield: 12 }",
2141 "yield /* comment */ { yield: 12 }",
2142 "yield * \n { yield: 12 }",
2143 "yield /* comment */ * \n { yield: 12 }",
2144 // You can return in a generator.
2145 "yield 1; return",
2146 "yield * 1; return",
2147 "yield 1; return 37",
2148 "yield * 1; return 37",
2149 "yield 1; return 37; yield 'dead';",
2150 "yield * 1; return 37; yield * 'dead';",
2151 // Yield is still a valid key in object literals.
2152 "({ yield: 1 })",
2153 "({ get yield() { } })",
2154 // Yield without RHS.
2155 "yield;",
2156 "yield",
2157 "yield\n",
2158 "yield /* comment */"
2159 "yield // comment\n"
2160 "(yield)",
2161 "[yield]",
2162 "{yield}",
2163 "yield, yield",
2164 "yield; yield",
2165 "(yield) ? yield : yield",
2166 "(yield) \n ? yield : yield",
2167 // If there is a newline before the next token, we don't look for RHS.
2168 "yield\nfor (;;) {}",
2169 NULL
2170 };
2171
2172 RunParserSyncTest(context_data, statement_data, kSuccess);
2173}
2174
2175
2176TEST(ErrorsYieldGenerator) {
2177 const char* context_data[][2] = {
2178 { "function * gen() {", "}" },
2179 { "\"use strict\"; function * gen() {", "}" },
2180 { NULL, NULL }
2181 };
2182
2183 const char* statement_data[] = {
2184 // Invalid yield expressions inside generators.
2185 "var yield;",
2186 "var foo, yield;",
2187 "try { } catch (yield) { }",
2188 "function yield() { }",
2189 // The name of the NFE is let-bound in the generator, which does not permit
2190 // yield to be an identifier.
2191 "(function yield() { })",
2192 "(function * yield() { })",
2193 // Yield isn't valid as a formal parameter for generators.
2194 "function * foo(yield) { }",
2195 "(function * foo(yield) { })",
2196 "yield = 1;",
2197 "var foo = yield = 1;",
2198 "++yield;",
2199 "yield++;",
2200 "yield *",
2201 "(yield *)",
2202 // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which
2203 // is invalid.
2204 "yield 3 + yield 4;",
2205 "yield: 34",
2206 "yield ? 1 : 2",
2207 // Parses as yield (/ yield): invalid.
2208 "yield / yield",
2209 "+ yield",
2210 "+ yield 3",
2211 // Invalid (no newline allowed between yield and *).
2212 "yield\n*3",
2213 // Invalid (we see a newline, so we parse {yield:42} as a statement, not an
2214 // object literal, and yield is not a valid label).
2215 "yield\n{yield: 42}",
2216 "yield /* comment */\n {yield: 42}",
2217 "yield //comment\n {yield: 42}",
2218 NULL
2219 };
2220
2221 RunParserSyncTest(context_data, statement_data, kError);
2222}
2223
2224
2225TEST(ErrorsNameOfStrictFunction) {
2226 // Tests that illegal tokens as names of a strict function produce the correct
2227 // errors.
2228 const char* context_data[][2] = {
2229 { "function ", ""},
2230 { "\"use strict\"; function", ""},
2231 { "function * ", ""},
2232 { "\"use strict\"; function * ", ""},
2233 { NULL, NULL }
2234 };
2235
2236 const char* statement_data[] = {
2237 "eval() {\"use strict\";}",
2238 "arguments() {\"use strict\";}",
2239 "interface() {\"use strict\";}",
2240 "yield() {\"use strict\";}",
2241 // Future reserved words are always illegal
2242 "function super() { }",
2243 "function super() {\"use strict\";}",
2244 NULL
2245 };
2246
2247 RunParserSyncTest(context_data, statement_data, kError);
2248}
2249
2250
2251TEST(NoErrorsNameOfStrictFunction) {
2252 const char* context_data[][2] = {
2253 { "function ", ""},
2254 { NULL, NULL }
2255 };
2256
2257 const char* statement_data[] = {
2258 "eval() { }",
2259 "arguments() { }",
2260 "interface() { }",
2261 "yield() { }",
2262 NULL
2263 };
2264
2265 RunParserSyncTest(context_data, statement_data, kSuccess);
2266}
2267
2268
2269TEST(NoErrorsNameOfStrictGenerator) {
2270 const char* context_data[][2] = {
2271 { "function * ", ""},
2272 { NULL, NULL }
2273 };
2274
2275 const char* statement_data[] = {
2276 "eval() { }",
2277 "arguments() { }",
2278 "interface() { }",
2279 "yield() { }",
2280 NULL
2281 };
2282
2283 RunParserSyncTest(context_data, statement_data, kSuccess);
2284}
2285
2286
2287TEST(ErrorsIllegalWordsAsLabelsSloppy) {
2288 // Using future reserved words as labels is always an error.
2289 const char* context_data[][2] = {
2290 { "", ""},
2291 { "function test_func() {", "}" },
2292 { "() => {", "}" },
2293 { NULL, NULL }
2294 };
2295
2296 const char* statement_data[] = {
2297 "super: while(true) { break super; }",
2298 NULL
2299 };
2300
2301 RunParserSyncTest(context_data, statement_data, kError);
2302}
2303
2304
2305TEST(ErrorsIllegalWordsAsLabelsStrict) {
2306 // Tests that illegal tokens as labels produce the correct errors.
2307 const char* context_data[][2] = {
2308 { "\"use strict\";", "" },
2309 { "function test_func() {\"use strict\"; ", "}"},
2310 { "() => {\"use strict\"; ", "}" },
2311 { NULL, NULL }
2312 };
2313
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002314#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002315 const char* statement_data[] = {
2316 "super: while(true) { break super; }",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002317 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 NULL
2319 };
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002320#undef LABELLED_WHILE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002321
2322 RunParserSyncTest(context_data, statement_data, kError);
2323}
2324
2325
2326TEST(NoErrorsIllegalWordsAsLabels) {
2327 // Using eval and arguments as labels is legal even in strict mode.
2328 const char* context_data[][2] = {
2329 { "", ""},
2330 { "function test_func() {", "}" },
2331 { "() => {", "}" },
2332 { "\"use strict\";", "" },
2333 { "\"use strict\"; function test_func() {", "}" },
2334 { "\"use strict\"; () => {", "}" },
2335 { NULL, NULL }
2336 };
2337
2338 const char* statement_data[] = {
2339 "mylabel: while(true) { break mylabel; }",
2340 "eval: while(true) { break eval; }",
2341 "arguments: while(true) { break arguments; }",
2342 NULL
2343 };
2344
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002345 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
2346 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2347 always_flags, arraysize(always_flags));
2348}
2349
2350
2351TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
2352 const char* context_data[][2] = {
2353 { "", ""},
2354 { "function test_func() {", "}" },
2355 { "() => {", "}" },
2356 { NULL, NULL }
2357 };
2358
2359#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
2360 const char* statement_data[] {
2361 FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
2362 NULL
2363 };
2364#undef LABELLED_WHILE
2365
2366 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002367 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2368 always_flags, arraysize(always_flags));
2369}
2370
2371
2372TEST(ErrorsParenthesizedLabels) {
2373 // Parenthesized identifiers shouldn't be recognized as labels.
2374 const char* context_data[][2] = {
2375 { "", ""},
2376 { "function test_func() {", "}" },
2377 { "() => {", "}" },
2378 { NULL, NULL }
2379 };
2380
2381 const char* statement_data[] = {
2382 "(mylabel): while(true) { break mylabel; }",
2383 NULL
2384 };
2385
2386 RunParserSyncTest(context_data, statement_data, kError);
2387}
2388
2389
2390TEST(NoErrorsParenthesizedDirectivePrologue) {
2391 // Parenthesized directive prologue shouldn't be recognized.
2392 const char* context_data[][2] = {
2393 { "", ""},
2394 { NULL, NULL }
2395 };
2396
2397 const char* statement_data[] = {
2398 "(\"use strict\"); var eval;",
2399 NULL
2400 };
2401
2402 RunParserSyncTest(context_data, statement_data, kSuccess);
2403}
2404
2405
2406TEST(ErrorsNotAnIdentifierName) {
2407 const char* context_data[][2] = {
2408 { "", ""},
2409 { "\"use strict\";", ""},
2410 { NULL, NULL }
2411 };
2412
2413 const char* statement_data[] = {
2414 "var foo = {}; foo.{;",
2415 "var foo = {}; foo.};",
2416 "var foo = {}; foo.=;",
2417 "var foo = {}; foo.888;",
2418 "var foo = {}; foo.-;",
2419 "var foo = {}; foo.--;",
2420 NULL
2421 };
2422
2423 RunParserSyncTest(context_data, statement_data, kError);
2424}
2425
2426
2427TEST(NoErrorsIdentifierNames) {
2428 // Keywords etc. are valid as property names.
2429 const char* context_data[][2] = {
2430 { "", ""},
2431 { "\"use strict\";", ""},
2432 { NULL, NULL }
2433 };
2434
2435 const char* statement_data[] = {
2436 "var foo = {}; foo.if;",
2437 "var foo = {}; foo.yield;",
2438 "var foo = {}; foo.super;",
2439 "var foo = {}; foo.interface;",
2440 "var foo = {}; foo.eval;",
2441 "var foo = {}; foo.arguments;",
2442 NULL
2443 };
2444
2445 RunParserSyncTest(context_data, statement_data, kSuccess);
2446}
2447
2448
2449TEST(DontRegressPreParserDataSizes) {
2450 // These tests make sure that Parser doesn't start producing less "preparse
2451 // data" (data which the embedder can cache).
2452 v8::V8::Initialize();
2453 v8::Isolate* isolate = CcTest::isolate();
2454 v8::HandleScope handles(isolate);
2455
2456 CcTest::i_isolate()->stack_guard()->SetStackLimit(
2457 i::GetCurrentStackPosition() - 128 * 1024);
2458
2459 struct TestCase {
2460 const char* program;
2461 int functions;
2462 } test_cases[] = {
2463 // No functions.
2464 {"var x = 42;", 0},
2465 // Functions.
2466 {"function foo() {}", 1}, {"function foo() {} function bar() {}", 2},
2467 // Getter / setter functions are recorded as functions if they're on the top
2468 // level.
2469 {"var x = {get foo(){} };", 1},
2470 // Functions insize lazy functions are not recorded.
2471 {"function lazy() { function a() {} function b() {} function c() {} }", 1},
2472 {"function lazy() { var x = {get foo(){} } }", 1},
2473 {NULL, 0}
2474 };
2475
2476 for (int i = 0; test_cases[i].program; i++) {
2477 const char* program = test_cases[i].program;
2478 i::Factory* factory = CcTest::i_isolate()->factory();
2479 i::Handle<i::String> source =
2480 factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
2481 i::Handle<i::Script> script = factory->NewScript(source);
2482 i::CompilationInfoWithZone info(script);
2483 i::ScriptData* sd = NULL;
2484 info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
2485 i::Parser::Parse(&info, true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002486 i::ParseData* pd = i::ParseData::FromCachedData(sd);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002487
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002488 if (pd->FunctionCount() != test_cases[i].functions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002489 v8::base::OS::Print(
2490 "Expected preparse data for program:\n"
2491 "\t%s\n"
2492 "to contain %d functions, however, received %d functions.\n",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002493 program, test_cases[i].functions, pd->FunctionCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002494 CHECK(false);
2495 }
2496 delete sd;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002497 delete pd;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002498 }
2499}
2500
2501
2502TEST(FunctionDeclaresItselfStrict) {
2503 // Tests that we produce the right kinds of errors when a function declares
2504 // itself strict (we cannot produce there errors as soon as we see the
2505 // offending identifiers, because we don't know at that point whether the
2506 // function is strict or not).
2507 const char* context_data[][2] = {
2508 {"function eval() {", "}"},
2509 {"function arguments() {", "}"},
2510 {"function yield() {", "}"},
2511 {"function interface() {", "}"},
2512 {"function foo(eval) {", "}"},
2513 {"function foo(arguments) {", "}"},
2514 {"function foo(yield) {", "}"},
2515 {"function foo(interface) {", "}"},
2516 {"function foo(bar, eval) {", "}"},
2517 {"function foo(bar, arguments) {", "}"},
2518 {"function foo(bar, yield) {", "}"},
2519 {"function foo(bar, interface) {", "}"},
2520 {"function foo(bar, bar) {", "}"},
2521 { NULL, NULL }
2522 };
2523
2524 const char* strict_statement_data[] = {
2525 "\"use strict\";",
2526 NULL
2527 };
2528
2529 const char* non_strict_statement_data[] = {
2530 ";",
2531 NULL
2532 };
2533
2534 RunParserSyncTest(context_data, strict_statement_data, kError);
2535 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
2536}
2537
2538
2539TEST(ErrorsTryWithoutCatchOrFinally) {
2540 const char* context_data[][2] = {
2541 {"", ""},
2542 { NULL, NULL }
2543 };
2544
2545 const char* statement_data[] = {
2546 "try { }",
2547 "try { } foo();",
2548 "try { } catch (e) foo();",
2549 "try { } catch { }",
2550 "try { } finally foo();",
2551 NULL
2552 };
2553
2554 RunParserSyncTest(context_data, statement_data, kError);
2555}
2556
2557
2558TEST(NoErrorsTryCatchFinally) {
2559 const char* context_data[][2] = {
2560 {"", ""},
2561 { NULL, NULL }
2562 };
2563
2564 const char* statement_data[] = {
2565 "try { } catch (e) { }",
2566 "try { } catch (e) { } finally { }",
2567 "try { } finally { }",
2568 NULL
2569 };
2570
2571 RunParserSyncTest(context_data, statement_data, kSuccess);
2572}
2573
2574
2575TEST(ErrorsRegexpLiteral) {
2576 const char* context_data[][2] = {
2577 {"var r = ", ""},
2578 { NULL, NULL }
2579 };
2580
2581 const char* statement_data[] = {
2582 "/unterminated",
2583 NULL
2584 };
2585
2586 RunParserSyncTest(context_data, statement_data, kError);
2587}
2588
2589
2590TEST(NoErrorsRegexpLiteral) {
2591 const char* context_data[][2] = {
2592 {"var r = ", ""},
2593 { NULL, NULL }
2594 };
2595
2596 const char* statement_data[] = {
2597 "/foo/",
2598 "/foo/g",
2599 "/foo/whatever", // This is an error but not detected by the parser.
2600 NULL
2601 };
2602
2603 RunParserSyncTest(context_data, statement_data, kSuccess);
2604}
2605
2606
2607TEST(Intrinsics) {
2608 const char* context_data[][2] = {
2609 {"", ""},
2610 { NULL, NULL }
2611 };
2612
2613 const char* statement_data[] = {
2614 "%someintrinsic(arg)",
2615 NULL
2616 };
2617
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002618 // This test requires kAllowNatives to succeed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002619 static const ParserFlag always_true_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002620 kAllowNatives
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002621 };
2622
2623 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2624 always_true_flags, 1);
2625}
2626
2627
2628TEST(NoErrorsNewExpression) {
2629 const char* context_data[][2] = {
2630 {"", ""},
2631 {"var f =", ""},
2632 { NULL, NULL }
2633 };
2634
2635 const char* statement_data[] = {
2636 "new foo",
2637 "new foo();",
2638 "new foo(1);",
2639 "new foo(1, 2);",
2640 // The first () will be processed as a part of the NewExpression and the
2641 // second () will be processed as part of LeftHandSideExpression.
2642 "new foo()();",
2643 // The first () will be processed as a part of the inner NewExpression and
2644 // the second () will be processed as a part of the outer NewExpression.
2645 "new new foo()();",
2646 "new foo.bar;",
2647 "new foo.bar();",
2648 "new foo.bar.baz;",
2649 "new foo.bar().baz;",
2650 "new foo[bar];",
2651 "new foo[bar]();",
2652 "new foo[bar][baz];",
2653 "new foo[bar]()[baz];",
2654 "new foo[bar].baz(baz)()[bar].baz;",
2655 "new \"foo\"", // Runtime error
2656 "new 1", // Runtime error
2657 // This even runs:
2658 "(new new Function(\"this.x = 1\")).x;",
2659 "new new Test_Two(String, 2).v(0123).length;",
2660 NULL
2661 };
2662
2663 RunParserSyncTest(context_data, statement_data, kSuccess);
2664}
2665
2666
2667TEST(ErrorsNewExpression) {
2668 const char* context_data[][2] = {
2669 {"", ""},
2670 {"var f =", ""},
2671 { NULL, NULL }
2672 };
2673
2674 const char* statement_data[] = {
2675 "new foo bar",
2676 "new ) foo",
2677 "new ++foo",
2678 "new foo ++",
2679 NULL
2680 };
2681
2682 RunParserSyncTest(context_data, statement_data, kError);
2683}
2684
2685
2686TEST(StrictObjectLiteralChecking) {
2687 const char* strict_context_data[][2] = {
2688 {"\"use strict\"; var myobject = {", "};"},
2689 {"\"use strict\"; var myobject = {", ",};"},
2690 { NULL, NULL }
2691 };
2692 const char* non_strict_context_data[][2] = {
2693 {"var myobject = {", "};"},
2694 {"var myobject = {", ",};"},
2695 { NULL, NULL }
2696 };
2697
2698 // These are only errors in strict mode.
2699 const char* statement_data[] = {
2700 "foo: 1, foo: 2",
2701 "\"foo\": 1, \"foo\": 2",
2702 "foo: 1, \"foo\": 2",
2703 "1: 1, 1: 2",
2704 "1: 1, \"1\": 2",
2705 "get: 1, get: 2", // Not a getter for real, just a property called get.
2706 "set: 1, set: 2", // Not a setter for real, just a property called set.
2707 NULL
2708 };
2709
2710 RunParserSyncTest(non_strict_context_data, statement_data, kSuccess);
2711 RunParserSyncTest(strict_context_data, statement_data, kError);
2712}
2713
2714
2715TEST(ErrorsObjectLiteralChecking) {
2716 const char* context_data[][2] = {
2717 {"\"use strict\"; var myobject = {", "};"},
2718 {"var myobject = {", "};"},
2719 { NULL, NULL }
2720 };
2721
2722 const char* statement_data[] = {
2723 ",",
2724 "foo: 1, get foo() {}",
2725 "foo: 1, set foo(v) {}",
2726 "\"foo\": 1, get \"foo\"() {}",
2727 "\"foo\": 1, set \"foo\"(v) {}",
2728 "1: 1, get 1() {}",
2729 "1: 1, set 1() {}",
2730 "get foo() {}, get foo() {}",
2731 "set foo(_) {}, set foo(_) {}",
2732 // It's counter-intuitive, but these collide too (even in classic
2733 // mode). Note that we can have "foo" and foo as properties in classic
2734 // mode,
2735 // but we cannot have "foo" and get foo, or foo and get "foo".
2736 "foo: 1, get \"foo\"() {}",
2737 "foo: 1, set \"foo\"(v) {}",
2738 "\"foo\": 1, get foo() {}",
2739 "\"foo\": 1, set foo(v) {}",
2740 "1: 1, get \"1\"() {}",
2741 "1: 1, set \"1\"() {}",
2742 "\"1\": 1, get 1() {}"
2743 "\"1\": 1, set 1(v) {}"
2744 // Wrong number of parameters
2745 "get bar(x) {}",
2746 "get bar(x, y) {}",
2747 "set bar() {}",
2748 "set bar(x, y) {}",
2749 // Parsing FunctionLiteral for getter or setter fails
2750 "get foo( +",
2751 "get foo() \"error\"",
2752 NULL};
2753
2754 RunParserSyncTest(context_data, statement_data, kError);
2755}
2756
2757
2758TEST(NoErrorsObjectLiteralChecking) {
2759 const char* context_data[][2] = {
2760 {"var myobject = {", "};"},
2761 {"var myobject = {", ",};"},
2762 {"\"use strict\"; var myobject = {", "};"},
2763 {"\"use strict\"; var myobject = {", ",};"},
2764 { NULL, NULL }
2765 };
2766
2767 const char* statement_data[] = {
2768 "foo: 1, bar: 2",
2769 "\"foo\": 1, \"bar\": 2",
2770 "1: 1, 2: 2",
2771 // Syntax: IdentifierName ':' AssignmentExpression
2772 "foo: bar = 5 + baz",
2773 // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}'
2774 "get foo() {}",
2775 "get \"foo\"() {}",
2776 "get 1() {}",
2777 // Syntax: 'set' PropertyName '(' PropertySetParameterList ')'
2778 // '{' FunctionBody '}'
2779 "set foo(v) {}",
2780 "set \"foo\"(v) {}",
2781 "set 1(v) {}",
2782 // Non-colliding getters and setters -> no errors
2783 "foo: 1, get bar() {}",
2784 "foo: 1, set bar(v) {}",
2785 "\"foo\": 1, get \"bar\"() {}",
2786 "\"foo\": 1, set \"bar\"(v) {}",
2787 "1: 1, get 2() {}",
2788 "1: 1, set 2(v) {}",
2789 "get: 1, get foo() {}",
2790 "set: 1, set foo(_) {}",
2791 // Keywords, future reserved and strict future reserved are also allowed as
2792 // property names.
2793 "if: 4",
2794 "interface: 5",
2795 "super: 6",
2796 "eval: 7",
2797 "arguments: 8",
2798 NULL
2799 };
2800
2801 RunParserSyncTest(context_data, statement_data, kSuccess);
2802}
2803
2804
2805TEST(TooManyArguments) {
2806 const char* context_data[][2] = {
2807 {"foo(", "0)"},
2808 { NULL, NULL }
2809 };
2810
2811 using v8::internal::Code;
2812 char statement[Code::kMaxArguments * 2 + 1];
2813 for (int i = 0; i < Code::kMaxArguments; ++i) {
2814 statement[2 * i] = '0';
2815 statement[2 * i + 1] = ',';
2816 }
2817 statement[Code::kMaxArguments * 2] = 0;
2818
2819 const char* statement_data[] = {
2820 statement,
2821 NULL
2822 };
2823
2824 // The test is quite slow, so run it with a reduced set of flags.
2825 static const ParserFlag empty_flags[] = {kAllowLazy};
2826 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
2827}
2828
2829
2830TEST(StrictDelete) {
2831 // "delete <Identifier>" is not allowed in strict mode.
2832 const char* strict_context_data[][2] = {
2833 {"\"use strict\"; ", ""},
2834 { NULL, NULL }
2835 };
2836
2837 const char* sloppy_context_data[][2] = {
2838 {"", ""},
2839 { NULL, NULL }
2840 };
2841
2842 // These are errors in the strict mode.
2843 const char* sloppy_statement_data[] = {
2844 "delete foo;",
2845 "delete foo + 1;",
2846 "delete (foo);",
2847 "delete eval;",
2848 "delete interface;",
2849 NULL
2850 };
2851
2852 // These are always OK
2853 const char* good_statement_data[] = {
2854 "delete this;",
2855 "delete 1;",
2856 "delete 1 + 2;",
2857 "delete foo();",
2858 "delete foo.bar;",
2859 "delete foo[bar];",
2860 "delete foo--;",
2861 "delete --foo;",
2862 "delete new foo();",
2863 "delete new foo(bar);",
2864 NULL
2865 };
2866
2867 // These are always errors
2868 const char* bad_statement_data[] = {
2869 "delete if;",
2870 NULL
2871 };
2872
2873 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
2874 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
2875
2876 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
2877 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
2878
2879 RunParserSyncTest(strict_context_data, bad_statement_data, kError);
2880 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
2881}
2882
2883
2884TEST(InvalidLeftHandSide) {
2885 const char* assignment_context_data[][2] = {
2886 {"", " = 1;"},
2887 {"\"use strict\"; ", " = 1;"},
2888 { NULL, NULL }
2889 };
2890
2891 const char* prefix_context_data[][2] = {
2892 {"++", ";"},
2893 {"\"use strict\"; ++", ";"},
2894 {NULL, NULL},
2895 };
2896
2897 const char* postfix_context_data[][2] = {
2898 {"", "++;"},
2899 {"\"use strict\"; ", "++;"},
2900 { NULL, NULL }
2901 };
2902
2903 // Good left hand sides for assigment or prefix / postfix operations.
2904 const char* good_statement_data[] = {
2905 "foo",
2906 "foo.bar",
2907 "foo[bar]",
2908 "foo()[bar]",
2909 "foo().bar",
2910 "this.foo",
2911 "this[foo]",
2912 "new foo()[bar]",
2913 "new foo().bar",
2914 "foo()",
2915 "foo(bar)",
2916 "foo[bar]()",
2917 "foo.bar()",
2918 "this()",
2919 "this.foo()",
2920 "this[foo].bar()",
2921 "this.foo[foo].bar(this)(bar)[foo]()",
2922 NULL
2923 };
2924
2925 // Bad left hand sides for assigment or prefix / postfix operations.
2926 const char* bad_statement_data_common[] = {
2927 "2",
2928 "new foo",
2929 "new foo()",
2930 "null",
2931 "if", // Unexpected token
2932 "{x: 1}", // Unexpected token
2933 "this",
2934 "\"bar\"",
2935 "(foo + bar)",
2936 "new new foo()[bar]", // means: new (new foo()[bar])
2937 "new new foo().bar", // means: new (new foo()[bar])
2938 NULL
2939 };
2940
2941 // These are not okay for assignment, but okay for prefix / postix.
2942 const char* bad_statement_data_for_assignment[] = {
2943 "++foo",
2944 "foo++",
2945 "foo + bar",
2946 NULL
2947 };
2948
2949 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
2950 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
2951 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
2952 kError);
2953
2954 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
2955 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
2956
2957 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
2958 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);
2959}
2960
2961
2962TEST(FuncNameInferrerBasic) {
2963 // Tests that function names are inferred properly.
2964 i::FLAG_allow_natives_syntax = true;
2965 v8::Isolate* isolate = CcTest::isolate();
2966 v8::HandleScope scope(isolate);
2967 LocalContext env;
2968 CompileRun("var foo1 = function() {}; "
2969 "var foo2 = function foo3() {}; "
2970 "function not_ctor() { "
2971 " var foo4 = function() {}; "
2972 " return %FunctionGetInferredName(foo4); "
2973 "} "
2974 "function Ctor() { "
2975 " var foo5 = function() {}; "
2976 " return %FunctionGetInferredName(foo5); "
2977 "} "
2978 "var obj1 = { foo6: function() {} }; "
2979 "var obj2 = { 'foo7': function() {} }; "
2980 "var obj3 = {}; "
2981 "obj3[1] = function() {}; "
2982 "var obj4 = {}; "
2983 "obj4[1] = function foo8() {}; "
2984 "var obj5 = {}; "
2985 "obj5['foo9'] = function() {}; "
2986 "var obj6 = { obj7 : { foo10: function() {} } };");
2987 ExpectString("%FunctionGetInferredName(foo1)", "foo1");
2988 // foo2 is not unnamed -> its name is not inferred.
2989 ExpectString("%FunctionGetInferredName(foo2)", "");
2990 ExpectString("not_ctor()", "foo4");
2991 ExpectString("Ctor()", "Ctor.foo5");
2992 ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6");
2993 ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7");
2994 ExpectString("%FunctionGetInferredName(obj3[1])",
2995 "obj3.(anonymous function)");
2996 ExpectString("%FunctionGetInferredName(obj4[1])", "");
2997 ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9");
2998 ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10");
2999}
3000
3001
3002TEST(FuncNameInferrerTwoByte) {
3003 // Tests function name inferring in cases where some parts of the inferred
3004 // function name are two-byte strings.
3005 i::FLAG_allow_natives_syntax = true;
3006 v8::Isolate* isolate = CcTest::isolate();
3007 v8::HandleScope scope(isolate);
3008 LocalContext env;
3009 uint16_t* two_byte_source = AsciiToTwoByteString(
3010 "var obj1 = { oXj2 : { foo1: function() {} } }; "
3011 "%FunctionGetInferredName(obj1.oXj2.foo1)");
3012 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3013 // Make it really non-Latin1 (replace the Xs with a non-Latin1 character).
3014 two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d;
3015 v8::Local<v8::String> source =
3016 v8::String::NewFromTwoByte(isolate, two_byte_source);
3017 v8::Local<v8::Value> result = CompileRun(source);
3018 CHECK(result->IsString());
3019 v8::Local<v8::String> expected_name =
3020 v8::String::NewFromTwoByte(isolate, two_byte_name);
3021 CHECK(result->Equals(expected_name));
3022 i::DeleteArray(two_byte_source);
3023 i::DeleteArray(two_byte_name);
3024}
3025
3026
3027TEST(FuncNameInferrerEscaped) {
3028 // The same as FuncNameInferrerTwoByte, except that we express the two-byte
3029 // character as a unicode escape.
3030 i::FLAG_allow_natives_syntax = true;
3031 v8::Isolate* isolate = CcTest::isolate();
3032 v8::HandleScope scope(isolate);
3033 LocalContext env;
3034 uint16_t* two_byte_source = AsciiToTwoByteString(
3035 "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; "
3036 "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)");
3037 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
3038 // Fix to correspond to the non-ASCII name in two_byte_source.
3039 two_byte_name[6] = 0x010d;
3040 v8::Local<v8::String> source =
3041 v8::String::NewFromTwoByte(isolate, two_byte_source);
3042 v8::Local<v8::Value> result = CompileRun(source);
3043 CHECK(result->IsString());
3044 v8::Local<v8::String> expected_name =
3045 v8::String::NewFromTwoByte(isolate, two_byte_name);
3046 CHECK(result->Equals(expected_name));
3047 i::DeleteArray(two_byte_source);
3048 i::DeleteArray(two_byte_name);
3049}
3050
3051
3052TEST(RegressionLazyFunctionWithErrorWithArg) {
3053 // The bug occurred when a lazy function had an error which requires a
3054 // parameter (such as "unknown label" here). The error message was processed
3055 // before the AstValueFactory containing the error message string was
3056 // internalized.
3057 v8::Isolate* isolate = CcTest::isolate();
3058 v8::HandleScope scope(isolate);
3059 LocalContext env;
3060 i::FLAG_lazy = true;
3061 i::FLAG_min_preparse_length = 0;
3062 CompileRun("function this_is_lazy() {\n"
3063 " break p;\n"
3064 "}\n"
3065 "this_is_lazy();\n");
3066}
3067
3068
3069TEST(SerializationOfMaybeAssignmentFlag) {
3070 i::Isolate* isolate = CcTest::i_isolate();
3071 i::Factory* factory = isolate->factory();
3072 i::HandleScope scope(isolate);
3073 LocalContext env;
3074
3075 const char* src =
3076 "function h() {"
3077 " var result = [];"
3078 " function f() {"
3079 " result.push(2);"
3080 " }"
3081 " function assertResult(r) {"
3082 " f();"
3083 " result = [];"
3084 " }"
3085 " assertResult([2]);"
3086 " assertResult([2]);"
3087 " return f;"
3088 "};"
3089 "h();";
3090
3091 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3092 i::SNPrintF(program, "%s", src);
3093 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3094 source->PrintOn(stdout);
3095 printf("\n");
3096 i::Zone zone(isolate);
3097 v8::Local<v8::Value> v = CompileRun(src);
3098 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3099 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3100 i::Context* context = f->context();
3101 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3102 avf.Internalize(isolate);
3103 const i::AstRawString* name = avf.GetOneByteString("result");
3104 i::Handle<i::String> str = name->string();
3105 CHECK(str->IsInternalizedString());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003106 i::Scope* script_scope =
3107 new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
3108 script_scope->Initialize();
3109 i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
3110 DCHECK(s != script_scope);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003111 DCHECK(name != NULL);
3112
3113 // Get result from h's function context (that is f's context)
3114 i::Variable* var = s->Lookup(name);
3115
3116 CHECK(var != NULL);
3117 // Maybe assigned should survive deserialization
3118 CHECK(var->maybe_assigned() == i::kMaybeAssigned);
3119 // TODO(sigurds) Figure out if is_used should survive context serialization.
3120}
3121
3122
3123TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
3124 i::Isolate* isolate = CcTest::i_isolate();
3125 i::Factory* factory = isolate->factory();
3126 i::HandleScope scope(isolate);
3127 LocalContext env;
3128
3129
3130 const char* src =
3131 "function f(x) {"
3132 " var a = arguments;"
3133 " function g(i) {"
3134 " ++a[0];"
3135 " };"
3136 " return g;"
3137 " }"
3138 "f(0);";
3139
3140 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3141 i::SNPrintF(program, "%s", src);
3142 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3143 source->PrintOn(stdout);
3144 printf("\n");
3145 i::Zone zone(isolate);
3146 v8::Local<v8::Value> v = CompileRun(src);
3147 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3148 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3149 i::Context* context = f->context();
3150 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3151 avf.Internalize(isolate);
3152
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003153 i::Scope* script_scope =
3154 new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
3155 script_scope->Initialize();
3156 i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
3157 DCHECK(s != script_scope);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003158 const i::AstRawString* name_x = avf.GetOneByteString("x");
3159
3160 // Get result from f's function context (that is g's outer context)
3161 i::Variable* var_x = s->Lookup(name_x);
3162 CHECK(var_x != NULL);
3163 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
3164}
3165
3166
3167TEST(ExportsMaybeAssigned) {
3168 i::FLAG_use_strict = true;
3169 i::FLAG_harmony_scoping = true;
3170 i::FLAG_harmony_modules = true;
3171
3172 i::Isolate* isolate = CcTest::i_isolate();
3173 i::Factory* factory = isolate->factory();
3174 i::HandleScope scope(isolate);
3175 LocalContext env;
3176
3177 const char* src =
3178 "module A {"
3179 " export var x = 1;"
3180 " export function f() { return x };"
3181 " export const y = 2;"
3182 " module B {}"
3183 " export module C {}"
3184 "};"
3185 "A.f";
3186
3187 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
3188 i::SNPrintF(program, "%s", src);
3189 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
3190 source->PrintOn(stdout);
3191 printf("\n");
3192 i::Zone zone(isolate);
3193 v8::Local<v8::Value> v = CompileRun(src);
3194 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
3195 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
3196 i::Context* context = f->context();
3197 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
3198 avf.Internalize(isolate);
3199
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003200 i::Scope* script_scope =
3201 new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
3202 script_scope->Initialize();
3203 i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
3204 DCHECK(s != script_scope);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003205 const i::AstRawString* name_x = avf.GetOneByteString("x");
3206 const i::AstRawString* name_f = avf.GetOneByteString("f");
3207 const i::AstRawString* name_y = avf.GetOneByteString("y");
3208 const i::AstRawString* name_B = avf.GetOneByteString("B");
3209 const i::AstRawString* name_C = avf.GetOneByteString("C");
3210
3211 // Get result from h's function context (that is f's context)
3212 i::Variable* var_x = s->Lookup(name_x);
3213 CHECK(var_x != NULL);
3214 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
3215 i::Variable* var_f = s->Lookup(name_f);
3216 CHECK(var_f != NULL);
3217 CHECK(var_f->maybe_assigned() == i::kMaybeAssigned);
3218 i::Variable* var_y = s->Lookup(name_y);
3219 CHECK(var_y != NULL);
3220 CHECK(var_y->maybe_assigned() == i::kNotAssigned);
3221 i::Variable* var_B = s->Lookup(name_B);
3222 CHECK(var_B != NULL);
3223 CHECK(var_B->maybe_assigned() == i::kNotAssigned);
3224 i::Variable* var_C = s->Lookup(name_C);
3225 CHECK(var_C != NULL);
3226 CHECK(var_C->maybe_assigned() == i::kNotAssigned);
3227}
3228
3229
3230TEST(InnerAssignment) {
3231 i::Isolate* isolate = CcTest::i_isolate();
3232 i::Factory* factory = isolate->factory();
3233 i::HandleScope scope(isolate);
3234 LocalContext env;
3235
3236 const char* prefix = "function f() {";
3237 const char* midfix = " function g() {";
3238 const char* suffix = "}}";
3239 struct { const char* source; bool assigned; bool strict; } outers[] = {
3240 // Actual assignments.
3241 { "var x; var x = 5;", true, false },
3242 { "var x; { var x = 5; }", true, false },
3243 { "'use strict'; let x; x = 6;", true, true },
3244 { "var x = 5; function x() {}", true, false },
3245 // Actual non-assignments.
3246 { "var x;", false, false },
3247 { "var x = 5;", false, false },
3248 { "'use strict'; let x;", false, true },
3249 { "'use strict'; let x = 6;", false, true },
3250 { "'use strict'; var x = 0; { let x = 6; }", false, true },
3251 { "'use strict'; var x = 0; { let x; x = 6; }", false, true },
3252 { "'use strict'; let x = 0; { let x = 6; }", false, true },
3253 { "'use strict'; let x = 0; { let x; x = 6; }", false, true },
3254 { "var x; try {} catch (x) { x = 5; }", false, false },
3255 { "function x() {}", false, false },
3256 // Eval approximation.
3257 { "var x; eval('');", true, false },
3258 { "eval(''); var x;", true, false },
3259 { "'use strict'; let x; eval('');", true, true },
3260 { "'use strict'; eval(''); let x;", true, true },
3261 // Non-assignments not recognized, because the analysis is approximative.
3262 { "var x; var x;", true, false },
3263 { "var x = 5; var x;", true, false },
3264 { "var x; { var x; }", true, false },
3265 { "var x; function x() {}", true, false },
3266 { "function x() {}; var x;", true, false },
3267 { "var x; try {} catch (x) { var x = 5; }", true, false },
3268 };
3269 struct { const char* source; bool assigned; bool with; } inners[] = {
3270 // Actual assignments.
3271 { "x = 1;", true, false },
3272 { "x++;", true, false },
3273 { "++x;", true, false },
3274 { "x--;", true, false },
3275 { "--x;", true, false },
3276 { "{ x = 1; }", true, false },
3277 { "'use strict'; { let x; }; x = 0;", true, false },
3278 { "'use strict'; { const x = 1; }; x = 0;", true, false },
3279 { "'use strict'; { function x() {} }; x = 0;", true, false },
3280 { "with ({}) { x = 1; }", true, true },
3281 { "eval('');", true, false },
3282 { "'use strict'; { let y; eval('') }", true, false },
3283 { "function h() { x = 0; }", true, false },
3284 { "(function() { x = 0; })", true, false },
3285 { "(function() { x = 0; })", true, false },
3286 { "with ({}) (function() { x = 0; })", true, true },
3287 // Actual non-assignments.
3288 { "", false, false },
3289 { "x;", false, false },
3290 { "var x;", false, false },
3291 { "var x = 8;", false, false },
3292 { "var x; x = 8;", false, false },
3293 { "'use strict'; let x;", false, false },
3294 { "'use strict'; let x = 8;", false, false },
3295 { "'use strict'; let x; x = 8;", false, false },
3296 { "'use strict'; const x = 8;", false, false },
3297 { "function x() {}", false, false },
3298 { "function x() { x = 0; }", false, false },
3299 { "function h(x) { x = 0; }", false, false },
3300 { "'use strict'; { let x; x = 0; }", false, false },
3301 { "{ var x; }; x = 0;", false, false },
3302 { "with ({}) {}", false, true },
3303 { "var x; { with ({}) { x = 1; } }", false, true },
3304 { "try {} catch(x) { x = 0; }", false, false },
3305 { "try {} catch(x) { with ({}) { x = 1; } }", false, true },
3306 // Eval approximation.
3307 { "eval('');", true, false },
3308 { "function h() { eval(''); }", true, false },
3309 { "(function() { eval(''); })", true, false },
3310 // Shadowing not recognized because of eval approximation.
3311 { "var x; eval('');", true, false },
3312 { "'use strict'; let x; eval('');", true, false },
3313 { "try {} catch(x) { eval(''); }", true, false },
3314 { "function x() { eval(''); }", true, false },
3315 { "(function(x) { eval(''); })", true, false },
3316 };
3317
3318 // Used to trigger lazy compilation of function
3319 int comment_len = 2048;
3320 i::ScopedVector<char> comment(comment_len + 1);
3321 i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0);
3322 int prefix_len = Utf8LengthHelper(prefix);
3323 int midfix_len = Utf8LengthHelper(midfix);
3324 int suffix_len = Utf8LengthHelper(suffix);
3325 for (unsigned i = 0; i < arraysize(outers); ++i) {
3326 const char* outer = outers[i].source;
3327 int outer_len = Utf8LengthHelper(outer);
3328 for (unsigned j = 0; j < arraysize(inners); ++j) {
3329 for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) {
3330 for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) {
3331 if (outers[i].strict && inners[j].with) continue;
3332 const char* inner = inners[j].source;
3333 int inner_len = Utf8LengthHelper(inner);
3334
3335 int outer_comment_len = outer_lazy ? comment_len : 0;
3336 int inner_comment_len = inner_lazy ? comment_len : 0;
3337 const char* outer_comment = outer_lazy ? comment.start() : "";
3338 const char* inner_comment = inner_lazy ? comment.start() : "";
3339 int len = prefix_len + outer_comment_len + outer_len + midfix_len +
3340 inner_comment_len + inner_len + suffix_len;
3341 i::ScopedVector<char> program(len + 1);
3342
3343 i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer,
3344 midfix, inner_comment, inner, suffix);
3345 i::Handle<i::String> source =
3346 factory->InternalizeUtf8String(program.start());
3347 source->PrintOn(stdout);
3348 printf("\n");
3349
3350 i::Handle<i::Script> script = factory->NewScript(source);
3351 i::CompilationInfoWithZone info(script);
3352 i::Parser::ParseInfo parse_info = {
3353 isolate->stack_guard()->real_climit(),
3354 isolate->heap()->HashSeed(), isolate->unicode_cache()};
3355 i::Parser parser(&info, &parse_info);
3356 parser.set_allow_harmony_scoping(true);
3357 CHECK(parser.Parse());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003358 CHECK(i::Compiler::Analyze(&info));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003359 CHECK(info.function() != NULL);
3360
3361 i::Scope* scope = info.function()->scope();
3362 CHECK_EQ(scope->inner_scopes()->length(), 1);
3363 i::Scope* inner_scope = scope->inner_scopes()->at(0);
3364 const i::AstRawString* var_name =
3365 info.ast_value_factory()->GetOneByteString("x");
3366 i::Variable* var = inner_scope->Lookup(var_name);
3367 bool expected = outers[i].assigned || inners[j].assigned;
3368 CHECK(var != NULL);
3369 CHECK(var->is_used() || !expected);
3370 CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected);
3371 }
3372 }
3373 }
3374 }
3375}
3376
3377namespace {
3378
3379int* global_use_counts = NULL;
3380
3381void MockUseCounterCallback(v8::Isolate* isolate,
3382 v8::Isolate::UseCounterFeature feature) {
3383 ++global_use_counts[feature];
3384}
3385
3386}
3387
3388
3389TEST(UseAsmUseCount) {
3390 i::Isolate* isolate = CcTest::i_isolate();
3391 i::HandleScope scope(isolate);
3392 LocalContext env;
3393 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3394 global_use_counts = use_counts;
3395 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3396 CompileRun("\"use asm\";\n"
3397 "var foo = 1;\n"
3398 "\"use asm\";\n" // Only the first one counts.
3399 "function bar() { \"use asm\"; var baz = 1; }");
3400 CHECK_EQ(2, use_counts[v8::Isolate::kUseAsm]);
3401}
3402
3403
3404TEST(ErrorsArrowFunctions) {
3405 // Tests that parser and preparser generate the same kind of errors
3406 // on invalid arrow function syntax.
3407 const char* context_data[][2] = {
3408 {"", ";"},
3409 {"v = ", ";"},
3410 {"bar ? (", ") : baz;"},
3411 {"bar ? baz : (", ");"},
3412 {"bar[", "];"},
3413 {"bar, ", ";"},
3414 {"", ", bar;"},
3415 {NULL, NULL}
3416 };
3417
3418 const char* statement_data[] = {
3419 "=> 0",
3420 "=>",
3421 "() =>",
3422 "=> {}",
3423 ") => {}",
3424 ", => {}",
3425 "(,) => {}",
3426 "return => {}",
3427 "() => {'value': 42}",
3428
3429 // Check that the early return introduced in ParsePrimaryExpression
3430 // does not accept stray closing parentheses.
3431 ")",
3432 ") => 0",
3433 "foo[()]",
3434 "()",
3435
3436 // Parameter lists with extra parens should be recognized as errors.
3437 "(()) => 0",
3438 "((x)) => 0",
3439 "((x, y)) => 0",
3440 "(x, (y)) => 0",
3441 "((x, y, z)) => 0",
3442 "(x, (y, z)) => 0",
3443 "((x, y), z) => 0",
3444
3445 // Parameter lists are always validated as strict, so those are errors.
3446 "eval => {}",
3447 "arguments => {}",
3448 "yield => {}",
3449 "interface => {}",
3450 "(eval) => {}",
3451 "(arguments) => {}",
3452 "(yield) => {}",
3453 "(interface) => {}",
3454 "(eval, bar) => {}",
3455 "(bar, eval) => {}",
3456 "(bar, arguments) => {}",
3457 "(bar, yield) => {}",
3458 "(bar, interface) => {}",
3459 // TODO(aperez): Detecting duplicates does not work in PreParser.
3460 // "(bar, bar) => {}",
3461
3462 // The parameter list is parsed as an expression, but only
3463 // a comma-separated list of identifier is valid.
3464 "32 => {}",
3465 "(32) => {}",
3466 "(a, 32) => {}",
3467 "if => {}",
3468 "(if) => {}",
3469 "(a, if) => {}",
3470 "a + b => {}",
3471 "(a + b) => {}",
3472 "(a + b, c) => {}",
3473 "(a, b - c) => {}",
3474 "\"a\" => {}",
3475 "(\"a\") => {}",
3476 "(\"a\", b) => {}",
3477 "(a, \"b\") => {}",
3478 "-a => {}",
3479 "(-a) => {}",
3480 "(-a, b) => {}",
3481 "(a, -b) => {}",
3482 "{} => {}",
3483 "({}) => {}",
3484 "(a, {}) => {}",
3485 "({}, a) => {}",
3486 "a++ => {}",
3487 "(a++) => {}",
3488 "(a++, b) => {}",
3489 "(a, b++) => {}",
3490 "[] => {}",
3491 "([]) => {}",
3492 "(a, []) => {}",
3493 "([], a) => {}",
3494 "(a = b) => {}",
3495 "(a = b, c) => {}",
3496 "(a, b = c) => {}",
3497 "(foo ? bar : baz) => {}",
3498 "(a, foo ? bar : baz) => {}",
3499 "(foo ? bar : baz, a) => {}",
3500 NULL
3501 };
3502
3503 // The test is quite slow, so run it with a reduced set of flags.
3504 static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003505 static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003506 RunParserSyncTest(context_data, statement_data, kError, flags,
3507 arraysize(flags), always_flags, arraysize(always_flags));
3508}
3509
3510
3511TEST(NoErrorsArrowFunctions) {
3512 // Tests that parser and preparser accept valid arrow functions syntax.
3513 const char* context_data[][2] = {
3514 {"", ";"},
3515 {"bar ? (", ") : baz;"},
3516 {"bar ? baz : (", ");"},
3517 {"bar, ", ";"},
3518 {"", ", bar;"},
3519 {NULL, NULL}
3520 };
3521
3522 const char* statement_data[] = {
3523 "() => {}",
3524 "() => { return 42 }",
3525 "x => { return x; }",
3526 "(x) => { return x; }",
3527 "(x, y) => { return x + y; }",
3528 "(x, y, z) => { return x + y + z; }",
3529 "(x, y) => { x.a = y; }",
3530 "() => 42",
3531 "x => x",
3532 "x => x * x",
3533 "(x) => x",
3534 "(x) => x * x",
3535 "(x, y) => x + y",
3536 "(x, y, z) => x, y, z",
3537 "(x, y) => x.a = y",
3538 "() => ({'value': 42})",
3539 "x => y => x + y",
3540 "(x, y) => (u, v) => x*u + y*v",
3541 "(x, y) => z => z * (x + y)",
3542 "x => (y, z) => z * (x + y)",
3543
3544 // Those are comma-separated expressions, with arrow functions as items.
3545 // They stress the code for validating arrow function parameter lists.
3546 "a, b => 0",
3547 "a, b, (c, d) => 0",
3548 "(a, b, (c, d) => 0)",
3549 "(a, b) => 0, (c, d) => 1",
3550 "(a, b => {}, a => a + 1)",
3551 "((a, b) => {}, (a => a + 1))",
3552 "(a, (a, (b, c) => 0))",
3553
3554 // Arrow has more precedence, this is the same as: foo ? bar : (baz = {})
3555 "foo ? bar : baz => {}",
3556 NULL
3557 };
3558
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003559 static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003560 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3561 always_flags, arraysize(always_flags));
3562}
3563
3564
3565TEST(NoErrorsSuper) {
3566 // Tests that parser and preparser accept 'super' keyword in right places.
3567 const char* context_data[][2] = {{"", ";"},
3568 {"k = ", ";"},
3569 {"foo(", ");"},
3570 {NULL, NULL}};
3571
3572 const char* statement_data[] = {
3573 "super.x",
3574 "super[27]",
3575 "new super",
3576 "new super()",
3577 "new super(12, 45)",
3578 "new new super",
3579 "new new super()",
3580 "new new super()()",
3581 "z.super", // Ok, property lookup.
3582 NULL};
3583
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003584 static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003585 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3586 always_flags, arraysize(always_flags));
3587}
3588
3589
3590TEST(ErrorsSuper) {
3591 // Tests that parser and preparser generate same errors for 'super'.
3592 const char* context_data[][2] = {{"", ";"},
3593 {"k = ", ";"},
3594 {"foo(", ");"},
3595 {NULL, NULL}};
3596
3597 const char* statement_data[] = {
3598 "super = x",
3599 "y = super",
3600 "f(super)",
3601 NULL};
3602
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003603 static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003604 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
3605 always_flags, arraysize(always_flags));
3606}
3607
3608
3609TEST(NoErrorsMethodDefinition) {
3610 const char* context_data[][2] = {{"({", "});"},
3611 {"'use strict'; ({", "});"},
3612 {"({*", "});"},
3613 {"'use strict'; ({*", "});"},
3614 {NULL, NULL}};
3615
3616 const char* object_literal_body_data[] = {
3617 "m() {}",
3618 "m(x) { return x; }",
3619 "m(x, y) {}, n() {}",
3620 "set(x, y) {}",
3621 "get(x, y) {}",
3622 NULL
3623 };
3624
3625 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3626 RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0,
3627 always_flags, arraysize(always_flags));
3628}
3629
3630
3631TEST(MethodDefinitionNames) {
3632 const char* context_data[][2] = {{"({", "(x, y) {}});"},
3633 {"'use strict'; ({", "(x, y) {}});"},
3634 {"({*", "(x, y) {}});"},
3635 {"'use strict'; ({*", "(x, y) {}});"},
3636 {NULL, NULL}};
3637
3638 const char* name_data[] = {
3639 "m",
3640 "'m'",
3641 "\"m\"",
3642 "\"m n\"",
3643 "true",
3644 "false",
3645 "null",
3646 "0",
3647 "1.2",
3648 "1e1",
3649 "1E1",
3650 "1e+1",
3651 "1e-1",
3652
3653 // Keywords
3654 "async",
3655 "await",
3656 "break",
3657 "case",
3658 "catch",
3659 "class",
3660 "const",
3661 "continue",
3662 "debugger",
3663 "default",
3664 "delete",
3665 "do",
3666 "else",
3667 "enum",
3668 "export",
3669 "extends",
3670 "finally",
3671 "for",
3672 "function",
3673 "if",
3674 "implements",
3675 "import",
3676 "in",
3677 "instanceof",
3678 "interface",
3679 "let",
3680 "new",
3681 "package",
3682 "private",
3683 "protected",
3684 "public",
3685 "return",
3686 "static",
3687 "super",
3688 "switch",
3689 "this",
3690 "throw",
3691 "try",
3692 "typeof",
3693 "var",
3694 "void",
3695 "while",
3696 "with",
3697 "yield",
3698 NULL
3699 };
3700
3701 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3702 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
3703 always_flags, arraysize(always_flags));
3704}
3705
3706
3707TEST(MethodDefinitionStrictFormalParamereters) {
3708 const char* context_data[][2] = {{"({method(", "){}});"},
3709 {"'use strict'; ({method(", "){}});"},
3710 {"({*method(", "){}});"},
3711 {"'use strict'; ({*method(", "){}});"},
3712 {NULL, NULL}};
3713
3714 const char* params_data[] = {
3715 "x, x",
3716 "x, y, x",
3717 "eval",
3718 "arguments",
3719 "var",
3720 "const",
3721 NULL
3722 };
3723
3724 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3725 RunParserSyncTest(context_data, params_data, kError, NULL, 0,
3726 always_flags, arraysize(always_flags));
3727}
3728
3729
3730TEST(MethodDefinitionDuplicateProperty) {
3731 // Duplicate properties are allowed in ES6 but we haven't removed that check
3732 // yet.
3733 const char* context_data[][2] = {{"'use strict'; ({", "});"},
3734 {NULL, NULL}};
3735
3736 const char* params_data[] = {
3737 "x: 1, x() {}",
3738 "x() {}, x: 1",
3739 "x() {}, get x() {}",
3740 "x() {}, set x(_) {}",
3741 "x() {}, x() {}",
3742 "x() {}, y() {}, x() {}",
3743 "x() {}, \"x\"() {}",
3744 "x() {}, 'x'() {}",
3745 "0() {}, '0'() {}",
3746 "1.0() {}, 1: 1",
3747
3748 "x: 1, *x() {}",
3749 "*x() {}, x: 1",
3750 "*x() {}, get x() {}",
3751 "*x() {}, set x(_) {}",
3752 "*x() {}, *x() {}",
3753 "*x() {}, y() {}, *x() {}",
3754 "*x() {}, *\"x\"() {}",
3755 "*x() {}, *'x'() {}",
3756 "*0() {}, *'0'() {}",
3757 "*1.0() {}, 1: 1",
3758
3759 NULL
3760 };
3761
3762 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3763 RunParserSyncTest(context_data, params_data, kError, NULL, 0,
3764 always_flags, arraysize(always_flags));
3765}
3766
3767
3768TEST(ClassExpressionNoErrors) {
3769 const char* context_data[][2] = {{"(", ");"},
3770 {"var C = ", ";"},
3771 {"bar, ", ";"},
3772 {NULL, NULL}};
3773 const char* class_data[] = {
3774 "class {}",
3775 "class name {}",
3776 "class extends F {}",
3777 "class name extends F {}",
3778 "class extends (F, G) {}",
3779 "class name extends (F, G) {}",
3780 "class extends class {} {}",
3781 "class name extends class {} {}",
3782 "class extends class base {} {}",
3783 "class name extends class base {} {}",
3784 NULL};
3785
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003786 static const ParserFlag always_flags[] = {
3787 kAllowHarmonyClasses, kAllowHarmonySloppy};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003788 RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
3789 always_flags, arraysize(always_flags));
3790}
3791
3792
3793TEST(ClassDeclarationNoErrors) {
3794 const char* context_data[][2] = {{"", ""},
3795 {"{", "}"},
3796 {"if (true) {", "}"},
3797 {NULL, NULL}};
3798 const char* statement_data[] = {
3799 "class name {}",
3800 "class name extends F {}",
3801 "class name extends (F, G) {}",
3802 "class name extends class {} {}",
3803 "class name extends class base {} {}",
3804 NULL};
3805
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003806 static const ParserFlag always_flags[] = {
3807 kAllowHarmonyClasses, kAllowHarmonySloppy};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003808 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3809 always_flags, arraysize(always_flags));
3810}
3811
3812
3813TEST(ClassBodyNoErrors) {
3814 // Tests that parser and preparser accept valid class syntax.
3815 const char* context_data[][2] = {{"(class {", "});"},
3816 {"(class extends Base {", "});"},
3817 {"class C {", "}"},
3818 {"class C extends Base {", "}"},
3819 {NULL, NULL}};
3820 const char* class_body_data[] = {
3821 ";",
3822 ";;",
3823 "m() {}",
3824 "m() {};",
3825 "; m() {}",
3826 "m() {}; n(x) {}",
3827 "get x() {}",
3828 "set x(v) {}",
3829 "get() {}",
3830 "set() {}",
3831 "*g() {}",
3832 "*g() {};",
3833 "; *g() {}",
3834 "*g() {}; *h(x) {}",
3835 "static() {}",
3836 "static m() {}",
3837 "static get x() {}",
3838 "static set x(v) {}",
3839 "static get() {}",
3840 "static set() {}",
3841 "static static() {}",
3842 "static get static() {}",
3843 "static set static(v) {}",
3844 "*static() {}",
3845 "*get() {}",
3846 "*set() {}",
3847 "static *g() {}",
3848 NULL};
3849
3850 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003851 kAllowHarmonyClasses,
3852 kAllowHarmonyObjectLiterals,
3853 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003854 };
3855 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
3856 always_flags, arraysize(always_flags));
3857}
3858
3859
3860TEST(ClassPropertyNameNoErrors) {
3861 const char* context_data[][2] = {{"(class {", "() {}});"},
3862 {"(class { get ", "() {}});"},
3863 {"(class { set ", "(v) {}});"},
3864 {"(class { static ", "() {}});"},
3865 {"(class { static get ", "() {}});"},
3866 {"(class { static set ", "(v) {}});"},
3867 {"(class { *", "() {}});"},
3868 {"(class { static *", "() {}});"},
3869 {"class C {", "() {}}"},
3870 {"class C { get ", "() {}}"},
3871 {"class C { set ", "(v) {}}"},
3872 {"class C { static ", "() {}}"},
3873 {"class C { static get ", "() {}}"},
3874 {"class C { static set ", "(v) {}}"},
3875 {"class C { *", "() {}}"},
3876 {"class C { static *", "() {}}"},
3877 {NULL, NULL}};
3878 const char* name_data[] = {
3879 "42",
3880 "42.5",
3881 "42e2",
3882 "42e+2",
3883 "42e-2",
3884 "null",
3885 "false",
3886 "true",
3887 "'str'",
3888 "\"str\"",
3889 "static",
3890 "get",
3891 "set",
3892 "var",
3893 "const",
3894 "let",
3895 "this",
3896 "class",
3897 "function",
3898 "yield",
3899 "if",
3900 "else",
3901 "for",
3902 "while",
3903 "do",
3904 "try",
3905 "catch",
3906 "finally",
3907 NULL};
3908
3909 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003910 kAllowHarmonyClasses,
3911 kAllowHarmonyObjectLiterals,
3912 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003913 };
3914 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
3915 always_flags, arraysize(always_flags));
3916}
3917
3918
3919TEST(ClassExpressionErrors) {
3920 const char* context_data[][2] = {{"(", ");"},
3921 {"var C = ", ";"},
3922 {"bar, ", ";"},
3923 {NULL, NULL}};
3924 const char* class_data[] = {
3925 "class",
3926 "class name",
3927 "class name extends",
3928 "class extends",
3929 "class {",
3930 "class { m }",
3931 "class { m; n }",
3932 "class { m: 1 }",
3933 "class { m(); n() }",
3934 "class { get m }",
3935 "class { get m() }",
3936 "class { get m() { }",
3937 "class { set m() {} }", // Missing required parameter.
3938 "class { m() {}, n() {} }", // No commas allowed.
3939 NULL};
3940
3941 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003942 kAllowHarmonyClasses,
3943 kAllowHarmonyObjectLiterals,
3944 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003945 };
3946 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
3947 always_flags, arraysize(always_flags));
3948}
3949
3950
3951TEST(ClassDeclarationErrors) {
3952 const char* context_data[][2] = {{"", ""},
3953 {"{", "}"},
3954 {"if (true) {", "}"},
3955 {NULL, NULL}};
3956 const char* class_data[] = {
3957 "class",
3958 "class name",
3959 "class name extends",
3960 "class extends",
3961 "class name {",
3962 "class name { m }",
3963 "class name { m; n }",
3964 "class name { m: 1 }",
3965 "class name { m(); n() }",
3966 "class name { get x }",
3967 "class name { get x() }",
3968 "class name { set x() {) }", // missing required param
3969 "class {}", // Name is required for declaration
3970 "class extends base {}",
3971 "class name { *",
3972 "class name { * }",
3973 "class name { *; }",
3974 "class name { *get x() {} }",
3975 "class name { *set x(_) {} }",
3976 "class name { *static m() {} }",
3977 NULL};
3978
3979 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003980 kAllowHarmonyClasses,
3981 kAllowHarmonyNumericLiterals,
3982 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003983 };
3984 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
3985 always_flags, arraysize(always_flags));
3986}
3987
3988
3989TEST(ClassNameErrors) {
3990 const char* context_data[][2] = {{"class ", "{}"},
3991 {"(class ", "{});"},
3992 {"'use strict'; class ", "{}"},
3993 {"'use strict'; (class ", "{});"},
3994 {NULL, NULL}};
3995 const char* class_name[] = {
3996 "arguments",
3997 "eval",
3998 "implements",
3999 "interface",
4000 "let",
4001 "package",
4002 "private",
4003 "protected",
4004 "public",
4005 "static",
4006 "var",
4007 "yield",
4008 NULL};
4009
4010 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004011 kAllowHarmonyClasses,
4012 kAllowHarmonyObjectLiterals,
4013 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004014 };
4015 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
4016 always_flags, arraysize(always_flags));
4017}
4018
4019
4020TEST(ClassGetterParamNameErrors) {
4021 const char* context_data[][2] = {
4022 {"class C { get name(", ") {} }"},
4023 {"(class { get name(", ") {} });"},
4024 {"'use strict'; class C { get name(", ") {} }"},
4025 {"'use strict'; (class { get name(", ") {} })"},
4026 {NULL, NULL}
4027 };
4028
4029 const char* class_name[] = {
4030 "arguments",
4031 "eval",
4032 "implements",
4033 "interface",
4034 "let",
4035 "package",
4036 "private",
4037 "protected",
4038 "public",
4039 "static",
4040 "var",
4041 "yield",
4042 NULL};
4043
4044 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004045 kAllowHarmonyClasses,
4046 kAllowHarmonyObjectLiterals,
4047 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004048 };
4049 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
4050 always_flags, arraysize(always_flags));
4051}
4052
4053
4054TEST(ClassStaticPrototypeErrors) {
4055 const char* context_data[][2] = {{"class C {", "}"},
4056 {"(class {", "});"},
4057 {NULL, NULL}};
4058
4059 const char* class_body_data[] = {
4060 "static prototype() {}",
4061 "static get prototype() {}",
4062 "static set prototype(_) {}",
4063 "static *prototype() {}",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004064 "static 'prototype'() {}",
4065 "static *'prototype'() {}",
4066 "static prot\\u006ftype() {}",
4067 "static 'prot\\u006ftype'() {}",
4068 "static get 'prot\\u006ftype'() {}",
4069 "static set 'prot\\u006ftype'(_) {}",
4070 "static *'prot\\u006ftype'() {}",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004071 NULL};
4072
4073 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004074 kAllowHarmonyClasses,
4075 kAllowHarmonyObjectLiterals,
4076 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004077 };
4078 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4079 always_flags, arraysize(always_flags));
4080}
4081
4082
4083TEST(ClassSpecialConstructorErrors) {
4084 const char* context_data[][2] = {{"class C {", "}"},
4085 {"(class {", "});"},
4086 {NULL, NULL}};
4087
4088 const char* class_body_data[] = {
4089 "get constructor() {}",
4090 "get constructor(_) {}",
4091 "*constructor() {}",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004092 "get 'constructor'() {}",
4093 "*'constructor'() {}",
4094 "get c\\u006fnstructor() {}",
4095 "*c\\u006fnstructor() {}",
4096 "get 'c\\u006fnstructor'() {}",
4097 "get 'c\\u006fnstructor'(_) {}",
4098 "*'c\\u006fnstructor'() {}",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004099 NULL};
4100
4101 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004102 kAllowHarmonyClasses,
4103 kAllowHarmonyObjectLiterals,
4104 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004105 };
4106 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4107 always_flags, arraysize(always_flags));
4108}
4109
4110
4111TEST(ClassConstructorNoErrors) {
4112 const char* context_data[][2] = {{"class C {", "}"},
4113 {"(class {", "});"},
4114 {NULL, NULL}};
4115
4116 const char* class_body_data[] = {
4117 "constructor() {}",
4118 "static constructor() {}",
4119 "static get constructor() {}",
4120 "static set constructor(_) {}",
4121 "static *constructor() {}",
4122 NULL};
4123
4124 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004125 kAllowHarmonyClasses,
4126 kAllowHarmonyObjectLiterals,
4127 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004128 };
4129 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4130 always_flags, arraysize(always_flags));
4131}
4132
4133
4134TEST(ClassMultipleConstructorErrors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004135 const char* context_data[][2] = {{"class C {", "}"},
4136 {"(class {", "});"},
4137 {NULL, NULL}};
4138
4139 const char* class_body_data[] = {
4140 "constructor() {}; constructor() {}",
4141 NULL};
4142
4143 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004144 kAllowHarmonyClasses,
4145 kAllowHarmonyObjectLiterals,
4146 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004147 };
4148 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4149 always_flags, arraysize(always_flags));
4150}
4151
4152
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004153TEST(ClassMultiplePropertyNamesNoErrors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004154 const char* context_data[][2] = {{"class C {", "}"},
4155 {"(class {", "});"},
4156 {NULL, NULL}};
4157
4158 const char* class_body_data[] = {
4159 "constructor() {}; static constructor() {}",
4160 "m() {}; static m() {}",
4161 "m() {}; m() {}",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004162 "static m() {}; static m() {}",
4163 "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004164 NULL};
4165
4166 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004167 kAllowHarmonyClasses,
4168 kAllowHarmonyObjectLiterals,
4169 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004170 };
4171 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
4172 always_flags, arraysize(always_flags));
4173}
4174
4175
4176TEST(ClassesAreStrictErrors) {
4177 const char* context_data[][2] = {{"", ""},
4178 {"(", ");"},
4179 {NULL, NULL}};
4180
4181 const char* class_body_data[] = {
4182 "class C { method() { with ({}) {} } }",
4183 "class C extends function() { with ({}) {} } {}",
4184 "class C { *method() { with ({}) {} } }",
4185 NULL};
4186
4187 static const ParserFlag always_flags[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004188 kAllowHarmonyClasses,
4189 kAllowHarmonyObjectLiterals,
4190 kAllowHarmonySloppy
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004191 };
4192 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
4193 always_flags, arraysize(always_flags));
Ben Murdoch692be652012-01-10 18:47:50 +00004194}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004195
4196
4197TEST(ObjectLiteralPropertyShorthandKeywordsError) {
4198 const char* context_data[][2] = {{"({", "});"},
4199 {"'use strict'; ({", "});"},
4200 {NULL, NULL}};
4201
4202 const char* name_data[] = {
4203 "break",
4204 "case",
4205 "catch",
4206 "class",
4207 "const",
4208 "continue",
4209 "debugger",
4210 "default",
4211 "delete",
4212 "do",
4213 "else",
4214 "enum",
4215 "export",
4216 "extends",
4217 "false",
4218 "finally",
4219 "for",
4220 "function",
4221 "if",
4222 "import",
4223 "in",
4224 "instanceof",
4225 "new",
4226 "null",
4227 "return",
4228 "super",
4229 "switch",
4230 "this",
4231 "throw",
4232 "true",
4233 "try",
4234 "typeof",
4235 "var",
4236 "void",
4237 "while",
4238 "with",
4239 NULL
4240 };
4241
4242 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4243 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4244 always_flags, arraysize(always_flags));
4245}
4246
4247
4248TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
4249 const char* context_data[][2] = {{"({", "});"},
4250 {NULL, NULL}};
4251
4252 const char* name_data[] = {
4253 "implements",
4254 "interface",
4255 "let",
4256 "package",
4257 "private",
4258 "protected",
4259 "public",
4260 "static",
4261 "yield",
4262 NULL
4263 };
4264
4265 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4266 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
4267 always_flags, arraysize(always_flags));
4268
4269 const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
4270 {NULL, NULL}};
4271 RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0,
4272 always_flags, arraysize(always_flags));
4273}
4274
4275
4276TEST(ObjectLiteralPropertyShorthandError) {
4277 const char* context_data[][2] = {{"({", "});"},
4278 {"'use strict'; ({", "});"},
4279 {NULL, NULL}};
4280
4281 const char* name_data[] = {
4282 "1",
4283 "1.2",
4284 "0",
4285 "0.1",
4286 "1.0",
4287 "1e1",
4288 "0x1",
4289 "\"s\"",
4290 "'s'",
4291 NULL
4292 };
4293
4294 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4295 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4296 always_flags, arraysize(always_flags));
4297}
4298
4299
4300TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
4301 const char* context_data[][2] = {{"", ""},
4302 {NULL, NULL}};
4303
4304 const char* name_data[] = {
4305 "function* g() { ({yield}); }",
4306 NULL
4307 };
4308
4309 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
4310 RunParserSyncTest(context_data, name_data, kError, NULL, 0,
4311 always_flags, arraysize(always_flags));
4312}
4313
4314
4315TEST(ConstParsingInForIn) {
4316 const char* context_data[][2] = {{"'use strict';", ""},
4317 {"function foo(){ 'use strict';", "}"},
4318 {NULL, NULL}};
4319
4320 const char* data[] = {
4321 "for(const x = 1; ; ) {}",
4322 "for(const x = 1, y = 2;;){}",
4323 "for(const x in [1,2,3]) {}",
4324 "for(const x of [1,2,3]) {}",
4325 NULL};
4326 static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
4327 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4328 arraysize(always_flags));
4329}
4330
4331
4332TEST(ConstParsingInForInError) {
4333 const char* context_data[][2] = {{"'use strict';", ""},
4334 {"function foo(){ 'use strict';", "}"},
4335 {NULL, NULL}};
4336
4337 const char* data[] = {
4338 "for(const x,y = 1; ; ) {}",
4339 "for(const x = 4 in [1,2,3]) {}",
4340 "for(const x = 4, y in [1,2,3]) {}",
4341 "for(const x = 4 of [1,2,3]) {}",
4342 "for(const x = 4, y of [1,2,3]) {}",
4343 "for(const x = 1, y = 2 in []) {}",
4344 "for(const x,y in []) {}",
4345 "for(const x = 1, y = 2 of []) {}",
4346 "for(const x,y of []) {}",
4347 NULL};
4348 static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
4349 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4350 arraysize(always_flags));
4351}
4352
4353
4354TEST(InvalidUnicodeEscapes) {
4355 const char* context_data[][2] = {{"", ""},
4356 {"'use strict';", ""},
4357 {NULL, NULL}};
4358 const char* data[] = {
4359 "var foob\\u123r = 0;",
4360 "var \\u123roo = 0;",
4361 "\"foob\\u123rr\"",
4362 // No escapes allowed in regexp flags
4363 "/regex/\\u0069g",
4364 "/regex/\\u006g",
4365 // Braces gone wrong
4366 "var foob\\u{c481r = 0;",
4367 "var foob\\uc481}r = 0;",
4368 "var \\u{0052oo = 0;",
4369 "var \\u0052}oo = 0;",
4370 "\"foob\\u{c481r\"",
4371 "var foob\\u{}ar = 0;",
4372 // Too high value for the unicode escape
4373 "\"\\u{110000}\"",
4374 // Not an unicode escape
4375 "var foob\\v1234r = 0;",
4376 "var foob\\U1234r = 0;",
4377 "var foob\\v{1234}r = 0;",
4378 "var foob\\U{1234}r = 0;",
4379 NULL};
4380 static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
4381 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4382 arraysize(always_flags));
4383}
4384
4385
4386TEST(UnicodeEscapes) {
4387 const char* context_data[][2] = {{"", ""},
4388 {"'use strict';", ""},
4389 {NULL, NULL}};
4390 const char* data[] = {
4391 // Identifier starting with escape
4392 "var \\u0052oo = 0;",
4393 "var \\u{0052}oo = 0;",
4394 "var \\u{52}oo = 0;",
4395 "var \\u{00000000052}oo = 0;",
4396 // Identifier with an escape but not starting with an escape
4397 "var foob\\uc481r = 0;",
4398 "var foob\\u{c481}r = 0;",
4399 // String with an escape
4400 "\"foob\\uc481r\"",
4401 "\"foob\\{uc481}r\"",
4402 // This character is a valid unicode character, representable as a surrogate
4403 // pair, not representable as 4 hex digits.
4404 "\"foo\\u{10e6d}\"",
4405 // Max value for the unicode escape
4406 "\"\\u{10ffff}\"",
4407 NULL};
4408 static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
4409 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4410 arraysize(always_flags));
4411}
4412
4413
4414TEST(ScanTemplateLiterals) {
4415 const char* context_data[][2] = {{"'use strict';", ""},
4416 {"function foo(){ 'use strict';"
4417 " var a, b, c; return ", "}"},
4418 {NULL, NULL}};
4419
4420 const char* data[] = {
4421 "``",
4422 "`no-subst-template`",
4423 "`template-head${a}`",
4424 "`${a}`",
4425 "`${a}template-tail`",
4426 "`template-head${a}template-tail`",
4427 "`${a}${b}${c}`",
4428 "`a${a}b${b}c${c}`",
4429 "`${a}a${b}b${c}c`",
4430 "`foo\n\nbar\r\nbaz`",
4431 "`foo\n\n${ bar }\r\nbaz`",
4432 "`foo${a /* comment */}`",
4433 "`foo${a // comment\n}`",
4434 "`foo${a \n}`",
4435 "`foo${a \r\n}`",
4436 "`foo${a \r}`",
4437 "`foo${/* comment */ a}`",
4438 "`foo${// comment\na}`",
4439 "`foo${\n a}`",
4440 "`foo${\r\n a}`",
4441 "`foo${\r a}`",
4442 "`foo${'a' in a}`",
4443 NULL};
4444 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4445 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4446 arraysize(always_flags));
4447}
4448
4449
4450TEST(ScanTaggedTemplateLiterals) {
4451 const char* context_data[][2] = {{"'use strict';", ""},
4452 {"function foo(){ 'use strict';"
4453 " function tag() {}"
4454 " var a, b, c; return ", "}"},
4455 {NULL, NULL}};
4456
4457 const char* data[] = {
4458 "tag ``",
4459 "tag `no-subst-template`",
4460 "tag`template-head${a}`",
4461 "tag `${a}`",
4462 "tag `${a}template-tail`",
4463 "tag `template-head${a}template-tail`",
4464 "tag\n`${a}${b}${c}`",
4465 "tag\r\n`a${a}b${b}c${c}`",
4466 "tag `${a}a${b}b${c}c`",
4467 "tag\t`foo\n\nbar\r\nbaz`",
4468 "tag\r`foo\n\n${ bar }\r\nbaz`",
4469 "tag`foo${a /* comment */}`",
4470 "tag`foo${a // comment\n}`",
4471 "tag`foo${a \n}`",
4472 "tag`foo${a \r\n}`",
4473 "tag`foo${a \r}`",
4474 "tag`foo${/* comment */ a}`",
4475 "tag`foo${// comment\na}`",
4476 "tag`foo${\n a}`",
4477 "tag`foo${\r\n a}`",
4478 "tag`foo${\r a}`",
4479 "tag`foo${'a' in a}`",
4480 NULL};
4481 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4482 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4483 arraysize(always_flags));
4484}
4485
4486
4487TEST(TemplateMaterializedLiterals) {
4488 const char* context_data[][2] = {
4489 {
4490 "'use strict';\n"
4491 "function tag() {}\n"
4492 "var a, b, c;\n"
4493 "(", ")"
4494 },
4495 {NULL, NULL}
4496 };
4497
4498 const char* data[] = {
4499 "tag``",
4500 "tag`a`",
4501 "tag`a${1}b`",
4502 "tag`a${1}b${2}c`",
4503 "``",
4504 "`a`",
4505 "`a${1}b`",
4506 "`a${1}b${2}c`",
4507 NULL
4508 };
4509
4510 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4511 RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
4512 arraysize(always_flags));
4513}
4514
4515
4516TEST(ScanUnterminatedTemplateLiterals) {
4517 const char* context_data[][2] = {{"'use strict';", ""},
4518 {"function foo(){ 'use strict';"
4519 " var a, b, c; return ", "}"},
4520 {NULL, NULL}};
4521
4522 const char* data[] = {
4523 "`no-subst-template",
4524 "`template-head${a}",
4525 "`${a}template-tail",
4526 "`template-head${a}template-tail",
4527 "`${a}${b}${c}",
4528 "`a${a}b${b}c${c}",
4529 "`${a}a${b}b${c}c",
4530 "`foo\n\nbar\r\nbaz",
4531 "`foo\n\n${ bar }\r\nbaz",
4532 "`foo${a /* comment } */`",
4533 "`foo${a /* comment } `*/",
4534 "`foo${a // comment}`",
4535 "`foo${a \n`",
4536 "`foo${a \r\n`",
4537 "`foo${a \r`",
4538 "`foo${/* comment */ a`",
4539 "`foo${// commenta}`",
4540 "`foo${\n a`",
4541 "`foo${\r\n a`",
4542 "`foo${\r a`",
4543 "`foo${fn(}`",
4544 "`foo${1 if}`",
4545 NULL};
4546 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4547 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4548 arraysize(always_flags));
4549}
4550
4551
4552TEST(TemplateLiteralsIllegalTokens) {
4553 const char* context_data[][2] = {{"'use strict';", ""},
4554 {"function foo(){ 'use strict';"
4555 " var a, b, c; return ", "}"},
4556 {NULL, NULL}};
4557 const char* data[] = {
4558 "`hello\\x`",
4559 "`hello\\x${1}`",
4560 "`hello${1}\\x`",
4561 "`hello${1}\\x${2}`",
4562 "`hello\\x\n`",
4563 "`hello\\x\n${1}`",
4564 "`hello${1}\\x\n`",
4565 "`hello${1}\\x\n${2}`",
4566 NULL};
4567
4568 static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
4569 RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
4570 arraysize(always_flags));
4571}
4572
4573
4574TEST(LexicalScopingSloppyMode) {
4575 const char* context_data[][2] = {
4576 {"", ""},
4577 {"function f() {", "}"},
4578 {"{", "}"},
4579 {NULL, NULL}};
4580 const char* bad_data[] = {
4581 "let x = 1;",
4582 "for(let x = 1;;){}",
4583 "for(let x of []){}",
4584 "for(let x in []){}",
4585 "class C {}",
4586 "class C extends D {}",
4587 "(class {})",
4588 "(class extends D {})",
4589 "(class C {})",
4590 "(class C extends D {})",
4591 NULL};
4592 static const ParserFlag always_true_flags[] = {
4593 kAllowHarmonyScoping, kAllowHarmonyClasses};
4594 static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
4595 RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
4596 always_true_flags, arraysize(always_true_flags),
4597 always_false_flags, arraysize(always_false_flags));
4598
4599 const char* good_data[] = {
4600 "let = 1;",
4601 "for(let = 1;;){}",
4602 NULL};
4603 RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0,
4604 always_true_flags, arraysize(always_true_flags),
4605 always_false_flags, arraysize(always_false_flags));
4606}