blob: 72f2298042956d13861f7e319d5e9a971b1acfa1 [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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034#include "src/ast-value-factory.h"
35#include "src/compiler.h"
36#include "src/execution.h"
37#include "src/isolate.h"
38#include "src/objects.h"
39#include "src/parser.h"
40#include "src/preparser.h"
41#include "src/rewriter.h"
42#include "src/scanner-character-streams.h"
43#include "src/token.h"
44#include "src/utils.h"
45
46#include "test/cctest/cctest.h"
Steve Blockd0582a62009-12-15 09:54:21 +000047
Ben Murdoch69a99ed2011-11-30 16:03:39 +000048TEST(ScanKeywords) {
Steve Blockd0582a62009-12-15 09:54:21 +000049 struct KeywordToken {
50 const char* keyword;
51 i::Token::Value token;
52 };
53
54 static const KeywordToken keywords[] = {
55#define KEYWORD(t, s, d) { s, i::Token::t },
Ben Murdoch69a99ed2011-11-30 16:03:39 +000056 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
Steve Blockd0582a62009-12-15 09:54:21 +000057#undef KEYWORD
58 { NULL, i::Token::IDENTIFIER }
59 };
60
Steve Blockd0582a62009-12-15 09:54:21 +000061 KeywordToken key_token;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000062 i::UnicodeCache unicode_cache;
63 i::byte buffer[32];
Steve Blockd0582a62009-12-15 09:54:21 +000064 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000065 const i::byte* keyword =
66 reinterpret_cast<const i::byte*>(key_token.keyword);
67 int length = i::StrLength(key_token.keyword);
68 CHECK(static_cast<int>(sizeof(buffer)) >= length);
69 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010070 i::Utf8ToUtf16CharacterStream stream(keyword, length);
71 i::Scanner scanner(&unicode_cache);
72 // The scanner should parse Harmony keywords for this test.
73 scanner.SetHarmonyScoping(true);
74 scanner.SetHarmonyModules(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 scanner.SetHarmonyClasses(true);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000076 scanner.Initialize(&stream);
77 CHECK_EQ(key_token.token, scanner.Next());
78 CHECK_EQ(i::Token::EOS, scanner.Next());
Steve Blockd0582a62009-12-15 09:54:21 +000079 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000080 // Removing characters will make keyword matching fail.
81 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010082 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
83 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000084 scanner.Initialize(&stream);
85 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
86 CHECK_EQ(i::Token::EOS, scanner.Next());
Steve Blockd0582a62009-12-15 09:54:21 +000087 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000088 // Adding characters will make keyword matching fail.
89 static const char chars_to_append[] = { 'z', '0', '_' };
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 for (int j = 0; j < static_cast<int>(arraysize(chars_to_append)); ++j) {
91 i::MemMove(buffer, keyword, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000092 buffer[length] = chars_to_append[j];
Ben Murdoch3ef787d2012-04-12 10:51:47 +010093 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
94 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000095 scanner.Initialize(&stream);
96 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
97 CHECK_EQ(i::Token::EOS, scanner.Next());
98 }
99 // Replacing characters will make keyword matching fail.
100 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101 i::MemMove(buffer, keyword, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000102 buffer[length - 1] = '_';
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100103 i::Utf8ToUtf16CharacterStream stream(buffer, length);
104 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000105 scanner.Initialize(&stream);
106 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
107 CHECK_EQ(i::Token::EOS, scanner.Next());
108 }
Steve Blockd0582a62009-12-15 09:54:21 +0000109 }
Steve Blockd0582a62009-12-15 09:54:21 +0000110}
111
Iain Merrick9ac36c92010-09-13 15:29:50 +0100112
113TEST(ScanHTMLEndComments) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000114 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000115 v8::Isolate* isolate = CcTest::isolate();
116 v8::HandleScope handles(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000117
Iain Merrick9ac36c92010-09-13 15:29:50 +0100118 // Regression test. See:
119 // http://code.google.com/p/chromium/issues/detail?id=53548
120 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000121 // is only whitespace before it on the line (with comments considered as
122 // whitespace, even a multiline-comment containing a newline).
123 // This was not the case if it occurred before the first real token
Iain Merrick9ac36c92010-09-13 15:29:50 +0100124 // in the input.
125 const char* tests[] = {
126 // Before first real token.
127 "--> is eol-comment\nvar y = 37;\n",
128 "\n --> is eol-comment\nvar y = 37;\n",
129 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
130 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
131 // After first real token.
132 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
133 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
134 NULL
135 };
136
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000137 const char* fail_tests[] = {
138 "x --> is eol-comment\nvar y = 37;\n",
139 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
140 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
141 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
142 "var x = 42; --> is eol-comment\nvar y = 37;\n",
143 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
144 NULL
145 };
146
Iain Merrick9ac36c92010-09-13 15:29:50 +0100147 // Parser/Scanner needs a stack limit.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 CcTest::i_isolate()->stack_guard()->SetStackLimit(
149 i::GetCurrentStackPosition() - 128 * 1024);
150 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Iain Merrick9ac36c92010-09-13 15:29:50 +0100151 for (int i = 0; tests[i]; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 const i::byte* source =
153 reinterpret_cast<const i::byte*>(tests[i]);
154 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i]));
155 i::CompleteParserRecorder log;
156 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
157 scanner.Initialize(&stream);
158 i::PreParser preparser(&scanner, &log, stack_limit);
159 preparser.set_allow_lazy(true);
160 i::PreParser::PreParseResult result = preparser.PreParseProgram();
161 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
162 CHECK(!log.HasError());
Iain Merrick9ac36c92010-09-13 15:29:50 +0100163 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000164
165 for (int i = 0; fail_tests[i]; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 const i::byte* source =
167 reinterpret_cast<const i::byte*>(fail_tests[i]);
168 i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i]));
169 i::CompleteParserRecorder log;
170 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
171 scanner.Initialize(&stream);
172 i::PreParser preparser(&scanner, &log, stack_limit);
173 preparser.set_allow_lazy(true);
174 i::PreParser::PreParseResult result = preparser.PreParseProgram();
175 // Even in the case of a syntax error, kPreParseSuccess is returned.
176 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
177 CHECK(log.HasError());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000178 }
Iain Merrick9ac36c92010-09-13 15:29:50 +0100179}
180
181
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000182class ScriptResource : public v8::String::ExternalOneByteStringResource {
Iain Merrick9ac36c92010-09-13 15:29:50 +0100183 public:
184 ScriptResource(const char* data, size_t length)
185 : data_(data), length_(length) { }
186
187 const char* data() const { return data_; }
188 size_t length() const { return length_; }
189
190 private:
191 const char* data_;
192 size_t length_;
193};
194
195
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196TEST(UsingCachedData) {
197 v8::Isolate* isolate = CcTest::isolate();
198 v8::HandleScope handles(isolate);
199 v8::Local<v8::Context> context = v8::Context::New(isolate);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100200 v8::Context::Scope context_scope(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 CcTest::i_isolate()->stack_guard()->SetStackLimit(
202 i::GetCurrentStackPosition() - 128 * 1024);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100203
204 // Source containing functions that might be lazily compiled and all types
205 // of symbols (string, propertyName, regexp).
206 const char* source =
207 "var x = 42;"
208 "function foo(a) { return function nolazy(b) { return a + b; } }"
209 "function bar(a) { if (a) return function lazy(b) { return b; } }"
210 "var z = {'string': 'string literal', bareword: 'propertyName', "
211 " 42: 'number literal', for: 'keyword as propertyName', "
212 " f\\u006fr: 'keyword propertyname with escape'};"
213 "var v = /RegExp Literal/;"
214 "var w = /RegExp Literal\\u0020With Escape/gin;"
215 "var y = { get getter() { return 42; }, "
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 " set setter(v) { this.value = v; }};"
217 "var f = a => function (b) { return a + b; };"
218 "var g = a => b => a + b;";
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100219 int source_length = i::StrLength(source);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100220
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 // ScriptResource will be deleted when the corresponding String is GCd.
222 v8::ScriptCompiler::Source script_source(v8::String::NewExternal(
223 isolate, new ScriptResource(source, source_length)));
224 i::FLAG_harmony_arrow_functions = true;
225 i::FLAG_min_preparse_length = 0;
226 v8::ScriptCompiler::Compile(isolate, &script_source,
227 v8::ScriptCompiler::kProduceParserCache);
228 CHECK(script_source.GetCachedData());
229
230 // Compile the script again, using the cached data.
Iain Merrick9ac36c92010-09-13 15:29:50 +0100231 bool lazy_flag = i::FLAG_lazy;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 i::FLAG_lazy = true;
233 v8::ScriptCompiler::Compile(isolate, &script_source,
234 v8::ScriptCompiler::kConsumeParserCache);
235 i::FLAG_lazy = false;
236 v8::ScriptCompiler::CompileUnbound(isolate, &script_source,
237 v8::ScriptCompiler::kConsumeParserCache);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100238 i::FLAG_lazy = lazy_flag;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239}
Iain Merrick9ac36c92010-09-13 15:29:50 +0100240
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241
242TEST(PreparseFunctionDataIsUsed) {
243 // This tests that we actually do use the function data generated by the
244 // preparser.
245
246 // Make preparsing work for short scripts.
247 i::FLAG_min_preparse_length = 0;
248 i::FLAG_harmony_arrow_functions = true;
249
250 v8::Isolate* isolate = CcTest::isolate();
251 v8::HandleScope handles(isolate);
252 v8::Local<v8::Context> context = v8::Context::New(isolate);
253 v8::Context::Scope context_scope(context);
254 CcTest::i_isolate()->stack_guard()->SetStackLimit(
255 i::GetCurrentStackPosition() - 128 * 1024);
256
257 const char* good_code[] = {
258 "function this_is_lazy() { var a; } function foo() { return 25; } foo();",
259 "var this_is_lazy = () => { var a; }; var foo = () => 25; foo();",
260 };
261
262 // Insert a syntax error inside the lazy function.
263 const char* bad_code[] = {
264 "function this_is_lazy() { if ( } function foo() { return 25; } foo();",
265 "var this_is_lazy = () => { if ( }; var foo = () => 25; foo();",
266 };
267
268 for (unsigned i = 0; i < arraysize(good_code); i++) {
269 v8::ScriptCompiler::Source good_source(v8_str(good_code[i]));
270 v8::ScriptCompiler::Compile(isolate, &good_source,
271 v8::ScriptCompiler::kProduceDataToCache);
272
273 const v8::ScriptCompiler::CachedData* cached_data =
274 good_source.GetCachedData();
275 CHECK(cached_data->data != NULL);
276 CHECK_GT(cached_data->length, 0);
277
278 // Now compile the erroneous code with the good preparse data. If the
279 // preparse data is used, the lazy function is skipped and it should
280 // compile fine.
281 v8::ScriptCompiler::Source bad_source(
282 v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData(
283 cached_data->data, cached_data->length));
284 v8::Local<v8::Value> result =
285 v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
286 CHECK(result->IsInt32());
287 CHECK_EQ(25, result->Int32Value());
288 }
Iain Merrick9ac36c92010-09-13 15:29:50 +0100289}
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800290
291
292TEST(StandAlonePreParser) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000293 v8::V8::Initialize();
294
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 CcTest::i_isolate()->stack_guard()->SetStackLimit(
296 i::GetCurrentStackPosition() - 128 * 1024);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800297
298 const char* programs[] = {
299 "{label: 42}",
300 "var x = 42;",
301 "function foo(x, y) { return x + y; }",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000302 "%ArgleBargle(glop);",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800303 "var x = new new Function('this.x = 42');",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 "var f = (x, y) => x + y;",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800305 NULL
306 };
307
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800309 for (int i = 0; programs[i]; i++) {
310 const char* program = programs[i];
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100311 i::Utf8ToUtf16CharacterStream stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100312 reinterpret_cast<const i::byte*>(program),
313 static_cast<unsigned>(strlen(program)));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800314 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100316 scanner.Initialize(&stream);
317
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 i::PreParser preparser(&scanner, &log, stack_limit);
319 preparser.set_allow_lazy(true);
320 preparser.set_allow_natives_syntax(true);
321 preparser.set_allow_arrow_functions(true);
322 i::PreParser::PreParseResult result = preparser.PreParseProgram();
323 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
324 CHECK(!log.HasError());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800325 }
326}
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800327
328
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100329TEST(StandAlonePreParserNoNatives) {
330 v8::V8::Initialize();
331
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 CcTest::i_isolate()->stack_guard()->SetStackLimit(
333 i::GetCurrentStackPosition() - 128 * 1024);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100334
335 const char* programs[] = {
336 "%ArgleBargle(glop);",
337 "var x = %_IsSmi(42);",
338 NULL
339 };
340
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100342 for (int i = 0; programs[i]; i++) {
343 const char* program = programs[i];
344 i::Utf8ToUtf16CharacterStream stream(
345 reinterpret_cast<const i::byte*>(program),
346 static_cast<unsigned>(strlen(program)));
347 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100349 scanner.Initialize(&stream);
350
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000351 // Preparser defaults to disallowing natives syntax.
352 i::PreParser preparser(&scanner, &log, stack_limit);
353 preparser.set_allow_lazy(true);
354 i::PreParser::PreParseResult result = preparser.PreParseProgram();
355 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
356 CHECK(log.HasError());
357 }
358}
359
360
361TEST(PreparsingObjectLiterals) {
362 // Regression test for a bug where the symbol stream produced by PreParser
363 // didn't match what Parser wanted to consume.
364 v8::Isolate* isolate = CcTest::isolate();
365 v8::HandleScope handles(isolate);
366 v8::Local<v8::Context> context = v8::Context::New(isolate);
367 v8::Context::Scope context_scope(context);
368 CcTest::i_isolate()->stack_guard()->SetStackLimit(
369 i::GetCurrentStackPosition() - 128 * 1024);
370
371 {
372 const char* source = "var myo = {if: \"foo\"}; myo.if;";
373 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
374 CHECK(result->IsString());
375 v8::String::Utf8Value utf8(result);
376 CHECK_EQ("foo", *utf8);
377 }
378
379 {
380 const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
381 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
382 CHECK(result->IsString());
383 v8::String::Utf8Value utf8(result);
384 CHECK_EQ("foo", *utf8);
385 }
386
387 {
388 const char* source = "var myo = {1: \"foo\"}; myo[1];";
389 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
390 CHECK(result->IsString());
391 v8::String::Utf8Value utf8(result);
392 CHECK_EQ("foo", *utf8);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100393 }
394}
395
396
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800397TEST(RegressChromium62639) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000398 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000399 i::Isolate* isolate = CcTest::i_isolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000400
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
402 128 * 1024);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800403
404 const char* program = "var x = 'something';\n"
405 "escape: function() {}";
406 // Fails parsing expecting an identifier after "function".
407 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
408 // and then used the invalid currently scanned literal. This always
409 // failed in debug mode, and sometimes crashed in release mode.
410
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100411 i::Utf8ToUtf16CharacterStream stream(
412 reinterpret_cast<const i::byte*>(program),
413 static_cast<unsigned>(strlen(program)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414 i::CompleteParserRecorder log;
415 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
416 scanner.Initialize(&stream);
417 i::PreParser preparser(&scanner, &log,
418 CcTest::i_isolate()->stack_guard()->real_climit());
419 preparser.set_allow_lazy(true);
420 i::PreParser::PreParseResult result = preparser.PreParseProgram();
421 // Even in the case of a syntax error, kPreParseSuccess is returned.
422 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
423 CHECK(log.HasError());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800424}
425
426
427TEST(Regress928) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000428 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429 i::Isolate* isolate = CcTest::i_isolate();
430 i::Factory* factory = isolate->factory();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000431
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800432 // Preparsing didn't consider the catch clause of a try statement
433 // as with-content, which made it assume that a function inside
434 // the block could be lazily compiled, and an extra, unexpected,
435 // entry was added to the data.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
437 128 * 1024);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800438
439 const char* program =
440 "try { } catch (e) { var foo = function () { /* first */ } }"
441 "var bar = function () { /* second */ }";
442
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443 v8::HandleScope handles(CcTest::isolate());
444 i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program);
445 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
446 i::CompleteParserRecorder log;
447 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
448 scanner.Initialize(&stream);
449 i::PreParser preparser(&scanner, &log,
450 CcTest::i_isolate()->stack_guard()->real_climit());
451 preparser.set_allow_lazy(true);
452 i::PreParser::PreParseResult result = preparser.PreParseProgram();
453 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
454 i::ScriptData* sd = log.GetScriptData();
455 i::ParseData pd(sd);
456 pd.Initialize();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800457
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100458 int first_function =
459 static_cast<int>(strstr(program, "function") - program);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100460 int first_lbrace = first_function + i::StrLength("function () ");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800461 CHECK_EQ('{', program[first_lbrace]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800463 CHECK(!entry1.is_valid());
464
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100465 int second_function =
466 static_cast<int>(strstr(program + first_lbrace, "function") - program);
467 int second_lbrace =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100468 second_function + i::StrLength("function () ");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800469 CHECK_EQ('{', program[second_lbrace]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470 i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800471 CHECK(entry2.is_valid());
472 CHECK_EQ('}', program[entry2.end_pos() - 1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 delete sd;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800474}
Ben Murdochb0fe1622011-05-05 13:52:32 +0100475
476
477TEST(PreParseOverflow) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000478 v8::V8::Initialize();
479
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000480 CcTest::i_isolate()->stack_guard()->SetStackLimit(
481 i::GetCurrentStackPosition() - 128 * 1024);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100482
483 size_t kProgramSize = 1024 * 1024;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
485 memset(program.get(), '(', kProgramSize);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100486 program[kProgramSize] = '\0';
487
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000488 uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100489
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100490 i::Utf8ToUtf16CharacterStream stream(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491 reinterpret_cast<const i::byte*>(program.get()),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100492 static_cast<unsigned>(kProgramSize));
493 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100495 scanner.Initialize(&stream);
496
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 i::PreParser preparser(&scanner, &log, stack_limit);
498 preparser.set_allow_lazy(true);
499 preparser.set_allow_arrow_functions(true);
500 i::PreParser::PreParseResult result = preparser.PreParseProgram();
501 CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100502}
503
504
505class TestExternalResource: public v8::String::ExternalStringResource {
506 public:
507 explicit TestExternalResource(uint16_t* data, int length)
508 : data_(data), length_(static_cast<size_t>(length)) { }
509
510 ~TestExternalResource() { }
511
512 const uint16_t* data() const {
513 return data_;
514 }
515
516 size_t length() const {
517 return length_;
518 }
519 private:
520 uint16_t* data_;
521 size_t length_;
522};
523
524
525#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
526
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527void TestCharacterStream(const char* one_byte_source, unsigned length,
528 unsigned start = 0, unsigned end = 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100529 if (end == 0) end = length;
530 unsigned sub_length = end - start;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 i::Isolate* isolate = CcTest::i_isolate();
532 i::Factory* factory = isolate->factory();
533 i::HandleScope test_scope(isolate);
Ben Murdoch589d6972011-11-30 16:04:58 +0000534 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100535 for (unsigned i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100537 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538 i::Vector<const char> one_byte_vector(one_byte_source,
539 static_cast<int>(length));
540 i::Handle<i::String> one_byte_string =
541 factory->NewStringFromAscii(one_byte_vector).ToHandleChecked();
542 TestExternalResource resource(uc16_buffer.get(), length);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100543 i::Handle<i::String> uc16_string(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100545
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100546 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100547 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 i::GenericStringUtf16CharacterStream string_stream(one_byte_string, start,
549 end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100550 i::Utf8ToUtf16CharacterStream utf8_stream(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 reinterpret_cast<const i::byte*>(one_byte_source), end);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100552 utf8_stream.SeekForward(start);
553
554 unsigned i = start;
555 while (i < end) {
556 // Read streams one char at a time
557 CHECK_EQU(i, uc16_stream.pos());
558 CHECK_EQU(i, string_stream.pos());
559 CHECK_EQU(i, utf8_stream.pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 int32_t c0 = one_byte_source[i];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100561 int32_t c1 = uc16_stream.Advance();
562 int32_t c2 = string_stream.Advance();
563 int32_t c3 = utf8_stream.Advance();
564 i++;
565 CHECK_EQ(c0, c1);
566 CHECK_EQ(c0, c2);
567 CHECK_EQ(c0, c3);
568 CHECK_EQU(i, uc16_stream.pos());
569 CHECK_EQU(i, string_stream.pos());
570 CHECK_EQU(i, utf8_stream.pos());
571 }
572 while (i > start + sub_length / 4) {
573 // Pushback, re-read, pushback again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574 int32_t c0 = one_byte_source[i - 1];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100575 CHECK_EQU(i, uc16_stream.pos());
576 CHECK_EQU(i, string_stream.pos());
577 CHECK_EQU(i, utf8_stream.pos());
578 uc16_stream.PushBack(c0);
579 string_stream.PushBack(c0);
580 utf8_stream.PushBack(c0);
581 i--;
582 CHECK_EQU(i, uc16_stream.pos());
583 CHECK_EQU(i, string_stream.pos());
584 CHECK_EQU(i, utf8_stream.pos());
585 int32_t c1 = uc16_stream.Advance();
586 int32_t c2 = string_stream.Advance();
587 int32_t c3 = utf8_stream.Advance();
588 i++;
589 CHECK_EQU(i, uc16_stream.pos());
590 CHECK_EQU(i, string_stream.pos());
591 CHECK_EQU(i, utf8_stream.pos());
592 CHECK_EQ(c0, c1);
593 CHECK_EQ(c0, c2);
594 CHECK_EQ(c0, c3);
595 uc16_stream.PushBack(c0);
596 string_stream.PushBack(c0);
597 utf8_stream.PushBack(c0);
598 i--;
599 CHECK_EQU(i, uc16_stream.pos());
600 CHECK_EQU(i, string_stream.pos());
601 CHECK_EQU(i, utf8_stream.pos());
602 }
603 unsigned halfway = start + sub_length / 2;
604 uc16_stream.SeekForward(halfway - i);
605 string_stream.SeekForward(halfway - i);
606 utf8_stream.SeekForward(halfway - i);
607 i = halfway;
608 CHECK_EQU(i, uc16_stream.pos());
609 CHECK_EQU(i, string_stream.pos());
610 CHECK_EQU(i, utf8_stream.pos());
611
612 while (i < end) {
613 // Read streams one char at a time
614 CHECK_EQU(i, uc16_stream.pos());
615 CHECK_EQU(i, string_stream.pos());
616 CHECK_EQU(i, utf8_stream.pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000617 int32_t c0 = one_byte_source[i];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100618 int32_t c1 = uc16_stream.Advance();
619 int32_t c2 = string_stream.Advance();
620 int32_t c3 = utf8_stream.Advance();
621 i++;
622 CHECK_EQ(c0, c1);
623 CHECK_EQ(c0, c2);
624 CHECK_EQ(c0, c3);
625 CHECK_EQU(i, uc16_stream.pos());
626 CHECK_EQU(i, string_stream.pos());
627 CHECK_EQU(i, utf8_stream.pos());
628 }
629
630 int32_t c1 = uc16_stream.Advance();
631 int32_t c2 = string_stream.Advance();
632 int32_t c3 = utf8_stream.Advance();
633 CHECK_LT(c1, 0);
634 CHECK_LT(c2, 0);
635 CHECK_LT(c3, 0);
636}
637
638
639TEST(CharacterStreams) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 v8::Isolate* isolate = CcTest::isolate();
641 v8::HandleScope handles(isolate);
642 v8::Local<v8::Context> context = v8::Context::New(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100643 v8::Context::Scope context_scope(context);
644
645 TestCharacterStream("abc\0\n\r\x7f", 7);
646 static const unsigned kBigStringSize = 4096;
647 char buffer[kBigStringSize + 1];
648 for (unsigned i = 0; i < kBigStringSize; i++) {
649 buffer[i] = static_cast<char>(i & 0x7f);
650 }
651 TestCharacterStream(buffer, kBigStringSize);
652
653 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
654
655 TestCharacterStream("\0", 1);
656 TestCharacterStream("", 0);
657}
658
659
660TEST(Utf8CharacterStream) {
661 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
662 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
663
664 static const int kAllUtf8CharsSize =
665 (unibrow::Utf8::kMaxOneByteChar + 1) +
666 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
667 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
668 static const unsigned kAllUtf8CharsSizeU =
669 static_cast<unsigned>(kAllUtf8CharsSize);
670
671 char buffer[kAllUtf8CharsSizeU];
672 unsigned cursor = 0;
673 for (int i = 0; i <= kMaxUC16Char; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100674 cursor += unibrow::Utf8::Encode(buffer + cursor,
675 i,
676 unibrow::Utf16::kNoPreviousCharacter);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100677 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000678 DCHECK(cursor == kAllUtf8CharsSizeU);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100679
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100680 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
681 kAllUtf8CharsSizeU);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100682 for (int i = 0; i <= kMaxUC16Char; i++) {
683 CHECK_EQU(i, stream.pos());
684 int32_t c = stream.Advance();
685 CHECK_EQ(i, c);
686 CHECK_EQU(i + 1, stream.pos());
687 }
688 for (int i = kMaxUC16Char; i >= 0; i--) {
689 CHECK_EQU(i + 1, stream.pos());
690 stream.PushBack(i);
691 CHECK_EQU(i, stream.pos());
692 }
693 int i = 0;
694 while (stream.pos() < kMaxUC16CharU) {
695 CHECK_EQU(i, stream.pos());
696 unsigned progress = stream.SeekForward(12);
697 i += progress;
698 int32_t c = stream.Advance();
699 if (i <= kMaxUC16Char) {
700 CHECK_EQ(i, c);
701 } else {
702 CHECK_EQ(-1, c);
703 }
704 i += 1;
705 CHECK_EQU(i, stream.pos());
706 }
707}
708
709#undef CHECK_EQU
710
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100711void TestStreamScanner(i::Utf16CharacterStream* stream,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100712 i::Token::Value* expected_tokens,
713 int skip_pos = 0, // Zero means not skipping.
714 int skip_to = 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Steve Block9fac8402011-05-12 15:51:54 +0100716 scanner.Initialize(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100717
718 int i = 0;
719 do {
720 i::Token::Value expected = expected_tokens[i];
721 i::Token::Value actual = scanner.Next();
722 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
723 if (scanner.location().end_pos == skip_pos) {
724 scanner.SeekForward(skip_to);
725 }
726 i++;
727 } while (expected_tokens[i] != i::Token::ILLEGAL);
728}
729
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730
Ben Murdochb0fe1622011-05-05 13:52:32 +0100731TEST(StreamScanner) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000732 v8::V8::Initialize();
733
Ben Murdochb0fe1622011-05-05 13:52:32 +0100734 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100735 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
736 static_cast<unsigned>(strlen(str1)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100737 i::Token::Value expectations1[] = {
738 i::Token::LBRACE,
739 i::Token::IDENTIFIER,
740 i::Token::IDENTIFIER,
741 i::Token::FOR,
742 i::Token::COLON,
743 i::Token::MUL,
744 i::Token::DIV,
745 i::Token::LT,
746 i::Token::SUB,
747 i::Token::IDENTIFIER,
748 i::Token::EOS,
749 i::Token::ILLEGAL
750 };
751 TestStreamScanner(&stream1, expectations1, 0, 0);
752
753 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100754 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
755 static_cast<unsigned>(strlen(str2)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100756 i::Token::Value expectations2[] = {
757 i::Token::CASE,
758 i::Token::DEFAULT,
759 i::Token::CONST,
760 i::Token::LBRACE,
761 // Skipped part here
762 i::Token::RBRACE,
763 i::Token::DO,
764 i::Token::EOS,
765 i::Token::ILLEGAL
766 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767 DCHECK_EQ('{', str2[19]);
768 DCHECK_EQ('}', str2[37]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100769 TestStreamScanner(&stream2, expectations2, 20, 37);
770
771 const char* str3 = "{}}}}";
772 i::Token::Value expectations3[] = {
773 i::Token::LBRACE,
774 i::Token::RBRACE,
775 i::Token::RBRACE,
776 i::Token::RBRACE,
777 i::Token::RBRACE,
778 i::Token::EOS,
779 i::Token::ILLEGAL
780 };
781 // Skip zero-four RBRACEs.
782 for (int i = 0; i <= 4; i++) {
783 expectations3[6 - i] = i::Token::ILLEGAL;
784 expectations3[5 - i] = i::Token::EOS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100785 i::Utf8ToUtf16CharacterStream stream3(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100786 reinterpret_cast<const i::byte*>(str3),
787 static_cast<unsigned>(strlen(str3)));
788 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
789 }
790}
Ben Murdoch086aeea2011-05-13 15:57:08 +0100791
792
793void TestScanRegExp(const char* re_source, const char* expected) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100794 i::Utf8ToUtf16CharacterStream stream(
Ben Murdoch086aeea2011-05-13 15:57:08 +0100795 reinterpret_cast<const i::byte*>(re_source),
796 static_cast<unsigned>(strlen(re_source)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000797 i::HandleScope scope(CcTest::i_isolate());
798 i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
Ben Murdoch086aeea2011-05-13 15:57:08 +0100799 scanner.Initialize(&stream);
800
801 i::Token::Value start = scanner.peek();
802 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
803 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
804 scanner.Next(); // Current token is now the regexp literal.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000805 i::Zone zone(CcTest::i_isolate());
806 i::AstValueFactory ast_value_factory(&zone,
807 CcTest::i_isolate()->heap()->HashSeed());
808 ast_value_factory.Internalize(CcTest::i_isolate());
809 i::Handle<i::String> val =
810 scanner.CurrentSymbol(&ast_value_factory)->string();
811 i::DisallowHeapAllocation no_alloc;
812 i::String::FlatContent content = val->GetFlatContent();
813 CHECK(content.IsOneByte());
814 i::Vector<const uint8_t> actual = content.ToOneByteVector();
Ben Murdoch086aeea2011-05-13 15:57:08 +0100815 for (int i = 0; i < actual.length(); i++) {
816 CHECK_NE('\0', expected[i]);
817 CHECK_EQ(expected[i], actual[i]);
818 }
819}
820
821
822TEST(RegExpScanning) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000823 v8::V8::Initialize();
824
Ben Murdoch086aeea2011-05-13 15:57:08 +0100825 // RegExp token with added garbage at the end. The scanner should only
826 // scan the RegExp until the terminating slash just before "flipperwald".
827 TestScanRegExp("/b/flipperwald", "b");
828 // Incomplete escape sequences doesn't hide the terminating slash.
829 TestScanRegExp("/\\x/flipperwald", "\\x");
830 TestScanRegExp("/\\u/flipperwald", "\\u");
831 TestScanRegExp("/\\u1/flipperwald", "\\u1");
832 TestScanRegExp("/\\u12/flipperwald", "\\u12");
833 TestScanRegExp("/\\u123/flipperwald", "\\u123");
834 TestScanRegExp("/\\c/flipperwald", "\\c");
835 TestScanRegExp("/\\c//flipperwald", "\\c");
836 // Slashes inside character classes are not terminating.
837 TestScanRegExp("/[/]/flipperwald", "[/]");
838 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
839 // Incomplete escape sequences inside a character class doesn't hide
840 // the end of the character class.
841 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
842 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
843 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
844 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
845 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
846 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
847 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
848 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
849 // Escaped ']'s wont end the character class.
850 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
851 // Escaped slashes are not terminating.
852 TestScanRegExp("/\\//flipperwald", "\\/");
853 // Starting with '=' works too.
854 TestScanRegExp("/=/", "=");
855 TestScanRegExp("/=?/", "=?");
856}
Ben Murdoch692be652012-01-10 18:47:50 +0000857
858
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100859static int Utf8LengthHelper(const char* s) {
860 int len = i::StrLength(s);
861 int character_length = len;
862 for (int i = 0; i < len; i++) {
863 unsigned char c = s[i];
864 int input_offset = 0;
865 int output_adjust = 0;
866 if (c > 0x7f) {
867 if (c < 0xc0) continue;
868 if (c >= 0xf0) {
869 if (c >= 0xf8) {
870 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
871 // byte.
872 continue; // Handle first UTF-8 byte.
873 }
874 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
875 // This 4 byte sequence could have been coded as a 3 byte sequence.
876 // Record a single kBadChar for the first byte and continue.
877 continue;
878 }
879 input_offset = 3;
880 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
881 character_length -= 2;
882 } else if (c >= 0xe0) {
883 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
884 // This 3 byte sequence could have been coded as a 2 byte sequence.
885 // Record a single kBadChar for the first byte and continue.
886 continue;
887 }
888 input_offset = 2;
889 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
890 output_adjust = 2;
891 } else {
892 if ((c & 0x1e) == 0) {
893 // This 2 byte sequence could have been coded as a 1 byte sequence.
894 // Record a single kBadChar for the first byte and continue.
895 continue;
896 }
897 input_offset = 1;
898 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
899 output_adjust = 1;
900 }
901 bool bad = false;
902 for (int j = 1; j <= input_offset; j++) {
903 if ((s[i + j] & 0xc0) != 0x80) {
904 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
905 // which is a single UTF-16 code unit.
906 bad = true;
907 break;
908 }
909 }
910 if (!bad) {
911 i += input_offset;
912 character_length -= output_adjust;
913 }
914 }
915 }
916 return character_length;
917}
918
919
920TEST(ScopePositions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000921 v8::internal::FLAG_harmony_scoping = true;
922
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100923 // Test the parser for correctly setting the start and end positions
924 // of a scope. We check the scope positions of exactly one scope
925 // nested in the global scope of a program. 'inner source' is the
926 // source code that determines the part of the source belonging
927 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
928 // parts of the source that belong to the global scope.
929 struct SourceData {
930 const char* outer_prefix;
931 const char* inner_source;
932 const char* outer_suffix;
933 i::ScopeType scope_type;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000934 i::StrictMode strict_mode;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100935 };
936
937 const SourceData source_data[] = {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000938 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
939 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100940 { " with ({}) ", "{\n"
941 " block;\n"
942 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000943 " more;", i::WITH_SCOPE, i::SLOPPY },
944 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100945 { " with ({}) ", "statement", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000946 " more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100947 { " with ({})\n"
948 " ", "statement;", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000949 " more;", i::WITH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100950 { " try {} catch ", "(e) { block; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000951 i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100952 { " try {} catch ", "(e) { block; }", "; more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953 i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100954 { " try {} catch ", "(e) {\n"
955 " block;\n"
956 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000957 " more;", i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100958 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 i::CATCH_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100960 { " start;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000961 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100962 { " start;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100964 { " start;\n"
965 " ", "{\n"
966 " let block;\n"
967 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000968 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100969 { " start;\n"
970 " function fun", "(a,b) { infunction; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000971 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100972 { " start;\n"
973 " function fun", "(a,b) {\n"
974 " infunction;\n"
975 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976 " more;", i::FUNCTION_SCOPE, i::SLOPPY },
977 // TODO(aperez): Change to use i::ARROW_SCOPE when implemented
978 { " start;\n", "(a,b) => a + b", "; more;",
979 i::FUNCTION_SCOPE, i::SLOPPY },
980 { " start;\n", "(a,b) => { return a+b; }", "\nmore;",
981 i::FUNCTION_SCOPE, i::SLOPPY },
982 { " start;\n"
983 " (function fun", "(a,b) { infunction; }", ")();",
984 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100985 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100987 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000988 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100989 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
990 " block;\n"
991 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100993 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000994 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100995 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000996 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100997 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
998 " statement;", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000999 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001000 { " for ", "(let x in {}) { block; }", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001002 { " for ", "(let x in {}) { block; }", "; more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001003 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001004 { " for ", "(let x in {}) {\n"
1005 " block;\n"
1006 " }", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001008 { " for ", "(let x in {}) statement;", " more;",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009 i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001010 { " for ", "(let x in {}) statement", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001011 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001012 { " for ", "(let x in {})\n"
1013 " statement;", "\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014 " more;", i::BLOCK_SCOPE, i::STRICT },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001015 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
1016 // the preparser off in terms of byte offsets.
1017 // 6 byte encoding.
1018 { " 'foo\355\240\201\355\260\211';\n"
1019 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001020 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001021 // 4 byte encoding.
1022 { " 'foo\360\220\220\212';\n"
1023 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001024 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001025 // 3 byte encoding of \u0fff.
1026 { " 'foo\340\277\277';\n"
1027 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001028 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001029 // Broken 6 byte encoding with missing last byte.
1030 { " 'foo\355\240\201\355\211';\n"
1031 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001032 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001033 // Broken 3 byte encoding of \u0fff with missing last byte.
1034 { " 'foo\340\277';\n"
1035 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001037 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
1038 { " 'foo\340';\n"
1039 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001040 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001041 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
1042 { " 'foo\340\203\277';\n"
1043 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001044 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001045 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
1046 { " 'foo\340\201\277';\n"
1047 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001048 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001049 // Unpaired lead surrogate.
1050 { " 'foo\355\240\201';\n"
1051 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001052 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001053 // Unpaired lead surrogate where following code point is a 3 byte sequence.
1054 { " 'foo\355\240\201\340\277\277';\n"
1055 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001057 // Unpaired lead surrogate where following code point is a 4 byte encoding
1058 // of a trail surrogate.
1059 { " 'foo\355\240\201\360\215\260\211';\n"
1060 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001061 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001062 // Unpaired trail surrogate.
1063 { " 'foo\355\260\211';\n"
1064 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001065 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001066 // 2 byte encoding of \u00ff.
1067 { " 'foo\303\277';\n"
1068 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001069 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001070 // Broken 2 byte encoding of \u00ff with missing last byte.
1071 { " 'foo\303';\n"
1072 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001073 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001074 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
1075 { " 'foo\301\277';\n"
1076 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001078 // Illegal 5 byte encoding.
1079 { " 'foo\370\277\277\277\277';\n"
1080 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001081 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001082 // Illegal 6 byte encoding.
1083 { " 'foo\374\277\277\277\277\277';\n"
1084 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001085 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001086 // Illegal 0xfe byte
1087 { " 'foo\376\277\277\277\277\277\277';\n"
1088 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001089 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001090 // Illegal 0xff byte
1091 { " 'foo\377\277\277\277\277\277\277\277';\n"
1092 " (function fun", "(a,b) { infunction; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001094 { " 'foo';\n"
1095 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001096 i::FUNCTION_SCOPE, i::SLOPPY },
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001097 { " 'foo';\n"
1098 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001099 i::FUNCTION_SCOPE, i::SLOPPY },
1100 { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001101 };
1102
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 i::Isolate* isolate = CcTest::i_isolate();
1104 i::Factory* factory = isolate->factory();
1105
1106 v8::HandleScope handles(CcTest::isolate());
1107 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001108 v8::Context::Scope context_scope(context);
1109
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001110 isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
1111 128 * 1024);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001112
1113 for (int i = 0; source_data[i].outer_prefix; i++) {
1114 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1115 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1116 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1117 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1118 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1119 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1120 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1121 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001122 i::ScopedVector<char> program(kProgramByteSize + 1);
1123 i::SNPrintF(program, "%s%s%s",
1124 source_data[i].outer_prefix,
1125 source_data[i].inner_source,
1126 source_data[i].outer_suffix);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001127
1128 // Parse program source.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129 i::Handle<i::String> source = factory->NewStringFromUtf8(
1130 i::CStrVector(program.start())).ToHandleChecked();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001131 CHECK_EQ(source->length(), kProgramSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001132 i::Handle<i::Script> script = factory->NewScript(source);
1133 i::CompilationInfoWithZone info(script);
1134 i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
1135 isolate->heap()->HashSeed(),
1136 isolate->unicode_cache()};
1137 i::Parser parser(&info, &parse_info);
1138 parser.set_allow_lazy(true);
1139 parser.set_allow_harmony_scoping(true);
1140 parser.set_allow_arrow_functions(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001141 info.MarkAsGlobal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001142 info.SetStrictMode(source_data[i].strict_mode);
1143 parser.Parse();
1144 CHECK(info.function() != NULL);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001145
1146 // Check scope types and positions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 i::Scope* scope = info.function()->scope();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001148 CHECK(scope->is_global_scope());
1149 CHECK_EQ(scope->start_position(), 0);
1150 CHECK_EQ(scope->end_position(), kProgramSize);
1151 CHECK_EQ(scope->inner_scopes()->length(), 1);
1152
1153 i::Scope* inner_scope = scope->inner_scopes()->at(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001154 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001155 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1156 // The end position of a token is one position after the last
1157 // character belonging to that token.
1158 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1159 }
1160}
1161
1162
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001163const char* ReadString(unsigned* start) {
1164 int length = start[0];
1165 char* result = i::NewArray<char>(length + 1);
1166 for (int i = 0; i < length; i++) {
1167 result[i] = start[i + 1];
1168 }
1169 result[length] = '\0';
1170 return result;
1171}
1172
1173
1174i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
1175 i::Isolate* isolate = CcTest::i_isolate();
1176 i::Factory* factory = isolate->factory();
1177 const char* message =
1178 ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
1179 i::Handle<i::String> format = v8::Utils::OpenHandle(
1180 *v8::String::NewFromUtf8(CcTest::isolate(), message));
1181 int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
1182 const char* arg = NULL;
1183 i::Handle<i::JSArray> args_array;
1184 if (arg_count == 1) {
1185 // Position after text found by skipping past length field and
1186 // length field content words.
1187 int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
1188 data[i::PreparseDataConstants::kMessageTextPos];
1189 arg = ReadString(&data[pos]);
1190 args_array = factory->NewJSArray(1);
1191 i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
1192 NONE, i::SLOPPY).Check();
1193 } else {
1194 CHECK_EQ(0, arg_count);
1195 args_array = factory->NewJSArray(0);
1196 }
1197
1198 i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
1199 i::Handle<i::Object> format_fun = i::Object::GetProperty(
1200 isolate, builtins, "FormatMessage").ToHandleChecked();
1201 i::Handle<i::Object> arg_handles[] = { format, args_array };
1202 i::Handle<i::Object> result = i::Execution::Call(
1203 isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked();
1204 CHECK(result->IsString());
1205 i::DeleteArray(message);
1206 i::DeleteArray(arg);
1207 data.Dispose();
1208 return i::Handle<i::String>::cast(result);
1209}
1210
1211
1212enum ParserFlag {
1213 kAllowLazy,
1214 kAllowNativesSyntax,
1215 kAllowHarmonyScoping,
1216 kAllowModules,
1217 kAllowHarmonyNumericLiterals,
1218 kAllowArrowFunctions,
1219 kAllowClasses,
1220 kAllowHarmonyObjectLiterals
1221};
1222
1223
1224enum ParserSyncTestResult {
1225 kSuccessOrError,
1226 kSuccess,
1227 kError
1228};
1229
1230template <typename Traits>
1231void SetParserFlags(i::ParserBase<Traits>* parser,
1232 i::EnumSet<ParserFlag> flags) {
1233 parser->set_allow_lazy(flags.Contains(kAllowLazy));
1234 parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
1235 parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
1236 parser->set_allow_modules(flags.Contains(kAllowModules));
1237 parser->set_allow_harmony_numeric_literals(
1238 flags.Contains(kAllowHarmonyNumericLiterals));
1239 parser->set_allow_harmony_object_literals(
1240 flags.Contains(kAllowHarmonyObjectLiterals));
1241 parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions));
1242 parser->set_allow_classes(flags.Contains(kAllowClasses));
1243}
1244
1245
1246void TestParserSyncWithFlags(i::Handle<i::String> source,
1247 i::EnumSet<ParserFlag> flags,
1248 ParserSyncTestResult result) {
1249 i::Isolate* isolate = CcTest::i_isolate();
1250 i::Factory* factory = isolate->factory();
1251
1252 uintptr_t stack_limit = isolate->stack_guard()->real_climit();
Ben Murdoch692be652012-01-10 18:47:50 +00001253
1254 // Preparse the data.
1255 i::CompleteParserRecorder log;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256 {
1257 i::Scanner scanner(isolate->unicode_cache());
1258 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1259 i::PreParser preparser(&scanner, &log, stack_limit);
1260 SetParserFlags(&preparser, flags);
1261 scanner.Initialize(&stream);
1262 i::PreParser::PreParseResult result = preparser.PreParseProgram();
1263 CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1264 }
1265
1266 bool preparse_error = log.HasError();
Ben Murdoch692be652012-01-10 18:47:50 +00001267
1268 // Parse the data
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269 i::FunctionLiteral* function;
1270 {
1271 i::Handle<i::Script> script = factory->NewScript(source);
1272 i::CompilationInfoWithZone info(script);
1273 i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
1274 isolate->heap()->HashSeed(),
1275 isolate->unicode_cache()};
1276 i::Parser parser(&info, &parse_info);
1277 SetParserFlags(&parser, flags);
1278 info.MarkAsGlobal();
1279 parser.Parse();
1280 function = info.function();
Ben Murdoch692be652012-01-10 18:47:50 +00001281 }
1282
1283 // Check that preparsing fails iff parsing fails.
Ben Murdoch692be652012-01-10 18:47:50 +00001284 if (function == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001285 // Extract exception from the parser.
1286 CHECK(isolate->has_pending_exception());
1287 i::Handle<i::JSObject> exception_handle(
1288 i::JSObject::cast(isolate->pending_exception()));
1289 i::Handle<i::String> message_string =
1290 i::Handle<i::String>::cast(i::Object::GetProperty(
1291 isolate, exception_handle, "message").ToHandleChecked());
1292
1293 if (result == kSuccess) {
1294 v8::base::OS::Print(
1295 "Parser failed on:\n"
1296 "\t%s\n"
1297 "with error:\n"
1298 "\t%s\n"
1299 "However, we expected no error.",
1300 source->ToCString().get(), message_string->ToCString().get());
1301 CHECK(false);
1302 }
1303
1304 if (!preparse_error) {
1305 v8::base::OS::Print(
1306 "Parser failed on:\n"
1307 "\t%s\n"
1308 "with error:\n"
1309 "\t%s\n"
1310 "However, the preparser succeeded",
1311 source->ToCString().get(), message_string->ToCString().get());
1312 CHECK(false);
1313 }
1314 // Check that preparser and parser produce the same error.
1315 i::Handle<i::String> preparser_message =
1316 FormatMessage(log.ErrorMessageData());
1317 if (!i::String::Equals(message_string, preparser_message)) {
1318 v8::base::OS::Print(
Ben Murdoch692be652012-01-10 18:47:50 +00001319 "Expected parser and preparser to produce the same error on:\n"
1320 "\t%s\n"
1321 "However, found the following error messages\n"
1322 "\tparser: %s\n"
1323 "\tpreparser: %s\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001324 source->ToCString().get(),
1325 message_string->ToCString().get(),
1326 preparser_message->ToCString().get());
Ben Murdoch692be652012-01-10 18:47:50 +00001327 CHECK(false);
1328 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001329 } else if (preparse_error) {
1330 v8::base::OS::Print(
1331 "Preparser failed on:\n"
1332 "\t%s\n"
1333 "with error:\n"
1334 "\t%s\n"
1335 "However, the parser succeeded",
1336 source->ToCString().get(),
1337 FormatMessage(log.ErrorMessageData())->ToCString().get());
1338 CHECK(false);
1339 } else if (result == kError) {
1340 v8::base::OS::Print(
1341 "Expected error on:\n"
1342 "\t%s\n"
1343 "However, parser and preparser succeeded",
1344 source->ToCString().get());
1345 CHECK(false);
Ben Murdoch692be652012-01-10 18:47:50 +00001346 }
1347}
1348
1349
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350void TestParserSync(const char* source,
1351 const ParserFlag* varying_flags,
1352 size_t varying_flags_length,
1353 ParserSyncTestResult result = kSuccessOrError,
1354 const ParserFlag* always_true_flags = NULL,
1355 size_t always_true_flags_length = 0) {
1356 i::Handle<i::String> str =
1357 CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
1358 for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
1359 i::EnumSet<ParserFlag> flags;
1360 for (size_t flag_index = 0; flag_index < varying_flags_length;
1361 ++flag_index) {
1362 if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]);
1363 }
1364 for (size_t flag_index = 0; flag_index < always_true_flags_length;
1365 ++flag_index) {
1366 flags.Add(always_true_flags[flag_index]);
1367 }
1368 TestParserSyncWithFlags(str, flags, result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001369 }
1370}
1371
1372
Ben Murdoch692be652012-01-10 18:47:50 +00001373TEST(ParserSync) {
1374 const char* context_data[][2] = {
1375 { "", "" },
1376 { "{", "}" },
1377 { "if (true) ", " else {}" },
1378 { "if (true) {} else ", "" },
1379 { "if (true) ", "" },
1380 { "do ", " while (false)" },
1381 { "while (false) ", "" },
1382 { "for (;;) ", "" },
1383 { "with ({})", "" },
1384 { "switch (12) { case 12: ", "}" },
1385 { "switch (12) { default: ", "}" },
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386 { "switch (12) { ", "case 12: }" },
Ben Murdoch692be652012-01-10 18:47:50 +00001387 { "label2: ", "" },
1388 { NULL, NULL }
1389 };
1390
1391 const char* statement_data[] = {
1392 "{}",
1393 "var x",
1394 "var x = 1",
1395 "const x",
1396 "const x = 1",
1397 ";",
1398 "12",
1399 "if (false) {} else ;",
1400 "if (false) {} else {}",
1401 "if (false) {} else 12",
1402 "if (false) ;"
1403 "if (false) {}",
1404 "if (false) 12",
1405 "do {} while (false)",
1406 "for (;;) ;",
1407 "for (;;) {}",
1408 "for (;;) 12",
1409 "continue",
1410 "continue label",
1411 "continue\nlabel",
1412 "break",
1413 "break label",
1414 "break\nlabel",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001415 // TODO(marja): activate once parsing 'return' is merged into ParserBase.
1416 // "return",
1417 // "return 12",
1418 // "return\n12",
Ben Murdoch692be652012-01-10 18:47:50 +00001419 "with ({}) ;",
1420 "with ({}) {}",
1421 "with ({}) 12",
1422 "switch ({}) { default: }"
1423 "label3: "
1424 "throw",
1425 "throw 12",
1426 "throw\n12",
1427 "try {} catch(e) {}",
1428 "try {} finally {}",
1429 "try {} catch(e) {} finally {}",
1430 "debugger",
1431 NULL
1432 };
1433
1434 const char* termination_data[] = {
1435 "",
1436 ";",
1437 "\n",
1438 ";\n",
1439 "\n;",
1440 NULL
1441 };
1442
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 v8::HandleScope handles(CcTest::isolate());
1444 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
Ben Murdoch692be652012-01-10 18:47:50 +00001445 v8::Context::Scope context_scope(context);
1446
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1448 i::GetCurrentStackPosition() - 128 * 1024);
1449
1450 static const ParserFlag flags1[] = {
1451 kAllowArrowFunctions,
1452 kAllowClasses,
1453 kAllowHarmonyNumericLiterals,
1454 kAllowHarmonyObjectLiterals,
1455 kAllowHarmonyScoping,
1456 kAllowLazy,
1457 kAllowModules,
1458 };
Ben Murdoch692be652012-01-10 18:47:50 +00001459
1460 for (int i = 0; context_data[i][0] != NULL; ++i) {
1461 for (int j = 0; statement_data[j] != NULL; ++j) {
1462 for (int k = 0; termination_data[k] != NULL; ++k) {
1463 int kPrefixLen = i::StrLength(context_data[i][0]);
1464 int kStatementLen = i::StrLength(statement_data[j]);
1465 int kTerminationLen = i::StrLength(termination_data[k]);
1466 int kSuffixLen = i::StrLength(context_data[i][1]);
1467 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1468 + kSuffixLen + i::StrLength("label: for (;;) { }");
1469
1470 // Plug the source code pieces together.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001471 i::ScopedVector<char> program(kProgramSize + 1);
1472 int length = i::SNPrintF(program,
Ben Murdoch692be652012-01-10 18:47:50 +00001473 "label: for (;;) { %s%s%s%s }",
1474 context_data[i][0],
1475 statement_data[j],
1476 termination_data[k],
1477 context_data[i][1]);
1478 CHECK(length == kProgramSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001479 TestParserSync(program.start(), flags1, arraysize(flags1));
Ben Murdoch692be652012-01-10 18:47:50 +00001480 }
1481 }
1482 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483
1484 // Neither Harmony numeric literals nor our natives syntax have any
1485 // interaction with the flags above, so test these separately to reduce
1486 // the combinatorial explosion.
1487 static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
1488 TestParserSync("0o1234", flags2, arraysize(flags2));
1489 TestParserSync("0b1011", flags2, arraysize(flags2));
1490
1491 static const ParserFlag flags3[] = { kAllowNativesSyntax };
1492 TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
1493}
1494
1495
1496TEST(StrictOctal) {
1497 // Test that syntax error caused by octal literal is reported correctly as
1498 // such (issue 2220).
1499 v8::V8::Initialize();
1500 v8::HandleScope scope(CcTest::isolate());
1501 v8::Context::Scope context_scope(
1502 v8::Context::New(CcTest::isolate()));
1503 v8::TryCatch try_catch;
1504 const char* script =
1505 "\"use strict\"; \n"
1506 "a = function() { \n"
1507 " b = function() { \n"
1508 " 01; \n"
1509 " }; \n"
1510 "}; \n";
1511 v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
1512 CHECK(try_catch.HasCaught());
1513 v8::String::Utf8Value exception(try_catch.Exception());
1514 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
1515 *exception);
1516}
1517
1518
1519void RunParserSyncTest(const char* context_data[][2],
1520 const char* statement_data[],
1521 ParserSyncTestResult result,
1522 const ParserFlag* flags = NULL,
1523 int flags_len = 0,
1524 const ParserFlag* always_true_flags = NULL,
1525 int always_true_flags_len = 0) {
1526 v8::HandleScope handles(CcTest::isolate());
1527 v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1528 v8::Context::Scope context_scope(context);
1529
1530 CcTest::i_isolate()->stack_guard()->SetStackLimit(
1531 i::GetCurrentStackPosition() - 128 * 1024);
1532
1533 static const ParserFlag default_flags[] = {
1534 kAllowArrowFunctions,
1535 kAllowClasses,
1536 kAllowHarmonyNumericLiterals,
1537 kAllowHarmonyObjectLiterals,
1538 kAllowHarmonyScoping,
1539 kAllowLazy,
1540 kAllowModules,
1541 kAllowNativesSyntax,
1542 };
1543 ParserFlag* generated_flags = NULL;
1544 if (flags == NULL) {
1545 flags = default_flags;
1546 flags_len = arraysize(default_flags);
1547 if (always_true_flags != NULL) {
1548 // Remove always_true_flags from default_flags.
1549 CHECK(always_true_flags_len < flags_len);
1550 generated_flags = new ParserFlag[flags_len - always_true_flags_len];
1551 int flag_index = 0;
1552 for (int i = 0; i < flags_len; ++i) {
1553 bool use_flag = true;
1554 for (int j = 0; j < always_true_flags_len; ++j) {
1555 if (flags[i] == always_true_flags[j]) {
1556 use_flag = false;
1557 break;
1558 }
1559 }
1560 if (use_flag) generated_flags[flag_index++] = flags[i];
1561 }
1562 CHECK(flag_index == flags_len - always_true_flags_len);
1563 flags_len = flag_index;
1564 flags = generated_flags;
1565 }
1566 }
1567 for (int i = 0; context_data[i][0] != NULL; ++i) {
1568 for (int j = 0; statement_data[j] != NULL; ++j) {
1569 int kPrefixLen = i::StrLength(context_data[i][0]);
1570 int kStatementLen = i::StrLength(statement_data[j]);
1571 int kSuffixLen = i::StrLength(context_data[i][1]);
1572 int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
1573
1574 // Plug the source code pieces together.
1575 i::ScopedVector<char> program(kProgramSize + 1);
1576 int length = i::SNPrintF(program,
1577 "%s%s%s",
1578 context_data[i][0],
1579 statement_data[j],
1580 context_data[i][1]);
1581 CHECK(length == kProgramSize);
1582 TestParserSync(program.start(),
1583 flags,
1584 flags_len,
1585 result,
1586 always_true_flags,
1587 always_true_flags_len);
1588 }
1589 }
1590 delete[] generated_flags;
1591}
1592
1593
1594TEST(ErrorsEvalAndArguments) {
1595 // Tests that both preparsing and parsing produce the right kind of errors for
1596 // using "eval" and "arguments" as identifiers. Without the strict mode, it's
1597 // ok to use "eval" or "arguments" as identifiers. With the strict mode, it
1598 // isn't.
1599 const char* context_data[][2] = {
1600 { "\"use strict\";", "" },
1601 { "var eval; function test_func() {\"use strict\"; ", "}"},
1602 { NULL, NULL }
1603 };
1604
1605 const char* statement_data[] = {
1606 "var eval;",
1607 "var arguments",
1608 "var foo, eval;",
1609 "var foo, arguments;",
1610 "try { } catch (eval) { }",
1611 "try { } catch (arguments) { }",
1612 "function eval() { }",
1613 "function arguments() { }",
1614 "function foo(eval) { }",
1615 "function foo(arguments) { }",
1616 "function foo(bar, eval) { }",
1617 "function foo(bar, arguments) { }",
1618 "(eval) => { }",
1619 "(arguments) => { }",
1620 "(foo, eval) => { }",
1621 "(foo, arguments) => { }",
1622 "eval = 1;",
1623 "arguments = 1;",
1624 "var foo = eval = 1;",
1625 "var foo = arguments = 1;",
1626 "++eval;",
1627 "++arguments;",
1628 "eval++;",
1629 "arguments++;",
1630 NULL
1631 };
1632
1633 RunParserSyncTest(context_data, statement_data, kError);
1634}
1635
1636
1637TEST(NoErrorsEvalAndArgumentsSloppy) {
1638 // Tests that both preparsing and parsing accept "eval" and "arguments" as
1639 // identifiers when needed.
1640 const char* context_data[][2] = {
1641 { "", "" },
1642 { "function test_func() {", "}"},
1643 { NULL, NULL }
1644 };
1645
1646 const char* statement_data[] = {
1647 "var eval;",
1648 "var arguments",
1649 "var foo, eval;",
1650 "var foo, arguments;",
1651 "try { } catch (eval) { }",
1652 "try { } catch (arguments) { }",
1653 "function eval() { }",
1654 "function arguments() { }",
1655 "function foo(eval) { }",
1656 "function foo(arguments) { }",
1657 "function foo(bar, eval) { }",
1658 "function foo(bar, arguments) { }",
1659 "eval = 1;",
1660 "arguments = 1;",
1661 "var foo = eval = 1;",
1662 "var foo = arguments = 1;",
1663 "++eval;",
1664 "++arguments;",
1665 "eval++;",
1666 "arguments++;",
1667 NULL
1668 };
1669
1670 RunParserSyncTest(context_data, statement_data, kSuccess);
1671}
1672
1673
1674TEST(NoErrorsEvalAndArgumentsStrict) {
1675 const char* context_data[][2] = {
1676 { "\"use strict\";", "" },
1677 { "function test_func() { \"use strict\";", "}" },
1678 { "() => { \"use strict\"; ", "}" },
1679 { NULL, NULL }
1680 };
1681
1682 const char* statement_data[] = {
1683 "eval;",
1684 "arguments;",
1685 "var foo = eval;",
1686 "var foo = arguments;",
1687 "var foo = { eval: 1 };",
1688 "var foo = { arguments: 1 };",
1689 "var foo = { }; foo.eval = {};",
1690 "var foo = { }; foo.arguments = {};",
1691 NULL
1692 };
1693
1694 static const ParserFlag always_flags[] = {kAllowArrowFunctions};
1695 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1696 always_flags, arraysize(always_flags));
1697}
1698
1699
1700TEST(ErrorsFutureStrictReservedWords) {
1701 // Tests that both preparsing and parsing produce the right kind of errors for
1702 // using future strict reserved words as identifiers. Without the strict mode,
1703 // it's ok to use future strict reserved words as identifiers. With the strict
1704 // mode, it isn't.
1705 const char* context_data[][2] = {
1706 { "\"use strict\";", "" },
1707 { "function test_func() {\"use strict\"; ", "}"},
1708 { "() => { \"use strict\"; ", "}" },
1709 { NULL, NULL }
1710 };
1711
1712 const char* statement_data[] = {
1713 "var interface;",
1714 "var foo, interface;",
1715 "try { } catch (interface) { }",
1716 "function interface() { }",
1717 "function foo(interface) { }",
1718 "function foo(bar, interface) { }",
1719 "interface = 1;",
1720 "var foo = interface = 1;",
1721 "++interface;",
1722 "interface++;",
1723 "var yield = 13;",
1724 NULL
1725 };
1726
1727 static const ParserFlag always_flags[] = {kAllowArrowFunctions};
1728 RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
1729 arraysize(always_flags));
1730}
1731
1732
1733TEST(NoErrorsFutureStrictReservedWords) {
1734 const char* context_data[][2] = {
1735 { "", "" },
1736 { "function test_func() {", "}"},
1737 { "() => {", "}" },
1738 { NULL, NULL }
1739 };
1740
1741 const char* statement_data[] = {
1742 "var interface;",
1743 "var foo, interface;",
1744 "try { } catch (interface) { }",
1745 "function interface() { }",
1746 "function foo(interface) { }",
1747 "function foo(bar, interface) { }",
1748 "interface = 1;",
1749 "var foo = interface = 1;",
1750 "++interface;",
1751 "interface++;",
1752 "var yield = 13;",
1753 NULL
1754 };
1755
1756 static const ParserFlag always_flags[] = {kAllowArrowFunctions};
1757 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
1758 always_flags, arraysize(always_flags));
1759}
1760
1761
1762TEST(ErrorsReservedWords) {
1763 // Tests that both preparsing and parsing produce the right kind of errors for
1764 // using future reserved words as identifiers. These tests don't depend on the
1765 // strict mode.
1766 const char* context_data[][2] = {
1767 { "", "" },
1768 { "\"use strict\";", "" },
1769 { "var eval; function test_func() {", "}"},
1770 { "var eval; function test_func() {\"use strict\"; ", "}"},
1771 { "var eval; () => {", "}"},
1772 { "var eval; () => {\"use strict\"; ", "}"},
1773 { NULL, NULL }
1774 };
1775
1776 const char* statement_data[] = {
1777 "var super;",
1778 "var foo, super;",
1779 "try { } catch (super) { }",
1780 "function super() { }",
1781 "function foo(super) { }",
1782 "function foo(bar, super) { }",
1783 "(super) => { }",
1784 "(bar, super) => { }",
1785 "super = 1;",
1786 "var foo = super = 1;",
1787 "++super;",
1788 "super++;",
1789 "function foo super",
1790 NULL
1791 };
1792
1793 RunParserSyncTest(context_data, statement_data, kError);
1794}
1795
1796
1797TEST(NoErrorsLetSloppyAllModes) {
1798 // In sloppy mode, it's okay to use "let" as identifier.
1799 const char* context_data[][2] = {
1800 { "", "" },
1801 { "function f() {", "}" },
1802 { "(function f() {", "})" },
1803 { NULL, NULL }
1804 };
1805
1806 const char* statement_data[] = {
1807 "var let;",
1808 "var foo, let;",
1809 "try { } catch (let) { }",
1810 "function let() { }",
1811 "(function let() { })",
1812 "function foo(let) { }",
1813 "function foo(bar, let) { }",
1814 "let = 1;",
1815 "var foo = let = 1;",
1816 "let * 2;",
1817 "++let;",
1818 "let++;",
1819 "let: 34",
1820 "function let(let) { let: let(let + let(0)); }",
1821 "({ let: 1 })",
1822 "({ get let() { 1 } })",
1823 "let(100)",
1824 NULL
1825 };
1826
1827 RunParserSyncTest(context_data, statement_data, kSuccess);
1828}
1829
1830
1831TEST(NoErrorsYieldSloppyAllModes) {
1832 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
1833 // generator (see other test).
1834 const char* context_data[][2] = {
1835 { "", "" },
1836 { "function not_gen() {", "}" },
1837 { "(function not_gen() {", "})" },
1838 { NULL, NULL }
1839 };
1840
1841 const char* statement_data[] = {
1842 "var yield;",
1843 "var foo, yield;",
1844 "try { } catch (yield) { }",
1845 "function yield() { }",
1846 "(function yield() { })",
1847 "function foo(yield) { }",
1848 "function foo(bar, yield) { }",
1849 "yield = 1;",
1850 "var foo = yield = 1;",
1851 "yield * 2;",
1852 "++yield;",
1853 "yield++;",
1854 "yield: 34",
1855 "function yield(yield) { yield: yield (yield + yield(0)); }",
1856 "({ yield: 1 })",
1857 "({ get yield() { 1 } })",
1858 "yield(100)",
1859 "yield[100]",
1860 NULL
1861 };
1862
1863 RunParserSyncTest(context_data, statement_data, kSuccess);
1864}
1865
1866
1867TEST(NoErrorsYieldSloppyGeneratorsEnabled) {
1868 // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
1869 // generator (see next test).
1870 const char* context_data[][2] = {
1871 { "", "" },
1872 { "function not_gen() {", "}" },
1873 { "function * gen() { function not_gen() {", "} }" },
1874 { "(function not_gen() {", "})" },
1875 { "(function * gen() { (function not_gen() {", "}) })" },
1876 { NULL, NULL }
1877 };
1878
1879 const char* statement_data[] = {
1880 "var yield;",
1881 "var foo, yield;",
1882 "try { } catch (yield) { }",
1883 "function yield() { }",
1884 "(function yield() { })",
1885 "function foo(yield) { }",
1886 "function foo(bar, yield) { }",
1887 "function * yield() { }",
1888 "(function * yield() { })",
1889 "yield = 1;",
1890 "var foo = yield = 1;",
1891 "yield * 2;",
1892 "++yield;",
1893 "yield++;",
1894 "yield: 34",
1895 "function yield(yield) { yield: yield (yield + yield(0)); }",
1896 "({ yield: 1 })",
1897 "({ get yield() { 1 } })",
1898 "yield(100)",
1899 "yield[100]",
1900 NULL
1901 };
1902
1903 RunParserSyncTest(context_data, statement_data, kSuccess);
1904}
1905
1906
1907TEST(ErrorsYieldStrict) {
1908 const char* context_data[][2] = {
1909 { "\"use strict\";", "" },
1910 { "\"use strict\"; function not_gen() {", "}" },
1911 { "function test_func() {\"use strict\"; ", "}"},
1912 { "\"use strict\"; function * gen() { function not_gen() {", "} }" },
1913 { "\"use strict\"; (function not_gen() {", "})" },
1914 { "\"use strict\"; (function * gen() { (function not_gen() {", "}) })" },
1915 { "() => {\"use strict\"; ", "}" },
1916 { NULL, NULL }
1917 };
1918
1919 const char* statement_data[] = {
1920 "var yield;",
1921 "var foo, yield;",
1922 "try { } catch (yield) { }",
1923 "function yield() { }",
1924 "(function yield() { })",
1925 "function foo(yield) { }",
1926 "function foo(bar, yield) { }",
1927 "function * yield() { }",
1928 "(function * yield() { })",
1929 "yield = 1;",
1930 "var foo = yield = 1;",
1931 "++yield;",
1932 "yield++;",
1933 "yield: 34;",
1934 NULL
1935 };
1936
1937 RunParserSyncTest(context_data, statement_data, kError);
1938}
1939
1940
1941TEST(NoErrorsGenerator) {
1942 const char* context_data[][2] = {
1943 { "function * gen() {", "}" },
1944 { "(function * gen() {", "})" },
1945 { "(function * () {", "})" },
1946 { NULL, NULL }
1947 };
1948
1949 const char* statement_data[] = {
1950 // A generator without a body is valid.
1951 ""
1952 // Valid yield expressions inside generators.
1953 "yield 2;",
1954 "yield * 2;",
1955 "yield * \n 2;",
1956 "yield yield 1;",
1957 "yield * yield * 1;",
1958 "yield 3 + (yield 4);",
1959 "yield * 3 + (yield * 4);",
1960 "(yield * 3) + (yield * 4);",
1961 "yield 3; yield 4;",
1962 "yield * 3; yield * 4;",
1963 "(function (yield) { })",
1964 "yield { yield: 12 }",
1965 "yield /* comment */ { yield: 12 }",
1966 "yield * \n { yield: 12 }",
1967 "yield /* comment */ * \n { yield: 12 }",
1968 // You can return in a generator.
1969 "yield 1; return",
1970 "yield * 1; return",
1971 "yield 1; return 37",
1972 "yield * 1; return 37",
1973 "yield 1; return 37; yield 'dead';",
1974 "yield * 1; return 37; yield * 'dead';",
1975 // Yield is still a valid key in object literals.
1976 "({ yield: 1 })",
1977 "({ get yield() { } })",
1978 // Yield without RHS.
1979 "yield;",
1980 "yield",
1981 "yield\n",
1982 "yield /* comment */"
1983 "yield // comment\n"
1984 "(yield)",
1985 "[yield]",
1986 "{yield}",
1987 "yield, yield",
1988 "yield; yield",
1989 "(yield) ? yield : yield",
1990 "(yield) \n ? yield : yield",
1991 // If there is a newline before the next token, we don't look for RHS.
1992 "yield\nfor (;;) {}",
1993 NULL
1994 };
1995
1996 RunParserSyncTest(context_data, statement_data, kSuccess);
1997}
1998
1999
2000TEST(ErrorsYieldGenerator) {
2001 const char* context_data[][2] = {
2002 { "function * gen() {", "}" },
2003 { "\"use strict\"; function * gen() {", "}" },
2004 { NULL, NULL }
2005 };
2006
2007 const char* statement_data[] = {
2008 // Invalid yield expressions inside generators.
2009 "var yield;",
2010 "var foo, yield;",
2011 "try { } catch (yield) { }",
2012 "function yield() { }",
2013 // The name of the NFE is let-bound in the generator, which does not permit
2014 // yield to be an identifier.
2015 "(function yield() { })",
2016 "(function * yield() { })",
2017 // Yield isn't valid as a formal parameter for generators.
2018 "function * foo(yield) { }",
2019 "(function * foo(yield) { })",
2020 "yield = 1;",
2021 "var foo = yield = 1;",
2022 "++yield;",
2023 "yield++;",
2024 "yield *",
2025 "(yield *)",
2026 // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which
2027 // is invalid.
2028 "yield 3 + yield 4;",
2029 "yield: 34",
2030 "yield ? 1 : 2",
2031 // Parses as yield (/ yield): invalid.
2032 "yield / yield",
2033 "+ yield",
2034 "+ yield 3",
2035 // Invalid (no newline allowed between yield and *).
2036 "yield\n*3",
2037 // Invalid (we see a newline, so we parse {yield:42} as a statement, not an
2038 // object literal, and yield is not a valid label).
2039 "yield\n{yield: 42}",
2040 "yield /* comment */\n {yield: 42}",
2041 "yield //comment\n {yield: 42}",
2042 NULL
2043 };
2044
2045 RunParserSyncTest(context_data, statement_data, kError);
2046}
2047
2048
2049TEST(ErrorsNameOfStrictFunction) {
2050 // Tests that illegal tokens as names of a strict function produce the correct
2051 // errors.
2052 const char* context_data[][2] = {
2053 { "function ", ""},
2054 { "\"use strict\"; function", ""},
2055 { "function * ", ""},
2056 { "\"use strict\"; function * ", ""},
2057 { NULL, NULL }
2058 };
2059
2060 const char* statement_data[] = {
2061 "eval() {\"use strict\";}",
2062 "arguments() {\"use strict\";}",
2063 "interface() {\"use strict\";}",
2064 "yield() {\"use strict\";}",
2065 // Future reserved words are always illegal
2066 "function super() { }",
2067 "function super() {\"use strict\";}",
2068 NULL
2069 };
2070
2071 RunParserSyncTest(context_data, statement_data, kError);
2072}
2073
2074
2075TEST(NoErrorsNameOfStrictFunction) {
2076 const char* context_data[][2] = {
2077 { "function ", ""},
2078 { NULL, NULL }
2079 };
2080
2081 const char* statement_data[] = {
2082 "eval() { }",
2083 "arguments() { }",
2084 "interface() { }",
2085 "yield() { }",
2086 NULL
2087 };
2088
2089 RunParserSyncTest(context_data, statement_data, kSuccess);
2090}
2091
2092
2093TEST(NoErrorsNameOfStrictGenerator) {
2094 const char* context_data[][2] = {
2095 { "function * ", ""},
2096 { NULL, NULL }
2097 };
2098
2099 const char* statement_data[] = {
2100 "eval() { }",
2101 "arguments() { }",
2102 "interface() { }",
2103 "yield() { }",
2104 NULL
2105 };
2106
2107 RunParserSyncTest(context_data, statement_data, kSuccess);
2108}
2109
2110
2111TEST(ErrorsIllegalWordsAsLabelsSloppy) {
2112 // Using future reserved words as labels is always an error.
2113 const char* context_data[][2] = {
2114 { "", ""},
2115 { "function test_func() {", "}" },
2116 { "() => {", "}" },
2117 { NULL, NULL }
2118 };
2119
2120 const char* statement_data[] = {
2121 "super: while(true) { break super; }",
2122 NULL
2123 };
2124
2125 RunParserSyncTest(context_data, statement_data, kError);
2126}
2127
2128
2129TEST(ErrorsIllegalWordsAsLabelsStrict) {
2130 // Tests that illegal tokens as labels produce the correct errors.
2131 const char* context_data[][2] = {
2132 { "\"use strict\";", "" },
2133 { "function test_func() {\"use strict\"; ", "}"},
2134 { "() => {\"use strict\"; ", "}" },
2135 { NULL, NULL }
2136 };
2137
2138 const char* statement_data[] = {
2139 "super: while(true) { break super; }",
2140 "interface: while(true) { break interface; }",
2141 "yield: while(true) { break yield; }",
2142 NULL
2143 };
2144
2145 RunParserSyncTest(context_data, statement_data, kError);
2146}
2147
2148
2149TEST(NoErrorsIllegalWordsAsLabels) {
2150 // Using eval and arguments as labels is legal even in strict mode.
2151 const char* context_data[][2] = {
2152 { "", ""},
2153 { "function test_func() {", "}" },
2154 { "() => {", "}" },
2155 { "\"use strict\";", "" },
2156 { "\"use strict\"; function test_func() {", "}" },
2157 { "\"use strict\"; () => {", "}" },
2158 { NULL, NULL }
2159 };
2160
2161 const char* statement_data[] = {
2162 "mylabel: while(true) { break mylabel; }",
2163 "eval: while(true) { break eval; }",
2164 "arguments: while(true) { break arguments; }",
2165 NULL
2166 };
2167
2168 static const ParserFlag always_flags[] = {kAllowArrowFunctions};
2169 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2170 always_flags, arraysize(always_flags));
2171}
2172
2173
2174TEST(ErrorsParenthesizedLabels) {
2175 // Parenthesized identifiers shouldn't be recognized as labels.
2176 const char* context_data[][2] = {
2177 { "", ""},
2178 { "function test_func() {", "}" },
2179 { "() => {", "}" },
2180 { NULL, NULL }
2181 };
2182
2183 const char* statement_data[] = {
2184 "(mylabel): while(true) { break mylabel; }",
2185 NULL
2186 };
2187
2188 RunParserSyncTest(context_data, statement_data, kError);
2189}
2190
2191
2192TEST(NoErrorsParenthesizedDirectivePrologue) {
2193 // Parenthesized directive prologue shouldn't be recognized.
2194 const char* context_data[][2] = {
2195 { "", ""},
2196 { NULL, NULL }
2197 };
2198
2199 const char* statement_data[] = {
2200 "(\"use strict\"); var eval;",
2201 NULL
2202 };
2203
2204 RunParserSyncTest(context_data, statement_data, kSuccess);
2205}
2206
2207
2208TEST(ErrorsNotAnIdentifierName) {
2209 const char* context_data[][2] = {
2210 { "", ""},
2211 { "\"use strict\";", ""},
2212 { NULL, NULL }
2213 };
2214
2215 const char* statement_data[] = {
2216 "var foo = {}; foo.{;",
2217 "var foo = {}; foo.};",
2218 "var foo = {}; foo.=;",
2219 "var foo = {}; foo.888;",
2220 "var foo = {}; foo.-;",
2221 "var foo = {}; foo.--;",
2222 NULL
2223 };
2224
2225 RunParserSyncTest(context_data, statement_data, kError);
2226}
2227
2228
2229TEST(NoErrorsIdentifierNames) {
2230 // Keywords etc. are valid as property names.
2231 const char* context_data[][2] = {
2232 { "", ""},
2233 { "\"use strict\";", ""},
2234 { NULL, NULL }
2235 };
2236
2237 const char* statement_data[] = {
2238 "var foo = {}; foo.if;",
2239 "var foo = {}; foo.yield;",
2240 "var foo = {}; foo.super;",
2241 "var foo = {}; foo.interface;",
2242 "var foo = {}; foo.eval;",
2243 "var foo = {}; foo.arguments;",
2244 NULL
2245 };
2246
2247 RunParserSyncTest(context_data, statement_data, kSuccess);
2248}
2249
2250
2251TEST(DontRegressPreParserDataSizes) {
2252 // These tests make sure that Parser doesn't start producing less "preparse
2253 // data" (data which the embedder can cache).
2254 v8::V8::Initialize();
2255 v8::Isolate* isolate = CcTest::isolate();
2256 v8::HandleScope handles(isolate);
2257
2258 CcTest::i_isolate()->stack_guard()->SetStackLimit(
2259 i::GetCurrentStackPosition() - 128 * 1024);
2260
2261 struct TestCase {
2262 const char* program;
2263 int functions;
2264 } test_cases[] = {
2265 // No functions.
2266 {"var x = 42;", 0},
2267 // Functions.
2268 {"function foo() {}", 1}, {"function foo() {} function bar() {}", 2},
2269 // Getter / setter functions are recorded as functions if they're on the top
2270 // level.
2271 {"var x = {get foo(){} };", 1},
2272 // Functions insize lazy functions are not recorded.
2273 {"function lazy() { function a() {} function b() {} function c() {} }", 1},
2274 {"function lazy() { var x = {get foo(){} } }", 1},
2275 {NULL, 0}
2276 };
2277
2278 for (int i = 0; test_cases[i].program; i++) {
2279 const char* program = test_cases[i].program;
2280 i::Factory* factory = CcTest::i_isolate()->factory();
2281 i::Handle<i::String> source =
2282 factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
2283 i::Handle<i::Script> script = factory->NewScript(source);
2284 i::CompilationInfoWithZone info(script);
2285 i::ScriptData* sd = NULL;
2286 info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
2287 i::Parser::Parse(&info, true);
2288 i::ParseData pd(sd);
2289
2290 if (pd.FunctionCount() != test_cases[i].functions) {
2291 v8::base::OS::Print(
2292 "Expected preparse data for program:\n"
2293 "\t%s\n"
2294 "to contain %d functions, however, received %d functions.\n",
2295 program, test_cases[i].functions, pd.FunctionCount());
2296 CHECK(false);
2297 }
2298 delete sd;
2299 }
2300}
2301
2302
2303TEST(FunctionDeclaresItselfStrict) {
2304 // Tests that we produce the right kinds of errors when a function declares
2305 // itself strict (we cannot produce there errors as soon as we see the
2306 // offending identifiers, because we don't know at that point whether the
2307 // function is strict or not).
2308 const char* context_data[][2] = {
2309 {"function eval() {", "}"},
2310 {"function arguments() {", "}"},
2311 {"function yield() {", "}"},
2312 {"function interface() {", "}"},
2313 {"function foo(eval) {", "}"},
2314 {"function foo(arguments) {", "}"},
2315 {"function foo(yield) {", "}"},
2316 {"function foo(interface) {", "}"},
2317 {"function foo(bar, eval) {", "}"},
2318 {"function foo(bar, arguments) {", "}"},
2319 {"function foo(bar, yield) {", "}"},
2320 {"function foo(bar, interface) {", "}"},
2321 {"function foo(bar, bar) {", "}"},
2322 { NULL, NULL }
2323 };
2324
2325 const char* strict_statement_data[] = {
2326 "\"use strict\";",
2327 NULL
2328 };
2329
2330 const char* non_strict_statement_data[] = {
2331 ";",
2332 NULL
2333 };
2334
2335 RunParserSyncTest(context_data, strict_statement_data, kError);
2336 RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
2337}
2338
2339
2340TEST(ErrorsTryWithoutCatchOrFinally) {
2341 const char* context_data[][2] = {
2342 {"", ""},
2343 { NULL, NULL }
2344 };
2345
2346 const char* statement_data[] = {
2347 "try { }",
2348 "try { } foo();",
2349 "try { } catch (e) foo();",
2350 "try { } catch { }",
2351 "try { } finally foo();",
2352 NULL
2353 };
2354
2355 RunParserSyncTest(context_data, statement_data, kError);
2356}
2357
2358
2359TEST(NoErrorsTryCatchFinally) {
2360 const char* context_data[][2] = {
2361 {"", ""},
2362 { NULL, NULL }
2363 };
2364
2365 const char* statement_data[] = {
2366 "try { } catch (e) { }",
2367 "try { } catch (e) { } finally { }",
2368 "try { } finally { }",
2369 NULL
2370 };
2371
2372 RunParserSyncTest(context_data, statement_data, kSuccess);
2373}
2374
2375
2376TEST(ErrorsRegexpLiteral) {
2377 const char* context_data[][2] = {
2378 {"var r = ", ""},
2379 { NULL, NULL }
2380 };
2381
2382 const char* statement_data[] = {
2383 "/unterminated",
2384 NULL
2385 };
2386
2387 RunParserSyncTest(context_data, statement_data, kError);
2388}
2389
2390
2391TEST(NoErrorsRegexpLiteral) {
2392 const char* context_data[][2] = {
2393 {"var r = ", ""},
2394 { NULL, NULL }
2395 };
2396
2397 const char* statement_data[] = {
2398 "/foo/",
2399 "/foo/g",
2400 "/foo/whatever", // This is an error but not detected by the parser.
2401 NULL
2402 };
2403
2404 RunParserSyncTest(context_data, statement_data, kSuccess);
2405}
2406
2407
2408TEST(Intrinsics) {
2409 const char* context_data[][2] = {
2410 {"", ""},
2411 { NULL, NULL }
2412 };
2413
2414 const char* statement_data[] = {
2415 "%someintrinsic(arg)",
2416 NULL
2417 };
2418
2419 // This test requires kAllowNativesSyntax to succeed.
2420 static const ParserFlag always_true_flags[] = {
2421 kAllowNativesSyntax
2422 };
2423
2424 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
2425 always_true_flags, 1);
2426}
2427
2428
2429TEST(NoErrorsNewExpression) {
2430 const char* context_data[][2] = {
2431 {"", ""},
2432 {"var f =", ""},
2433 { NULL, NULL }
2434 };
2435
2436 const char* statement_data[] = {
2437 "new foo",
2438 "new foo();",
2439 "new foo(1);",
2440 "new foo(1, 2);",
2441 // The first () will be processed as a part of the NewExpression and the
2442 // second () will be processed as part of LeftHandSideExpression.
2443 "new foo()();",
2444 // The first () will be processed as a part of the inner NewExpression and
2445 // the second () will be processed as a part of the outer NewExpression.
2446 "new new foo()();",
2447 "new foo.bar;",
2448 "new foo.bar();",
2449 "new foo.bar.baz;",
2450 "new foo.bar().baz;",
2451 "new foo[bar];",
2452 "new foo[bar]();",
2453 "new foo[bar][baz];",
2454 "new foo[bar]()[baz];",
2455 "new foo[bar].baz(baz)()[bar].baz;",
2456 "new \"foo\"", // Runtime error
2457 "new 1", // Runtime error
2458 // This even runs:
2459 "(new new Function(\"this.x = 1\")).x;",
2460 "new new Test_Two(String, 2).v(0123).length;",
2461 NULL
2462 };
2463
2464 RunParserSyncTest(context_data, statement_data, kSuccess);
2465}
2466
2467
2468TEST(ErrorsNewExpression) {
2469 const char* context_data[][2] = {
2470 {"", ""},
2471 {"var f =", ""},
2472 { NULL, NULL }
2473 };
2474
2475 const char* statement_data[] = {
2476 "new foo bar",
2477 "new ) foo",
2478 "new ++foo",
2479 "new foo ++",
2480 NULL
2481 };
2482
2483 RunParserSyncTest(context_data, statement_data, kError);
2484}
2485
2486
2487TEST(StrictObjectLiteralChecking) {
2488 const char* strict_context_data[][2] = {
2489 {"\"use strict\"; var myobject = {", "};"},
2490 {"\"use strict\"; var myobject = {", ",};"},
2491 { NULL, NULL }
2492 };
2493 const char* non_strict_context_data[][2] = {
2494 {"var myobject = {", "};"},
2495 {"var myobject = {", ",};"},
2496 { NULL, NULL }
2497 };
2498
2499 // These are only errors in strict mode.
2500 const char* statement_data[] = {
2501 "foo: 1, foo: 2",
2502 "\"foo\": 1, \"foo\": 2",
2503 "foo: 1, \"foo\": 2",
2504 "1: 1, 1: 2",
2505 "1: 1, \"1\": 2",
2506 "get: 1, get: 2", // Not a getter for real, just a property called get.
2507 "set: 1, set: 2", // Not a setter for real, just a property called set.
2508 NULL
2509 };
2510
2511 RunParserSyncTest(non_strict_context_data, statement_data, kSuccess);
2512 RunParserSyncTest(strict_context_data, statement_data, kError);
2513}
2514
2515
2516TEST(ErrorsObjectLiteralChecking) {
2517 const char* context_data[][2] = {
2518 {"\"use strict\"; var myobject = {", "};"},
2519 {"var myobject = {", "};"},
2520 { NULL, NULL }
2521 };
2522
2523 const char* statement_data[] = {
2524 ",",
2525 "foo: 1, get foo() {}",
2526 "foo: 1, set foo(v) {}",
2527 "\"foo\": 1, get \"foo\"() {}",
2528 "\"foo\": 1, set \"foo\"(v) {}",
2529 "1: 1, get 1() {}",
2530 "1: 1, set 1() {}",
2531 "get foo() {}, get foo() {}",
2532 "set foo(_) {}, set foo(_) {}",
2533 // It's counter-intuitive, but these collide too (even in classic
2534 // mode). Note that we can have "foo" and foo as properties in classic
2535 // mode,
2536 // but we cannot have "foo" and get foo, or foo and get "foo".
2537 "foo: 1, get \"foo\"() {}",
2538 "foo: 1, set \"foo\"(v) {}",
2539 "\"foo\": 1, get foo() {}",
2540 "\"foo\": 1, set foo(v) {}",
2541 "1: 1, get \"1\"() {}",
2542 "1: 1, set \"1\"() {}",
2543 "\"1\": 1, get 1() {}"
2544 "\"1\": 1, set 1(v) {}"
2545 // Wrong number of parameters
2546 "get bar(x) {}",
2547 "get bar(x, y) {}",
2548 "set bar() {}",
2549 "set bar(x, y) {}",
2550 // Parsing FunctionLiteral for getter or setter fails
2551 "get foo( +",
2552 "get foo() \"error\"",
2553 NULL};
2554
2555 RunParserSyncTest(context_data, statement_data, kError);
2556}
2557
2558
2559TEST(NoErrorsObjectLiteralChecking) {
2560 const char* context_data[][2] = {
2561 {"var myobject = {", "};"},
2562 {"var myobject = {", ",};"},
2563 {"\"use strict\"; var myobject = {", "};"},
2564 {"\"use strict\"; var myobject = {", ",};"},
2565 { NULL, NULL }
2566 };
2567
2568 const char* statement_data[] = {
2569 "foo: 1, bar: 2",
2570 "\"foo\": 1, \"bar\": 2",
2571 "1: 1, 2: 2",
2572 // Syntax: IdentifierName ':' AssignmentExpression
2573 "foo: bar = 5 + baz",
2574 // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}'
2575 "get foo() {}",
2576 "get \"foo\"() {}",
2577 "get 1() {}",
2578 // Syntax: 'set' PropertyName '(' PropertySetParameterList ')'
2579 // '{' FunctionBody '}'
2580 "set foo(v) {}",
2581 "set \"foo\"(v) {}",
2582 "set 1(v) {}",
2583 // Non-colliding getters and setters -> no errors
2584 "foo: 1, get bar() {}",
2585 "foo: 1, set bar(v) {}",
2586 "\"foo\": 1, get \"bar\"() {}",
2587 "\"foo\": 1, set \"bar\"(v) {}",
2588 "1: 1, get 2() {}",
2589 "1: 1, set 2(v) {}",
2590 "get: 1, get foo() {}",
2591 "set: 1, set foo(_) {}",
2592 // Keywords, future reserved and strict future reserved are also allowed as
2593 // property names.
2594 "if: 4",
2595 "interface: 5",
2596 "super: 6",
2597 "eval: 7",
2598 "arguments: 8",
2599 NULL
2600 };
2601
2602 RunParserSyncTest(context_data, statement_data, kSuccess);
2603}
2604
2605
2606TEST(TooManyArguments) {
2607 const char* context_data[][2] = {
2608 {"foo(", "0)"},
2609 { NULL, NULL }
2610 };
2611
2612 using v8::internal::Code;
2613 char statement[Code::kMaxArguments * 2 + 1];
2614 for (int i = 0; i < Code::kMaxArguments; ++i) {
2615 statement[2 * i] = '0';
2616 statement[2 * i + 1] = ',';
2617 }
2618 statement[Code::kMaxArguments * 2] = 0;
2619
2620 const char* statement_data[] = {
2621 statement,
2622 NULL
2623 };
2624
2625 // The test is quite slow, so run it with a reduced set of flags.
2626 static const ParserFlag empty_flags[] = {kAllowLazy};
2627 RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
2628}
2629
2630
2631TEST(StrictDelete) {
2632 // "delete <Identifier>" is not allowed in strict mode.
2633 const char* strict_context_data[][2] = {
2634 {"\"use strict\"; ", ""},
2635 { NULL, NULL }
2636 };
2637
2638 const char* sloppy_context_data[][2] = {
2639 {"", ""},
2640 { NULL, NULL }
2641 };
2642
2643 // These are errors in the strict mode.
2644 const char* sloppy_statement_data[] = {
2645 "delete foo;",
2646 "delete foo + 1;",
2647 "delete (foo);",
2648 "delete eval;",
2649 "delete interface;",
2650 NULL
2651 };
2652
2653 // These are always OK
2654 const char* good_statement_data[] = {
2655 "delete this;",
2656 "delete 1;",
2657 "delete 1 + 2;",
2658 "delete foo();",
2659 "delete foo.bar;",
2660 "delete foo[bar];",
2661 "delete foo--;",
2662 "delete --foo;",
2663 "delete new foo();",
2664 "delete new foo(bar);",
2665 NULL
2666 };
2667
2668 // These are always errors
2669 const char* bad_statement_data[] = {
2670 "delete if;",
2671 NULL
2672 };
2673
2674 RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
2675 RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
2676
2677 RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
2678 RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
2679
2680 RunParserSyncTest(strict_context_data, bad_statement_data, kError);
2681 RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
2682}
2683
2684
2685TEST(InvalidLeftHandSide) {
2686 const char* assignment_context_data[][2] = {
2687 {"", " = 1;"},
2688 {"\"use strict\"; ", " = 1;"},
2689 { NULL, NULL }
2690 };
2691
2692 const char* prefix_context_data[][2] = {
2693 {"++", ";"},
2694 {"\"use strict\"; ++", ";"},
2695 {NULL, NULL},
2696 };
2697
2698 const char* postfix_context_data[][2] = {
2699 {"", "++;"},
2700 {"\"use strict\"; ", "++;"},
2701 { NULL, NULL }
2702 };
2703
2704 // Good left hand sides for assigment or prefix / postfix operations.
2705 const char* good_statement_data[] = {
2706 "foo",
2707 "foo.bar",
2708 "foo[bar]",
2709 "foo()[bar]",
2710 "foo().bar",
2711 "this.foo",
2712 "this[foo]",
2713 "new foo()[bar]",
2714 "new foo().bar",
2715 "foo()",
2716 "foo(bar)",
2717 "foo[bar]()",
2718 "foo.bar()",
2719 "this()",
2720 "this.foo()",
2721 "this[foo].bar()",
2722 "this.foo[foo].bar(this)(bar)[foo]()",
2723 NULL
2724 };
2725
2726 // Bad left hand sides for assigment or prefix / postfix operations.
2727 const char* bad_statement_data_common[] = {
2728 "2",
2729 "new foo",
2730 "new foo()",
2731 "null",
2732 "if", // Unexpected token
2733 "{x: 1}", // Unexpected token
2734 "this",
2735 "\"bar\"",
2736 "(foo + bar)",
2737 "new new foo()[bar]", // means: new (new foo()[bar])
2738 "new new foo().bar", // means: new (new foo()[bar])
2739 NULL
2740 };
2741
2742 // These are not okay for assignment, but okay for prefix / postix.
2743 const char* bad_statement_data_for_assignment[] = {
2744 "++foo",
2745 "foo++",
2746 "foo + bar",
2747 NULL
2748 };
2749
2750 RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
2751 RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
2752 RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
2753 kError);
2754
2755 RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
2756 RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
2757
2758 RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
2759 RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);
2760}
2761
2762
2763TEST(FuncNameInferrerBasic) {
2764 // Tests that function names are inferred properly.
2765 i::FLAG_allow_natives_syntax = true;
2766 v8::Isolate* isolate = CcTest::isolate();
2767 v8::HandleScope scope(isolate);
2768 LocalContext env;
2769 CompileRun("var foo1 = function() {}; "
2770 "var foo2 = function foo3() {}; "
2771 "function not_ctor() { "
2772 " var foo4 = function() {}; "
2773 " return %FunctionGetInferredName(foo4); "
2774 "} "
2775 "function Ctor() { "
2776 " var foo5 = function() {}; "
2777 " return %FunctionGetInferredName(foo5); "
2778 "} "
2779 "var obj1 = { foo6: function() {} }; "
2780 "var obj2 = { 'foo7': function() {} }; "
2781 "var obj3 = {}; "
2782 "obj3[1] = function() {}; "
2783 "var obj4 = {}; "
2784 "obj4[1] = function foo8() {}; "
2785 "var obj5 = {}; "
2786 "obj5['foo9'] = function() {}; "
2787 "var obj6 = { obj7 : { foo10: function() {} } };");
2788 ExpectString("%FunctionGetInferredName(foo1)", "foo1");
2789 // foo2 is not unnamed -> its name is not inferred.
2790 ExpectString("%FunctionGetInferredName(foo2)", "");
2791 ExpectString("not_ctor()", "foo4");
2792 ExpectString("Ctor()", "Ctor.foo5");
2793 ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6");
2794 ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7");
2795 ExpectString("%FunctionGetInferredName(obj3[1])",
2796 "obj3.(anonymous function)");
2797 ExpectString("%FunctionGetInferredName(obj4[1])", "");
2798 ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9");
2799 ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10");
2800}
2801
2802
2803TEST(FuncNameInferrerTwoByte) {
2804 // Tests function name inferring in cases where some parts of the inferred
2805 // function name are two-byte strings.
2806 i::FLAG_allow_natives_syntax = true;
2807 v8::Isolate* isolate = CcTest::isolate();
2808 v8::HandleScope scope(isolate);
2809 LocalContext env;
2810 uint16_t* two_byte_source = AsciiToTwoByteString(
2811 "var obj1 = { oXj2 : { foo1: function() {} } }; "
2812 "%FunctionGetInferredName(obj1.oXj2.foo1)");
2813 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
2814 // Make it really non-Latin1 (replace the Xs with a non-Latin1 character).
2815 two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d;
2816 v8::Local<v8::String> source =
2817 v8::String::NewFromTwoByte(isolate, two_byte_source);
2818 v8::Local<v8::Value> result = CompileRun(source);
2819 CHECK(result->IsString());
2820 v8::Local<v8::String> expected_name =
2821 v8::String::NewFromTwoByte(isolate, two_byte_name);
2822 CHECK(result->Equals(expected_name));
2823 i::DeleteArray(two_byte_source);
2824 i::DeleteArray(two_byte_name);
2825}
2826
2827
2828TEST(FuncNameInferrerEscaped) {
2829 // The same as FuncNameInferrerTwoByte, except that we express the two-byte
2830 // character as a unicode escape.
2831 i::FLAG_allow_natives_syntax = true;
2832 v8::Isolate* isolate = CcTest::isolate();
2833 v8::HandleScope scope(isolate);
2834 LocalContext env;
2835 uint16_t* two_byte_source = AsciiToTwoByteString(
2836 "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; "
2837 "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)");
2838 uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
2839 // Fix to correspond to the non-ASCII name in two_byte_source.
2840 two_byte_name[6] = 0x010d;
2841 v8::Local<v8::String> source =
2842 v8::String::NewFromTwoByte(isolate, two_byte_source);
2843 v8::Local<v8::Value> result = CompileRun(source);
2844 CHECK(result->IsString());
2845 v8::Local<v8::String> expected_name =
2846 v8::String::NewFromTwoByte(isolate, two_byte_name);
2847 CHECK(result->Equals(expected_name));
2848 i::DeleteArray(two_byte_source);
2849 i::DeleteArray(two_byte_name);
2850}
2851
2852
2853TEST(RegressionLazyFunctionWithErrorWithArg) {
2854 // The bug occurred when a lazy function had an error which requires a
2855 // parameter (such as "unknown label" here). The error message was processed
2856 // before the AstValueFactory containing the error message string was
2857 // internalized.
2858 v8::Isolate* isolate = CcTest::isolate();
2859 v8::HandleScope scope(isolate);
2860 LocalContext env;
2861 i::FLAG_lazy = true;
2862 i::FLAG_min_preparse_length = 0;
2863 CompileRun("function this_is_lazy() {\n"
2864 " break p;\n"
2865 "}\n"
2866 "this_is_lazy();\n");
2867}
2868
2869
2870TEST(SerializationOfMaybeAssignmentFlag) {
2871 i::Isolate* isolate = CcTest::i_isolate();
2872 i::Factory* factory = isolate->factory();
2873 i::HandleScope scope(isolate);
2874 LocalContext env;
2875
2876 const char* src =
2877 "function h() {"
2878 " var result = [];"
2879 " function f() {"
2880 " result.push(2);"
2881 " }"
2882 " function assertResult(r) {"
2883 " f();"
2884 " result = [];"
2885 " }"
2886 " assertResult([2]);"
2887 " assertResult([2]);"
2888 " return f;"
2889 "};"
2890 "h();";
2891
2892 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
2893 i::SNPrintF(program, "%s", src);
2894 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
2895 source->PrintOn(stdout);
2896 printf("\n");
2897 i::Zone zone(isolate);
2898 v8::Local<v8::Value> v = CompileRun(src);
2899 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
2900 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
2901 i::Context* context = f->context();
2902 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
2903 avf.Internalize(isolate);
2904 const i::AstRawString* name = avf.GetOneByteString("result");
2905 i::Handle<i::String> str = name->string();
2906 CHECK(str->IsInternalizedString());
2907 i::Scope* global_scope =
2908 new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
2909 global_scope->Initialize();
2910 i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
2911 DCHECK(s != global_scope);
2912 DCHECK(name != NULL);
2913
2914 // Get result from h's function context (that is f's context)
2915 i::Variable* var = s->Lookup(name);
2916
2917 CHECK(var != NULL);
2918 // Maybe assigned should survive deserialization
2919 CHECK(var->maybe_assigned() == i::kMaybeAssigned);
2920 // TODO(sigurds) Figure out if is_used should survive context serialization.
2921}
2922
2923
2924TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
2925 i::Isolate* isolate = CcTest::i_isolate();
2926 i::Factory* factory = isolate->factory();
2927 i::HandleScope scope(isolate);
2928 LocalContext env;
2929
2930
2931 const char* src =
2932 "function f(x) {"
2933 " var a = arguments;"
2934 " function g(i) {"
2935 " ++a[0];"
2936 " };"
2937 " return g;"
2938 " }"
2939 "f(0);";
2940
2941 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
2942 i::SNPrintF(program, "%s", src);
2943 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
2944 source->PrintOn(stdout);
2945 printf("\n");
2946 i::Zone zone(isolate);
2947 v8::Local<v8::Value> v = CompileRun(src);
2948 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
2949 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
2950 i::Context* context = f->context();
2951 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
2952 avf.Internalize(isolate);
2953
2954 i::Scope* global_scope =
2955 new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
2956 global_scope->Initialize();
2957 i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
2958 DCHECK(s != global_scope);
2959 const i::AstRawString* name_x = avf.GetOneByteString("x");
2960
2961 // Get result from f's function context (that is g's outer context)
2962 i::Variable* var_x = s->Lookup(name_x);
2963 CHECK(var_x != NULL);
2964 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
2965}
2966
2967
2968TEST(ExportsMaybeAssigned) {
2969 i::FLAG_use_strict = true;
2970 i::FLAG_harmony_scoping = true;
2971 i::FLAG_harmony_modules = true;
2972
2973 i::Isolate* isolate = CcTest::i_isolate();
2974 i::Factory* factory = isolate->factory();
2975 i::HandleScope scope(isolate);
2976 LocalContext env;
2977
2978 const char* src =
2979 "module A {"
2980 " export var x = 1;"
2981 " export function f() { return x };"
2982 " export const y = 2;"
2983 " module B {}"
2984 " export module C {}"
2985 "};"
2986 "A.f";
2987
2988 i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
2989 i::SNPrintF(program, "%s", src);
2990 i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
2991 source->PrintOn(stdout);
2992 printf("\n");
2993 i::Zone zone(isolate);
2994 v8::Local<v8::Value> v = CompileRun(src);
2995 i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
2996 i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
2997 i::Context* context = f->context();
2998 i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
2999 avf.Internalize(isolate);
3000
3001 i::Scope* global_scope =
3002 new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
3003 global_scope->Initialize();
3004 i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
3005 DCHECK(s != global_scope);
3006 const i::AstRawString* name_x = avf.GetOneByteString("x");
3007 const i::AstRawString* name_f = avf.GetOneByteString("f");
3008 const i::AstRawString* name_y = avf.GetOneByteString("y");
3009 const i::AstRawString* name_B = avf.GetOneByteString("B");
3010 const i::AstRawString* name_C = avf.GetOneByteString("C");
3011
3012 // Get result from h's function context (that is f's context)
3013 i::Variable* var_x = s->Lookup(name_x);
3014 CHECK(var_x != NULL);
3015 CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
3016 i::Variable* var_f = s->Lookup(name_f);
3017 CHECK(var_f != NULL);
3018 CHECK(var_f->maybe_assigned() == i::kMaybeAssigned);
3019 i::Variable* var_y = s->Lookup(name_y);
3020 CHECK(var_y != NULL);
3021 CHECK(var_y->maybe_assigned() == i::kNotAssigned);
3022 i::Variable* var_B = s->Lookup(name_B);
3023 CHECK(var_B != NULL);
3024 CHECK(var_B->maybe_assigned() == i::kNotAssigned);
3025 i::Variable* var_C = s->Lookup(name_C);
3026 CHECK(var_C != NULL);
3027 CHECK(var_C->maybe_assigned() == i::kNotAssigned);
3028}
3029
3030
3031TEST(InnerAssignment) {
3032 i::Isolate* isolate = CcTest::i_isolate();
3033 i::Factory* factory = isolate->factory();
3034 i::HandleScope scope(isolate);
3035 LocalContext env;
3036
3037 const char* prefix = "function f() {";
3038 const char* midfix = " function g() {";
3039 const char* suffix = "}}";
3040 struct { const char* source; bool assigned; bool strict; } outers[] = {
3041 // Actual assignments.
3042 { "var x; var x = 5;", true, false },
3043 { "var x; { var x = 5; }", true, false },
3044 { "'use strict'; let x; x = 6;", true, true },
3045 { "var x = 5; function x() {}", true, false },
3046 // Actual non-assignments.
3047 { "var x;", false, false },
3048 { "var x = 5;", false, false },
3049 { "'use strict'; let x;", false, true },
3050 { "'use strict'; let x = 6;", false, true },
3051 { "'use strict'; var x = 0; { let x = 6; }", false, true },
3052 { "'use strict'; var x = 0; { let x; x = 6; }", false, true },
3053 { "'use strict'; let x = 0; { let x = 6; }", false, true },
3054 { "'use strict'; let x = 0; { let x; x = 6; }", false, true },
3055 { "var x; try {} catch (x) { x = 5; }", false, false },
3056 { "function x() {}", false, false },
3057 // Eval approximation.
3058 { "var x; eval('');", true, false },
3059 { "eval(''); var x;", true, false },
3060 { "'use strict'; let x; eval('');", true, true },
3061 { "'use strict'; eval(''); let x;", true, true },
3062 // Non-assignments not recognized, because the analysis is approximative.
3063 { "var x; var x;", true, false },
3064 { "var x = 5; var x;", true, false },
3065 { "var x; { var x; }", true, false },
3066 { "var x; function x() {}", true, false },
3067 { "function x() {}; var x;", true, false },
3068 { "var x; try {} catch (x) { var x = 5; }", true, false },
3069 };
3070 struct { const char* source; bool assigned; bool with; } inners[] = {
3071 // Actual assignments.
3072 { "x = 1;", true, false },
3073 { "x++;", true, false },
3074 { "++x;", true, false },
3075 { "x--;", true, false },
3076 { "--x;", true, false },
3077 { "{ x = 1; }", true, false },
3078 { "'use strict'; { let x; }; x = 0;", true, false },
3079 { "'use strict'; { const x = 1; }; x = 0;", true, false },
3080 { "'use strict'; { function x() {} }; x = 0;", true, false },
3081 { "with ({}) { x = 1; }", true, true },
3082 { "eval('');", true, false },
3083 { "'use strict'; { let y; eval('') }", true, false },
3084 { "function h() { x = 0; }", true, false },
3085 { "(function() { x = 0; })", true, false },
3086 { "(function() { x = 0; })", true, false },
3087 { "with ({}) (function() { x = 0; })", true, true },
3088 // Actual non-assignments.
3089 { "", false, false },
3090 { "x;", false, false },
3091 { "var x;", false, false },
3092 { "var x = 8;", false, false },
3093 { "var x; x = 8;", false, false },
3094 { "'use strict'; let x;", false, false },
3095 { "'use strict'; let x = 8;", false, false },
3096 { "'use strict'; let x; x = 8;", false, false },
3097 { "'use strict'; const x = 8;", false, false },
3098 { "function x() {}", false, false },
3099 { "function x() { x = 0; }", false, false },
3100 { "function h(x) { x = 0; }", false, false },
3101 { "'use strict'; { let x; x = 0; }", false, false },
3102 { "{ var x; }; x = 0;", false, false },
3103 { "with ({}) {}", false, true },
3104 { "var x; { with ({}) { x = 1; } }", false, true },
3105 { "try {} catch(x) { x = 0; }", false, false },
3106 { "try {} catch(x) { with ({}) { x = 1; } }", false, true },
3107 // Eval approximation.
3108 { "eval('');", true, false },
3109 { "function h() { eval(''); }", true, false },
3110 { "(function() { eval(''); })", true, false },
3111 // Shadowing not recognized because of eval approximation.
3112 { "var x; eval('');", true, false },
3113 { "'use strict'; let x; eval('');", true, false },
3114 { "try {} catch(x) { eval(''); }", true, false },
3115 { "function x() { eval(''); }", true, false },
3116 { "(function(x) { eval(''); })", true, false },
3117 };
3118
3119 // Used to trigger lazy compilation of function
3120 int comment_len = 2048;
3121 i::ScopedVector<char> comment(comment_len + 1);
3122 i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0);
3123 int prefix_len = Utf8LengthHelper(prefix);
3124 int midfix_len = Utf8LengthHelper(midfix);
3125 int suffix_len = Utf8LengthHelper(suffix);
3126 for (unsigned i = 0; i < arraysize(outers); ++i) {
3127 const char* outer = outers[i].source;
3128 int outer_len = Utf8LengthHelper(outer);
3129 for (unsigned j = 0; j < arraysize(inners); ++j) {
3130 for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) {
3131 for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) {
3132 if (outers[i].strict && inners[j].with) continue;
3133 const char* inner = inners[j].source;
3134 int inner_len = Utf8LengthHelper(inner);
3135
3136 int outer_comment_len = outer_lazy ? comment_len : 0;
3137 int inner_comment_len = inner_lazy ? comment_len : 0;
3138 const char* outer_comment = outer_lazy ? comment.start() : "";
3139 const char* inner_comment = inner_lazy ? comment.start() : "";
3140 int len = prefix_len + outer_comment_len + outer_len + midfix_len +
3141 inner_comment_len + inner_len + suffix_len;
3142 i::ScopedVector<char> program(len + 1);
3143
3144 i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer,
3145 midfix, inner_comment, inner, suffix);
3146 i::Handle<i::String> source =
3147 factory->InternalizeUtf8String(program.start());
3148 source->PrintOn(stdout);
3149 printf("\n");
3150
3151 i::Handle<i::Script> script = factory->NewScript(source);
3152 i::CompilationInfoWithZone info(script);
3153 i::Parser::ParseInfo parse_info = {
3154 isolate->stack_guard()->real_climit(),
3155 isolate->heap()->HashSeed(), isolate->unicode_cache()};
3156 i::Parser parser(&info, &parse_info);
3157 parser.set_allow_harmony_scoping(true);
3158 CHECK(parser.Parse());
3159 CHECK(i::Rewriter::Rewrite(&info));
3160 CHECK(i::Scope::Analyze(&info));
3161 CHECK(info.function() != NULL);
3162
3163 i::Scope* scope = info.function()->scope();
3164 CHECK_EQ(scope->inner_scopes()->length(), 1);
3165 i::Scope* inner_scope = scope->inner_scopes()->at(0);
3166 const i::AstRawString* var_name =
3167 info.ast_value_factory()->GetOneByteString("x");
3168 i::Variable* var = inner_scope->Lookup(var_name);
3169 bool expected = outers[i].assigned || inners[j].assigned;
3170 CHECK(var != NULL);
3171 CHECK(var->is_used() || !expected);
3172 CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected);
3173 }
3174 }
3175 }
3176 }
3177}
3178
3179namespace {
3180
3181int* global_use_counts = NULL;
3182
3183void MockUseCounterCallback(v8::Isolate* isolate,
3184 v8::Isolate::UseCounterFeature feature) {
3185 ++global_use_counts[feature];
3186}
3187
3188}
3189
3190
3191TEST(UseAsmUseCount) {
3192 i::Isolate* isolate = CcTest::i_isolate();
3193 i::HandleScope scope(isolate);
3194 LocalContext env;
3195 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
3196 global_use_counts = use_counts;
3197 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
3198 CompileRun("\"use asm\";\n"
3199 "var foo = 1;\n"
3200 "\"use asm\";\n" // Only the first one counts.
3201 "function bar() { \"use asm\"; var baz = 1; }");
3202 CHECK_EQ(2, use_counts[v8::Isolate::kUseAsm]);
3203}
3204
3205
3206TEST(ErrorsArrowFunctions) {
3207 // Tests that parser and preparser generate the same kind of errors
3208 // on invalid arrow function syntax.
3209 const char* context_data[][2] = {
3210 {"", ";"},
3211 {"v = ", ";"},
3212 {"bar ? (", ") : baz;"},
3213 {"bar ? baz : (", ");"},
3214 {"bar[", "];"},
3215 {"bar, ", ";"},
3216 {"", ", bar;"},
3217 {NULL, NULL}
3218 };
3219
3220 const char* statement_data[] = {
3221 "=> 0",
3222 "=>",
3223 "() =>",
3224 "=> {}",
3225 ") => {}",
3226 ", => {}",
3227 "(,) => {}",
3228 "return => {}",
3229 "() => {'value': 42}",
3230
3231 // Check that the early return introduced in ParsePrimaryExpression
3232 // does not accept stray closing parentheses.
3233 ")",
3234 ") => 0",
3235 "foo[()]",
3236 "()",
3237
3238 // Parameter lists with extra parens should be recognized as errors.
3239 "(()) => 0",
3240 "((x)) => 0",
3241 "((x, y)) => 0",
3242 "(x, (y)) => 0",
3243 "((x, y, z)) => 0",
3244 "(x, (y, z)) => 0",
3245 "((x, y), z) => 0",
3246
3247 // Parameter lists are always validated as strict, so those are errors.
3248 "eval => {}",
3249 "arguments => {}",
3250 "yield => {}",
3251 "interface => {}",
3252 "(eval) => {}",
3253 "(arguments) => {}",
3254 "(yield) => {}",
3255 "(interface) => {}",
3256 "(eval, bar) => {}",
3257 "(bar, eval) => {}",
3258 "(bar, arguments) => {}",
3259 "(bar, yield) => {}",
3260 "(bar, interface) => {}",
3261 // TODO(aperez): Detecting duplicates does not work in PreParser.
3262 // "(bar, bar) => {}",
3263
3264 // The parameter list is parsed as an expression, but only
3265 // a comma-separated list of identifier is valid.
3266 "32 => {}",
3267 "(32) => {}",
3268 "(a, 32) => {}",
3269 "if => {}",
3270 "(if) => {}",
3271 "(a, if) => {}",
3272 "a + b => {}",
3273 "(a + b) => {}",
3274 "(a + b, c) => {}",
3275 "(a, b - c) => {}",
3276 "\"a\" => {}",
3277 "(\"a\") => {}",
3278 "(\"a\", b) => {}",
3279 "(a, \"b\") => {}",
3280 "-a => {}",
3281 "(-a) => {}",
3282 "(-a, b) => {}",
3283 "(a, -b) => {}",
3284 "{} => {}",
3285 "({}) => {}",
3286 "(a, {}) => {}",
3287 "({}, a) => {}",
3288 "a++ => {}",
3289 "(a++) => {}",
3290 "(a++, b) => {}",
3291 "(a, b++) => {}",
3292 "[] => {}",
3293 "([]) => {}",
3294 "(a, []) => {}",
3295 "([], a) => {}",
3296 "(a = b) => {}",
3297 "(a = b, c) => {}",
3298 "(a, b = c) => {}",
3299 "(foo ? bar : baz) => {}",
3300 "(a, foo ? bar : baz) => {}",
3301 "(foo ? bar : baz, a) => {}",
3302 NULL
3303 };
3304
3305 // The test is quite slow, so run it with a reduced set of flags.
3306 static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
3307 static const ParserFlag always_flags[] = { kAllowArrowFunctions };
3308 RunParserSyncTest(context_data, statement_data, kError, flags,
3309 arraysize(flags), always_flags, arraysize(always_flags));
3310}
3311
3312
3313TEST(NoErrorsArrowFunctions) {
3314 // Tests that parser and preparser accept valid arrow functions syntax.
3315 const char* context_data[][2] = {
3316 {"", ";"},
3317 {"bar ? (", ") : baz;"},
3318 {"bar ? baz : (", ");"},
3319 {"bar, ", ";"},
3320 {"", ", bar;"},
3321 {NULL, NULL}
3322 };
3323
3324 const char* statement_data[] = {
3325 "() => {}",
3326 "() => { return 42 }",
3327 "x => { return x; }",
3328 "(x) => { return x; }",
3329 "(x, y) => { return x + y; }",
3330 "(x, y, z) => { return x + y + z; }",
3331 "(x, y) => { x.a = y; }",
3332 "() => 42",
3333 "x => x",
3334 "x => x * x",
3335 "(x) => x",
3336 "(x) => x * x",
3337 "(x, y) => x + y",
3338 "(x, y, z) => x, y, z",
3339 "(x, y) => x.a = y",
3340 "() => ({'value': 42})",
3341 "x => y => x + y",
3342 "(x, y) => (u, v) => x*u + y*v",
3343 "(x, y) => z => z * (x + y)",
3344 "x => (y, z) => z * (x + y)",
3345
3346 // Those are comma-separated expressions, with arrow functions as items.
3347 // They stress the code for validating arrow function parameter lists.
3348 "a, b => 0",
3349 "a, b, (c, d) => 0",
3350 "(a, b, (c, d) => 0)",
3351 "(a, b) => 0, (c, d) => 1",
3352 "(a, b => {}, a => a + 1)",
3353 "((a, b) => {}, (a => a + 1))",
3354 "(a, (a, (b, c) => 0))",
3355
3356 // Arrow has more precedence, this is the same as: foo ? bar : (baz = {})
3357 "foo ? bar : baz => {}",
3358 NULL
3359 };
3360
3361 static const ParserFlag always_flags[] = {kAllowArrowFunctions};
3362 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3363 always_flags, arraysize(always_flags));
3364}
3365
3366
3367TEST(NoErrorsSuper) {
3368 // Tests that parser and preparser accept 'super' keyword in right places.
3369 const char* context_data[][2] = {{"", ";"},
3370 {"k = ", ";"},
3371 {"foo(", ");"},
3372 {NULL, NULL}};
3373
3374 const char* statement_data[] = {
3375 "super.x",
3376 "super[27]",
3377 "new super",
3378 "new super()",
3379 "new super(12, 45)",
3380 "new new super",
3381 "new new super()",
3382 "new new super()()",
3383 "z.super", // Ok, property lookup.
3384 NULL};
3385
3386 static const ParserFlag always_flags[] = {kAllowClasses};
3387 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3388 always_flags, arraysize(always_flags));
3389}
3390
3391
3392TEST(ErrorsSuper) {
3393 // Tests that parser and preparser generate same errors for 'super'.
3394 const char* context_data[][2] = {{"", ";"},
3395 {"k = ", ";"},
3396 {"foo(", ");"},
3397 {NULL, NULL}};
3398
3399 const char* statement_data[] = {
3400 "super = x",
3401 "y = super",
3402 "f(super)",
3403 NULL};
3404
3405 static const ParserFlag always_flags[] = {kAllowClasses};
3406 RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
3407 always_flags, arraysize(always_flags));
3408}
3409
3410
3411TEST(NoErrorsMethodDefinition) {
3412 const char* context_data[][2] = {{"({", "});"},
3413 {"'use strict'; ({", "});"},
3414 {"({*", "});"},
3415 {"'use strict'; ({*", "});"},
3416 {NULL, NULL}};
3417
3418 const char* object_literal_body_data[] = {
3419 "m() {}",
3420 "m(x) { return x; }",
3421 "m(x, y) {}, n() {}",
3422 "set(x, y) {}",
3423 "get(x, y) {}",
3424 NULL
3425 };
3426
3427 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3428 RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0,
3429 always_flags, arraysize(always_flags));
3430}
3431
3432
3433TEST(MethodDefinitionNames) {
3434 const char* context_data[][2] = {{"({", "(x, y) {}});"},
3435 {"'use strict'; ({", "(x, y) {}});"},
3436 {"({*", "(x, y) {}});"},
3437 {"'use strict'; ({*", "(x, y) {}});"},
3438 {NULL, NULL}};
3439
3440 const char* name_data[] = {
3441 "m",
3442 "'m'",
3443 "\"m\"",
3444 "\"m n\"",
3445 "true",
3446 "false",
3447 "null",
3448 "0",
3449 "1.2",
3450 "1e1",
3451 "1E1",
3452 "1e+1",
3453 "1e-1",
3454
3455 // Keywords
3456 "async",
3457 "await",
3458 "break",
3459 "case",
3460 "catch",
3461 "class",
3462 "const",
3463 "continue",
3464 "debugger",
3465 "default",
3466 "delete",
3467 "do",
3468 "else",
3469 "enum",
3470 "export",
3471 "extends",
3472 "finally",
3473 "for",
3474 "function",
3475 "if",
3476 "implements",
3477 "import",
3478 "in",
3479 "instanceof",
3480 "interface",
3481 "let",
3482 "new",
3483 "package",
3484 "private",
3485 "protected",
3486 "public",
3487 "return",
3488 "static",
3489 "super",
3490 "switch",
3491 "this",
3492 "throw",
3493 "try",
3494 "typeof",
3495 "var",
3496 "void",
3497 "while",
3498 "with",
3499 "yield",
3500 NULL
3501 };
3502
3503 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3504 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
3505 always_flags, arraysize(always_flags));
3506}
3507
3508
3509TEST(MethodDefinitionStrictFormalParamereters) {
3510 const char* context_data[][2] = {{"({method(", "){}});"},
3511 {"'use strict'; ({method(", "){}});"},
3512 {"({*method(", "){}});"},
3513 {"'use strict'; ({*method(", "){}});"},
3514 {NULL, NULL}};
3515
3516 const char* params_data[] = {
3517 "x, x",
3518 "x, y, x",
3519 "eval",
3520 "arguments",
3521 "var",
3522 "const",
3523 NULL
3524 };
3525
3526 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3527 RunParserSyncTest(context_data, params_data, kError, NULL, 0,
3528 always_flags, arraysize(always_flags));
3529}
3530
3531
3532TEST(MethodDefinitionDuplicateProperty) {
3533 // Duplicate properties are allowed in ES6 but we haven't removed that check
3534 // yet.
3535 const char* context_data[][2] = {{"'use strict'; ({", "});"},
3536 {NULL, NULL}};
3537
3538 const char* params_data[] = {
3539 "x: 1, x() {}",
3540 "x() {}, x: 1",
3541 "x() {}, get x() {}",
3542 "x() {}, set x(_) {}",
3543 "x() {}, x() {}",
3544 "x() {}, y() {}, x() {}",
3545 "x() {}, \"x\"() {}",
3546 "x() {}, 'x'() {}",
3547 "0() {}, '0'() {}",
3548 "1.0() {}, 1: 1",
3549
3550 "x: 1, *x() {}",
3551 "*x() {}, x: 1",
3552 "*x() {}, get x() {}",
3553 "*x() {}, set x(_) {}",
3554 "*x() {}, *x() {}",
3555 "*x() {}, y() {}, *x() {}",
3556 "*x() {}, *\"x\"() {}",
3557 "*x() {}, *'x'() {}",
3558 "*0() {}, *'0'() {}",
3559 "*1.0() {}, 1: 1",
3560
3561 NULL
3562 };
3563
3564 static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
3565 RunParserSyncTest(context_data, params_data, kError, NULL, 0,
3566 always_flags, arraysize(always_flags));
3567}
3568
3569
3570TEST(ClassExpressionNoErrors) {
3571 const char* context_data[][2] = {{"(", ");"},
3572 {"var C = ", ";"},
3573 {"bar, ", ";"},
3574 {NULL, NULL}};
3575 const char* class_data[] = {
3576 "class {}",
3577 "class name {}",
3578 "class extends F {}",
3579 "class name extends F {}",
3580 "class extends (F, G) {}",
3581 "class name extends (F, G) {}",
3582 "class extends class {} {}",
3583 "class name extends class {} {}",
3584 "class extends class base {} {}",
3585 "class name extends class base {} {}",
3586 NULL};
3587
3588 static const ParserFlag always_flags[] = {kAllowClasses};
3589 RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
3590 always_flags, arraysize(always_flags));
3591}
3592
3593
3594TEST(ClassDeclarationNoErrors) {
3595 const char* context_data[][2] = {{"", ""},
3596 {"{", "}"},
3597 {"if (true) {", "}"},
3598 {NULL, NULL}};
3599 const char* statement_data[] = {
3600 "class name {}",
3601 "class name extends F {}",
3602 "class name extends (F, G) {}",
3603 "class name extends class {} {}",
3604 "class name extends class base {} {}",
3605 NULL};
3606
3607 static const ParserFlag always_flags[] = {kAllowClasses};
3608 RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
3609 always_flags, arraysize(always_flags));
3610}
3611
3612
3613TEST(ClassBodyNoErrors) {
3614 // Tests that parser and preparser accept valid class syntax.
3615 const char* context_data[][2] = {{"(class {", "});"},
3616 {"(class extends Base {", "});"},
3617 {"class C {", "}"},
3618 {"class C extends Base {", "}"},
3619 {NULL, NULL}};
3620 const char* class_body_data[] = {
3621 ";",
3622 ";;",
3623 "m() {}",
3624 "m() {};",
3625 "; m() {}",
3626 "m() {}; n(x) {}",
3627 "get x() {}",
3628 "set x(v) {}",
3629 "get() {}",
3630 "set() {}",
3631 "*g() {}",
3632 "*g() {};",
3633 "; *g() {}",
3634 "*g() {}; *h(x) {}",
3635 "static() {}",
3636 "static m() {}",
3637 "static get x() {}",
3638 "static set x(v) {}",
3639 "static get() {}",
3640 "static set() {}",
3641 "static static() {}",
3642 "static get static() {}",
3643 "static set static(v) {}",
3644 "*static() {}",
3645 "*get() {}",
3646 "*set() {}",
3647 "static *g() {}",
3648 NULL};
3649
3650 static const ParserFlag always_flags[] = {
3651 kAllowClasses,
3652 kAllowHarmonyObjectLiterals
3653 };
3654 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
3655 always_flags, arraysize(always_flags));
3656}
3657
3658
3659TEST(ClassPropertyNameNoErrors) {
3660 const char* context_data[][2] = {{"(class {", "() {}});"},
3661 {"(class { get ", "() {}});"},
3662 {"(class { set ", "(v) {}});"},
3663 {"(class { static ", "() {}});"},
3664 {"(class { static get ", "() {}});"},
3665 {"(class { static set ", "(v) {}});"},
3666 {"(class { *", "() {}});"},
3667 {"(class { static *", "() {}});"},
3668 {"class C {", "() {}}"},
3669 {"class C { get ", "() {}}"},
3670 {"class C { set ", "(v) {}}"},
3671 {"class C { static ", "() {}}"},
3672 {"class C { static get ", "() {}}"},
3673 {"class C { static set ", "(v) {}}"},
3674 {"class C { *", "() {}}"},
3675 {"class C { static *", "() {}}"},
3676 {NULL, NULL}};
3677 const char* name_data[] = {
3678 "42",
3679 "42.5",
3680 "42e2",
3681 "42e+2",
3682 "42e-2",
3683 "null",
3684 "false",
3685 "true",
3686 "'str'",
3687 "\"str\"",
3688 "static",
3689 "get",
3690 "set",
3691 "var",
3692 "const",
3693 "let",
3694 "this",
3695 "class",
3696 "function",
3697 "yield",
3698 "if",
3699 "else",
3700 "for",
3701 "while",
3702 "do",
3703 "try",
3704 "catch",
3705 "finally",
3706 NULL};
3707
3708 static const ParserFlag always_flags[] = {
3709 kAllowClasses,
3710 kAllowHarmonyObjectLiterals
3711 };
3712 RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
3713 always_flags, arraysize(always_flags));
3714}
3715
3716
3717TEST(ClassExpressionErrors) {
3718 const char* context_data[][2] = {{"(", ");"},
3719 {"var C = ", ";"},
3720 {"bar, ", ";"},
3721 {NULL, NULL}};
3722 const char* class_data[] = {
3723 "class",
3724 "class name",
3725 "class name extends",
3726 "class extends",
3727 "class {",
3728 "class { m }",
3729 "class { m; n }",
3730 "class { m: 1 }",
3731 "class { m(); n() }",
3732 "class { get m }",
3733 "class { get m() }",
3734 "class { get m() { }",
3735 "class { set m() {} }", // Missing required parameter.
3736 "class { m() {}, n() {} }", // No commas allowed.
3737 NULL};
3738
3739 static const ParserFlag always_flags[] = {
3740 kAllowClasses,
3741 kAllowHarmonyObjectLiterals
3742 };
3743 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
3744 always_flags, arraysize(always_flags));
3745}
3746
3747
3748TEST(ClassDeclarationErrors) {
3749 const char* context_data[][2] = {{"", ""},
3750 {"{", "}"},
3751 {"if (true) {", "}"},
3752 {NULL, NULL}};
3753 const char* class_data[] = {
3754 "class",
3755 "class name",
3756 "class name extends",
3757 "class extends",
3758 "class name {",
3759 "class name { m }",
3760 "class name { m; n }",
3761 "class name { m: 1 }",
3762 "class name { m(); n() }",
3763 "class name { get x }",
3764 "class name { get x() }",
3765 "class name { set x() {) }", // missing required param
3766 "class {}", // Name is required for declaration
3767 "class extends base {}",
3768 "class name { *",
3769 "class name { * }",
3770 "class name { *; }",
3771 "class name { *get x() {} }",
3772 "class name { *set x(_) {} }",
3773 "class name { *static m() {} }",
3774 NULL};
3775
3776 static const ParserFlag always_flags[] = {
3777 kAllowClasses,
3778 kAllowHarmonyNumericLiterals
3779 };
3780 RunParserSyncTest(context_data, class_data, kError, NULL, 0,
3781 always_flags, arraysize(always_flags));
3782}
3783
3784
3785TEST(ClassNameErrors) {
3786 const char* context_data[][2] = {{"class ", "{}"},
3787 {"(class ", "{});"},
3788 {"'use strict'; class ", "{}"},
3789 {"'use strict'; (class ", "{});"},
3790 {NULL, NULL}};
3791 const char* class_name[] = {
3792 "arguments",
3793 "eval",
3794 "implements",
3795 "interface",
3796 "let",
3797 "package",
3798 "private",
3799 "protected",
3800 "public",
3801 "static",
3802 "var",
3803 "yield",
3804 NULL};
3805
3806 static const ParserFlag always_flags[] = {
3807 kAllowClasses,
3808 kAllowHarmonyObjectLiterals
3809 };
3810 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
3811 always_flags, arraysize(always_flags));
3812}
3813
3814
3815TEST(ClassGetterParamNameErrors) {
3816 const char* context_data[][2] = {
3817 {"class C { get name(", ") {} }"},
3818 {"(class { get name(", ") {} });"},
3819 {"'use strict'; class C { get name(", ") {} }"},
3820 {"'use strict'; (class { get name(", ") {} })"},
3821 {NULL, NULL}
3822 };
3823
3824 const char* class_name[] = {
3825 "arguments",
3826 "eval",
3827 "implements",
3828 "interface",
3829 "let",
3830 "package",
3831 "private",
3832 "protected",
3833 "public",
3834 "static",
3835 "var",
3836 "yield",
3837 NULL};
3838
3839 static const ParserFlag always_flags[] = {
3840 kAllowClasses,
3841 kAllowHarmonyObjectLiterals
3842 };
3843 RunParserSyncTest(context_data, class_name, kError, NULL, 0,
3844 always_flags, arraysize(always_flags));
3845}
3846
3847
3848TEST(ClassStaticPrototypeErrors) {
3849 const char* context_data[][2] = {{"class C {", "}"},
3850 {"(class {", "});"},
3851 {NULL, NULL}};
3852
3853 const char* class_body_data[] = {
3854 "static prototype() {}",
3855 "static get prototype() {}",
3856 "static set prototype(_) {}",
3857 "static *prototype() {}",
3858 NULL};
3859
3860 static const ParserFlag always_flags[] = {
3861 kAllowClasses,
3862 kAllowHarmonyObjectLiterals
3863 };
3864 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
3865 always_flags, arraysize(always_flags));
3866}
3867
3868
3869TEST(ClassSpecialConstructorErrors) {
3870 const char* context_data[][2] = {{"class C {", "}"},
3871 {"(class {", "});"},
3872 {NULL, NULL}};
3873
3874 const char* class_body_data[] = {
3875 "get constructor() {}",
3876 "get constructor(_) {}",
3877 "*constructor() {}",
3878 NULL};
3879
3880 static const ParserFlag always_flags[] = {
3881 kAllowClasses,
3882 kAllowHarmonyObjectLiterals
3883 };
3884 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
3885 always_flags, arraysize(always_flags));
3886}
3887
3888
3889TEST(ClassConstructorNoErrors) {
3890 const char* context_data[][2] = {{"class C {", "}"},
3891 {"(class {", "});"},
3892 {NULL, NULL}};
3893
3894 const char* class_body_data[] = {
3895 "constructor() {}",
3896 "static constructor() {}",
3897 "static get constructor() {}",
3898 "static set constructor(_) {}",
3899 "static *constructor() {}",
3900 NULL};
3901
3902 static const ParserFlag always_flags[] = {
3903 kAllowClasses,
3904 kAllowHarmonyObjectLiterals
3905 };
3906 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
3907 always_flags, arraysize(always_flags));
3908}
3909
3910
3911TEST(ClassMultipleConstructorErrors) {
3912 // We currently do not allow any duplicate properties in class bodies. This
3913 // test ensures that when we change that we still throw on duplicate
3914 // constructors.
3915 const char* context_data[][2] = {{"class C {", "}"},
3916 {"(class {", "});"},
3917 {NULL, NULL}};
3918
3919 const char* class_body_data[] = {
3920 "constructor() {}; constructor() {}",
3921 NULL};
3922
3923 static const ParserFlag always_flags[] = {
3924 kAllowClasses,
3925 kAllowHarmonyObjectLiterals
3926 };
3927 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
3928 always_flags, arraysize(always_flags));
3929}
3930
3931
3932// TODO(arv): We should allow duplicate property names.
3933// https://code.google.com/p/v8/issues/detail?id=3570
3934DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
3935 const char* context_data[][2] = {{"class C {", "}"},
3936 {"(class {", "});"},
3937 {NULL, NULL}};
3938
3939 const char* class_body_data[] = {
3940 "constructor() {}; static constructor() {}",
3941 "m() {}; static m() {}",
3942 "m() {}; m() {}",
3943 NULL};
3944
3945 static const ParserFlag always_flags[] = {
3946 kAllowClasses,
3947 kAllowHarmonyObjectLiterals
3948 };
3949 RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
3950 always_flags, arraysize(always_flags));
3951}
3952
3953
3954TEST(ClassesAreStrictErrors) {
3955 const char* context_data[][2] = {{"", ""},
3956 {"(", ");"},
3957 {NULL, NULL}};
3958
3959 const char* class_body_data[] = {
3960 "class C { method() { with ({}) {} } }",
3961 "class C extends function() { with ({}) {} } {}",
3962 "class C { *method() { with ({}) {} } }",
3963 NULL};
3964
3965 static const ParserFlag always_flags[] = {
3966 kAllowClasses,
3967 kAllowHarmonyObjectLiterals
3968 };
3969 RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
3970 always_flags, arraysize(always_flags));
Ben Murdoch692be652012-01-10 18:47:50 +00003971}