blob: 05fea0bbb617ba0a9b06f140f8a144df122fd712 [file] [log] [blame]
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.orgc4c92722009-11-18 14:12:51 +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
28#include <stdlib.h>
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000029#include <stdio.h>
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000030#include <string.h>
ager@chromium.orgc4c92722009-11-18 14:12:51 +000031
ulan@chromium.org57ff8812013-05-10 08:16:55 +000032// TODO(dcarney): remove
33#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
34
ager@chromium.orgc4c92722009-11-18 14:12:51 +000035#include "v8.h"
36
ager@chromium.orgc4c92722009-11-18 14:12:51 +000037#include "cctest.h"
ricow@chromium.org27bf2882011-11-17 08:34:43 +000038#include "compiler.h"
ricow@chromium.org55ee8072011-09-08 16:33:10 +000039#include "execution.h"
40#include "isolate.h"
41#include "parser.h"
42#include "preparser.h"
43#include "scanner-character-streams.h"
44#include "token.h"
45#include "utils.h"
ager@chromium.orgc4c92722009-11-18 14:12:51 +000046
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000047TEST(ScanKeywords) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000048 struct KeywordToken {
49 const char* keyword;
50 i::Token::Value token;
51 };
52
53 static const KeywordToken keywords[] = {
54#define KEYWORD(t, s, d) { s, i::Token::t },
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000055 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
ager@chromium.orgc4c92722009-11-18 14:12:51 +000056#undef KEYWORD
57 { NULL, i::Token::IDENTIFIER }
58 };
59
ager@chromium.orgc4c92722009-11-18 14:12:51 +000060 KeywordToken key_token;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000061 i::UnicodeCache unicode_cache;
62 i::byte buffer[32];
ager@chromium.orgc4c92722009-11-18 14:12:51 +000063 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000064 const i::byte* keyword =
65 reinterpret_cast<const i::byte*>(key_token.keyword);
66 int length = i::StrLength(key_token.keyword);
67 CHECK(static_cast<int>(sizeof(buffer)) >= length);
68 {
yangguo@chromium.org154ff992012-03-13 08:09:54 +000069 i::Utf8ToUtf16CharacterStream stream(keyword, length);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000070 i::Scanner scanner(&unicode_cache);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000071 // The scanner should parse Harmony keywords for this test.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000072 scanner.SetHarmonyScoping(true);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000073 scanner.SetHarmonyModules(true);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000074 scanner.Initialize(&stream);
75 CHECK_EQ(key_token.token, scanner.Next());
76 CHECK_EQ(i::Token::EOS, scanner.Next());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000077 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000078 // Removing characters will make keyword matching fail.
79 {
yangguo@chromium.org154ff992012-03-13 08:09:54 +000080 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000081 i::Scanner scanner(&unicode_cache);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000082 scanner.Initialize(&stream);
83 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
84 CHECK_EQ(i::Token::EOS, scanner.Next());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000085 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000086 // Adding characters will make keyword matching fail.
87 static const char chars_to_append[] = { 'z', '0', '_' };
88 for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000089 i::OS::MemMove(buffer, keyword, length);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000090 buffer[length] = chars_to_append[j];
yangguo@chromium.org154ff992012-03-13 08:09:54 +000091 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000092 i::Scanner scanner(&unicode_cache);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000093 scanner.Initialize(&stream);
94 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
95 CHECK_EQ(i::Token::EOS, scanner.Next());
96 }
97 // Replacing characters will make keyword matching fail.
98 {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000099 i::OS::MemMove(buffer, keyword, length);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000100 buffer[length - 1] = '_';
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000101 i::Utf8ToUtf16CharacterStream stream(buffer, length);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000102 i::Scanner scanner(&unicode_cache);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000103 scanner.Initialize(&stream);
104 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
105 CHECK_EQ(i::Token::EOS, scanner.Next());
106 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000107 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000108}
109
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000110
111TEST(ScanHTMLEndComments) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000112 v8::V8::Initialize();
113
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000114 // Regression test. See:
115 // http://code.google.com/p/chromium/issues/detail?id=53548
116 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000117 // is only whitespace before it on the line (with comments considered as
118 // whitespace, even a multiline-comment containing a newline).
119 // This was not the case if it occurred before the first real token
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000120 // in the input.
121 const char* tests[] = {
122 // Before first real token.
123 "--> is eol-comment\nvar y = 37;\n",
124 "\n --> is eol-comment\nvar y = 37;\n",
125 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
126 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
127 // After first real token.
128 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
129 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
130 NULL
131 };
132
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000133 const char* fail_tests[] = {
134 "x --> is eol-comment\nvar y = 37;\n",
135 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
136 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
137 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
138 "var x = 42; --> is eol-comment\nvar y = 37;\n",
139 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
140 NULL
141 };
142
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000143 // Parser/Scanner needs a stack limit.
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000144 int marker;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 i::Isolate::Current()->stack_guard()->SetStackLimit(
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000146 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
147
148 for (int i = 0; tests[i]; i++) {
149 v8::ScriptData* data =
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000150 v8::ScriptData::PreCompile(tests[i], i::StrLength(tests[i]));
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000151 CHECK(data != NULL && !data->HasError());
152 delete data;
153 }
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000154
155 for (int i = 0; fail_tests[i]; i++) {
156 v8::ScriptData* data =
157 v8::ScriptData::PreCompile(fail_tests[i], i::StrLength(fail_tests[i]));
158 CHECK(data == NULL || data->HasError());
159 delete data;
160 }
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000161}
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000162
163
164class ScriptResource : public v8::String::ExternalAsciiStringResource {
165 public:
166 ScriptResource(const char* data, size_t length)
167 : data_(data), length_(length) { }
168
169 const char* data() const { return data_; }
170 size_t length() const { return length_; }
171
172 private:
173 const char* data_;
174 size_t length_;
175};
176
177
178TEST(Preparsing) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000179 v8::Isolate* isolate = v8::Isolate::GetCurrent();
180 v8::HandleScope handles(isolate);
181 v8::Local<v8::Context> context = v8::Context::New(isolate);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000182 v8::Context::Scope context_scope(context);
183 int marker;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 i::Isolate::Current()->stack_guard()->SetStackLimit(
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000185 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
186
187 // Source containing functions that might be lazily compiled and all types
188 // of symbols (string, propertyName, regexp).
189 const char* source =
190 "var x = 42;"
191 "function foo(a) { return function nolazy(b) { return a + b; } }"
192 "function bar(a) { if (a) return function lazy(b) { return b; } }"
193 "var z = {'string': 'string literal', bareword: 'propertyName', "
194 " 42: 'number literal', for: 'keyword as propertyName', "
195 " f\\u006fr: 'keyword propertyname with escape'};"
196 "var v = /RegExp Literal/;"
197 "var w = /RegExp Literal\\u0020With Escape/gin;"
198 "var y = { get getter() { return 42; }, "
199 " set setter(v) { this.value = v; }};";
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000200 int source_length = i::StrLength(source);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000201 const char* error_source = "var x = y z;";
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000202 int error_source_length = i::StrLength(error_source);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000203
204 v8::ScriptData* preparse =
205 v8::ScriptData::PreCompile(source, source_length);
206 CHECK(!preparse->HasError());
207 bool lazy_flag = i::FLAG_lazy;
208 {
209 i::FLAG_lazy = true;
210 ScriptResource* resource = new ScriptResource(source, source_length);
211 v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
212 v8::Script::Compile(script_source, NULL, preparse);
213 }
214
215 {
216 i::FLAG_lazy = false;
217
218 ScriptResource* resource = new ScriptResource(source, source_length);
219 v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
220 v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
221 }
222 delete preparse;
223 i::FLAG_lazy = lazy_flag;
224
225 // Syntax error.
226 v8::ScriptData* error_preparse =
227 v8::ScriptData::PreCompile(error_source, error_source_length);
228 CHECK(error_preparse->HasError());
229 i::ScriptDataImpl *pre_impl =
230 reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
231 i::Scanner::Location error_location =
232 pre_impl->MessageLocation();
233 // Error is at "z" in source, location 10..11.
234 CHECK_EQ(10, error_location.beg_pos);
235 CHECK_EQ(11, error_location.end_pos);
236 // Should not crash.
237 const char* message = pre_impl->BuildMessage();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000238 pre_impl->BuildArgs();
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000239 CHECK_GT(strlen(message), 0);
240}
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000241
242
243TEST(StandAlonePreParser) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000244 v8::V8::Initialize();
245
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000246 int marker;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 i::Isolate::Current()->stack_guard()->SetStackLimit(
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000248 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
249
250 const char* programs[] = {
251 "{label: 42}",
252 "var x = 42;",
253 "function foo(x, y) { return x + y; }",
whesse@chromium.org7b260152011-06-20 15:33:18 +0000254 "%ArgleBargle(glop);",
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000255 "var x = new new Function('this.x = 42');",
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000256 NULL
257 };
258
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000259 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000260 for (int i = 0; programs[i]; i++) {
261 const char* program = programs[i];
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000262 i::Utf8ToUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000263 reinterpret_cast<const i::byte*>(program),
264 static_cast<unsigned>(strlen(program)));
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000265 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000266 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000267 scanner.Initialize(&stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000268
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000269 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
270 preparser.set_allow_lazy(true);
271 preparser.set_allow_natives_syntax(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000272 v8::preparser::PreParser::PreParseResult result =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000273 preparser.PreParseProgram();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000274 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000275 i::ScriptDataImpl data(log.ExtractData());
276 CHECK(!data.has_error());
277 }
278}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000279
280
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000281TEST(StandAlonePreParserNoNatives) {
282 v8::V8::Initialize();
283
284 int marker;
285 i::Isolate::Current()->stack_guard()->SetStackLimit(
286 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
287
288 const char* programs[] = {
289 "%ArgleBargle(glop);",
290 "var x = %_IsSmi(42);",
291 NULL
292 };
293
294 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
295 for (int i = 0; programs[i]; i++) {
296 const char* program = programs[i];
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000297 i::Utf8ToUtf16CharacterStream stream(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000298 reinterpret_cast<const i::byte*>(program),
299 static_cast<unsigned>(strlen(program)));
300 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000302 scanner.Initialize(&stream);
303
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000304 // Preparser defaults to disallowing natives syntax.
305 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
306 preparser.set_allow_lazy(true);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000307 v8::preparser::PreParser::PreParseResult result =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000308 preparser.PreParseProgram();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000309 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
310 i::ScriptDataImpl data(log.ExtractData());
311 // Data contains syntax error.
312 CHECK(data.has_error());
313 }
314}
315
316
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000317TEST(RegressChromium62639) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000318 v8::V8::Initialize();
319
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000320 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000321 i::Isolate::Current()->stack_guard()->SetStackLimit(
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000322 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
323
324 const char* program = "var x = 'something';\n"
325 "escape: function() {}";
326 // Fails parsing expecting an identifier after "function".
327 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
328 // and then used the invalid currently scanned literal. This always
329 // failed in debug mode, and sometimes crashed in release mode.
330
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000331 i::Utf8ToUtf16CharacterStream stream(
332 reinterpret_cast<const i::byte*>(program),
333 static_cast<unsigned>(strlen(program)));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000334 i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000335 CHECK(data->HasError());
336 delete data;
337}
338
339
340TEST(Regress928) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000341 v8::V8::Initialize();
342
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000343 // Preparsing didn't consider the catch clause of a try statement
344 // as with-content, which made it assume that a function inside
345 // the block could be lazily compiled, and an extra, unexpected,
346 // entry was added to the data.
347 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000348 i::Isolate::Current()->stack_guard()->SetStackLimit(
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000349 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
350
351 const char* program =
352 "try { } catch (e) { var foo = function () { /* first */ } }"
353 "var bar = function () { /* second */ }";
354
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000355 v8::HandleScope handles(v8::Isolate::GetCurrent());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000356 i::Handle<i::String> source(
357 FACTORY->NewStringFromAscii(i::CStrVector(program)));
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000358 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000359 i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000360 CHECK(!data->HasError());
361
362 data->Initialize();
363
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000364 int first_function =
365 static_cast<int>(strstr(program, "function") - program);
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000366 int first_lbrace = first_function + i::StrLength("function () ");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000367 CHECK_EQ('{', program[first_lbrace]);
368 i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
369 CHECK(!entry1.is_valid());
370
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000371 int second_function =
372 static_cast<int>(strstr(program + first_lbrace, "function") - program);
373 int second_lbrace =
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000374 second_function + i::StrLength("function () ");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000375 CHECK_EQ('{', program[second_lbrace]);
376 i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
377 CHECK(entry2.is_valid());
378 CHECK_EQ('}', program[entry2.end_pos() - 1]);
379 delete data;
380}
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000381
382
383TEST(PreParseOverflow) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000384 v8::V8::Initialize();
385
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000386 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000387 i::Isolate::Current()->stack_guard()->SetStackLimit(
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000388 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
389
390 size_t kProgramSize = 1024 * 1024;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000391 i::SmartArrayPointer<char> program(
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000392 reinterpret_cast<char*>(malloc(kProgramSize + 1)));
393 memset(*program, '(', kProgramSize);
394 program[kProgramSize] = '\0';
395
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000396 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000397
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000398 i::Utf8ToUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000399 reinterpret_cast<const i::byte*>(*program),
400 static_cast<unsigned>(kProgramSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000401 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000402 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000403 scanner.Initialize(&stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000404
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000405 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
406 preparser.set_allow_lazy(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000407 v8::preparser::PreParser::PreParseResult result =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000408 preparser.PreParseProgram();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000409 CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
410}
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000411
412
413class TestExternalResource: public v8::String::ExternalStringResource {
414 public:
415 explicit TestExternalResource(uint16_t* data, int length)
416 : data_(data), length_(static_cast<size_t>(length)) { }
417
418 ~TestExternalResource() { }
419
420 const uint16_t* data() const {
421 return data_;
422 }
423
424 size_t length() const {
425 return length_;
426 }
427 private:
428 uint16_t* data_;
429 size_t length_;
430};
431
432
433#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
434
435void TestCharacterStream(const char* ascii_source,
436 unsigned length,
437 unsigned start = 0,
438 unsigned end = 0) {
439 if (end == 0) end = length;
440 unsigned sub_length = end - start;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000441 i::HandleScope test_scope(i::Isolate::Current());
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000442 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000443 for (unsigned i = 0; i < length; i++) {
444 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
445 }
446 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
447 i::Handle<i::String> ascii_string(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 FACTORY->NewStringFromAscii(ascii_vector));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000449 TestExternalResource resource(*uc16_buffer, length);
450 i::Handle<i::String> uc16_string(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 FACTORY->NewExternalStringFromTwoByte(&resource));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000452
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000453 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000454 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000455 i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
456 i::Utf8ToUtf16CharacterStream utf8_stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000457 reinterpret_cast<const i::byte*>(ascii_source), end);
458 utf8_stream.SeekForward(start);
459
460 unsigned i = start;
461 while (i < end) {
462 // Read streams one char at a time
463 CHECK_EQU(i, uc16_stream.pos());
464 CHECK_EQU(i, string_stream.pos());
465 CHECK_EQU(i, utf8_stream.pos());
466 int32_t c0 = ascii_source[i];
467 int32_t c1 = uc16_stream.Advance();
468 int32_t c2 = string_stream.Advance();
469 int32_t c3 = utf8_stream.Advance();
470 i++;
471 CHECK_EQ(c0, c1);
472 CHECK_EQ(c0, c2);
473 CHECK_EQ(c0, c3);
474 CHECK_EQU(i, uc16_stream.pos());
475 CHECK_EQU(i, string_stream.pos());
476 CHECK_EQU(i, utf8_stream.pos());
477 }
478 while (i > start + sub_length / 4) {
479 // Pushback, re-read, pushback again.
480 int32_t c0 = ascii_source[i - 1];
481 CHECK_EQU(i, uc16_stream.pos());
482 CHECK_EQU(i, string_stream.pos());
483 CHECK_EQU(i, utf8_stream.pos());
484 uc16_stream.PushBack(c0);
485 string_stream.PushBack(c0);
486 utf8_stream.PushBack(c0);
487 i--;
488 CHECK_EQU(i, uc16_stream.pos());
489 CHECK_EQU(i, string_stream.pos());
490 CHECK_EQU(i, utf8_stream.pos());
491 int32_t c1 = uc16_stream.Advance();
492 int32_t c2 = string_stream.Advance();
493 int32_t c3 = utf8_stream.Advance();
494 i++;
495 CHECK_EQU(i, uc16_stream.pos());
496 CHECK_EQU(i, string_stream.pos());
497 CHECK_EQU(i, utf8_stream.pos());
498 CHECK_EQ(c0, c1);
499 CHECK_EQ(c0, c2);
500 CHECK_EQ(c0, c3);
501 uc16_stream.PushBack(c0);
502 string_stream.PushBack(c0);
503 utf8_stream.PushBack(c0);
504 i--;
505 CHECK_EQU(i, uc16_stream.pos());
506 CHECK_EQU(i, string_stream.pos());
507 CHECK_EQU(i, utf8_stream.pos());
508 }
509 unsigned halfway = start + sub_length / 2;
510 uc16_stream.SeekForward(halfway - i);
511 string_stream.SeekForward(halfway - i);
512 utf8_stream.SeekForward(halfway - i);
513 i = halfway;
514 CHECK_EQU(i, uc16_stream.pos());
515 CHECK_EQU(i, string_stream.pos());
516 CHECK_EQU(i, utf8_stream.pos());
517
518 while (i < end) {
519 // Read streams one char at a time
520 CHECK_EQU(i, uc16_stream.pos());
521 CHECK_EQU(i, string_stream.pos());
522 CHECK_EQU(i, utf8_stream.pos());
523 int32_t c0 = ascii_source[i];
524 int32_t c1 = uc16_stream.Advance();
525 int32_t c2 = string_stream.Advance();
526 int32_t c3 = utf8_stream.Advance();
527 i++;
528 CHECK_EQ(c0, c1);
529 CHECK_EQ(c0, c2);
530 CHECK_EQ(c0, c3);
531 CHECK_EQU(i, uc16_stream.pos());
532 CHECK_EQU(i, string_stream.pos());
533 CHECK_EQU(i, utf8_stream.pos());
534 }
535
536 int32_t c1 = uc16_stream.Advance();
537 int32_t c2 = string_stream.Advance();
538 int32_t c3 = utf8_stream.Advance();
539 CHECK_LT(c1, 0);
540 CHECK_LT(c2, 0);
541 CHECK_LT(c3, 0);
542}
543
544
545TEST(CharacterStreams) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000546 v8::Isolate* isolate = v8::Isolate::GetCurrent();
547 v8::HandleScope handles(isolate);
548 v8::Local<v8::Context> context = v8::Context::New(isolate);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000549 v8::Context::Scope context_scope(context);
550
551 TestCharacterStream("abc\0\n\r\x7f", 7);
552 static const unsigned kBigStringSize = 4096;
553 char buffer[kBigStringSize + 1];
554 for (unsigned i = 0; i < kBigStringSize; i++) {
555 buffer[i] = static_cast<char>(i & 0x7f);
556 }
557 TestCharacterStream(buffer, kBigStringSize);
558
559 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
560
561 TestCharacterStream("\0", 1);
562 TestCharacterStream("", 0);
563}
564
565
566TEST(Utf8CharacterStream) {
567 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
568 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
569
570 static const int kAllUtf8CharsSize =
571 (unibrow::Utf8::kMaxOneByteChar + 1) +
572 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
573 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
574 static const unsigned kAllUtf8CharsSizeU =
575 static_cast<unsigned>(kAllUtf8CharsSize);
576
577 char buffer[kAllUtf8CharsSizeU];
578 unsigned cursor = 0;
579 for (int i = 0; i <= kMaxUC16Char; i++) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000580 cursor += unibrow::Utf8::Encode(buffer + cursor,
581 i,
582 unibrow::Utf16::kNoPreviousCharacter);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000583 }
584 ASSERT(cursor == kAllUtf8CharsSizeU);
585
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000586 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
587 kAllUtf8CharsSizeU);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000588 for (int i = 0; i <= kMaxUC16Char; i++) {
589 CHECK_EQU(i, stream.pos());
590 int32_t c = stream.Advance();
591 CHECK_EQ(i, c);
592 CHECK_EQU(i + 1, stream.pos());
593 }
594 for (int i = kMaxUC16Char; i >= 0; i--) {
595 CHECK_EQU(i + 1, stream.pos());
596 stream.PushBack(i);
597 CHECK_EQU(i, stream.pos());
598 }
599 int i = 0;
600 while (stream.pos() < kMaxUC16CharU) {
601 CHECK_EQU(i, stream.pos());
602 unsigned progress = stream.SeekForward(12);
603 i += progress;
604 int32_t c = stream.Advance();
605 if (i <= kMaxUC16Char) {
606 CHECK_EQ(i, c);
607 } else {
608 CHECK_EQ(-1, c);
609 }
610 i += 1;
611 CHECK_EQU(i, stream.pos());
612 }
613}
614
615#undef CHECK_EQU
616
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000617void TestStreamScanner(i::Utf16CharacterStream* stream,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000618 i::Token::Value* expected_tokens,
619 int skip_pos = 0, // Zero means not skipping.
620 int skip_to = 0) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000621 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000622 scanner.Initialize(stream);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000623
624 int i = 0;
625 do {
626 i::Token::Value expected = expected_tokens[i];
627 i::Token::Value actual = scanner.Next();
628 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
629 if (scanner.location().end_pos == skip_pos) {
630 scanner.SeekForward(skip_to);
631 }
632 i++;
633 } while (expected_tokens[i] != i::Token::ILLEGAL);
634}
635
636TEST(StreamScanner) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000637 v8::V8::Initialize();
638
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000639 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000640 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
641 static_cast<unsigned>(strlen(str1)));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000642 i::Token::Value expectations1[] = {
643 i::Token::LBRACE,
644 i::Token::IDENTIFIER,
645 i::Token::IDENTIFIER,
646 i::Token::FOR,
647 i::Token::COLON,
648 i::Token::MUL,
649 i::Token::DIV,
650 i::Token::LT,
651 i::Token::SUB,
652 i::Token::IDENTIFIER,
653 i::Token::EOS,
654 i::Token::ILLEGAL
655 };
656 TestStreamScanner(&stream1, expectations1, 0, 0);
657
658 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000659 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
660 static_cast<unsigned>(strlen(str2)));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000661 i::Token::Value expectations2[] = {
662 i::Token::CASE,
663 i::Token::DEFAULT,
664 i::Token::CONST,
665 i::Token::LBRACE,
666 // Skipped part here
667 i::Token::RBRACE,
668 i::Token::DO,
669 i::Token::EOS,
670 i::Token::ILLEGAL
671 };
672 ASSERT_EQ('{', str2[19]);
673 ASSERT_EQ('}', str2[37]);
674 TestStreamScanner(&stream2, expectations2, 20, 37);
675
676 const char* str3 = "{}}}}";
677 i::Token::Value expectations3[] = {
678 i::Token::LBRACE,
679 i::Token::RBRACE,
680 i::Token::RBRACE,
681 i::Token::RBRACE,
682 i::Token::RBRACE,
683 i::Token::EOS,
684 i::Token::ILLEGAL
685 };
686 // Skip zero-four RBRACEs.
687 for (int i = 0; i <= 4; i++) {
688 expectations3[6 - i] = i::Token::ILLEGAL;
689 expectations3[5 - i] = i::Token::EOS;
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000690 i::Utf8ToUtf16CharacterStream stream3(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000691 reinterpret_cast<const i::byte*>(str3),
692 static_cast<unsigned>(strlen(str3)));
693 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
694 }
695}
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000696
697
698void TestScanRegExp(const char* re_source, const char* expected) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000699 i::Utf8ToUtf16CharacterStream stream(
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000700 reinterpret_cast<const i::byte*>(re_source),
701 static_cast<unsigned>(strlen(re_source)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000702 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000703 scanner.Initialize(&stream);
704
705 i::Token::Value start = scanner.peek();
706 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
707 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
708 scanner.Next(); // Current token is now the regexp literal.
709 CHECK(scanner.is_literal_ascii());
710 i::Vector<const char> actual = scanner.literal_ascii_string();
711 for (int i = 0; i < actual.length(); i++) {
712 CHECK_NE('\0', expected[i]);
713 CHECK_EQ(expected[i], actual[i]);
714 }
715}
716
717
718TEST(RegExpScanning) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000719 v8::V8::Initialize();
720
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000721 // RegExp token with added garbage at the end. The scanner should only
722 // scan the RegExp until the terminating slash just before "flipperwald".
723 TestScanRegExp("/b/flipperwald", "b");
724 // Incomplete escape sequences doesn't hide the terminating slash.
725 TestScanRegExp("/\\x/flipperwald", "\\x");
726 TestScanRegExp("/\\u/flipperwald", "\\u");
727 TestScanRegExp("/\\u1/flipperwald", "\\u1");
728 TestScanRegExp("/\\u12/flipperwald", "\\u12");
729 TestScanRegExp("/\\u123/flipperwald", "\\u123");
730 TestScanRegExp("/\\c/flipperwald", "\\c");
731 TestScanRegExp("/\\c//flipperwald", "\\c");
732 // Slashes inside character classes are not terminating.
733 TestScanRegExp("/[/]/flipperwald", "[/]");
734 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
735 // Incomplete escape sequences inside a character class doesn't hide
736 // the end of the character class.
737 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
738 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
739 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
740 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
741 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
742 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
743 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
744 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
745 // Escaped ']'s wont end the character class.
746 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
747 // Escaped slashes are not terminating.
748 TestScanRegExp("/\\//flipperwald", "\\/");
749 // Starting with '=' works too.
750 TestScanRegExp("/=/", "=");
751 TestScanRegExp("/=?/", "=?");
752}
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000753
754
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000755static int Utf8LengthHelper(const char* s) {
756 int len = i::StrLength(s);
757 int character_length = len;
758 for (int i = 0; i < len; i++) {
759 unsigned char c = s[i];
760 int input_offset = 0;
761 int output_adjust = 0;
762 if (c > 0x7f) {
763 if (c < 0xc0) continue;
764 if (c >= 0xf0) {
765 if (c >= 0xf8) {
766 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
767 // byte.
768 continue; // Handle first UTF-8 byte.
769 }
770 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
771 // This 4 byte sequence could have been coded as a 3 byte sequence.
772 // Record a single kBadChar for the first byte and continue.
773 continue;
774 }
775 input_offset = 3;
776 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
777 character_length -= 2;
778 } else if (c >= 0xe0) {
779 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
780 // This 3 byte sequence could have been coded as a 2 byte sequence.
781 // Record a single kBadChar for the first byte and continue.
782 continue;
783 }
784 input_offset = 2;
785 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
786 output_adjust = 2;
787 } else {
788 if ((c & 0x1e) == 0) {
789 // This 2 byte sequence could have been coded as a 1 byte sequence.
790 // Record a single kBadChar for the first byte and continue.
791 continue;
792 }
793 input_offset = 1;
794 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
795 output_adjust = 1;
796 }
797 bool bad = false;
798 for (int j = 1; j <= input_offset; j++) {
799 if ((s[i + j] & 0xc0) != 0x80) {
800 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
801 // which is a single UTF-16 code unit.
802 bad = true;
803 break;
804 }
805 }
806 if (!bad) {
807 i += input_offset;
808 character_length -= output_adjust;
809 }
810 }
811 }
812 return character_length;
813}
814
815
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000816TEST(ScopePositions) {
817 // Test the parser for correctly setting the start and end positions
818 // of a scope. We check the scope positions of exactly one scope
819 // nested in the global scope of a program. 'inner source' is the
820 // source code that determines the part of the source belonging
821 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
822 // parts of the source that belong to the global scope.
823 struct SourceData {
824 const char* outer_prefix;
825 const char* inner_source;
826 const char* outer_suffix;
827 i::ScopeType scope_type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000828 i::LanguageMode language_mode;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000829 };
830
831 const SourceData source_data[] = {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000832 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
833 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000834 { " with ({}) ", "{\n"
835 " block;\n"
836 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000837 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
838 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000839 { " with ({}) ", "statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000840 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000841 { " with ({})\n"
842 " ", "statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000843 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
844 { " try {} catch ", "(e) { block; }", " more;",
845 i::CATCH_SCOPE, i::CLASSIC_MODE },
846 { " try {} catch ", "(e) { block; }", "; more;",
847 i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000848 { " try {} catch ", "(e) {\n"
849 " block;\n"
850 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000851 " more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000852 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000853 i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000854 { " start;\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000855 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000856 { " start;\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000857 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000858 { " start;\n"
859 " ", "{\n"
860 " let block;\n"
861 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000862 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000863 { " start;\n"
864 " function fun", "(a,b) { infunction; }", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000865 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000866 { " start;\n"
867 " function fun", "(a,b) {\n"
868 " infunction;\n"
869 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000870 " more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000871 { " (function fun", "(a,b) { infunction; }", ")();",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000872 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000873 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000874 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000875 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000876 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000877 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
878 " block;\n"
879 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000880 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000881 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000882 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000883 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000884 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000885 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
886 " statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000887 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
888 { " for ", "(let x in {}) { block; }", " more;",
889 i::BLOCK_SCOPE, i::EXTENDED_MODE },
890 { " for ", "(let x in {}) { block; }", "; more;",
891 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000892 { " for ", "(let x in {}) {\n"
893 " block;\n"
894 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000895 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
896 { " for ", "(let x in {}) statement;", " more;",
897 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000898 { " for ", "(let x in {}) statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000899 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000900 { " for ", "(let x in {})\n"
901 " statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000902 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000903 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
904 // the preparser off in terms of byte offsets.
905 // 6 byte encoding.
906 { " 'foo\355\240\201\355\260\211';\n"
907 " (function fun", "(a,b) { infunction; }", ")();",
908 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
909 // 4 byte encoding.
910 { " 'foo\360\220\220\212';\n"
911 " (function fun", "(a,b) { infunction; }", ")();",
912 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
913 // 3 byte encoding of \u0fff.
914 { " 'foo\340\277\277';\n"
915 " (function fun", "(a,b) { infunction; }", ")();",
916 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
917 // Broken 6 byte encoding with missing last byte.
918 { " 'foo\355\240\201\355\211';\n"
919 " (function fun", "(a,b) { infunction; }", ")();",
920 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
921 // Broken 3 byte encoding of \u0fff with missing last byte.
922 { " 'foo\340\277';\n"
923 " (function fun", "(a,b) { infunction; }", ")();",
924 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
925 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
926 { " 'foo\340';\n"
927 " (function fun", "(a,b) { infunction; }", ")();",
928 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
929 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
930 { " 'foo\340\203\277';\n"
931 " (function fun", "(a,b) { infunction; }", ")();",
932 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
933 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
934 { " 'foo\340\201\277';\n"
935 " (function fun", "(a,b) { infunction; }", ")();",
936 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
937 // Unpaired lead surrogate.
938 { " 'foo\355\240\201';\n"
939 " (function fun", "(a,b) { infunction; }", ")();",
940 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
941 // Unpaired lead surrogate where following code point is a 3 byte sequence.
942 { " 'foo\355\240\201\340\277\277';\n"
943 " (function fun", "(a,b) { infunction; }", ")();",
944 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
945 // Unpaired lead surrogate where following code point is a 4 byte encoding
946 // of a trail surrogate.
947 { " 'foo\355\240\201\360\215\260\211';\n"
948 " (function fun", "(a,b) { infunction; }", ")();",
949 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
950 // Unpaired trail surrogate.
951 { " 'foo\355\260\211';\n"
952 " (function fun", "(a,b) { infunction; }", ")();",
953 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
954 // 2 byte encoding of \u00ff.
955 { " 'foo\303\277';\n"
956 " (function fun", "(a,b) { infunction; }", ")();",
957 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
958 // Broken 2 byte encoding of \u00ff with missing last byte.
959 { " 'foo\303';\n"
960 " (function fun", "(a,b) { infunction; }", ")();",
961 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
962 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
963 { " 'foo\301\277';\n"
964 " (function fun", "(a,b) { infunction; }", ")();",
965 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
966 // Illegal 5 byte encoding.
967 { " 'foo\370\277\277\277\277';\n"
968 " (function fun", "(a,b) { infunction; }", ")();",
969 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
970 // Illegal 6 byte encoding.
971 { " 'foo\374\277\277\277\277\277';\n"
972 " (function fun", "(a,b) { infunction; }", ")();",
973 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
974 // Illegal 0xfe byte
975 { " 'foo\376\277\277\277\277\277\277';\n"
976 " (function fun", "(a,b) { infunction; }", ")();",
977 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
978 // Illegal 0xff byte
979 { " 'foo\377\277\277\277\277\277\277\277';\n"
980 " (function fun", "(a,b) { infunction; }", ")();",
981 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
982 { " 'foo';\n"
983 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
984 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
985 { " 'foo';\n"
986 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
987 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000988 { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000989 };
990
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000991 v8::HandleScope handles(v8::Isolate::GetCurrent());
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000992 v8::Handle<v8::Context> context = v8::Context::New(v8::Isolate::GetCurrent());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000993 v8::Context::Scope context_scope(context);
994
995 int marker;
996 i::Isolate::Current()->stack_guard()->SetStackLimit(
997 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
998
999 for (int i = 0; source_data[i].outer_prefix; i++) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001000 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1001 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1002 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1003 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1004 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1005 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001007 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1008 i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
1009 i::OS::SNPrintF(program, "%s%s%s",
1010 source_data[i].outer_prefix,
1011 source_data[i].inner_source,
1012 source_data[i].outer_suffix);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001013
1014 // Parse program source.
1015 i::Handle<i::String> source(
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001016 FACTORY->NewStringFromUtf8(i::CStrVector(program.start())));
1017 CHECK_EQ(source->length(), kProgramSize);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001018 i::Handle<i::Script> script = FACTORY->NewScript(source);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001019 i::CompilationInfoWithZone info(script);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001020 i::Parser parser(&info);
1021 parser.set_allow_lazy(true);
1022 parser.set_allow_harmony_scoping(true);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001023 info.MarkAsGlobal();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001024 info.SetLanguageMode(source_data[i].language_mode);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001025 i::FunctionLiteral* function = parser.ParseProgram();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001026 CHECK(function != NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001027
1028 // Check scope types and positions.
1029 i::Scope* scope = function->scope();
1030 CHECK(scope->is_global_scope());
1031 CHECK_EQ(scope->start_position(), 0);
1032 CHECK_EQ(scope->end_position(), kProgramSize);
1033 CHECK_EQ(scope->inner_scopes()->length(), 1);
1034
1035 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1036 CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
1037 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1038 // The end position of a token is one position after the last
1039 // character belonging to that token.
1040 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1041 }
1042}
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001043
1044
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001045i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) {
1046 i::Handle<i::String> format = v8::Utils::OpenHandle(
1047 *v8::String::New(data->BuildMessage()));
1048 i::Vector<const char*> args = data->BuildArgs();
1049 i::Handle<i::JSArray> args_array = FACTORY->NewJSArray(args.length());
1050 for (int i = 0; i < args.length(); i++) {
1051 i::JSArray::SetElement(args_array,
1052 i,
1053 v8::Utils::OpenHandle(*v8::String::New(args[i])),
1054 NONE,
1055 i::kNonStrictMode);
1056 }
1057 i::Handle<i::JSObject> builtins(i::Isolate::Current()->js_builtins_object());
1058 i::Handle<i::Object> format_fun =
1059 i::GetProperty(builtins, "FormatMessage");
1060 i::Handle<i::Object> arg_handles[] = { format, args_array };
1061 bool has_exception = false;
1062 i::Handle<i::Object> result =
1063 i::Execution::Call(format_fun, builtins, 2, arg_handles, &has_exception);
1064 CHECK(!has_exception);
1065 CHECK(result->IsString());
1066 return i::Handle<i::String>::cast(result);
1067}
1068
1069
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001070enum ParserFlag {
1071 kAllowLazy,
1072 kAllowNativesSyntax,
1073 kAllowHarmonyScoping,
1074 kAllowModules,
1075 kAllowGenerators,
1076 kParserFlagCount
1077};
1078
1079
1080static bool checkParserFlag(unsigned flags, ParserFlag flag) {
1081 return flags & (1 << flag);
1082}
1083
1084
1085#define SET_PARSER_FLAGS(parser, flags) \
1086 parser.set_allow_lazy(checkParserFlag(flags, kAllowLazy)); \
1087 parser.set_allow_natives_syntax(checkParserFlag(flags, \
1088 kAllowNativesSyntax)); \
1089 parser.set_allow_harmony_scoping(checkParserFlag(flags, \
1090 kAllowHarmonyScoping)); \
1091 parser.set_allow_modules(checkParserFlag(flags, kAllowModules)); \
1092 parser.set_allow_generators(checkParserFlag(flags, kAllowGenerators));
1093
1094void TestParserSyncWithFlags(i::Handle<i::String> source, unsigned flags) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001095 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001096
1097 // Preparse the data.
1098 i::CompleteParserRecorder log;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001099 {
1100 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
1101 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1102 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
1103 SET_PARSER_FLAGS(preparser, flags);
1104 scanner.Initialize(&stream);
1105 v8::preparser::PreParser::PreParseResult result =
1106 preparser.PreParseProgram();
1107 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
1108 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001109 i::ScriptDataImpl data(log.ExtractData());
1110
1111 // Parse the data
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001112 i::FunctionLiteral* function;
1113 {
1114 i::Handle<i::Script> script = FACTORY->NewScript(source);
1115 i::CompilationInfoWithZone info(script);
1116 i::Parser parser(&info);
1117 SET_PARSER_FLAGS(parser, flags);
1118 info.MarkAsGlobal();
1119 function = parser.ParseProgram();
1120 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001121
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001122 // Check that preparsing fails iff parsing fails.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001123 if (function == NULL) {
1124 // Extract exception from the parser.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001125 CHECK(i::Isolate::Current()->has_pending_exception());
1126 i::MaybeObject* maybe_object = i::Isolate::Current()->pending_exception();
1127 i::JSObject* exception = NULL;
1128 CHECK(maybe_object->To(&exception));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001129 i::Handle<i::JSObject> exception_handle(exception);
1130 i::Handle<i::String> message_string =
1131 i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001132
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001133 if (!data.has_error()) {
1134 i::OS::Print(
1135 "Parser failed on:\n"
1136 "\t%s\n"
1137 "with error:\n"
1138 "\t%s\n"
1139 "However, the preparser succeeded",
1140 *source->ToCString(), *message_string->ToCString());
1141 CHECK(false);
1142 }
1143 // Check that preparser and parser produce the same error.
1144 i::Handle<i::String> preparser_message = FormatMessage(&data);
1145 if (!message_string->Equals(*preparser_message)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001146 i::OS::Print(
1147 "Expected parser and preparser to produce the same error on:\n"
1148 "\t%s\n"
1149 "However, found the following error messages\n"
1150 "\tparser: %s\n"
1151 "\tpreparser: %s\n",
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001152 *source->ToCString(),
1153 *message_string->ToCString(),
1154 *preparser_message->ToCString());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001155 CHECK(false);
1156 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001157 } else if (data.has_error()) {
1158 i::OS::Print(
1159 "Preparser failed on:\n"
1160 "\t%s\n"
1161 "with error:\n"
1162 "\t%s\n"
1163 "However, the parser succeeded",
1164 *source->ToCString(), *FormatMessage(&data)->ToCString());
1165 CHECK(false);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001166 }
1167}
1168
1169
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001170void TestParserSync(i::Handle<i::String> source) {
1171 for (unsigned flags = 0; flags < (1 << kParserFlagCount); ++flags) {
1172 TestParserSyncWithFlags(source, flags);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001173 }
1174}
1175
1176
1177TEST(ParserSync) {
1178 const char* context_data[][2] = {
1179 { "", "" },
1180 { "{", "}" },
1181 { "if (true) ", " else {}" },
1182 { "if (true) {} else ", "" },
1183 { "if (true) ", "" },
1184 { "do ", " while (false)" },
1185 { "while (false) ", "" },
1186 { "for (;;) ", "" },
1187 { "with ({})", "" },
1188 { "switch (12) { case 12: ", "}" },
1189 { "switch (12) { default: ", "}" },
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001190 { "switch (12) { ", "case 12: }" },
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001191 { "label2: ", "" },
1192 { NULL, NULL }
1193 };
1194
1195 const char* statement_data[] = {
1196 "{}",
1197 "var x",
1198 "var x = 1",
1199 "const x",
1200 "const x = 1",
1201 ";",
1202 "12",
1203 "if (false) {} else ;",
1204 "if (false) {} else {}",
1205 "if (false) {} else 12",
1206 "if (false) ;"
1207 "if (false) {}",
1208 "if (false) 12",
1209 "do {} while (false)",
1210 "for (;;) ;",
1211 "for (;;) {}",
1212 "for (;;) 12",
1213 "continue",
1214 "continue label",
1215 "continue\nlabel",
1216 "break",
1217 "break label",
1218 "break\nlabel",
1219 "return",
1220 "return 12",
1221 "return\n12",
1222 "with ({}) ;",
1223 "with ({}) {}",
1224 "with ({}) 12",
1225 "switch ({}) { default: }"
1226 "label3: "
1227 "throw",
1228 "throw 12",
1229 "throw\n12",
1230 "try {} catch(e) {}",
1231 "try {} finally {}",
1232 "try {} catch(e) {} finally {}",
1233 "debugger",
1234 NULL
1235 };
1236
1237 const char* termination_data[] = {
1238 "",
1239 ";",
1240 "\n",
1241 ";\n",
1242 "\n;",
1243 NULL
1244 };
1245
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001246 // TODO(mstarzinger): Disabled in GC stress mode for now, we should find the
1247 // correct timeout for this and re-enable this test again.
1248 if (i::FLAG_stress_compaction) return;
1249
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001250 v8::HandleScope handles(v8::Isolate::GetCurrent());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001251 v8::Handle<v8::Context> context = v8::Context::New(v8::Isolate::GetCurrent());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001252 v8::Context::Scope context_scope(context);
1253
1254 int marker;
1255 i::Isolate::Current()->stack_guard()->SetStackLimit(
1256 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1257
1258 for (int i = 0; context_data[i][0] != NULL; ++i) {
1259 for (int j = 0; statement_data[j] != NULL; ++j) {
1260 for (int k = 0; termination_data[k] != NULL; ++k) {
1261 int kPrefixLen = i::StrLength(context_data[i][0]);
1262 int kStatementLen = i::StrLength(statement_data[j]);
1263 int kTerminationLen = i::StrLength(termination_data[k]);
1264 int kSuffixLen = i::StrLength(context_data[i][1]);
1265 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1266 + kSuffixLen + i::StrLength("label: for (;;) { }");
1267
1268 // Plug the source code pieces together.
1269 i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
1270 int length = i::OS::SNPrintF(program,
1271 "label: for (;;) { %s%s%s%s }",
1272 context_data[i][0],
1273 statement_data[j],
1274 termination_data[k],
1275 context_data[i][1]);
1276 CHECK(length == kProgramSize);
1277 i::Handle<i::String> source =
1278 FACTORY->NewStringFromAscii(i::CStrVector(program.start()));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001279 TestParserSync(source);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001280 }
1281 }
1282 }
1283}
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001284
1285
1286TEST(PreparserStrictOctal) {
1287 // Test that syntax error caused by octal literal is reported correctly as
1288 // such (issue 2220).
1289 v8::internal::FLAG_min_preparse_length = 1; // Force preparsing.
1290 v8::V8::Initialize();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001291 v8::HandleScope scope(v8::Isolate::GetCurrent());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001292 v8::Context::Scope context_scope(
1293 v8::Context::New(v8::Isolate::GetCurrent()));
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001294 v8::TryCatch try_catch;
1295 const char* script =
1296 "\"use strict\"; \n"
1297 "a = function() { \n"
1298 " b = function() { \n"
1299 " 01; \n"
1300 " }; \n"
1301 "}; \n";
1302 v8::Script::Compile(v8::String::New(script));
1303 CHECK(try_catch.HasCaught());
1304 v8::String::Utf8Value exception(try_catch.Exception());
1305 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
1306 *exception);
1307}