blob: c7331bdb91b33bb5af60316343331b629d7547f5 [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
32#include "v8.h"
33
ager@chromium.orgc4c92722009-11-18 14:12:51 +000034#include "cctest.h"
ricow@chromium.org27bf2882011-11-17 08:34:43 +000035#include "compiler.h"
ricow@chromium.org55ee8072011-09-08 16:33:10 +000036#include "execution.h"
37#include "isolate.h"
38#include "parser.h"
39#include "preparser.h"
40#include "scanner-character-streams.h"
41#include "token.h"
42#include "utils.h"
ager@chromium.orgc4c92722009-11-18 14:12:51 +000043
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000044TEST(ScanKeywords) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000045 struct KeywordToken {
46 const char* keyword;
47 i::Token::Value token;
48 };
49
50 static const KeywordToken keywords[] = {
51#define KEYWORD(t, s, d) { s, i::Token::t },
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000052 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
ager@chromium.orgc4c92722009-11-18 14:12:51 +000053#undef KEYWORD
54 { NULL, i::Token::IDENTIFIER }
55 };
56
ager@chromium.orgc4c92722009-11-18 14:12:51 +000057 KeywordToken key_token;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000058 i::UnicodeCache unicode_cache;
59 i::byte buffer[32];
ager@chromium.orgc4c92722009-11-18 14:12:51 +000060 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000061 const i::byte* keyword =
62 reinterpret_cast<const i::byte*>(key_token.keyword);
63 int length = i::StrLength(key_token.keyword);
64 CHECK(static_cast<int>(sizeof(buffer)) >= length);
65 {
yangguo@chromium.org154ff992012-03-13 08:09:54 +000066 i::Utf8ToUtf16CharacterStream stream(keyword, length);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000067 i::Scanner scanner(&unicode_cache);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000068 // The scanner should parse Harmony keywords for this test.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000069 scanner.SetHarmonyScoping(true);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +000070 scanner.SetHarmonyModules(true);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000071 scanner.Initialize(&stream);
72 CHECK_EQ(key_token.token, scanner.Next());
73 CHECK_EQ(i::Token::EOS, scanner.Next());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000074 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000075 // Removing characters will make keyword matching fail.
76 {
yangguo@chromium.org154ff992012-03-13 08:09:54 +000077 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000078 i::Scanner scanner(&unicode_cache);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000079 scanner.Initialize(&stream);
80 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
81 CHECK_EQ(i::Token::EOS, scanner.Next());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000082 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000083 // Adding characters will make keyword matching fail.
84 static const char chars_to_append[] = { 'z', '0', '_' };
85 for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000086 i::OS::MemMove(buffer, keyword, length);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000087 buffer[length] = chars_to_append[j];
yangguo@chromium.org154ff992012-03-13 08:09:54 +000088 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000089 i::Scanner scanner(&unicode_cache);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000090 scanner.Initialize(&stream);
91 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
92 CHECK_EQ(i::Token::EOS, scanner.Next());
93 }
94 // Replacing characters will make keyword matching fail.
95 {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000096 i::OS::MemMove(buffer, keyword, length);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000097 buffer[length - 1] = '_';
yangguo@chromium.org154ff992012-03-13 08:09:54 +000098 i::Utf8ToUtf16CharacterStream stream(buffer, length);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000099 i::Scanner scanner(&unicode_cache);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000100 scanner.Initialize(&stream);
101 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
102 CHECK_EQ(i::Token::EOS, scanner.Next());
103 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000104 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000105}
106
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000107
108TEST(ScanHTMLEndComments) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000109 v8::V8::Initialize();
110
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000111 // Regression test. See:
112 // http://code.google.com/p/chromium/issues/detail?id=53548
113 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000114 // is only whitespace before it on the line (with comments considered as
115 // whitespace, even a multiline-comment containing a newline).
116 // This was not the case if it occurred before the first real token
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000117 // in the input.
118 const char* tests[] = {
119 // Before first real token.
120 "--> is eol-comment\nvar y = 37;\n",
121 "\n --> is eol-comment\nvar y = 37;\n",
122 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
123 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
124 // After first real token.
125 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
126 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
127 NULL
128 };
129
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000130 const char* fail_tests[] = {
131 "x --> is eol-comment\nvar y = 37;\n",
132 "\"\\n\" --> is eol-comment\nvar y = 37;\n",
133 "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
134 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
135 "var x = 42; --> is eol-comment\nvar y = 37;\n",
136 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
137 NULL
138 };
139
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000140 // Parser/Scanner needs a stack limit.
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000141 int marker;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000142 i::Isolate::Current()->stack_guard()->SetStackLimit(
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000143 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
144
145 for (int i = 0; tests[i]; i++) {
146 v8::ScriptData* data =
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000147 v8::ScriptData::PreCompile(tests[i], i::StrLength(tests[i]));
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000148 CHECK(data != NULL && !data->HasError());
149 delete data;
150 }
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000151
152 for (int i = 0; fail_tests[i]; i++) {
153 v8::ScriptData* data =
154 v8::ScriptData::PreCompile(fail_tests[i], i::StrLength(fail_tests[i]));
155 CHECK(data == NULL || data->HasError());
156 delete data;
157 }
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000158}
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000159
160
161class ScriptResource : public v8::String::ExternalAsciiStringResource {
162 public:
163 ScriptResource(const char* data, size_t length)
164 : data_(data), length_(length) { }
165
166 const char* data() const { return data_; }
167 size_t length() const { return length_; }
168
169 private:
170 const char* data_;
171 size_t length_;
172};
173
174
175TEST(Preparsing) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000176 v8::HandleScope handles(v8::Isolate::GetCurrent());
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000177 v8::Persistent<v8::Context> context = v8::Context::New();
178 v8::Context::Scope context_scope(context);
179 int marker;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 i::Isolate::Current()->stack_guard()->SetStackLimit(
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000181 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
182
183 // Source containing functions that might be lazily compiled and all types
184 // of symbols (string, propertyName, regexp).
185 const char* source =
186 "var x = 42;"
187 "function foo(a) { return function nolazy(b) { return a + b; } }"
188 "function bar(a) { if (a) return function lazy(b) { return b; } }"
189 "var z = {'string': 'string literal', bareword: 'propertyName', "
190 " 42: 'number literal', for: 'keyword as propertyName', "
191 " f\\u006fr: 'keyword propertyname with escape'};"
192 "var v = /RegExp Literal/;"
193 "var w = /RegExp Literal\\u0020With Escape/gin;"
194 "var y = { get getter() { return 42; }, "
195 " set setter(v) { this.value = v; }};";
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000196 int source_length = i::StrLength(source);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000197 const char* error_source = "var x = y z;";
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000198 int error_source_length = i::StrLength(error_source);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000199
200 v8::ScriptData* preparse =
201 v8::ScriptData::PreCompile(source, source_length);
202 CHECK(!preparse->HasError());
203 bool lazy_flag = i::FLAG_lazy;
204 {
205 i::FLAG_lazy = true;
206 ScriptResource* resource = new ScriptResource(source, source_length);
207 v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
208 v8::Script::Compile(script_source, NULL, preparse);
209 }
210
211 {
212 i::FLAG_lazy = false;
213
214 ScriptResource* resource = new ScriptResource(source, source_length);
215 v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
216 v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
217 }
218 delete preparse;
219 i::FLAG_lazy = lazy_flag;
220
221 // Syntax error.
222 v8::ScriptData* error_preparse =
223 v8::ScriptData::PreCompile(error_source, error_source_length);
224 CHECK(error_preparse->HasError());
225 i::ScriptDataImpl *pre_impl =
226 reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
227 i::Scanner::Location error_location =
228 pre_impl->MessageLocation();
229 // Error is at "z" in source, location 10..11.
230 CHECK_EQ(10, error_location.beg_pos);
231 CHECK_EQ(11, error_location.end_pos);
232 // Should not crash.
233 const char* message = pre_impl->BuildMessage();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000234 pre_impl->BuildArgs();
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000235 CHECK_GT(strlen(message), 0);
236}
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000237
238
239TEST(StandAlonePreParser) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000240 v8::V8::Initialize();
241
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000242 int marker;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 i::Isolate::Current()->stack_guard()->SetStackLimit(
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000244 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
245
246 const char* programs[] = {
247 "{label: 42}",
248 "var x = 42;",
249 "function foo(x, y) { return x + y; }",
whesse@chromium.org7b260152011-06-20 15:33:18 +0000250 "%ArgleBargle(glop);",
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000251 "var x = new new Function('this.x = 42');",
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000252 NULL
253 };
254
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000255 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000256 for (int i = 0; programs[i]; i++) {
257 const char* program = programs[i];
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000258 i::Utf8ToUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000259 reinterpret_cast<const i::byte*>(program),
260 static_cast<unsigned>(strlen(program)));
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000261 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000262 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000263 scanner.Initialize(&stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000264
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000265 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
266 preparser.set_allow_lazy(true);
267 preparser.set_allow_natives_syntax(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000268 v8::preparser::PreParser::PreParseResult result =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000269 preparser.PreParseProgram();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000270 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000271 i::ScriptDataImpl data(log.ExtractData());
272 CHECK(!data.has_error());
273 }
274}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000275
276
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000277TEST(StandAlonePreParserNoNatives) {
278 v8::V8::Initialize();
279
280 int marker;
281 i::Isolate::Current()->stack_guard()->SetStackLimit(
282 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
283
284 const char* programs[] = {
285 "%ArgleBargle(glop);",
286 "var x = %_IsSmi(42);",
287 NULL
288 };
289
290 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
291 for (int i = 0; programs[i]; i++) {
292 const char* program = programs[i];
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000293 i::Utf8ToUtf16CharacterStream stream(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000294 reinterpret_cast<const i::byte*>(program),
295 static_cast<unsigned>(strlen(program)));
296 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000297 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000298 scanner.Initialize(&stream);
299
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000300 // Preparser defaults to disallowing natives syntax.
301 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
302 preparser.set_allow_lazy(true);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000303 v8::preparser::PreParser::PreParseResult result =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000304 preparser.PreParseProgram();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000305 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
306 i::ScriptDataImpl data(log.ExtractData());
307 // Data contains syntax error.
308 CHECK(data.has_error());
309 }
310}
311
312
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000313TEST(RegressChromium62639) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000314 v8::V8::Initialize();
315
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000316 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000317 i::Isolate::Current()->stack_guard()->SetStackLimit(
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000318 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
319
320 const char* program = "var x = 'something';\n"
321 "escape: function() {}";
322 // Fails parsing expecting an identifier after "function".
323 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
324 // and then used the invalid currently scanned literal. This always
325 // failed in debug mode, and sometimes crashed in release mode.
326
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000327 i::Utf8ToUtf16CharacterStream stream(
328 reinterpret_cast<const i::byte*>(program),
329 static_cast<unsigned>(strlen(program)));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000330 i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000331 CHECK(data->HasError());
332 delete data;
333}
334
335
336TEST(Regress928) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000337 v8::V8::Initialize();
338
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000339 // Preparsing didn't consider the catch clause of a try statement
340 // as with-content, which made it assume that a function inside
341 // the block could be lazily compiled, and an extra, unexpected,
342 // entry was added to the data.
343 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000344 i::Isolate::Current()->stack_guard()->SetStackLimit(
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000345 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
346
347 const char* program =
348 "try { } catch (e) { var foo = function () { /* first */ } }"
349 "var bar = function () { /* second */ }";
350
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000351 v8::HandleScope handles(v8::Isolate::GetCurrent());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000352 i::Handle<i::String> source(
353 FACTORY->NewStringFromAscii(i::CStrVector(program)));
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000354 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000355 i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000356 CHECK(!data->HasError());
357
358 data->Initialize();
359
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000360 int first_function =
361 static_cast<int>(strstr(program, "function") - program);
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000362 int first_lbrace = first_function + i::StrLength("function () ");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000363 CHECK_EQ('{', program[first_lbrace]);
364 i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
365 CHECK(!entry1.is_valid());
366
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000367 int second_function =
368 static_cast<int>(strstr(program + first_lbrace, "function") - program);
369 int second_lbrace =
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000370 second_function + i::StrLength("function () ");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000371 CHECK_EQ('{', program[second_lbrace]);
372 i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
373 CHECK(entry2.is_valid());
374 CHECK_EQ('}', program[entry2.end_pos() - 1]);
375 delete data;
376}
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000377
378
379TEST(PreParseOverflow) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000380 v8::V8::Initialize();
381
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000382 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000383 i::Isolate::Current()->stack_guard()->SetStackLimit(
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000384 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
385
386 size_t kProgramSize = 1024 * 1024;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000387 i::SmartArrayPointer<char> program(
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000388 reinterpret_cast<char*>(malloc(kProgramSize + 1)));
389 memset(*program, '(', kProgramSize);
390 program[kProgramSize] = '\0';
391
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000392 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000393
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000394 i::Utf8ToUtf16CharacterStream stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000395 reinterpret_cast<const i::byte*>(*program),
396 static_cast<unsigned>(kProgramSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000397 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000398 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000399 scanner.Initialize(&stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000400
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000401 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
402 preparser.set_allow_lazy(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000403 v8::preparser::PreParser::PreParseResult result =
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000404 preparser.PreParseProgram();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000405 CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
406}
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000407
408
409class TestExternalResource: public v8::String::ExternalStringResource {
410 public:
411 explicit TestExternalResource(uint16_t* data, int length)
412 : data_(data), length_(static_cast<size_t>(length)) { }
413
414 ~TestExternalResource() { }
415
416 const uint16_t* data() const {
417 return data_;
418 }
419
420 size_t length() const {
421 return length_;
422 }
423 private:
424 uint16_t* data_;
425 size_t length_;
426};
427
428
429#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
430
431void TestCharacterStream(const char* ascii_source,
432 unsigned length,
433 unsigned start = 0,
434 unsigned end = 0) {
435 if (end == 0) end = length;
436 unsigned sub_length = end - start;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000437 i::HandleScope test_scope(i::Isolate::Current());
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000438 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000439 for (unsigned i = 0; i < length; i++) {
440 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
441 }
442 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
443 i::Handle<i::String> ascii_string(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 FACTORY->NewStringFromAscii(ascii_vector));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000445 TestExternalResource resource(*uc16_buffer, length);
446 i::Handle<i::String> uc16_string(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 FACTORY->NewExternalStringFromTwoByte(&resource));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000448
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000449 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000450 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000451 i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
452 i::Utf8ToUtf16CharacterStream utf8_stream(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000453 reinterpret_cast<const i::byte*>(ascii_source), end);
454 utf8_stream.SeekForward(start);
455
456 unsigned i = start;
457 while (i < end) {
458 // Read streams one char at a time
459 CHECK_EQU(i, uc16_stream.pos());
460 CHECK_EQU(i, string_stream.pos());
461 CHECK_EQU(i, utf8_stream.pos());
462 int32_t c0 = ascii_source[i];
463 int32_t c1 = uc16_stream.Advance();
464 int32_t c2 = string_stream.Advance();
465 int32_t c3 = utf8_stream.Advance();
466 i++;
467 CHECK_EQ(c0, c1);
468 CHECK_EQ(c0, c2);
469 CHECK_EQ(c0, c3);
470 CHECK_EQU(i, uc16_stream.pos());
471 CHECK_EQU(i, string_stream.pos());
472 CHECK_EQU(i, utf8_stream.pos());
473 }
474 while (i > start + sub_length / 4) {
475 // Pushback, re-read, pushback again.
476 int32_t c0 = ascii_source[i - 1];
477 CHECK_EQU(i, uc16_stream.pos());
478 CHECK_EQU(i, string_stream.pos());
479 CHECK_EQU(i, utf8_stream.pos());
480 uc16_stream.PushBack(c0);
481 string_stream.PushBack(c0);
482 utf8_stream.PushBack(c0);
483 i--;
484 CHECK_EQU(i, uc16_stream.pos());
485 CHECK_EQU(i, string_stream.pos());
486 CHECK_EQU(i, utf8_stream.pos());
487 int32_t c1 = uc16_stream.Advance();
488 int32_t c2 = string_stream.Advance();
489 int32_t c3 = utf8_stream.Advance();
490 i++;
491 CHECK_EQU(i, uc16_stream.pos());
492 CHECK_EQU(i, string_stream.pos());
493 CHECK_EQU(i, utf8_stream.pos());
494 CHECK_EQ(c0, c1);
495 CHECK_EQ(c0, c2);
496 CHECK_EQ(c0, c3);
497 uc16_stream.PushBack(c0);
498 string_stream.PushBack(c0);
499 utf8_stream.PushBack(c0);
500 i--;
501 CHECK_EQU(i, uc16_stream.pos());
502 CHECK_EQU(i, string_stream.pos());
503 CHECK_EQU(i, utf8_stream.pos());
504 }
505 unsigned halfway = start + sub_length / 2;
506 uc16_stream.SeekForward(halfway - i);
507 string_stream.SeekForward(halfway - i);
508 utf8_stream.SeekForward(halfway - i);
509 i = halfway;
510 CHECK_EQU(i, uc16_stream.pos());
511 CHECK_EQU(i, string_stream.pos());
512 CHECK_EQU(i, utf8_stream.pos());
513
514 while (i < end) {
515 // Read streams one char at a time
516 CHECK_EQU(i, uc16_stream.pos());
517 CHECK_EQU(i, string_stream.pos());
518 CHECK_EQU(i, utf8_stream.pos());
519 int32_t c0 = ascii_source[i];
520 int32_t c1 = uc16_stream.Advance();
521 int32_t c2 = string_stream.Advance();
522 int32_t c3 = utf8_stream.Advance();
523 i++;
524 CHECK_EQ(c0, c1);
525 CHECK_EQ(c0, c2);
526 CHECK_EQ(c0, c3);
527 CHECK_EQU(i, uc16_stream.pos());
528 CHECK_EQU(i, string_stream.pos());
529 CHECK_EQU(i, utf8_stream.pos());
530 }
531
532 int32_t c1 = uc16_stream.Advance();
533 int32_t c2 = string_stream.Advance();
534 int32_t c3 = utf8_stream.Advance();
535 CHECK_LT(c1, 0);
536 CHECK_LT(c2, 0);
537 CHECK_LT(c3, 0);
538}
539
540
541TEST(CharacterStreams) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000542 v8::HandleScope handles(v8::Isolate::GetCurrent());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000543 v8::Persistent<v8::Context> context = v8::Context::New();
544 v8::Context::Scope context_scope(context);
545
546 TestCharacterStream("abc\0\n\r\x7f", 7);
547 static const unsigned kBigStringSize = 4096;
548 char buffer[kBigStringSize + 1];
549 for (unsigned i = 0; i < kBigStringSize; i++) {
550 buffer[i] = static_cast<char>(i & 0x7f);
551 }
552 TestCharacterStream(buffer, kBigStringSize);
553
554 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
555
556 TestCharacterStream("\0", 1);
557 TestCharacterStream("", 0);
558}
559
560
561TEST(Utf8CharacterStream) {
562 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
563 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
564
565 static const int kAllUtf8CharsSize =
566 (unibrow::Utf8::kMaxOneByteChar + 1) +
567 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
568 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
569 static const unsigned kAllUtf8CharsSizeU =
570 static_cast<unsigned>(kAllUtf8CharsSize);
571
572 char buffer[kAllUtf8CharsSizeU];
573 unsigned cursor = 0;
574 for (int i = 0; i <= kMaxUC16Char; i++) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000575 cursor += unibrow::Utf8::Encode(buffer + cursor,
576 i,
577 unibrow::Utf16::kNoPreviousCharacter);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000578 }
579 ASSERT(cursor == kAllUtf8CharsSizeU);
580
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000581 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
582 kAllUtf8CharsSizeU);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000583 for (int i = 0; i <= kMaxUC16Char; i++) {
584 CHECK_EQU(i, stream.pos());
585 int32_t c = stream.Advance();
586 CHECK_EQ(i, c);
587 CHECK_EQU(i + 1, stream.pos());
588 }
589 for (int i = kMaxUC16Char; i >= 0; i--) {
590 CHECK_EQU(i + 1, stream.pos());
591 stream.PushBack(i);
592 CHECK_EQU(i, stream.pos());
593 }
594 int i = 0;
595 while (stream.pos() < kMaxUC16CharU) {
596 CHECK_EQU(i, stream.pos());
597 unsigned progress = stream.SeekForward(12);
598 i += progress;
599 int32_t c = stream.Advance();
600 if (i <= kMaxUC16Char) {
601 CHECK_EQ(i, c);
602 } else {
603 CHECK_EQ(-1, c);
604 }
605 i += 1;
606 CHECK_EQU(i, stream.pos());
607 }
608}
609
610#undef CHECK_EQU
611
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000612void TestStreamScanner(i::Utf16CharacterStream* stream,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000613 i::Token::Value* expected_tokens,
614 int skip_pos = 0, // Zero means not skipping.
615 int skip_to = 0) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000616 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000617 scanner.Initialize(stream);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000618
619 int i = 0;
620 do {
621 i::Token::Value expected = expected_tokens[i];
622 i::Token::Value actual = scanner.Next();
623 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
624 if (scanner.location().end_pos == skip_pos) {
625 scanner.SeekForward(skip_to);
626 }
627 i++;
628 } while (expected_tokens[i] != i::Token::ILLEGAL);
629}
630
631TEST(StreamScanner) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000632 v8::V8::Initialize();
633
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000634 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000635 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
636 static_cast<unsigned>(strlen(str1)));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000637 i::Token::Value expectations1[] = {
638 i::Token::LBRACE,
639 i::Token::IDENTIFIER,
640 i::Token::IDENTIFIER,
641 i::Token::FOR,
642 i::Token::COLON,
643 i::Token::MUL,
644 i::Token::DIV,
645 i::Token::LT,
646 i::Token::SUB,
647 i::Token::IDENTIFIER,
648 i::Token::EOS,
649 i::Token::ILLEGAL
650 };
651 TestStreamScanner(&stream1, expectations1, 0, 0);
652
653 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000654 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
655 static_cast<unsigned>(strlen(str2)));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000656 i::Token::Value expectations2[] = {
657 i::Token::CASE,
658 i::Token::DEFAULT,
659 i::Token::CONST,
660 i::Token::LBRACE,
661 // Skipped part here
662 i::Token::RBRACE,
663 i::Token::DO,
664 i::Token::EOS,
665 i::Token::ILLEGAL
666 };
667 ASSERT_EQ('{', str2[19]);
668 ASSERT_EQ('}', str2[37]);
669 TestStreamScanner(&stream2, expectations2, 20, 37);
670
671 const char* str3 = "{}}}}";
672 i::Token::Value expectations3[] = {
673 i::Token::LBRACE,
674 i::Token::RBRACE,
675 i::Token::RBRACE,
676 i::Token::RBRACE,
677 i::Token::RBRACE,
678 i::Token::EOS,
679 i::Token::ILLEGAL
680 };
681 // Skip zero-four RBRACEs.
682 for (int i = 0; i <= 4; i++) {
683 expectations3[6 - i] = i::Token::ILLEGAL;
684 expectations3[5 - i] = i::Token::EOS;
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000685 i::Utf8ToUtf16CharacterStream stream3(
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000686 reinterpret_cast<const i::byte*>(str3),
687 static_cast<unsigned>(strlen(str3)));
688 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
689 }
690}
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000691
692
693void TestScanRegExp(const char* re_source, const char* expected) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000694 i::Utf8ToUtf16CharacterStream stream(
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000695 reinterpret_cast<const i::byte*>(re_source),
696 static_cast<unsigned>(strlen(re_source)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000698 scanner.Initialize(&stream);
699
700 i::Token::Value start = scanner.peek();
701 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
702 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
703 scanner.Next(); // Current token is now the regexp literal.
704 CHECK(scanner.is_literal_ascii());
705 i::Vector<const char> actual = scanner.literal_ascii_string();
706 for (int i = 0; i < actual.length(); i++) {
707 CHECK_NE('\0', expected[i]);
708 CHECK_EQ(expected[i], actual[i]);
709 }
710}
711
712
713TEST(RegExpScanning) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000714 v8::V8::Initialize();
715
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000716 // RegExp token with added garbage at the end. The scanner should only
717 // scan the RegExp until the terminating slash just before "flipperwald".
718 TestScanRegExp("/b/flipperwald", "b");
719 // Incomplete escape sequences doesn't hide the terminating slash.
720 TestScanRegExp("/\\x/flipperwald", "\\x");
721 TestScanRegExp("/\\u/flipperwald", "\\u");
722 TestScanRegExp("/\\u1/flipperwald", "\\u1");
723 TestScanRegExp("/\\u12/flipperwald", "\\u12");
724 TestScanRegExp("/\\u123/flipperwald", "\\u123");
725 TestScanRegExp("/\\c/flipperwald", "\\c");
726 TestScanRegExp("/\\c//flipperwald", "\\c");
727 // Slashes inside character classes are not terminating.
728 TestScanRegExp("/[/]/flipperwald", "[/]");
729 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
730 // Incomplete escape sequences inside a character class doesn't hide
731 // the end of the character class.
732 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
733 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
734 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
735 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
736 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
737 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
738 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
739 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
740 // Escaped ']'s wont end the character class.
741 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
742 // Escaped slashes are not terminating.
743 TestScanRegExp("/\\//flipperwald", "\\/");
744 // Starting with '=' works too.
745 TestScanRegExp("/=/", "=");
746 TestScanRegExp("/=?/", "=?");
747}
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000748
749
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000750static int Utf8LengthHelper(const char* s) {
751 int len = i::StrLength(s);
752 int character_length = len;
753 for (int i = 0; i < len; i++) {
754 unsigned char c = s[i];
755 int input_offset = 0;
756 int output_adjust = 0;
757 if (c > 0x7f) {
758 if (c < 0xc0) continue;
759 if (c >= 0xf0) {
760 if (c >= 0xf8) {
761 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
762 // byte.
763 continue; // Handle first UTF-8 byte.
764 }
765 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
766 // This 4 byte sequence could have been coded as a 3 byte sequence.
767 // Record a single kBadChar for the first byte and continue.
768 continue;
769 }
770 input_offset = 3;
771 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
772 character_length -= 2;
773 } else if (c >= 0xe0) {
774 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
775 // This 3 byte sequence could have been coded as a 2 byte sequence.
776 // Record a single kBadChar for the first byte and continue.
777 continue;
778 }
779 input_offset = 2;
780 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
781 output_adjust = 2;
782 } else {
783 if ((c & 0x1e) == 0) {
784 // This 2 byte sequence could have been coded as a 1 byte sequence.
785 // Record a single kBadChar for the first byte and continue.
786 continue;
787 }
788 input_offset = 1;
789 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
790 output_adjust = 1;
791 }
792 bool bad = false;
793 for (int j = 1; j <= input_offset; j++) {
794 if ((s[i + j] & 0xc0) != 0x80) {
795 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
796 // which is a single UTF-16 code unit.
797 bad = true;
798 break;
799 }
800 }
801 if (!bad) {
802 i += input_offset;
803 character_length -= output_adjust;
804 }
805 }
806 }
807 return character_length;
808}
809
810
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000811TEST(ScopePositions) {
812 // Test the parser for correctly setting the start and end positions
813 // of a scope. We check the scope positions of exactly one scope
814 // nested in the global scope of a program. 'inner source' is the
815 // source code that determines the part of the source belonging
816 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
817 // parts of the source that belong to the global scope.
818 struct SourceData {
819 const char* outer_prefix;
820 const char* inner_source;
821 const char* outer_suffix;
822 i::ScopeType scope_type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000823 i::LanguageMode language_mode;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000824 };
825
826 const SourceData source_data[] = {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000827 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
828 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000829 { " with ({}) ", "{\n"
830 " block;\n"
831 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000832 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
833 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000834 { " with ({}) ", "statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000835 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000836 { " with ({})\n"
837 " ", "statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000838 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
839 { " try {} catch ", "(e) { block; }", " more;",
840 i::CATCH_SCOPE, i::CLASSIC_MODE },
841 { " try {} catch ", "(e) { block; }", "; more;",
842 i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000843 { " try {} catch ", "(e) {\n"
844 " block;\n"
845 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000846 " more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000847 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000848 i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000849 { " start;\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000850 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000851 { " start;\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000852 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000853 { " start;\n"
854 " ", "{\n"
855 " let block;\n"
856 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000857 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000858 { " start;\n"
859 " function fun", "(a,b) { infunction; }", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000860 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000861 { " start;\n"
862 " function fun", "(a,b) {\n"
863 " infunction;\n"
864 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000865 " more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000866 { " (function fun", "(a,b) { infunction; }", ")();",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000867 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000868 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000869 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000870 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000871 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000872 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
873 " block;\n"
874 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000875 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000876 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000877 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000878 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000879 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000880 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
881 " statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000882 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
883 { " for ", "(let x in {}) { block; }", " more;",
884 i::BLOCK_SCOPE, i::EXTENDED_MODE },
885 { " for ", "(let x in {}) { block; }", "; more;",
886 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000887 { " for ", "(let x in {}) {\n"
888 " block;\n"
889 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000890 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
891 { " for ", "(let x in {}) statement;", " more;",
892 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000893 { " for ", "(let x in {}) statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000894 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000895 { " for ", "(let x in {})\n"
896 " statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000897 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000898 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
899 // the preparser off in terms of byte offsets.
900 // 6 byte encoding.
901 { " 'foo\355\240\201\355\260\211';\n"
902 " (function fun", "(a,b) { infunction; }", ")();",
903 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
904 // 4 byte encoding.
905 { " 'foo\360\220\220\212';\n"
906 " (function fun", "(a,b) { infunction; }", ")();",
907 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
908 // 3 byte encoding of \u0fff.
909 { " 'foo\340\277\277';\n"
910 " (function fun", "(a,b) { infunction; }", ")();",
911 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
912 // Broken 6 byte encoding with missing last byte.
913 { " 'foo\355\240\201\355\211';\n"
914 " (function fun", "(a,b) { infunction; }", ")();",
915 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
916 // Broken 3 byte encoding of \u0fff with missing last byte.
917 { " 'foo\340\277';\n"
918 " (function fun", "(a,b) { infunction; }", ")();",
919 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
920 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
921 { " 'foo\340';\n"
922 " (function fun", "(a,b) { infunction; }", ")();",
923 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
924 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
925 { " 'foo\340\203\277';\n"
926 " (function fun", "(a,b) { infunction; }", ")();",
927 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
928 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
929 { " 'foo\340\201\277';\n"
930 " (function fun", "(a,b) { infunction; }", ")();",
931 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
932 // Unpaired lead surrogate.
933 { " 'foo\355\240\201';\n"
934 " (function fun", "(a,b) { infunction; }", ")();",
935 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
936 // Unpaired lead surrogate where following code point is a 3 byte sequence.
937 { " 'foo\355\240\201\340\277\277';\n"
938 " (function fun", "(a,b) { infunction; }", ")();",
939 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
940 // Unpaired lead surrogate where following code point is a 4 byte encoding
941 // of a trail surrogate.
942 { " 'foo\355\240\201\360\215\260\211';\n"
943 " (function fun", "(a,b) { infunction; }", ")();",
944 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
945 // Unpaired trail surrogate.
946 { " 'foo\355\260\211';\n"
947 " (function fun", "(a,b) { infunction; }", ")();",
948 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
949 // 2 byte encoding of \u00ff.
950 { " 'foo\303\277';\n"
951 " (function fun", "(a,b) { infunction; }", ")();",
952 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
953 // Broken 2 byte encoding of \u00ff with missing last byte.
954 { " 'foo\303';\n"
955 " (function fun", "(a,b) { infunction; }", ")();",
956 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
957 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
958 { " 'foo\301\277';\n"
959 " (function fun", "(a,b) { infunction; }", ")();",
960 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
961 // Illegal 5 byte encoding.
962 { " 'foo\370\277\277\277\277';\n"
963 " (function fun", "(a,b) { infunction; }", ")();",
964 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
965 // Illegal 6 byte encoding.
966 { " 'foo\374\277\277\277\277\277';\n"
967 " (function fun", "(a,b) { infunction; }", ")();",
968 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
969 // Illegal 0xfe byte
970 { " 'foo\376\277\277\277\277\277\277';\n"
971 " (function fun", "(a,b) { infunction; }", ")();",
972 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
973 // Illegal 0xff byte
974 { " 'foo\377\277\277\277\277\277\277\277';\n"
975 " (function fun", "(a,b) { infunction; }", ")();",
976 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
977 { " 'foo';\n"
978 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
979 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
980 { " 'foo';\n"
981 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
982 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000983 { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000984 };
985
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000986 v8::HandleScope handles(v8::Isolate::GetCurrent());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000987 v8::Persistent<v8::Context> context = v8::Context::New();
988 v8::Context::Scope context_scope(context);
989
990 int marker;
991 i::Isolate::Current()->stack_guard()->SetStackLimit(
992 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
993
994 for (int i = 0; source_data[i].outer_prefix; i++) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000995 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
996 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
997 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
998 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
999 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1000 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001001 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001002 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1003 i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
1004 i::OS::SNPrintF(program, "%s%s%s",
1005 source_data[i].outer_prefix,
1006 source_data[i].inner_source,
1007 source_data[i].outer_suffix);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001008
1009 // Parse program source.
1010 i::Handle<i::String> source(
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001011 FACTORY->NewStringFromUtf8(i::CStrVector(program.start())));
1012 CHECK_EQ(source->length(), kProgramSize);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001013 i::Handle<i::Script> script = FACTORY->NewScript(source);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001014 i::CompilationInfoWithZone info(script);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001015 i::Parser parser(&info);
1016 parser.set_allow_lazy(true);
1017 parser.set_allow_harmony_scoping(true);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001018 info.MarkAsGlobal();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001019 info.SetLanguageMode(source_data[i].language_mode);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001020 i::FunctionLiteral* function = parser.ParseProgram();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001021 CHECK(function != NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001022
1023 // Check scope types and positions.
1024 i::Scope* scope = function->scope();
1025 CHECK(scope->is_global_scope());
1026 CHECK_EQ(scope->start_position(), 0);
1027 CHECK_EQ(scope->end_position(), kProgramSize);
1028 CHECK_EQ(scope->inner_scopes()->length(), 1);
1029
1030 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1031 CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
1032 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1033 // The end position of a token is one position after the last
1034 // character belonging to that token.
1035 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1036 }
1037}
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001038
1039
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001040i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) {
1041 i::Handle<i::String> format = v8::Utils::OpenHandle(
1042 *v8::String::New(data->BuildMessage()));
1043 i::Vector<const char*> args = data->BuildArgs();
1044 i::Handle<i::JSArray> args_array = FACTORY->NewJSArray(args.length());
1045 for (int i = 0; i < args.length(); i++) {
1046 i::JSArray::SetElement(args_array,
1047 i,
1048 v8::Utils::OpenHandle(*v8::String::New(args[i])),
1049 NONE,
1050 i::kNonStrictMode);
1051 }
1052 i::Handle<i::JSObject> builtins(i::Isolate::Current()->js_builtins_object());
1053 i::Handle<i::Object> format_fun =
1054 i::GetProperty(builtins, "FormatMessage");
1055 i::Handle<i::Object> arg_handles[] = { format, args_array };
1056 bool has_exception = false;
1057 i::Handle<i::Object> result =
1058 i::Execution::Call(format_fun, builtins, 2, arg_handles, &has_exception);
1059 CHECK(!has_exception);
1060 CHECK(result->IsString());
1061 return i::Handle<i::String>::cast(result);
1062}
1063
1064
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001065enum ParserFlag {
1066 kAllowLazy,
1067 kAllowNativesSyntax,
1068 kAllowHarmonyScoping,
1069 kAllowModules,
1070 kAllowGenerators,
1071 kParserFlagCount
1072};
1073
1074
1075static bool checkParserFlag(unsigned flags, ParserFlag flag) {
1076 return flags & (1 << flag);
1077}
1078
1079
1080#define SET_PARSER_FLAGS(parser, flags) \
1081 parser.set_allow_lazy(checkParserFlag(flags, kAllowLazy)); \
1082 parser.set_allow_natives_syntax(checkParserFlag(flags, \
1083 kAllowNativesSyntax)); \
1084 parser.set_allow_harmony_scoping(checkParserFlag(flags, \
1085 kAllowHarmonyScoping)); \
1086 parser.set_allow_modules(checkParserFlag(flags, kAllowModules)); \
1087 parser.set_allow_generators(checkParserFlag(flags, kAllowGenerators));
1088
1089void TestParserSyncWithFlags(i::Handle<i::String> source, unsigned flags) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001090 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001091
1092 // Preparse the data.
1093 i::CompleteParserRecorder log;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001094 {
1095 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
1096 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1097 v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
1098 SET_PARSER_FLAGS(preparser, flags);
1099 scanner.Initialize(&stream);
1100 v8::preparser::PreParser::PreParseResult result =
1101 preparser.PreParseProgram();
1102 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
1103 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001104 i::ScriptDataImpl data(log.ExtractData());
1105
1106 // Parse the data
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001107 i::FunctionLiteral* function;
1108 {
1109 i::Handle<i::Script> script = FACTORY->NewScript(source);
1110 i::CompilationInfoWithZone info(script);
1111 i::Parser parser(&info);
1112 SET_PARSER_FLAGS(parser, flags);
1113 info.MarkAsGlobal();
1114 function = parser.ParseProgram();
1115 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001116
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001117 // Check that preparsing fails iff parsing fails.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001118 if (function == NULL) {
1119 // Extract exception from the parser.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001120 CHECK(i::Isolate::Current()->has_pending_exception());
1121 i::MaybeObject* maybe_object = i::Isolate::Current()->pending_exception();
1122 i::JSObject* exception = NULL;
1123 CHECK(maybe_object->To(&exception));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001124 i::Handle<i::JSObject> exception_handle(exception);
1125 i::Handle<i::String> message_string =
1126 i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001127
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001128 if (!data.has_error()) {
1129 i::OS::Print(
1130 "Parser failed on:\n"
1131 "\t%s\n"
1132 "with error:\n"
1133 "\t%s\n"
1134 "However, the preparser succeeded",
1135 *source->ToCString(), *message_string->ToCString());
1136 CHECK(false);
1137 }
1138 // Check that preparser and parser produce the same error.
1139 i::Handle<i::String> preparser_message = FormatMessage(&data);
1140 if (!message_string->Equals(*preparser_message)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001141 i::OS::Print(
1142 "Expected parser and preparser to produce the same error on:\n"
1143 "\t%s\n"
1144 "However, found the following error messages\n"
1145 "\tparser: %s\n"
1146 "\tpreparser: %s\n",
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001147 *source->ToCString(),
1148 *message_string->ToCString(),
1149 *preparser_message->ToCString());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001150 CHECK(false);
1151 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001152 } else if (data.has_error()) {
1153 i::OS::Print(
1154 "Preparser failed on:\n"
1155 "\t%s\n"
1156 "with error:\n"
1157 "\t%s\n"
1158 "However, the parser succeeded",
1159 *source->ToCString(), *FormatMessage(&data)->ToCString());
1160 CHECK(false);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001161 }
1162}
1163
1164
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001165void TestParserSync(i::Handle<i::String> source) {
1166 for (unsigned flags = 0; flags < (1 << kParserFlagCount); ++flags) {
1167 TestParserSyncWithFlags(source, flags);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001168 }
1169}
1170
1171
1172TEST(ParserSync) {
1173 const char* context_data[][2] = {
1174 { "", "" },
1175 { "{", "}" },
1176 { "if (true) ", " else {}" },
1177 { "if (true) {} else ", "" },
1178 { "if (true) ", "" },
1179 { "do ", " while (false)" },
1180 { "while (false) ", "" },
1181 { "for (;;) ", "" },
1182 { "with ({})", "" },
1183 { "switch (12) { case 12: ", "}" },
1184 { "switch (12) { default: ", "}" },
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001185 { "switch (12) { ", "case 12: }" },
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001186 { "label2: ", "" },
1187 { NULL, NULL }
1188 };
1189
1190 const char* statement_data[] = {
1191 "{}",
1192 "var x",
1193 "var x = 1",
1194 "const x",
1195 "const x = 1",
1196 ";",
1197 "12",
1198 "if (false) {} else ;",
1199 "if (false) {} else {}",
1200 "if (false) {} else 12",
1201 "if (false) ;"
1202 "if (false) {}",
1203 "if (false) 12",
1204 "do {} while (false)",
1205 "for (;;) ;",
1206 "for (;;) {}",
1207 "for (;;) 12",
1208 "continue",
1209 "continue label",
1210 "continue\nlabel",
1211 "break",
1212 "break label",
1213 "break\nlabel",
1214 "return",
1215 "return 12",
1216 "return\n12",
1217 "with ({}) ;",
1218 "with ({}) {}",
1219 "with ({}) 12",
1220 "switch ({}) { default: }"
1221 "label3: "
1222 "throw",
1223 "throw 12",
1224 "throw\n12",
1225 "try {} catch(e) {}",
1226 "try {} finally {}",
1227 "try {} catch(e) {} finally {}",
1228 "debugger",
1229 NULL
1230 };
1231
1232 const char* termination_data[] = {
1233 "",
1234 ";",
1235 "\n",
1236 ";\n",
1237 "\n;",
1238 NULL
1239 };
1240
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001241 v8::HandleScope handles(v8::Isolate::GetCurrent());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001242 v8::Persistent<v8::Context> context = v8::Context::New();
1243 v8::Context::Scope context_scope(context);
1244
1245 int marker;
1246 i::Isolate::Current()->stack_guard()->SetStackLimit(
1247 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1248
1249 for (int i = 0; context_data[i][0] != NULL; ++i) {
1250 for (int j = 0; statement_data[j] != NULL; ++j) {
1251 for (int k = 0; termination_data[k] != NULL; ++k) {
1252 int kPrefixLen = i::StrLength(context_data[i][0]);
1253 int kStatementLen = i::StrLength(statement_data[j]);
1254 int kTerminationLen = i::StrLength(termination_data[k]);
1255 int kSuffixLen = i::StrLength(context_data[i][1]);
1256 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1257 + kSuffixLen + i::StrLength("label: for (;;) { }");
1258
1259 // Plug the source code pieces together.
1260 i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
1261 int length = i::OS::SNPrintF(program,
1262 "label: for (;;) { %s%s%s%s }",
1263 context_data[i][0],
1264 statement_data[j],
1265 termination_data[k],
1266 context_data[i][1]);
1267 CHECK(length == kProgramSize);
1268 i::Handle<i::String> source =
1269 FACTORY->NewStringFromAscii(i::CStrVector(program.start()));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001270 TestParserSync(source);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001271 }
1272 }
1273 }
1274}
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001275
1276
1277TEST(PreparserStrictOctal) {
1278 // Test that syntax error caused by octal literal is reported correctly as
1279 // such (issue 2220).
1280 v8::internal::FLAG_min_preparse_length = 1; // Force preparsing.
1281 v8::V8::Initialize();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001282 v8::HandleScope scope(v8::Isolate::GetCurrent());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001283 v8::Context::Scope context_scope(v8::Context::New());
1284 v8::TryCatch try_catch;
1285 const char* script =
1286 "\"use strict\"; \n"
1287 "a = function() { \n"
1288 " b = function() { \n"
1289 " 01; \n"
1290 " }; \n"
1291 "}; \n";
1292 v8::Script::Compile(v8::String::New(script));
1293 CHECK(try_catch.HasCaught());
1294 v8::String::Utf8Value exception(try_catch.Exception());
1295 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
1296 *exception);
1297}