blob: cd8a6aff382934ae11c8ce45212e967f6c1fedd7 [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 {
66 i::Utf8ToUC16CharacterStream 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 {
77 i::Utf8ToUC16CharacterStream 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) {
86 memmove(buffer, keyword, length);
87 buffer[length] = chars_to_append[j];
88 i::Utf8ToUC16CharacterStream 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 {
96 memmove(buffer, keyword, length);
97 buffer[length - 1] = '_';
98 i::Utf8ToUC16CharacterStream 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) {
176 v8::HandleScope handles;
177 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];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000258 i::Utf8ToUC16CharacterStream stream(
259 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
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000265 int flags = i::kAllowLazy | i::kAllowNativesSyntax;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000266 v8::preparser::PreParser::PreParseResult result =
267 v8::preparser::PreParser::PreParseProgram(&scanner,
268 &log,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000269 flags,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000270 stack_limit);
271 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000272 i::ScriptDataImpl data(log.ExtractData());
273 CHECK(!data.has_error());
274 }
275}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000276
277
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000278TEST(StandAlonePreParserNoNatives) {
279 v8::V8::Initialize();
280
281 int marker;
282 i::Isolate::Current()->stack_guard()->SetStackLimit(
283 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
284
285 const char* programs[] = {
286 "%ArgleBargle(glop);",
287 "var x = %_IsSmi(42);",
288 NULL
289 };
290
291 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
292 for (int i = 0; programs[i]; i++) {
293 const char* program = programs[i];
294 i::Utf8ToUC16CharacterStream stream(
295 reinterpret_cast<const i::byte*>(program),
296 static_cast<unsigned>(strlen(program)));
297 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000298 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000299 scanner.Initialize(&stream);
300
301 // Flags don't allow natives syntax.
302 v8::preparser::PreParser::PreParseResult result =
303 v8::preparser::PreParser::PreParseProgram(&scanner,
304 &log,
305 i::kAllowLazy,
306 stack_limit);
307 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
308 i::ScriptDataImpl data(log.ExtractData());
309 // Data contains syntax error.
310 CHECK(data.has_error());
311 }
312}
313
314
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000315TEST(RegressChromium62639) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000316 v8::V8::Initialize();
317
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000318 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000319 i::Isolate::Current()->stack_guard()->SetStackLimit(
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000320 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
321
322 const char* program = "var x = 'something';\n"
323 "escape: function() {}";
324 // Fails parsing expecting an identifier after "function".
325 // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
326 // and then used the invalid currently scanned literal. This always
327 // failed in debug mode, and sometimes crashed in release mode.
328
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000329 i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
330 static_cast<unsigned>(strlen(program)));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000331 i::ScriptDataImpl* data =
danno@chromium.orgb6451162011-08-17 14:33:23 +0000332 i::ParserApi::PreParse(&stream, NULL, false);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000333 CHECK(data->HasError());
334 delete data;
335}
336
337
338TEST(Regress928) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000339 v8::V8::Initialize();
340
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000341 // Preparsing didn't consider the catch clause of a try statement
342 // as with-content, which made it assume that a function inside
343 // the block could be lazily compiled, and an extra, unexpected,
344 // entry was added to the data.
345 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000346 i::Isolate::Current()->stack_guard()->SetStackLimit(
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000347 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
348
349 const char* program =
350 "try { } catch (e) { var foo = function () { /* first */ } }"
351 "var bar = function () { /* second */ }";
352
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000353 v8::HandleScope handles;
354 i::Handle<i::String> source(
355 FACTORY->NewStringFromAscii(i::CStrVector(program)));
356 i::ScriptDataImpl* data = i::ParserApi::PartialPreParse(source, NULL, false);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000357 CHECK(!data->HasError());
358
359 data->Initialize();
360
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000361 int first_function =
362 static_cast<int>(strstr(program, "function") - program);
363 int first_lbrace = first_function + static_cast<int>(strlen("function () "));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000364 CHECK_EQ('{', program[first_lbrace]);
365 i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
366 CHECK(!entry1.is_valid());
367
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000368 int second_function =
369 static_cast<int>(strstr(program + first_lbrace, "function") - program);
370 int second_lbrace =
371 second_function + static_cast<int>(strlen("function () "));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000372 CHECK_EQ('{', program[second_lbrace]);
373 i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
374 CHECK(entry2.is_valid());
375 CHECK_EQ('}', program[entry2.end_pos() - 1]);
376 delete data;
377}
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000378
379
380TEST(PreParseOverflow) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000381 v8::V8::Initialize();
382
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000383 int marker;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000384 i::Isolate::Current()->stack_guard()->SetStackLimit(
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000385 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
386
387 size_t kProgramSize = 1024 * 1024;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000388 i::SmartArrayPointer<char> program(
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000389 reinterpret_cast<char*>(malloc(kProgramSize + 1)));
390 memset(*program, '(', kProgramSize);
391 program[kProgramSize] = '\0';
392
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000393 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000394
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000395 i::Utf8ToUC16CharacterStream stream(
396 reinterpret_cast<const i::byte*>(*program),
397 static_cast<unsigned>(kProgramSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000398 i::CompleteParserRecorder log;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000399 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000400 scanner.Initialize(&stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000401
402
403 v8::preparser::PreParser::PreParseResult result =
404 v8::preparser::PreParser::PreParseProgram(&scanner,
405 &log,
406 true,
407 stack_limit);
408 CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
409}
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000410
411
412class TestExternalResource: public v8::String::ExternalStringResource {
413 public:
414 explicit TestExternalResource(uint16_t* data, int length)
415 : data_(data), length_(static_cast<size_t>(length)) { }
416
417 ~TestExternalResource() { }
418
419 const uint16_t* data() const {
420 return data_;
421 }
422
423 size_t length() const {
424 return length_;
425 }
426 private:
427 uint16_t* data_;
428 size_t length_;
429};
430
431
432#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
433
434void TestCharacterStream(const char* ascii_source,
435 unsigned length,
436 unsigned start = 0,
437 unsigned end = 0) {
438 if (end == 0) end = length;
439 unsigned sub_length = end - start;
440 i::HandleScope test_scope;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000441 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000442 for (unsigned i = 0; i < length; i++) {
443 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
444 }
445 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
446 i::Handle<i::String> ascii_string(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 FACTORY->NewStringFromAscii(ascii_vector));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000448 TestExternalResource resource(*uc16_buffer, length);
449 i::Handle<i::String> uc16_string(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 FACTORY->NewExternalStringFromTwoByte(&resource));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000451
452 i::ExternalTwoByteStringUC16CharacterStream uc16_stream(
453 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
454 i::GenericStringUC16CharacterStream string_stream(ascii_string, start, end);
455 i::Utf8ToUC16CharacterStream utf8_stream(
456 reinterpret_cast<const i::byte*>(ascii_source), end);
457 utf8_stream.SeekForward(start);
458
459 unsigned i = start;
460 while (i < end) {
461 // Read streams one char at a time
462 CHECK_EQU(i, uc16_stream.pos());
463 CHECK_EQU(i, string_stream.pos());
464 CHECK_EQU(i, utf8_stream.pos());
465 int32_t c0 = ascii_source[i];
466 int32_t c1 = uc16_stream.Advance();
467 int32_t c2 = string_stream.Advance();
468 int32_t c3 = utf8_stream.Advance();
469 i++;
470 CHECK_EQ(c0, c1);
471 CHECK_EQ(c0, c2);
472 CHECK_EQ(c0, c3);
473 CHECK_EQU(i, uc16_stream.pos());
474 CHECK_EQU(i, string_stream.pos());
475 CHECK_EQU(i, utf8_stream.pos());
476 }
477 while (i > start + sub_length / 4) {
478 // Pushback, re-read, pushback again.
479 int32_t c0 = ascii_source[i - 1];
480 CHECK_EQU(i, uc16_stream.pos());
481 CHECK_EQU(i, string_stream.pos());
482 CHECK_EQU(i, utf8_stream.pos());
483 uc16_stream.PushBack(c0);
484 string_stream.PushBack(c0);
485 utf8_stream.PushBack(c0);
486 i--;
487 CHECK_EQU(i, uc16_stream.pos());
488 CHECK_EQU(i, string_stream.pos());
489 CHECK_EQU(i, utf8_stream.pos());
490 int32_t c1 = uc16_stream.Advance();
491 int32_t c2 = string_stream.Advance();
492 int32_t c3 = utf8_stream.Advance();
493 i++;
494 CHECK_EQU(i, uc16_stream.pos());
495 CHECK_EQU(i, string_stream.pos());
496 CHECK_EQU(i, utf8_stream.pos());
497 CHECK_EQ(c0, c1);
498 CHECK_EQ(c0, c2);
499 CHECK_EQ(c0, c3);
500 uc16_stream.PushBack(c0);
501 string_stream.PushBack(c0);
502 utf8_stream.PushBack(c0);
503 i--;
504 CHECK_EQU(i, uc16_stream.pos());
505 CHECK_EQU(i, string_stream.pos());
506 CHECK_EQU(i, utf8_stream.pos());
507 }
508 unsigned halfway = start + sub_length / 2;
509 uc16_stream.SeekForward(halfway - i);
510 string_stream.SeekForward(halfway - i);
511 utf8_stream.SeekForward(halfway - i);
512 i = halfway;
513 CHECK_EQU(i, uc16_stream.pos());
514 CHECK_EQU(i, string_stream.pos());
515 CHECK_EQU(i, utf8_stream.pos());
516
517 while (i < end) {
518 // Read streams one char at a time
519 CHECK_EQU(i, uc16_stream.pos());
520 CHECK_EQU(i, string_stream.pos());
521 CHECK_EQU(i, utf8_stream.pos());
522 int32_t c0 = ascii_source[i];
523 int32_t c1 = uc16_stream.Advance();
524 int32_t c2 = string_stream.Advance();
525 int32_t c3 = utf8_stream.Advance();
526 i++;
527 CHECK_EQ(c0, c1);
528 CHECK_EQ(c0, c2);
529 CHECK_EQ(c0, c3);
530 CHECK_EQU(i, uc16_stream.pos());
531 CHECK_EQU(i, string_stream.pos());
532 CHECK_EQU(i, utf8_stream.pos());
533 }
534
535 int32_t c1 = uc16_stream.Advance();
536 int32_t c2 = string_stream.Advance();
537 int32_t c3 = utf8_stream.Advance();
538 CHECK_LT(c1, 0);
539 CHECK_LT(c2, 0);
540 CHECK_LT(c3, 0);
541}
542
543
544TEST(CharacterStreams) {
545 v8::HandleScope handles;
546 v8::Persistent<v8::Context> context = v8::Context::New();
547 v8::Context::Scope context_scope(context);
548
549 TestCharacterStream("abc\0\n\r\x7f", 7);
550 static const unsigned kBigStringSize = 4096;
551 char buffer[kBigStringSize + 1];
552 for (unsigned i = 0; i < kBigStringSize; i++) {
553 buffer[i] = static_cast<char>(i & 0x7f);
554 }
555 TestCharacterStream(buffer, kBigStringSize);
556
557 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
558
559 TestCharacterStream("\0", 1);
560 TestCharacterStream("", 0);
561}
562
563
564TEST(Utf8CharacterStream) {
565 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
566 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
567
568 static const int kAllUtf8CharsSize =
569 (unibrow::Utf8::kMaxOneByteChar + 1) +
570 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
571 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
572 static const unsigned kAllUtf8CharsSizeU =
573 static_cast<unsigned>(kAllUtf8CharsSize);
574
575 char buffer[kAllUtf8CharsSizeU];
576 unsigned cursor = 0;
577 for (int i = 0; i <= kMaxUC16Char; i++) {
578 cursor += unibrow::Utf8::Encode(buffer + cursor, i);
579 }
580 ASSERT(cursor == kAllUtf8CharsSizeU);
581
582 i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
583 kAllUtf8CharsSizeU);
584 for (int i = 0; i <= kMaxUC16Char; i++) {
585 CHECK_EQU(i, stream.pos());
586 int32_t c = stream.Advance();
587 CHECK_EQ(i, c);
588 CHECK_EQU(i + 1, stream.pos());
589 }
590 for (int i = kMaxUC16Char; i >= 0; i--) {
591 CHECK_EQU(i + 1, stream.pos());
592 stream.PushBack(i);
593 CHECK_EQU(i, stream.pos());
594 }
595 int i = 0;
596 while (stream.pos() < kMaxUC16CharU) {
597 CHECK_EQU(i, stream.pos());
598 unsigned progress = stream.SeekForward(12);
599 i += progress;
600 int32_t c = stream.Advance();
601 if (i <= kMaxUC16Char) {
602 CHECK_EQ(i, c);
603 } else {
604 CHECK_EQ(-1, c);
605 }
606 i += 1;
607 CHECK_EQU(i, stream.pos());
608 }
609}
610
611#undef CHECK_EQU
612
613void TestStreamScanner(i::UC16CharacterStream* stream,
614 i::Token::Value* expected_tokens,
615 int skip_pos = 0, // Zero means not skipping.
616 int skip_to = 0) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000617 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000618 scanner.Initialize(stream);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000619
620 int i = 0;
621 do {
622 i::Token::Value expected = expected_tokens[i];
623 i::Token::Value actual = scanner.Next();
624 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
625 if (scanner.location().end_pos == skip_pos) {
626 scanner.SeekForward(skip_to);
627 }
628 i++;
629 } while (expected_tokens[i] != i::Token::ILLEGAL);
630}
631
632TEST(StreamScanner) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000633 v8::V8::Initialize();
634
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000635 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
636 i::Utf8ToUC16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
637 static_cast<unsigned>(strlen(str1)));
638 i::Token::Value expectations1[] = {
639 i::Token::LBRACE,
640 i::Token::IDENTIFIER,
641 i::Token::IDENTIFIER,
642 i::Token::FOR,
643 i::Token::COLON,
644 i::Token::MUL,
645 i::Token::DIV,
646 i::Token::LT,
647 i::Token::SUB,
648 i::Token::IDENTIFIER,
649 i::Token::EOS,
650 i::Token::ILLEGAL
651 };
652 TestStreamScanner(&stream1, expectations1, 0, 0);
653
654 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
655 i::Utf8ToUC16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
656 static_cast<unsigned>(strlen(str2)));
657 i::Token::Value expectations2[] = {
658 i::Token::CASE,
659 i::Token::DEFAULT,
660 i::Token::CONST,
661 i::Token::LBRACE,
662 // Skipped part here
663 i::Token::RBRACE,
664 i::Token::DO,
665 i::Token::EOS,
666 i::Token::ILLEGAL
667 };
668 ASSERT_EQ('{', str2[19]);
669 ASSERT_EQ('}', str2[37]);
670 TestStreamScanner(&stream2, expectations2, 20, 37);
671
672 const char* str3 = "{}}}}";
673 i::Token::Value expectations3[] = {
674 i::Token::LBRACE,
675 i::Token::RBRACE,
676 i::Token::RBRACE,
677 i::Token::RBRACE,
678 i::Token::RBRACE,
679 i::Token::EOS,
680 i::Token::ILLEGAL
681 };
682 // Skip zero-four RBRACEs.
683 for (int i = 0; i <= 4; i++) {
684 expectations3[6 - i] = i::Token::ILLEGAL;
685 expectations3[5 - i] = i::Token::EOS;
686 i::Utf8ToUC16CharacterStream stream3(
687 reinterpret_cast<const i::byte*>(str3),
688 static_cast<unsigned>(strlen(str3)));
689 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
690 }
691}
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000692
693
694void TestScanRegExp(const char* re_source, const char* expected) {
695 i::Utf8ToUC16CharacterStream stream(
696 reinterpret_cast<const i::byte*>(re_source),
697 static_cast<unsigned>(strlen(re_source)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000698 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000699 scanner.Initialize(&stream);
700
701 i::Token::Value start = scanner.peek();
702 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
703 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
704 scanner.Next(); // Current token is now the regexp literal.
705 CHECK(scanner.is_literal_ascii());
706 i::Vector<const char> actual = scanner.literal_ascii_string();
707 for (int i = 0; i < actual.length(); i++) {
708 CHECK_NE('\0', expected[i]);
709 CHECK_EQ(expected[i], actual[i]);
710 }
711}
712
713
714TEST(RegExpScanning) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000715 v8::V8::Initialize();
716
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000717 // RegExp token with added garbage at the end. The scanner should only
718 // scan the RegExp until the terminating slash just before "flipperwald".
719 TestScanRegExp("/b/flipperwald", "b");
720 // Incomplete escape sequences doesn't hide the terminating slash.
721 TestScanRegExp("/\\x/flipperwald", "\\x");
722 TestScanRegExp("/\\u/flipperwald", "\\u");
723 TestScanRegExp("/\\u1/flipperwald", "\\u1");
724 TestScanRegExp("/\\u12/flipperwald", "\\u12");
725 TestScanRegExp("/\\u123/flipperwald", "\\u123");
726 TestScanRegExp("/\\c/flipperwald", "\\c");
727 TestScanRegExp("/\\c//flipperwald", "\\c");
728 // Slashes inside character classes are not terminating.
729 TestScanRegExp("/[/]/flipperwald", "[/]");
730 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
731 // Incomplete escape sequences inside a character class doesn't hide
732 // the end of the character class.
733 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
734 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
735 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
736 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
737 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
738 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
739 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
740 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
741 // Escaped ']'s wont end the character class.
742 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
743 // Escaped slashes are not terminating.
744 TestScanRegExp("/\\//flipperwald", "\\/");
745 // Starting with '=' works too.
746 TestScanRegExp("/=/", "=");
747 TestScanRegExp("/=?/", "=?");
748}
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000749
750
751TEST(ScopePositions) {
752 // Test the parser for correctly setting the start and end positions
753 // of a scope. We check the scope positions of exactly one scope
754 // nested in the global scope of a program. 'inner source' is the
755 // source code that determines the part of the source belonging
756 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
757 // parts of the source that belong to the global scope.
758 struct SourceData {
759 const char* outer_prefix;
760 const char* inner_source;
761 const char* outer_suffix;
762 i::ScopeType scope_type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000763 i::LanguageMode language_mode;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000764 };
765
766 const SourceData source_data[] = {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000767 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
768 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000769 { " with ({}) ", "{\n"
770 " block;\n"
771 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000772 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
773 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000774 { " with ({}) ", "statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000775 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000776 { " with ({})\n"
777 " ", "statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000778 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
779 { " try {} catch ", "(e) { block; }", " more;",
780 i::CATCH_SCOPE, i::CLASSIC_MODE },
781 { " try {} catch ", "(e) { block; }", "; more;",
782 i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000783 { " try {} catch ", "(e) {\n"
784 " block;\n"
785 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000786 " more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000787 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000788 i::CATCH_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000789 { " start;\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000790 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000791 { " start;\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000792 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000793 { " start;\n"
794 " ", "{\n"
795 " let block;\n"
796 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000797 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000798 { " start;\n"
799 " function fun", "(a,b) { infunction; }", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000800 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000801 { " start;\n"
802 " function fun", "(a,b) {\n"
803 " infunction;\n"
804 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000805 " more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000806 { " (function fun", "(a,b) { infunction; }", ")();",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000807 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000808 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000809 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000810 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000811 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000812 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
813 " block;\n"
814 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000815 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000816 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000817 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000818 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000819 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000820 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
821 " statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000822 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
823 { " for ", "(let x in {}) { block; }", " more;",
824 i::BLOCK_SCOPE, i::EXTENDED_MODE },
825 { " for ", "(let x in {}) { block; }", "; more;",
826 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000827 { " for ", "(let x in {}) {\n"
828 " block;\n"
829 " }", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000830 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
831 { " for ", "(let x in {}) statement;", " more;",
832 i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000833 { " for ", "(let x in {}) statement", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000834 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000835 { " for ", "(let x in {})\n"
836 " statement;", "\n"
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000837 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
838 { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000839 };
840
841 v8::HandleScope handles;
842 v8::Persistent<v8::Context> context = v8::Context::New();
843 v8::Context::Scope context_scope(context);
844
845 int marker;
846 i::Isolate::Current()->stack_guard()->SetStackLimit(
847 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000848 i::FLAG_harmony_scoping = true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000849
850 for (int i = 0; source_data[i].outer_prefix; i++) {
851 int kPrefixLen = i::StrLength(source_data[i].outer_prefix);
852 int kInnerLen = i::StrLength(source_data[i].inner_source);
853 int kSuffixLen = i::StrLength(source_data[i].outer_suffix);
854 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
855 i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000856 int length = i::OS::SNPrintF(program, "%s%s%s",
857 source_data[i].outer_prefix,
858 source_data[i].inner_source,
859 source_data[i].outer_suffix);
860 CHECK(length == kProgramSize);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000861
862 // Parse program source.
863 i::Handle<i::String> source(
864 FACTORY->NewStringFromAscii(i::CStrVector(program.start())));
865 i::Handle<i::Script> script = FACTORY->NewScript(source);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000866 i::Parser parser(script, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000867 i::CompilationInfo info(script);
868 info.MarkAsGlobal();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000869 info.SetLanguageMode(source_data[i].language_mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000870 i::FunctionLiteral* function = parser.ParseProgram(&info);
871 CHECK(function != NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000872
873 // Check scope types and positions.
874 i::Scope* scope = function->scope();
875 CHECK(scope->is_global_scope());
876 CHECK_EQ(scope->start_position(), 0);
877 CHECK_EQ(scope->end_position(), kProgramSize);
878 CHECK_EQ(scope->inner_scopes()->length(), 1);
879
880 i::Scope* inner_scope = scope->inner_scopes()->at(0);
881 CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
882 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
883 // The end position of a token is one position after the last
884 // character belonging to that token.
885 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
886 }
887}
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000888
889
890void TestParserSync(i::Handle<i::String> source, int flags) {
891 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
892 bool harmony_scoping = ((i::kLanguageModeMask & flags) == i::EXTENDED_MODE);
893
894 // Preparse the data.
895 i::CompleteParserRecorder log;
896 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
897 i::GenericStringUC16CharacterStream stream(source, 0, source->length());
898 scanner.SetHarmonyScoping(harmony_scoping);
899 scanner.Initialize(&stream);
900 v8::preparser::PreParser::PreParseResult result =
901 v8::preparser::PreParser::PreParseProgram(
902 &scanner, &log, flags, stack_limit);
903 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
904 i::ScriptDataImpl data(log.ExtractData());
905
906 // Parse the data
907 i::Handle<i::Script> script = FACTORY->NewScript(source);
908 bool save_harmony_scoping = i::FLAG_harmony_scoping;
909 i::FLAG_harmony_scoping = harmony_scoping;
910 i::Parser parser(script, flags, NULL, NULL);
911 i::CompilationInfo info(script);
912 info.MarkAsGlobal();
913 i::FunctionLiteral* function = parser.ParseProgram(&info);
914 i::FLAG_harmony_scoping = save_harmony_scoping;
915
916 i::String* type_string = NULL;
917 if (function == NULL) {
918 // Extract exception from the parser.
919 i::Handle<i::String> type_symbol = FACTORY->LookupAsciiSymbol("type");
920 CHECK(i::Isolate::Current()->has_pending_exception());
921 i::MaybeObject* maybe_object = i::Isolate::Current()->pending_exception();
922 i::JSObject* exception = NULL;
923 CHECK(maybe_object->To(&exception));
924
925 // Get the type string.
926 maybe_object = exception->GetProperty(*type_symbol);
927 CHECK(maybe_object->To(&type_string));
928 }
929
930 // Check that preparsing fails iff parsing fails.
931 if (data.has_error() && function != NULL) {
932 i::OS::Print(
933 "Preparser failed on:\n"
934 "\t%s\n"
935 "with error:\n"
936 "\t%s\n"
937 "However, the parser succeeded",
938 *source->ToCString(), data.BuildMessage());
939 CHECK(false);
940 } else if (!data.has_error() && function == NULL) {
941 i::OS::Print(
942 "Parser failed on:\n"
943 "\t%s\n"
944 "with error:\n"
945 "\t%s\n"
946 "However, the preparser succeeded",
947 *source->ToCString(), *type_string->ToCString());
948 CHECK(false);
949 }
950
951 // Check that preparser and parser produce the same error.
952 if (function == NULL) {
953 if (!type_string->IsEqualTo(i::CStrVector(data.BuildMessage()))) {
954 i::OS::Print(
955 "Expected parser and preparser to produce the same error on:\n"
956 "\t%s\n"
957 "However, found the following error messages\n"
958 "\tparser: %s\n"
959 "\tpreparser: %s\n",
960 *source->ToCString(), *type_string->ToCString(), data.BuildMessage());
961 CHECK(false);
962 }
963 }
964}
965
966
967void TestParserSyncWithFlags(i::Handle<i::String> source) {
968 static const int kFlagsCount = 6;
969 const int flags[kFlagsCount] = {
970 i::kNoParsingFlags | i::CLASSIC_MODE,
971 i::kNoParsingFlags | i::STRICT_MODE,
972 i::kNoParsingFlags | i::EXTENDED_MODE,
973 i::kAllowLazy | i::CLASSIC_MODE,
974 i::kAllowLazy | i::STRICT_MODE,
975 i::kAllowLazy | i::EXTENDED_MODE
976 };
977
978 for (int k = 0; k < kFlagsCount; ++k) {
979 TestParserSync(source, flags[k]);
980 }
981}
982
983
984TEST(ParserSync) {
985 const char* context_data[][2] = {
986 { "", "" },
987 { "{", "}" },
988 { "if (true) ", " else {}" },
989 { "if (true) {} else ", "" },
990 { "if (true) ", "" },
991 { "do ", " while (false)" },
992 { "while (false) ", "" },
993 { "for (;;) ", "" },
994 { "with ({})", "" },
995 { "switch (12) { case 12: ", "}" },
996 { "switch (12) { default: ", "}" },
997 { "label2: ", "" },
998 { NULL, NULL }
999 };
1000
1001 const char* statement_data[] = {
1002 "{}",
1003 "var x",
1004 "var x = 1",
1005 "const x",
1006 "const x = 1",
1007 ";",
1008 "12",
1009 "if (false) {} else ;",
1010 "if (false) {} else {}",
1011 "if (false) {} else 12",
1012 "if (false) ;"
1013 "if (false) {}",
1014 "if (false) 12",
1015 "do {} while (false)",
1016 "for (;;) ;",
1017 "for (;;) {}",
1018 "for (;;) 12",
1019 "continue",
1020 "continue label",
1021 "continue\nlabel",
1022 "break",
1023 "break label",
1024 "break\nlabel",
1025 "return",
1026 "return 12",
1027 "return\n12",
1028 "with ({}) ;",
1029 "with ({}) {}",
1030 "with ({}) 12",
1031 "switch ({}) { default: }"
1032 "label3: "
1033 "throw",
1034 "throw 12",
1035 "throw\n12",
1036 "try {} catch(e) {}",
1037 "try {} finally {}",
1038 "try {} catch(e) {} finally {}",
1039 "debugger",
1040 NULL
1041 };
1042
1043 const char* termination_data[] = {
1044 "",
1045 ";",
1046 "\n",
1047 ";\n",
1048 "\n;",
1049 NULL
1050 };
1051
1052 v8::HandleScope handles;
1053 v8::Persistent<v8::Context> context = v8::Context::New();
1054 v8::Context::Scope context_scope(context);
1055
1056 int marker;
1057 i::Isolate::Current()->stack_guard()->SetStackLimit(
1058 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1059
1060 for (int i = 0; context_data[i][0] != NULL; ++i) {
1061 for (int j = 0; statement_data[j] != NULL; ++j) {
1062 for (int k = 0; termination_data[k] != NULL; ++k) {
1063 int kPrefixLen = i::StrLength(context_data[i][0]);
1064 int kStatementLen = i::StrLength(statement_data[j]);
1065 int kTerminationLen = i::StrLength(termination_data[k]);
1066 int kSuffixLen = i::StrLength(context_data[i][1]);
1067 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1068 + kSuffixLen + i::StrLength("label: for (;;) { }");
1069
1070 // Plug the source code pieces together.
1071 i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
1072 int length = i::OS::SNPrintF(program,
1073 "label: for (;;) { %s%s%s%s }",
1074 context_data[i][0],
1075 statement_data[j],
1076 termination_data[k],
1077 context_data[i][1]);
1078 CHECK(length == kProgramSize);
1079 i::Handle<i::String> source =
1080 FACTORY->NewStringFromAscii(i::CStrVector(program.start()));
1081 TestParserSyncWithFlags(source);
1082 }
1083 }
1084 }
1085}