blob: 6bcae7c308a4fd5fdcaa1a22ae566230d3310c68 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blockd0582a62009-12-15 09:54:21 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080029#include <stdio.h>
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080030#include <string.h>
Steve Blockd0582a62009-12-15 09:54:21 +000031
32#include "v8.h"
33
Steve Blockd0582a62009-12-15 09:54:21 +000034#include "cctest.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010035#include "compiler.h"
Ben Murdoch589d6972011-11-30 16:04:58 +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"
Steve Blockd0582a62009-12-15 09:54:21 +000043
Ben Murdoch69a99ed2011-11-30 16:03:39 +000044TEST(ScanKeywords) {
Steve Blockd0582a62009-12-15 09:54:21 +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 },
Ben Murdoch69a99ed2011-11-30 16:03:39 +000052 TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
Steve Blockd0582a62009-12-15 09:54:21 +000053#undef KEYWORD
54 { NULL, i::Token::IDENTIFIER }
55 };
56
Steve Blockd0582a62009-12-15 09:54:21 +000057 KeywordToken key_token;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000058 i::UnicodeCache unicode_cache;
59 i::byte buffer[32];
Steve Blockd0582a62009-12-15 09:54:21 +000060 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +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 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010066 i::Utf8ToUtf16CharacterStream stream(keyword, length);
67 i::Scanner scanner(&unicode_cache);
68 // The scanner should parse Harmony keywords for this test.
69 scanner.SetHarmonyScoping(true);
70 scanner.SetHarmonyModules(true);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000071 scanner.Initialize(&stream);
72 CHECK_EQ(key_token.token, scanner.Next());
73 CHECK_EQ(i::Token::EOS, scanner.Next());
Steve Blockd0582a62009-12-15 09:54:21 +000074 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000075 // Removing characters will make keyword matching fail.
76 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010077 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
78 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000079 scanner.Initialize(&stream);
80 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
81 CHECK_EQ(i::Token::EOS, scanner.Next());
Steve Blockd0582a62009-12-15 09:54:21 +000082 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +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];
Ben Murdoch3ef787d2012-04-12 10:51:47 +010088 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
89 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +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] = '_';
Ben Murdoch3ef787d2012-04-12 10:51:47 +010098 i::Utf8ToUtf16CharacterStream stream(buffer, length);
99 i::Scanner scanner(&unicode_cache);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000100 scanner.Initialize(&stream);
101 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
102 CHECK_EQ(i::Token::EOS, scanner.Next());
103 }
Steve Blockd0582a62009-12-15 09:54:21 +0000104 }
Steve Blockd0582a62009-12-15 09:54:21 +0000105}
106
Iain Merrick9ac36c92010-09-13 15:29:50 +0100107
108TEST(ScanHTMLEndComments) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000109 v8::V8::Initialize();
110
Iain Merrick9ac36c92010-09-13 15:29:50 +0100111 // 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
Ben Murdoch3fb3ca82011-12-02 17:19:32 +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
Iain Merrick9ac36c92010-09-13 15:29:50 +0100117 // 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
Ben Murdoch3fb3ca82011-12-02 17:19:32 +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
Iain Merrick9ac36c92010-09-13 15:29:50 +0100140 // Parser/Scanner needs a stack limit.
141 int marker;
Steve Block44f0eee2011-05-26 01:26:41 +0100142 i::Isolate::Current()->stack_guard()->SetStackLimit(
Iain Merrick9ac36c92010-09-13 15:29:50 +0100143 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
144
145 for (int i = 0; tests[i]; i++) {
146 v8::ScriptData* data =
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100147 v8::ScriptData::PreCompile(tests[i], i::StrLength(tests[i]));
Iain Merrick9ac36c92010-09-13 15:29:50 +0100148 CHECK(data != NULL && !data->HasError());
149 delete data;
150 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +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 }
Iain Merrick9ac36c92010-09-13 15:29:50 +0100158}
159
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;
Steve Block44f0eee2011-05-26 01:26:41 +0100180 i::Isolate::Current()->stack_guard()->SetStackLimit(
Iain Merrick9ac36c92010-09-13 15:29:50 +0100181 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; }};";
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100196 int source_length = i::StrLength(source);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100197 const char* error_source = "var x = y z;";
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100198 int error_source_length = i::StrLength(error_source);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100199
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();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100234 pre_impl->BuildArgs();
Iain Merrick9ac36c92010-09-13 15:29:50 +0100235 CHECK_GT(strlen(message), 0);
236}
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800237
238
239TEST(StandAlonePreParser) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000240 v8::V8::Initialize();
241
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800242 int marker;
Steve Block44f0eee2011-05-26 01:26:41 +0100243 i::Isolate::Current()->stack_guard()->SetStackLimit(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800244 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; }",
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000250 "%ArgleBargle(glop);",
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800251 "var x = new new Function('this.x = 42');",
252 NULL
253 };
254
Ben Murdoch8b112d22011-06-08 16:22:53 +0100255 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800256 for (int i = 0; programs[i]; i++) {
257 const char* program = programs[i];
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100258 i::Utf8ToUtf16CharacterStream stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100259 reinterpret_cast<const i::byte*>(program),
260 static_cast<unsigned>(strlen(program)));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800261 i::CompleteParserRecorder log;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100262 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100263 scanner.Initialize(&stream);
264
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100265 int flags = i::kAllowLazy | i::kAllowNativesSyntax;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100266 v8::preparser::PreParser::PreParseResult result =
267 v8::preparser::PreParser::PreParseProgram(&scanner,
268 &log,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100269 flags,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100270 stack_limit);
271 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800272 i::ScriptDataImpl data(log.ExtractData());
273 CHECK(!data.has_error());
274 }
275}
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800276
277
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100278TEST(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::Utf8ToUtf16CharacterStream stream(
295 reinterpret_cast<const i::byte*>(program),
296 static_cast<unsigned>(strlen(program)));
297 i::CompleteParserRecorder log;
298 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
299 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
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800315TEST(RegressChromium62639) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000316 v8::V8::Initialize();
317
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800318 int marker;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100319 i::Isolate::Current()->stack_guard()->SetStackLimit(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800320 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
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100329 i::Utf8ToUtf16CharacterStream stream(
330 reinterpret_cast<const i::byte*>(program),
331 static_cast<unsigned>(strlen(program)));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800332 i::ScriptDataImpl* data =
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000333 i::ParserApi::PreParse(&stream, NULL, false);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800334 CHECK(data->HasError());
335 delete data;
336}
337
338
339TEST(Regress928) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000340 v8::V8::Initialize();
341
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800342 // Preparsing didn't consider the catch clause of a try statement
343 // as with-content, which made it assume that a function inside
344 // the block could be lazily compiled, and an extra, unexpected,
345 // entry was added to the data.
346 int marker;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100347 i::Isolate::Current()->stack_guard()->SetStackLimit(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800348 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
349
350 const char* program =
351 "try { } catch (e) { var foo = function () { /* first */ } }"
352 "var bar = function () { /* second */ }";
353
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100354 v8::HandleScope handles;
355 i::Handle<i::String> source(
356 FACTORY->NewStringFromAscii(i::CStrVector(program)));
357 i::ScriptDataImpl* data = i::ParserApi::PartialPreParse(source, NULL, false);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800358 CHECK(!data->HasError());
359
360 data->Initialize();
361
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100362 int first_function =
363 static_cast<int>(strstr(program, "function") - program);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100364 int first_lbrace = first_function + i::StrLength("function () ");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800365 CHECK_EQ('{', program[first_lbrace]);
366 i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
367 CHECK(!entry1.is_valid());
368
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100369 int second_function =
370 static_cast<int>(strstr(program + first_lbrace, "function") - program);
371 int second_lbrace =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100372 second_function + i::StrLength("function () ");
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800373 CHECK_EQ('{', program[second_lbrace]);
374 i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
375 CHECK(entry2.is_valid());
376 CHECK_EQ('}', program[entry2.end_pos() - 1]);
377 delete data;
378}
Ben Murdochb0fe1622011-05-05 13:52:32 +0100379
380
381TEST(PreParseOverflow) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000382 v8::V8::Initialize();
383
Ben Murdochb0fe1622011-05-05 13:52:32 +0100384 int marker;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100385 i::Isolate::Current()->stack_guard()->SetStackLimit(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100386 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
387
388 size_t kProgramSize = 1024 * 1024;
Ben Murdoch589d6972011-11-30 16:04:58 +0000389 i::SmartArrayPointer<char> program(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100390 reinterpret_cast<char*>(malloc(kProgramSize + 1)));
391 memset(*program, '(', kProgramSize);
392 program[kProgramSize] = '\0';
393
Ben Murdoch8b112d22011-06-08 16:22:53 +0100394 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100395
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100396 i::Utf8ToUtf16CharacterStream stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100397 reinterpret_cast<const i::byte*>(*program),
398 static_cast<unsigned>(kProgramSize));
399 i::CompleteParserRecorder log;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100400 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100401 scanner.Initialize(&stream);
402
403
404 v8::preparser::PreParser::PreParseResult result =
405 v8::preparser::PreParser::PreParseProgram(&scanner,
406 &log,
407 true,
408 stack_limit);
409 CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
410}
411
412
413class TestExternalResource: public v8::String::ExternalStringResource {
414 public:
415 explicit TestExternalResource(uint16_t* data, int length)
416 : data_(data), length_(static_cast<size_t>(length)) { }
417
418 ~TestExternalResource() { }
419
420 const uint16_t* data() const {
421 return data_;
422 }
423
424 size_t length() const {
425 return length_;
426 }
427 private:
428 uint16_t* data_;
429 size_t length_;
430};
431
432
433#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
434
435void TestCharacterStream(const char* ascii_source,
436 unsigned length,
437 unsigned start = 0,
438 unsigned end = 0) {
439 if (end == 0) end = length;
440 unsigned sub_length = end - start;
441 i::HandleScope test_scope;
Ben Murdoch589d6972011-11-30 16:04:58 +0000442 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443 for (unsigned i = 0; i < length; i++) {
444 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
445 }
446 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
447 i::Handle<i::String> ascii_string(
Steve Block44f0eee2011-05-26 01:26:41 +0100448 FACTORY->NewStringFromAscii(ascii_vector));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100449 TestExternalResource resource(*uc16_buffer, length);
450 i::Handle<i::String> uc16_string(
Steve Block44f0eee2011-05-26 01:26:41 +0100451 FACTORY->NewExternalStringFromTwoByte(&resource));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100452
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100453 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100454 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100455 i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
456 i::Utf8ToUtf16CharacterStream utf8_stream(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100457 reinterpret_cast<const i::byte*>(ascii_source), end);
458 utf8_stream.SeekForward(start);
459
460 unsigned i = start;
461 while (i < end) {
462 // Read streams one char at a time
463 CHECK_EQU(i, uc16_stream.pos());
464 CHECK_EQU(i, string_stream.pos());
465 CHECK_EQU(i, utf8_stream.pos());
466 int32_t c0 = ascii_source[i];
467 int32_t c1 = uc16_stream.Advance();
468 int32_t c2 = string_stream.Advance();
469 int32_t c3 = utf8_stream.Advance();
470 i++;
471 CHECK_EQ(c0, c1);
472 CHECK_EQ(c0, c2);
473 CHECK_EQ(c0, c3);
474 CHECK_EQU(i, uc16_stream.pos());
475 CHECK_EQU(i, string_stream.pos());
476 CHECK_EQU(i, utf8_stream.pos());
477 }
478 while (i > start + sub_length / 4) {
479 // Pushback, re-read, pushback again.
480 int32_t c0 = ascii_source[i - 1];
481 CHECK_EQU(i, uc16_stream.pos());
482 CHECK_EQU(i, string_stream.pos());
483 CHECK_EQU(i, utf8_stream.pos());
484 uc16_stream.PushBack(c0);
485 string_stream.PushBack(c0);
486 utf8_stream.PushBack(c0);
487 i--;
488 CHECK_EQU(i, uc16_stream.pos());
489 CHECK_EQU(i, string_stream.pos());
490 CHECK_EQU(i, utf8_stream.pos());
491 int32_t c1 = uc16_stream.Advance();
492 int32_t c2 = string_stream.Advance();
493 int32_t c3 = utf8_stream.Advance();
494 i++;
495 CHECK_EQU(i, uc16_stream.pos());
496 CHECK_EQU(i, string_stream.pos());
497 CHECK_EQU(i, utf8_stream.pos());
498 CHECK_EQ(c0, c1);
499 CHECK_EQ(c0, c2);
500 CHECK_EQ(c0, c3);
501 uc16_stream.PushBack(c0);
502 string_stream.PushBack(c0);
503 utf8_stream.PushBack(c0);
504 i--;
505 CHECK_EQU(i, uc16_stream.pos());
506 CHECK_EQU(i, string_stream.pos());
507 CHECK_EQU(i, utf8_stream.pos());
508 }
509 unsigned halfway = start + sub_length / 2;
510 uc16_stream.SeekForward(halfway - i);
511 string_stream.SeekForward(halfway - i);
512 utf8_stream.SeekForward(halfway - i);
513 i = halfway;
514 CHECK_EQU(i, uc16_stream.pos());
515 CHECK_EQU(i, string_stream.pos());
516 CHECK_EQU(i, utf8_stream.pos());
517
518 while (i < end) {
519 // Read streams one char at a time
520 CHECK_EQU(i, uc16_stream.pos());
521 CHECK_EQU(i, string_stream.pos());
522 CHECK_EQU(i, utf8_stream.pos());
523 int32_t c0 = ascii_source[i];
524 int32_t c1 = uc16_stream.Advance();
525 int32_t c2 = string_stream.Advance();
526 int32_t c3 = utf8_stream.Advance();
527 i++;
528 CHECK_EQ(c0, c1);
529 CHECK_EQ(c0, c2);
530 CHECK_EQ(c0, c3);
531 CHECK_EQU(i, uc16_stream.pos());
532 CHECK_EQU(i, string_stream.pos());
533 CHECK_EQU(i, utf8_stream.pos());
534 }
535
536 int32_t c1 = uc16_stream.Advance();
537 int32_t c2 = string_stream.Advance();
538 int32_t c3 = utf8_stream.Advance();
539 CHECK_LT(c1, 0);
540 CHECK_LT(c2, 0);
541 CHECK_LT(c3, 0);
542}
543
544
545TEST(CharacterStreams) {
546 v8::HandleScope handles;
547 v8::Persistent<v8::Context> context = v8::Context::New();
548 v8::Context::Scope context_scope(context);
549
550 TestCharacterStream("abc\0\n\r\x7f", 7);
551 static const unsigned kBigStringSize = 4096;
552 char buffer[kBigStringSize + 1];
553 for (unsigned i = 0; i < kBigStringSize; i++) {
554 buffer[i] = static_cast<char>(i & 0x7f);
555 }
556 TestCharacterStream(buffer, kBigStringSize);
557
558 TestCharacterStream(buffer, kBigStringSize, 576, 3298);
559
560 TestCharacterStream("\0", 1);
561 TestCharacterStream("", 0);
562}
563
564
565TEST(Utf8CharacterStream) {
566 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
567 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
568
569 static const int kAllUtf8CharsSize =
570 (unibrow::Utf8::kMaxOneByteChar + 1) +
571 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
572 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
573 static const unsigned kAllUtf8CharsSizeU =
574 static_cast<unsigned>(kAllUtf8CharsSize);
575
576 char buffer[kAllUtf8CharsSizeU];
577 unsigned cursor = 0;
578 for (int i = 0; i <= kMaxUC16Char; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100579 cursor += unibrow::Utf8::Encode(buffer + cursor,
580 i,
581 unibrow::Utf16::kNoPreviousCharacter);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100582 }
583 ASSERT(cursor == kAllUtf8CharsSizeU);
584
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100585 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
586 kAllUtf8CharsSizeU);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100587 for (int i = 0; i <= kMaxUC16Char; i++) {
588 CHECK_EQU(i, stream.pos());
589 int32_t c = stream.Advance();
590 CHECK_EQ(i, c);
591 CHECK_EQU(i + 1, stream.pos());
592 }
593 for (int i = kMaxUC16Char; i >= 0; i--) {
594 CHECK_EQU(i + 1, stream.pos());
595 stream.PushBack(i);
596 CHECK_EQU(i, stream.pos());
597 }
598 int i = 0;
599 while (stream.pos() < kMaxUC16CharU) {
600 CHECK_EQU(i, stream.pos());
601 unsigned progress = stream.SeekForward(12);
602 i += progress;
603 int32_t c = stream.Advance();
604 if (i <= kMaxUC16Char) {
605 CHECK_EQ(i, c);
606 } else {
607 CHECK_EQ(-1, c);
608 }
609 i += 1;
610 CHECK_EQU(i, stream.pos());
611 }
612}
613
614#undef CHECK_EQU
615
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100616void TestStreamScanner(i::Utf16CharacterStream* stream,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100617 i::Token::Value* expected_tokens,
618 int skip_pos = 0, // Zero means not skipping.
619 int skip_to = 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100620 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
Steve Block9fac8402011-05-12 15:51:54 +0100621 scanner.Initialize(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100622
623 int i = 0;
624 do {
625 i::Token::Value expected = expected_tokens[i];
626 i::Token::Value actual = scanner.Next();
627 CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
628 if (scanner.location().end_pos == skip_pos) {
629 scanner.SeekForward(skip_to);
630 }
631 i++;
632 } while (expected_tokens[i] != i::Token::ILLEGAL);
633}
634
635TEST(StreamScanner) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000636 v8::V8::Initialize();
637
Ben Murdochb0fe1622011-05-05 13:52:32 +0100638 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100639 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
640 static_cast<unsigned>(strlen(str1)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100641 i::Token::Value expectations1[] = {
642 i::Token::LBRACE,
643 i::Token::IDENTIFIER,
644 i::Token::IDENTIFIER,
645 i::Token::FOR,
646 i::Token::COLON,
647 i::Token::MUL,
648 i::Token::DIV,
649 i::Token::LT,
650 i::Token::SUB,
651 i::Token::IDENTIFIER,
652 i::Token::EOS,
653 i::Token::ILLEGAL
654 };
655 TestStreamScanner(&stream1, expectations1, 0, 0);
656
657 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100658 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
659 static_cast<unsigned>(strlen(str2)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100660 i::Token::Value expectations2[] = {
661 i::Token::CASE,
662 i::Token::DEFAULT,
663 i::Token::CONST,
664 i::Token::LBRACE,
665 // Skipped part here
666 i::Token::RBRACE,
667 i::Token::DO,
668 i::Token::EOS,
669 i::Token::ILLEGAL
670 };
671 ASSERT_EQ('{', str2[19]);
672 ASSERT_EQ('}', str2[37]);
673 TestStreamScanner(&stream2, expectations2, 20, 37);
674
675 const char* str3 = "{}}}}";
676 i::Token::Value expectations3[] = {
677 i::Token::LBRACE,
678 i::Token::RBRACE,
679 i::Token::RBRACE,
680 i::Token::RBRACE,
681 i::Token::RBRACE,
682 i::Token::EOS,
683 i::Token::ILLEGAL
684 };
685 // Skip zero-four RBRACEs.
686 for (int i = 0; i <= 4; i++) {
687 expectations3[6 - i] = i::Token::ILLEGAL;
688 expectations3[5 - i] = i::Token::EOS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100689 i::Utf8ToUtf16CharacterStream stream3(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100690 reinterpret_cast<const i::byte*>(str3),
691 static_cast<unsigned>(strlen(str3)));
692 TestStreamScanner(&stream3, expectations3, 1, 1 + i);
693 }
694}
Ben Murdoch086aeea2011-05-13 15:57:08 +0100695
696
697void TestScanRegExp(const char* re_source, const char* expected) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100698 i::Utf8ToUtf16CharacterStream stream(
Ben Murdoch086aeea2011-05-13 15:57:08 +0100699 reinterpret_cast<const i::byte*>(re_source),
700 static_cast<unsigned>(strlen(re_source)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100701 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
Ben Murdoch086aeea2011-05-13 15:57:08 +0100702 scanner.Initialize(&stream);
703
704 i::Token::Value start = scanner.peek();
705 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
706 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
707 scanner.Next(); // Current token is now the regexp literal.
708 CHECK(scanner.is_literal_ascii());
709 i::Vector<const char> actual = scanner.literal_ascii_string();
710 for (int i = 0; i < actual.length(); i++) {
711 CHECK_NE('\0', expected[i]);
712 CHECK_EQ(expected[i], actual[i]);
713 }
714}
715
716
717TEST(RegExpScanning) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000718 v8::V8::Initialize();
719
Ben Murdoch086aeea2011-05-13 15:57:08 +0100720 // RegExp token with added garbage at the end. The scanner should only
721 // scan the RegExp until the terminating slash just before "flipperwald".
722 TestScanRegExp("/b/flipperwald", "b");
723 // Incomplete escape sequences doesn't hide the terminating slash.
724 TestScanRegExp("/\\x/flipperwald", "\\x");
725 TestScanRegExp("/\\u/flipperwald", "\\u");
726 TestScanRegExp("/\\u1/flipperwald", "\\u1");
727 TestScanRegExp("/\\u12/flipperwald", "\\u12");
728 TestScanRegExp("/\\u123/flipperwald", "\\u123");
729 TestScanRegExp("/\\c/flipperwald", "\\c");
730 TestScanRegExp("/\\c//flipperwald", "\\c");
731 // Slashes inside character classes are not terminating.
732 TestScanRegExp("/[/]/flipperwald", "[/]");
733 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
734 // Incomplete escape sequences inside a character class doesn't hide
735 // the end of the character class.
736 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
737 TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
738 TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
739 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
740 TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
741 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
742 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
743 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
744 // Escaped ']'s wont end the character class.
745 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
746 // Escaped slashes are not terminating.
747 TestScanRegExp("/\\//flipperwald", "\\/");
748 // Starting with '=' works too.
749 TestScanRegExp("/=/", "=");
750 TestScanRegExp("/=?/", "=?");
751}
Ben Murdoch692be652012-01-10 18:47:50 +0000752
753
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100754static int Utf8LengthHelper(const char* s) {
755 int len = i::StrLength(s);
756 int character_length = len;
757 for (int i = 0; i < len; i++) {
758 unsigned char c = s[i];
759 int input_offset = 0;
760 int output_adjust = 0;
761 if (c > 0x7f) {
762 if (c < 0xc0) continue;
763 if (c >= 0xf0) {
764 if (c >= 0xf8) {
765 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
766 // byte.
767 continue; // Handle first UTF-8 byte.
768 }
769 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
770 // This 4 byte sequence could have been coded as a 3 byte sequence.
771 // Record a single kBadChar for the first byte and continue.
772 continue;
773 }
774 input_offset = 3;
775 // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
776 character_length -= 2;
777 } else if (c >= 0xe0) {
778 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
779 // This 3 byte sequence could have been coded as a 2 byte sequence.
780 // Record a single kBadChar for the first byte and continue.
781 continue;
782 }
783 input_offset = 2;
784 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
785 output_adjust = 2;
786 } else {
787 if ((c & 0x1e) == 0) {
788 // This 2 byte sequence could have been coded as a 1 byte sequence.
789 // Record a single kBadChar for the first byte and continue.
790 continue;
791 }
792 input_offset = 1;
793 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
794 output_adjust = 1;
795 }
796 bool bad = false;
797 for (int j = 1; j <= input_offset; j++) {
798 if ((s[i + j] & 0xc0) != 0x80) {
799 // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
800 // which is a single UTF-16 code unit.
801 bad = true;
802 break;
803 }
804 }
805 if (!bad) {
806 i += input_offset;
807 character_length -= output_adjust;
808 }
809 }
810 }
811 return character_length;
812}
813
814
815TEST(ScopePositions) {
816 // Test the parser for correctly setting the start and end positions
817 // of a scope. We check the scope positions of exactly one scope
818 // nested in the global scope of a program. 'inner source' is the
819 // source code that determines the part of the source belonging
820 // to the nested scope. 'outer_prefix' and 'outer_suffix' are
821 // parts of the source that belong to the global scope.
822 struct SourceData {
823 const char* outer_prefix;
824 const char* inner_source;
825 const char* outer_suffix;
826 i::ScopeType scope_type;
827 i::LanguageMode language_mode;
828 };
829
830 const SourceData source_data[] = {
831 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
832 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
833 { " with ({}) ", "{\n"
834 " block;\n"
835 " }", "\n"
836 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
837 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
838 { " with ({}) ", "statement", "\n"
839 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
840 { " with ({})\n"
841 " ", "statement;", "\n"
842 " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
843 { " try {} catch ", "(e) { block; }", " more;",
844 i::CATCH_SCOPE, i::CLASSIC_MODE },
845 { " try {} catch ", "(e) { block; }", "; more;",
846 i::CATCH_SCOPE, i::CLASSIC_MODE },
847 { " try {} catch ", "(e) {\n"
848 " block;\n"
849 " }", "\n"
850 " more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
851 { " try {} catch ", "(e) { block; }", " finally { block; } more;",
852 i::CATCH_SCOPE, i::CLASSIC_MODE },
853 { " start;\n"
854 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
855 { " start;\n"
856 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
857 { " start;\n"
858 " ", "{\n"
859 " let block;\n"
860 " }", "\n"
861 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
862 { " start;\n"
863 " function fun", "(a,b) { infunction; }", " more;",
864 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
865 { " start;\n"
866 " function fun", "(a,b) {\n"
867 " infunction;\n"
868 " }", "\n"
869 " more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
870 { " (function fun", "(a,b) { infunction; }", ")();",
871 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
872 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
873 i::BLOCK_SCOPE, i::EXTENDED_MODE },
874 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
875 i::BLOCK_SCOPE, i::EXTENDED_MODE },
876 { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
877 " block;\n"
878 " }", "\n"
879 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
880 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
881 i::BLOCK_SCOPE, i::EXTENDED_MODE },
882 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
883 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
884 { " for ", "(let x = 1 ; x < 10; ++ x)\n"
885 " statement;", "\n"
886 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
887 { " for ", "(let x in {}) { block; }", " more;",
888 i::BLOCK_SCOPE, i::EXTENDED_MODE },
889 { " for ", "(let x in {}) { block; }", "; more;",
890 i::BLOCK_SCOPE, i::EXTENDED_MODE },
891 { " for ", "(let x in {}) {\n"
892 " block;\n"
893 " }", "\n"
894 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
895 { " for ", "(let x in {}) statement;", " more;",
896 i::BLOCK_SCOPE, i::EXTENDED_MODE },
897 { " for ", "(let x in {}) statement", "\n"
898 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
899 { " for ", "(let x in {})\n"
900 " statement;", "\n"
901 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
902 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
903 // the preparser off in terms of byte offsets.
904 // 6 byte encoding.
905 { " 'foo\355\240\201\355\260\211';\n"
906 " (function fun", "(a,b) { infunction; }", ")();",
907 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
908 // 4 byte encoding.
909 { " 'foo\360\220\220\212';\n"
910 " (function fun", "(a,b) { infunction; }", ")();",
911 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
912 // 3 byte encoding of \u0fff.
913 { " 'foo\340\277\277';\n"
914 " (function fun", "(a,b) { infunction; }", ")();",
915 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
916 // Broken 6 byte encoding with missing last byte.
917 { " 'foo\355\240\201\355\211';\n"
918 " (function fun", "(a,b) { infunction; }", ")();",
919 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
920 // Broken 3 byte encoding of \u0fff with missing last byte.
921 { " 'foo\340\277';\n"
922 " (function fun", "(a,b) { infunction; }", ")();",
923 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
924 // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
925 { " 'foo\340';\n"
926 " (function fun", "(a,b) { infunction; }", ")();",
927 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
928 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
929 { " 'foo\340\203\277';\n"
930 " (function fun", "(a,b) { infunction; }", ")();",
931 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
932 // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
933 { " 'foo\340\201\277';\n"
934 " (function fun", "(a,b) { infunction; }", ")();",
935 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
936 // Unpaired lead surrogate.
937 { " 'foo\355\240\201';\n"
938 " (function fun", "(a,b) { infunction; }", ")();",
939 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
940 // Unpaired lead surrogate where following code point is a 3 byte sequence.
941 { " 'foo\355\240\201\340\277\277';\n"
942 " (function fun", "(a,b) { infunction; }", ")();",
943 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
944 // Unpaired lead surrogate where following code point is a 4 byte encoding
945 // of a trail surrogate.
946 { " 'foo\355\240\201\360\215\260\211';\n"
947 " (function fun", "(a,b) { infunction; }", ")();",
948 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
949 // Unpaired trail surrogate.
950 { " 'foo\355\260\211';\n"
951 " (function fun", "(a,b) { infunction; }", ")();",
952 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
953 // 2 byte encoding of \u00ff.
954 { " 'foo\303\277';\n"
955 " (function fun", "(a,b) { infunction; }", ")();",
956 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
957 // Broken 2 byte encoding of \u00ff with missing last byte.
958 { " 'foo\303';\n"
959 " (function fun", "(a,b) { infunction; }", ")();",
960 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
961 // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
962 { " 'foo\301\277';\n"
963 " (function fun", "(a,b) { infunction; }", ")();",
964 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
965 // Illegal 5 byte encoding.
966 { " 'foo\370\277\277\277\277';\n"
967 " (function fun", "(a,b) { infunction; }", ")();",
968 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
969 // Illegal 6 byte encoding.
970 { " 'foo\374\277\277\277\277\277';\n"
971 " (function fun", "(a,b) { infunction; }", ")();",
972 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
973 // Illegal 0xfe byte
974 { " 'foo\376\277\277\277\277\277\277';\n"
975 " (function fun", "(a,b) { infunction; }", ")();",
976 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
977 // Illegal 0xff byte
978 { " 'foo\377\277\277\277\277\277\277\277';\n"
979 " (function fun", "(a,b) { infunction; }", ")();",
980 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
981 { " 'foo';\n"
982 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
983 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
984 { " 'foo';\n"
985 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
986 i::FUNCTION_SCOPE, i::CLASSIC_MODE },
987 { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
988 };
989
990 v8::HandleScope handles;
991 v8::Persistent<v8::Context> context = v8::Context::New();
992 v8::Context::Scope context_scope(context);
993
994 int marker;
995 i::Isolate::Current()->stack_guard()->SetStackLimit(
996 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
997 i::FLAG_harmony_scoping = true;
998
999 for (int i = 0; source_data[i].outer_prefix; i++) {
1000 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1001 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1002 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1003 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1004 int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1005 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1006 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1007 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1008 i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
1009 i::OS::SNPrintF(program, "%s%s%s",
1010 source_data[i].outer_prefix,
1011 source_data[i].inner_source,
1012 source_data[i].outer_suffix);
1013
1014 // Parse program source.
1015 i::Handle<i::String> source(
1016 FACTORY->NewStringFromUtf8(i::CStrVector(program.start())));
1017 CHECK_EQ(source->length(), kProgramSize);
1018 i::Handle<i::Script> script = FACTORY->NewScript(source);
1019 i::Parser parser(script, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
1020 i::CompilationInfo info(script);
1021 info.MarkAsGlobal();
1022 info.SetLanguageMode(source_data[i].language_mode);
1023 i::FunctionLiteral* function = parser.ParseProgram(&info);
1024 CHECK(function != NULL);
1025
1026 // Check scope types and positions.
1027 i::Scope* scope = function->scope();
1028 CHECK(scope->is_global_scope());
1029 CHECK_EQ(scope->start_position(), 0);
1030 CHECK_EQ(scope->end_position(), kProgramSize);
1031 CHECK_EQ(scope->inner_scopes()->length(), 1);
1032
1033 i::Scope* inner_scope = scope->inner_scopes()->at(0);
1034 CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
1035 CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1036 // The end position of a token is one position after the last
1037 // character belonging to that token.
1038 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1039 }
1040}
1041
1042
1043void TestParserSync(i::Handle<i::String> source, int flags) {
Ben Murdoch692be652012-01-10 18:47:50 +00001044 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001045 bool harmony_scoping = ((i::kLanguageModeMask & flags) == i::EXTENDED_MODE);
Ben Murdoch692be652012-01-10 18:47:50 +00001046
1047 // Preparse the data.
1048 i::CompleteParserRecorder log;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001049 i::Scanner scanner(i::Isolate::Current()->unicode_cache());
1050 i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1051 scanner.SetHarmonyScoping(harmony_scoping);
Ben Murdoch692be652012-01-10 18:47:50 +00001052 scanner.Initialize(&stream);
1053 v8::preparser::PreParser::PreParseResult result =
1054 v8::preparser::PreParser::PreParseProgram(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001055 &scanner, &log, flags, stack_limit);
Ben Murdoch692be652012-01-10 18:47:50 +00001056 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
1057 i::ScriptDataImpl data(log.ExtractData());
1058
1059 // Parse the data
1060 i::Handle<i::Script> script = FACTORY->NewScript(source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001061 bool save_harmony_scoping = i::FLAG_harmony_scoping;
1062 i::FLAG_harmony_scoping = harmony_scoping;
1063 i::Parser parser(script, flags, NULL, NULL);
1064 i::CompilationInfo info(script);
1065 info.MarkAsGlobal();
1066 i::FunctionLiteral* function = parser.ParseProgram(&info);
1067 i::FLAG_harmony_scoping = save_harmony_scoping;
Ben Murdoch692be652012-01-10 18:47:50 +00001068
1069 i::String* type_string = NULL;
1070 if (function == NULL) {
1071 // Extract exception from the parser.
1072 i::Handle<i::String> type_symbol = FACTORY->LookupAsciiSymbol("type");
1073 CHECK(i::Isolate::Current()->has_pending_exception());
1074 i::MaybeObject* maybe_object = i::Isolate::Current()->pending_exception();
1075 i::JSObject* exception = NULL;
1076 CHECK(maybe_object->To(&exception));
1077
1078 // Get the type string.
1079 maybe_object = exception->GetProperty(*type_symbol);
1080 CHECK(maybe_object->To(&type_string));
1081 }
1082
1083 // Check that preparsing fails iff parsing fails.
1084 if (data.has_error() && function != NULL) {
1085 i::OS::Print(
1086 "Preparser failed on:\n"
1087 "\t%s\n"
1088 "with error:\n"
1089 "\t%s\n"
1090 "However, the parser succeeded",
1091 *source->ToCString(), data.BuildMessage());
1092 CHECK(false);
1093 } else if (!data.has_error() && function == NULL) {
1094 i::OS::Print(
1095 "Parser failed on:\n"
1096 "\t%s\n"
1097 "with error:\n"
1098 "\t%s\n"
1099 "However, the preparser succeeded",
1100 *source->ToCString(), *type_string->ToCString());
1101 CHECK(false);
1102 }
1103
1104 // Check that preparser and parser produce the same error.
1105 if (function == NULL) {
1106 if (!type_string->IsEqualTo(i::CStrVector(data.BuildMessage()))) {
1107 i::OS::Print(
1108 "Expected parser and preparser to produce the same error on:\n"
1109 "\t%s\n"
1110 "However, found the following error messages\n"
1111 "\tparser: %s\n"
1112 "\tpreparser: %s\n",
1113 *source->ToCString(), *type_string->ToCString(), data.BuildMessage());
1114 CHECK(false);
1115 }
1116 }
1117}
1118
1119
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001120void TestParserSyncWithFlags(i::Handle<i::String> source) {
1121 static const int kFlagsCount = 6;
1122 const int flags[kFlagsCount] = {
1123 i::kNoParsingFlags | i::CLASSIC_MODE,
1124 i::kNoParsingFlags | i::STRICT_MODE,
1125 i::kNoParsingFlags | i::EXTENDED_MODE,
1126 i::kAllowLazy | i::CLASSIC_MODE,
1127 i::kAllowLazy | i::STRICT_MODE,
1128 i::kAllowLazy | i::EXTENDED_MODE
1129 };
1130
1131 for (int k = 0; k < kFlagsCount; ++k) {
1132 TestParserSync(source, flags[k]);
1133 }
1134}
1135
1136
Ben Murdoch692be652012-01-10 18:47:50 +00001137TEST(ParserSync) {
1138 const char* context_data[][2] = {
1139 { "", "" },
1140 { "{", "}" },
1141 { "if (true) ", " else {}" },
1142 { "if (true) {} else ", "" },
1143 { "if (true) ", "" },
1144 { "do ", " while (false)" },
1145 { "while (false) ", "" },
1146 { "for (;;) ", "" },
1147 { "with ({})", "" },
1148 { "switch (12) { case 12: ", "}" },
1149 { "switch (12) { default: ", "}" },
1150 { "label2: ", "" },
1151 { NULL, NULL }
1152 };
1153
1154 const char* statement_data[] = {
1155 "{}",
1156 "var x",
1157 "var x = 1",
1158 "const x",
1159 "const x = 1",
1160 ";",
1161 "12",
1162 "if (false) {} else ;",
1163 "if (false) {} else {}",
1164 "if (false) {} else 12",
1165 "if (false) ;"
1166 "if (false) {}",
1167 "if (false) 12",
1168 "do {} while (false)",
1169 "for (;;) ;",
1170 "for (;;) {}",
1171 "for (;;) 12",
1172 "continue",
1173 "continue label",
1174 "continue\nlabel",
1175 "break",
1176 "break label",
1177 "break\nlabel",
1178 "return",
1179 "return 12",
1180 "return\n12",
1181 "with ({}) ;",
1182 "with ({}) {}",
1183 "with ({}) 12",
1184 "switch ({}) { default: }"
1185 "label3: "
1186 "throw",
1187 "throw 12",
1188 "throw\n12",
1189 "try {} catch(e) {}",
1190 "try {} finally {}",
1191 "try {} catch(e) {} finally {}",
1192 "debugger",
1193 NULL
1194 };
1195
1196 const char* termination_data[] = {
1197 "",
1198 ";",
1199 "\n",
1200 ";\n",
1201 "\n;",
1202 NULL
1203 };
1204
1205 v8::HandleScope handles;
1206 v8::Persistent<v8::Context> context = v8::Context::New();
1207 v8::Context::Scope context_scope(context);
1208
1209 int marker;
1210 i::Isolate::Current()->stack_guard()->SetStackLimit(
1211 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1212
1213 for (int i = 0; context_data[i][0] != NULL; ++i) {
1214 for (int j = 0; statement_data[j] != NULL; ++j) {
1215 for (int k = 0; termination_data[k] != NULL; ++k) {
1216 int kPrefixLen = i::StrLength(context_data[i][0]);
1217 int kStatementLen = i::StrLength(statement_data[j]);
1218 int kTerminationLen = i::StrLength(termination_data[k]);
1219 int kSuffixLen = i::StrLength(context_data[i][1]);
1220 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1221 + kSuffixLen + i::StrLength("label: for (;;) { }");
1222
1223 // Plug the source code pieces together.
1224 i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
1225 int length = i::OS::SNPrintF(program,
1226 "label: for (;;) { %s%s%s%s }",
1227 context_data[i][0],
1228 statement_data[j],
1229 termination_data[k],
1230 context_data[i][1]);
1231 CHECK(length == kProgramSize);
1232 i::Handle<i::String> source =
1233 FACTORY->NewStringFromAscii(i::CStrVector(program.start()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001234 TestParserSyncWithFlags(source);
Ben Murdoch692be652012-01-10 18:47:50 +00001235 }
1236 }
1237 }
1238}