The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-parsing.cc @ f230a1cf

History | View | Annotate | Download (46.2 KB)

1
// Copyright 2012 the V8 project authors. All rights reserved.
2
// 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>
29
#include <stdio.h>
30
#include <string.h>
31

    
32
#include "v8.h"
33

    
34
#include "cctest.h"
35
#include "compiler.h"
36
#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"
43

    
44
TEST(ScanKeywords) {
45
  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 },
52
      TOKEN_LIST(IGNORE_TOKEN, KEYWORD)
53
#undef KEYWORD
54
      { NULL, i::Token::IDENTIFIER }
55
  };
56

    
57
  KeywordToken key_token;
58
  i::UnicodeCache unicode_cache;
59
  i::byte buffer[32];
60
  for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
61
    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::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);
71
      scanner.Initialize(&stream);
72
      CHECK_EQ(key_token.token, scanner.Next());
73
      CHECK_EQ(i::Token::EOS, scanner.Next());
74
    }
75
    // Removing characters will make keyword matching fail.
76
    {
77
      i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
78
      i::Scanner scanner(&unicode_cache);
79
      scanner.Initialize(&stream);
80
      CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
81
      CHECK_EQ(i::Token::EOS, scanner.Next());
82
    }
83
    // 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
      i::OS::MemMove(buffer, keyword, length);
87
      buffer[length] = chars_to_append[j];
88
      i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
89
      i::Scanner scanner(&unicode_cache);
90
      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
      i::OS::MemMove(buffer, keyword, length);
97
      buffer[length - 1] = '_';
98
      i::Utf8ToUtf16CharacterStream stream(buffer, length);
99
      i::Scanner scanner(&unicode_cache);
100
      scanner.Initialize(&stream);
101
      CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
102
      CHECK_EQ(i::Token::EOS, scanner.Next());
103
    }
104
  }
105
}
106

    
107

    
108
TEST(ScanHTMLEndComments) {
109
  v8::V8::Initialize();
110
  v8::Isolate* isolate = CcTest::isolate();
111

    
112
  // Regression test. See:
113
  //    http://code.google.com/p/chromium/issues/detail?id=53548
114
  // Tests that --> is correctly interpreted as comment-to-end-of-line if there
115
  // is only whitespace before it on the line (with comments considered as
116
  // whitespace, even a multiline-comment containing a newline).
117
  // This was not the case if it occurred before the first real token
118
  // in the input.
119
  const char* tests[] = {
120
      // Before first real token.
121
      "--> is eol-comment\nvar y = 37;\n",
122
      "\n --> is eol-comment\nvar y = 37;\n",
123
      "/* precomment */ --> is eol-comment\nvar y = 37;\n",
124
      "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
125
      // After first real token.
126
      "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
127
      "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
128
      NULL
129
  };
130

    
131
  const char* fail_tests[] = {
132
      "x --> is eol-comment\nvar y = 37;\n",
133
      "\"\\n\" --> is eol-comment\nvar y = 37;\n",
134
      "x/* precomment */ --> is eol-comment\nvar y = 37;\n",
135
      "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n",
136
      "var x = 42; --> is eol-comment\nvar y = 37;\n",
137
      "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n",
138
      NULL
139
  };
140

    
141
  // Parser/Scanner needs a stack limit.
142
  int marker;
143
  CcTest::i_isolate()->stack_guard()->SetStackLimit(
144
      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
145

    
146
  for (int i = 0; tests[i]; i++) {
147
    v8::ScriptData* data =
148
        v8::ScriptData::PreCompile(isolate, tests[i], i::StrLength(tests[i]));
149
    CHECK(data != NULL && !data->HasError());
150
    delete data;
151
  }
152

    
153
  for (int i = 0; fail_tests[i]; i++) {
154
    v8::ScriptData* data = v8::ScriptData::PreCompile(
155
        isolate, fail_tests[i], i::StrLength(fail_tests[i]));
156
    CHECK(data == NULL || data->HasError());
157
    delete data;
158
  }
159
}
160

    
161

    
162
class ScriptResource : public v8::String::ExternalAsciiStringResource {
163
 public:
164
  ScriptResource(const char* data, size_t length)
165
      : data_(data), length_(length) { }
166

    
167
  const char* data() const { return data_; }
168
  size_t length() const { return length_; }
169

    
170
 private:
171
  const char* data_;
172
  size_t length_;
173
};
174

    
175

    
176
TEST(Preparsing) {
177
  v8::Isolate* isolate = CcTest::isolate();
178
  v8::HandleScope handles(isolate);
179
  v8::Local<v8::Context> context = v8::Context::New(isolate);
180
  v8::Context::Scope context_scope(context);
181
  int marker;
182
  CcTest::i_isolate()->stack_guard()->SetStackLimit(
183
      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
184

    
185
  // Source containing functions that might be lazily compiled  and all types
186
  // of symbols (string, propertyName, regexp).
187
  const char* source =
188
      "var x = 42;"
189
      "function foo(a) { return function nolazy(b) { return a + b; } }"
190
      "function bar(a) { if (a) return function lazy(b) { return b; } }"
191
      "var z = {'string': 'string literal', bareword: 'propertyName', "
192
      "         42: 'number literal', for: 'keyword as propertyName', "
193
      "         f\\u006fr: 'keyword propertyname with escape'};"
194
      "var v = /RegExp Literal/;"
195
      "var w = /RegExp Literal\\u0020With Escape/gin;"
196
      "var y = { get getter() { return 42; }, "
197
      "          set setter(v) { this.value = v; }};";
198
  int source_length = i::StrLength(source);
199
  const char* error_source = "var x = y z;";
200
  int error_source_length = i::StrLength(error_source);
201

    
202
  v8::ScriptData* preparse =
203
      v8::ScriptData::PreCompile(isolate, source, source_length);
204
  CHECK(!preparse->HasError());
205
  bool lazy_flag = i::FLAG_lazy;
206
  {
207
    i::FLAG_lazy = true;
208
    ScriptResource* resource = new ScriptResource(source, source_length);
209
    v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
210
    v8::Script::Compile(script_source, NULL, preparse);
211
  }
212

    
213
  {
214
    i::FLAG_lazy = false;
215

    
216
    ScriptResource* resource = new ScriptResource(source, source_length);
217
    v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
218
    v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
219
  }
220
  delete preparse;
221
  i::FLAG_lazy = lazy_flag;
222

    
223
  // Syntax error.
224
  v8::ScriptData* error_preparse =
225
      v8::ScriptData::PreCompile(isolate, error_source, error_source_length);
226
  CHECK(error_preparse->HasError());
227
  i::ScriptDataImpl *pre_impl =
228
      reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
229
  i::Scanner::Location error_location =
230
      pre_impl->MessageLocation();
231
  // Error is at "z" in source, location 10..11.
232
  CHECK_EQ(10, error_location.beg_pos);
233
  CHECK_EQ(11, error_location.end_pos);
234
  // Should not crash.
235
  const char* message = pre_impl->BuildMessage();
236
  pre_impl->BuildArgs();
237
  CHECK_GT(strlen(message), 0);
238
}
239

    
240

    
241
TEST(StandAlonePreParser) {
242
  v8::V8::Initialize();
243

    
244
  int marker;
245
  CcTest::i_isolate()->stack_guard()->SetStackLimit(
246
      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
247

    
248
  const char* programs[] = {
249
      "{label: 42}",
250
      "var x = 42;",
251
      "function foo(x, y) { return x + y; }",
252
      "%ArgleBargle(glop);",
253
      "var x = new new Function('this.x = 42');",
254
      NULL
255
  };
256

    
257
  uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
258
  for (int i = 0; programs[i]; i++) {
259
    const char* program = programs[i];
260
    i::Utf8ToUtf16CharacterStream stream(
261
        reinterpret_cast<const i::byte*>(program),
262
        static_cast<unsigned>(strlen(program)));
263
    i::CompleteParserRecorder log;
264
    i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
265
    scanner.Initialize(&stream);
266

    
267
    i::PreParser preparser(&scanner, &log, stack_limit);
268
    preparser.set_allow_lazy(true);
269
    preparser.set_allow_natives_syntax(true);
270
    i::PreParser::PreParseResult result = preparser.PreParseProgram();
271
    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
272
    i::ScriptDataImpl data(log.ExtractData());
273
    CHECK(!data.has_error());
274
  }
275
}
276

    
277

    
278
TEST(StandAlonePreParserNoNatives) {
279
  v8::V8::Initialize();
280

    
281
  int marker;
282
  CcTest::i_isolate()->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 = CcTest::i_isolate()->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(CcTest::i_isolate()->unicode_cache());
299
    scanner.Initialize(&stream);
300

    
301
    // Preparser defaults to disallowing natives syntax.
302
    i::PreParser preparser(&scanner, &log, stack_limit);
303
    preparser.set_allow_lazy(true);
304
    i::PreParser::PreParseResult result = preparser.PreParseProgram();
305
    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
306
    i::ScriptDataImpl data(log.ExtractData());
307
    // Data contains syntax error.
308
    CHECK(data.has_error());
309
  }
310
}
311

    
312

    
313
TEST(RegressChromium62639) {
314
  v8::V8::Initialize();
315
  i::Isolate* isolate = CcTest::i_isolate();
316

    
317
  int marker;
318
  isolate->stack_guard()->SetStackLimit(
319
      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
320

    
321
  const char* program = "var x = 'something';\n"
322
                        "escape: function() {}";
323
  // Fails parsing expecting an identifier after "function".
324
  // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
325
  // and then used the invalid currently scanned literal. This always
326
  // failed in debug mode, and sometimes crashed in release mode.
327

    
328
  i::Utf8ToUtf16CharacterStream stream(
329
      reinterpret_cast<const i::byte*>(program),
330
      static_cast<unsigned>(strlen(program)));
331
  i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
332
  CHECK(data->HasError());
333
  delete data;
334
}
335

    
336

    
337
TEST(Regress928) {
338
  v8::V8::Initialize();
339
  i::Isolate* isolate = CcTest::i_isolate();
340
  i::Factory* factory = isolate->factory();
341

    
342
  // 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;
347
  isolate->stack_guard()->SetStackLimit(
348
      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

    
354
  v8::HandleScope handles(CcTest::isolate());
355
  i::Handle<i::String> source(
356
      factory->NewStringFromAscii(i::CStrVector(program)));
357
  i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
358
  i::ScriptDataImpl* data = i::PreParserApi::PreParse(isolate, &stream);
359
  CHECK(!data->HasError());
360

    
361
  data->Initialize();
362

    
363
  int first_function =
364
      static_cast<int>(strstr(program, "function") - program);
365
  int first_lbrace = first_function + i::StrLength("function () ");
366
  CHECK_EQ('{', program[first_lbrace]);
367
  i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
368
  CHECK(!entry1.is_valid());
369

    
370
  int second_function =
371
      static_cast<int>(strstr(program + first_lbrace, "function") - program);
372
  int second_lbrace =
373
      second_function + i::StrLength("function () ");
374
  CHECK_EQ('{', program[second_lbrace]);
375
  i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
376
  CHECK(entry2.is_valid());
377
  CHECK_EQ('}', program[entry2.end_pos() - 1]);
378
  delete data;
379
}
380

    
381

    
382
TEST(PreParseOverflow) {
383
  v8::V8::Initialize();
384

    
385
  int marker;
386
  CcTest::i_isolate()->stack_guard()->SetStackLimit(
387
      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
388

    
389
  size_t kProgramSize = 1024 * 1024;
390
  i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
391
  memset(*program, '(', kProgramSize);
392
  program[kProgramSize] = '\0';
393

    
394
  uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
395

    
396
  i::Utf8ToUtf16CharacterStream stream(
397
      reinterpret_cast<const i::byte*>(*program),
398
      static_cast<unsigned>(kProgramSize));
399
  i::CompleteParserRecorder log;
400
  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
401
  scanner.Initialize(&stream);
402

    
403
  i::PreParser preparser(&scanner, &log, stack_limit);
404
  preparser.set_allow_lazy(true);
405
  i::PreParser::PreParseResult result = preparser.PreParseProgram();
406
  CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
407
}
408

    
409

    
410
class TestExternalResource: public v8::String::ExternalStringResource {
411
 public:
412
  explicit TestExternalResource(uint16_t* data, int length)
413
      : data_(data), length_(static_cast<size_t>(length)) { }
414

    
415
  ~TestExternalResource() { }
416

    
417
  const uint16_t* data() const {
418
    return data_;
419
  }
420

    
421
  size_t length() const {
422
    return length_;
423
  }
424
 private:
425
  uint16_t* data_;
426
  size_t length_;
427
};
428

    
429

    
430
#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
431

    
432
void TestCharacterStream(const char* ascii_source,
433
                         unsigned length,
434
                         unsigned start = 0,
435
                         unsigned end = 0) {
436
  if (end == 0) end = length;
437
  unsigned sub_length = end - start;
438
  i::Isolate* isolate = CcTest::i_isolate();
439
  i::Factory* factory = isolate->factory();
440
  i::HandleScope test_scope(isolate);
441
  i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
442
  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(
447
      factory->NewStringFromAscii(ascii_vector));
448
  TestExternalResource resource(*uc16_buffer, length);
449
  i::Handle<i::String> uc16_string(
450
      factory->NewExternalStringFromTwoByte(&resource));
451

    
452
  i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
453
      i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
454
  i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
455
  i::Utf8ToUtf16CharacterStream 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

    
544
TEST(CharacterStreams) {
545
  v8::Isolate* isolate = CcTest::isolate();
546
  v8::HandleScope handles(isolate);
547
  v8::Local<v8::Context> context = v8::Context::New(isolate);
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

    
565
TEST(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++) {
579
    cursor += unibrow::Utf8::Encode(buffer + cursor,
580
                                    i,
581
                                    unibrow::Utf16::kNoPreviousCharacter);
582
  }
583
  ASSERT(cursor == kAllUtf8CharsSizeU);
584

    
585
  i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
586
                                       kAllUtf8CharsSizeU);
587
  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

    
616
void TestStreamScanner(i::Utf16CharacterStream* stream,
617
                       i::Token::Value* expected_tokens,
618
                       int skip_pos = 0,  // Zero means not skipping.
619
                       int skip_to = 0) {
620
  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
621
  scanner.Initialize(stream);
622

    
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

    
635

    
636
TEST(StreamScanner) {
637
  v8::V8::Initialize();
638

    
639
  const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
640
  i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
641
                                        static_cast<unsigned>(strlen(str1)));
642
  i::Token::Value expectations1[] = {
643
      i::Token::LBRACE,
644
      i::Token::IDENTIFIER,
645
      i::Token::IDENTIFIER,
646
      i::Token::FOR,
647
      i::Token::COLON,
648
      i::Token::MUL,
649
      i::Token::DIV,
650
      i::Token::LT,
651
      i::Token::SUB,
652
      i::Token::IDENTIFIER,
653
      i::Token::EOS,
654
      i::Token::ILLEGAL
655
  };
656
  TestStreamScanner(&stream1, expectations1, 0, 0);
657

    
658
  const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
659
  i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
660
                                        static_cast<unsigned>(strlen(str2)));
661
  i::Token::Value expectations2[] = {
662
      i::Token::CASE,
663
      i::Token::DEFAULT,
664
      i::Token::CONST,
665
      i::Token::LBRACE,
666
      // Skipped part here
667
      i::Token::RBRACE,
668
      i::Token::DO,
669
      i::Token::EOS,
670
      i::Token::ILLEGAL
671
  };
672
  ASSERT_EQ('{', str2[19]);
673
  ASSERT_EQ('}', str2[37]);
674
  TestStreamScanner(&stream2, expectations2, 20, 37);
675

    
676
  const char* str3 = "{}}}}";
677
  i::Token::Value expectations3[] = {
678
      i::Token::LBRACE,
679
      i::Token::RBRACE,
680
      i::Token::RBRACE,
681
      i::Token::RBRACE,
682
      i::Token::RBRACE,
683
      i::Token::EOS,
684
      i::Token::ILLEGAL
685
  };
686
  // Skip zero-four RBRACEs.
687
  for (int i = 0; i <= 4; i++) {
688
     expectations3[6 - i] = i::Token::ILLEGAL;
689
     expectations3[5 - i] = i::Token::EOS;
690
     i::Utf8ToUtf16CharacterStream stream3(
691
         reinterpret_cast<const i::byte*>(str3),
692
         static_cast<unsigned>(strlen(str3)));
693
     TestStreamScanner(&stream3, expectations3, 1, 1 + i);
694
  }
695
}
696

    
697

    
698
void TestScanRegExp(const char* re_source, const char* expected) {
699
  i::Utf8ToUtf16CharacterStream stream(
700
       reinterpret_cast<const i::byte*>(re_source),
701
       static_cast<unsigned>(strlen(re_source)));
702
  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
703
  scanner.Initialize(&stream);
704

    
705
  i::Token::Value start = scanner.peek();
706
  CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
707
  CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
708
  scanner.Next();  // Current token is now the regexp literal.
709
  CHECK(scanner.is_literal_ascii());
710
  i::Vector<const char> actual = scanner.literal_ascii_string();
711
  for (int i = 0; i < actual.length(); i++) {
712
    CHECK_NE('\0', expected[i]);
713
    CHECK_EQ(expected[i], actual[i]);
714
  }
715
}
716

    
717

    
718
TEST(RegExpScanning) {
719
  v8::V8::Initialize();
720

    
721
  // RegExp token with added garbage at the end. The scanner should only
722
  // scan the RegExp until the terminating slash just before "flipperwald".
723
  TestScanRegExp("/b/flipperwald", "b");
724
  // Incomplete escape sequences doesn't hide the terminating slash.
725
  TestScanRegExp("/\\x/flipperwald", "\\x");
726
  TestScanRegExp("/\\u/flipperwald", "\\u");
727
  TestScanRegExp("/\\u1/flipperwald", "\\u1");
728
  TestScanRegExp("/\\u12/flipperwald", "\\u12");
729
  TestScanRegExp("/\\u123/flipperwald", "\\u123");
730
  TestScanRegExp("/\\c/flipperwald", "\\c");
731
  TestScanRegExp("/\\c//flipperwald", "\\c");
732
  // Slashes inside character classes are not terminating.
733
  TestScanRegExp("/[/]/flipperwald", "[/]");
734
  TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
735
  // Incomplete escape sequences inside a character class doesn't hide
736
  // the end of the character class.
737
  TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
738
  TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
739
  TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
740
  TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
741
  TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
742
  TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
743
  TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
744
  TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
745
  // Escaped ']'s wont end the character class.
746
  TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
747
  // Escaped slashes are not terminating.
748
  TestScanRegExp("/\\//flipperwald", "\\/");
749
  // Starting with '=' works too.
750
  TestScanRegExp("/=/", "=");
751
  TestScanRegExp("/=?/", "=?");
752
}
753

    
754

    
755
static int Utf8LengthHelper(const char* s) {
756
  int len = i::StrLength(s);
757
  int character_length = len;
758
  for (int i = 0; i < len; i++) {
759
    unsigned char c = s[i];
760
    int input_offset = 0;
761
    int output_adjust = 0;
762
    if (c > 0x7f) {
763
      if (c < 0xc0) continue;
764
      if (c >= 0xf0) {
765
        if (c >= 0xf8) {
766
          // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
767
          // byte.
768
          continue;  // Handle first UTF-8 byte.
769
        }
770
        if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
771
          // This 4 byte sequence could have been coded as a 3 byte sequence.
772
          // Record a single kBadChar for the first byte and continue.
773
          continue;
774
        }
775
        input_offset = 3;
776
        // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
777
        character_length -= 2;
778
      } else if (c >= 0xe0) {
779
        if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
780
          // This 3 byte sequence could have been coded as a 2 byte sequence.
781
          // Record a single kBadChar for the first byte and continue.
782
          continue;
783
        }
784
        input_offset = 2;
785
        // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
786
        output_adjust = 2;
787
      } else {
788
        if ((c & 0x1e) == 0) {
789
          // This 2 byte sequence could have been coded as a 1 byte sequence.
790
          // Record a single kBadChar for the first byte and continue.
791
          continue;
792
        }
793
        input_offset = 1;
794
        // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
795
        output_adjust = 1;
796
      }
797
      bool bad = false;
798
      for (int j = 1; j <= input_offset; j++) {
799
        if ((s[i + j] & 0xc0) != 0x80) {
800
          // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
801
          // which is a single UTF-16 code unit.
802
          bad = true;
803
          break;
804
        }
805
      }
806
      if (!bad) {
807
        i += input_offset;
808
        character_length -= output_adjust;
809
      }
810
    }
811
  }
812
  return character_length;
813
}
814

    
815

    
816
TEST(ScopePositions) {
817
  // Test the parser for correctly setting the start and end positions
818
  // of a scope. We check the scope positions of exactly one scope
819
  // nested in the global scope of a program. 'inner source' is the
820
  // source code that determines the part of the source belonging
821
  // to the nested scope. 'outer_prefix' and 'outer_suffix' are
822
  // parts of the source that belong to the global scope.
823
  struct SourceData {
824
    const char* outer_prefix;
825
    const char* inner_source;
826
    const char* outer_suffix;
827
    i::ScopeType scope_type;
828
    i::LanguageMode language_mode;
829
  };
830

    
831
  const SourceData source_data[] = {
832
    { "  with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
833
    { "  with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
834
    { "  with ({}) ", "{\n"
835
      "    block;\n"
836
      "  }", "\n"
837
      "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
838
    { "  with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
839
    { "  with ({}) ", "statement", "\n"
840
      "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
841
    { "  with ({})\n"
842
      "    ", "statement;", "\n"
843
      "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
844
    { "  try {} catch ", "(e) { block; }", " more;",
845
      i::CATCH_SCOPE, i::CLASSIC_MODE },
846
    { "  try {} catch ", "(e) { block; }", "; more;",
847
      i::CATCH_SCOPE, i::CLASSIC_MODE },
848
    { "  try {} catch ", "(e) {\n"
849
      "    block;\n"
850
      "  }", "\n"
851
      "  more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
852
    { "  try {} catch ", "(e) { block; }", " finally { block; } more;",
853
      i::CATCH_SCOPE, i::CLASSIC_MODE },
854
    { "  start;\n"
855
      "  ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
856
    { "  start;\n"
857
      "  ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
858
    { "  start;\n"
859
      "  ", "{\n"
860
      "    let block;\n"
861
      "  }", "\n"
862
      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
863
    { "  start;\n"
864
      "  function fun", "(a,b) { infunction; }", " more;",
865
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
866
    { "  start;\n"
867
      "  function fun", "(a,b) {\n"
868
      "    infunction;\n"
869
      "  }", "\n"
870
      "  more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
871
    { "  (function fun", "(a,b) { infunction; }", ")();",
872
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
873
    { "  for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
874
      i::BLOCK_SCOPE, i::EXTENDED_MODE },
875
    { "  for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
876
      i::BLOCK_SCOPE, i::EXTENDED_MODE },
877
    { "  for ", "(let x = 1 ; x < 10; ++ x) {\n"
878
      "    block;\n"
879
      "  }", "\n"
880
      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
881
    { "  for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
882
      i::BLOCK_SCOPE, i::EXTENDED_MODE },
883
    { "  for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
884
      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
885
    { "  for ", "(let x = 1 ; x < 10; ++ x)\n"
886
      "    statement;", "\n"
887
      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
888
    { "  for ", "(let x in {}) { block; }", " more;",
889
      i::BLOCK_SCOPE, i::EXTENDED_MODE },
890
    { "  for ", "(let x in {}) { block; }", "; more;",
891
      i::BLOCK_SCOPE, i::EXTENDED_MODE },
892
    { "  for ", "(let x in {}) {\n"
893
      "    block;\n"
894
      "  }", "\n"
895
      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
896
    { "  for ", "(let x in {}) statement;", " more;",
897
      i::BLOCK_SCOPE, i::EXTENDED_MODE },
898
    { "  for ", "(let x in {}) statement", "\n"
899
      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
900
    { "  for ", "(let x in {})\n"
901
      "    statement;", "\n"
902
      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
903
    // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
904
    // the preparser off in terms of byte offsets.
905
    // 6 byte encoding.
906
    { "  'foo\355\240\201\355\260\211';\n"
907
      "  (function fun", "(a,b) { infunction; }", ")();",
908
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
909
    // 4 byte encoding.
910
    { "  'foo\360\220\220\212';\n"
911
      "  (function fun", "(a,b) { infunction; }", ")();",
912
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
913
    // 3 byte encoding of \u0fff.
914
    { "  'foo\340\277\277';\n"
915
      "  (function fun", "(a,b) { infunction; }", ")();",
916
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
917
    // Broken 6 byte encoding with missing last byte.
918
    { "  'foo\355\240\201\355\211';\n"
919
      "  (function fun", "(a,b) { infunction; }", ")();",
920
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
921
    // Broken 3 byte encoding of \u0fff with missing last byte.
922
    { "  'foo\340\277';\n"
923
      "  (function fun", "(a,b) { infunction; }", ")();",
924
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
925
    // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
926
    { "  'foo\340';\n"
927
      "  (function fun", "(a,b) { infunction; }", ")();",
928
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
929
    // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
930
    { "  'foo\340\203\277';\n"
931
      "  (function fun", "(a,b) { infunction; }", ")();",
932
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
933
    // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
934
    { "  'foo\340\201\277';\n"
935
      "  (function fun", "(a,b) { infunction; }", ")();",
936
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
937
    // Unpaired lead surrogate.
938
    { "  'foo\355\240\201';\n"
939
      "  (function fun", "(a,b) { infunction; }", ")();",
940
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
941
    // Unpaired lead surrogate where following code point is a 3 byte sequence.
942
    { "  'foo\355\240\201\340\277\277';\n"
943
      "  (function fun", "(a,b) { infunction; }", ")();",
944
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
945
    // Unpaired lead surrogate where following code point is a 4 byte encoding
946
    // of a trail surrogate.
947
    { "  'foo\355\240\201\360\215\260\211';\n"
948
      "  (function fun", "(a,b) { infunction; }", ")();",
949
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
950
    // Unpaired trail surrogate.
951
    { "  'foo\355\260\211';\n"
952
      "  (function fun", "(a,b) { infunction; }", ")();",
953
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
954
    // 2 byte encoding of \u00ff.
955
    { "  'foo\303\277';\n"
956
      "  (function fun", "(a,b) { infunction; }", ")();",
957
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
958
    // Broken 2 byte encoding of \u00ff with missing last byte.
959
    { "  'foo\303';\n"
960
      "  (function fun", "(a,b) { infunction; }", ")();",
961
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
962
    // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
963
    { "  'foo\301\277';\n"
964
      "  (function fun", "(a,b) { infunction; }", ")();",
965
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
966
    // Illegal 5 byte encoding.
967
    { "  'foo\370\277\277\277\277';\n"
968
      "  (function fun", "(a,b) { infunction; }", ")();",
969
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
970
    // Illegal 6 byte encoding.
971
    { "  'foo\374\277\277\277\277\277';\n"
972
      "  (function fun", "(a,b) { infunction; }", ")();",
973
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
974
    // Illegal 0xfe byte
975
    { "  'foo\376\277\277\277\277\277\277';\n"
976
      "  (function fun", "(a,b) { infunction; }", ")();",
977
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
978
    // Illegal 0xff byte
979
    { "  'foo\377\277\277\277\277\277\277\277';\n"
980
      "  (function fun", "(a,b) { infunction; }", ")();",
981
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
982
    { "  'foo';\n"
983
      "  (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
984
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
985
    { "  'foo';\n"
986
      "  (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
987
      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
988
    { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
989
  };
990

    
991
  i::Isolate* isolate = CcTest::i_isolate();
992
  i::Factory* factory = isolate->factory();
993

    
994
  v8::HandleScope handles(CcTest::isolate());
995
  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
996
  v8::Context::Scope context_scope(context);
997

    
998
  int marker;
999
  isolate->stack_guard()->SetStackLimit(
1000
      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1001

    
1002
  for (int i = 0; source_data[i].outer_prefix; i++) {
1003
    int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1004
    int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1005
    int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1006
    int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1007
    int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1008
    int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1009
    int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1010
    int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1011
    i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
1012
    i::OS::SNPrintF(program, "%s%s%s",
1013
                             source_data[i].outer_prefix,
1014
                             source_data[i].inner_source,
1015
                             source_data[i].outer_suffix);
1016

    
1017
    // Parse program source.
1018
    i::Handle<i::String> source(
1019
        factory->NewStringFromUtf8(i::CStrVector(program.start())));
1020
    CHECK_EQ(source->length(), kProgramSize);
1021
    i::Handle<i::Script> script = factory->NewScript(source);
1022
    i::CompilationInfoWithZone info(script);
1023
    i::Parser parser(&info);
1024
    parser.set_allow_lazy(true);
1025
    parser.set_allow_harmony_scoping(true);
1026
    info.MarkAsGlobal();
1027
    info.SetLanguageMode(source_data[i].language_mode);
1028
    parser.Parse();
1029
    CHECK(info.function() != NULL);
1030

    
1031
    // Check scope types and positions.
1032
    i::Scope* scope = info.function()->scope();
1033
    CHECK(scope->is_global_scope());
1034
    CHECK_EQ(scope->start_position(), 0);
1035
    CHECK_EQ(scope->end_position(), kProgramSize);
1036
    CHECK_EQ(scope->inner_scopes()->length(), 1);
1037

    
1038
    i::Scope* inner_scope = scope->inner_scopes()->at(0);
1039
    CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
1040
    CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1041
    // The end position of a token is one position after the last
1042
    // character belonging to that token.
1043
    CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1044
  }
1045
}
1046

    
1047

    
1048
i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) {
1049
  i::Isolate* isolate = CcTest::i_isolate();
1050
  i::Factory* factory = isolate->factory();
1051
  const char* message = data->BuildMessage();
1052
  i::Handle<i::String> format = v8::Utils::OpenHandle(
1053
                                    *v8::String::New(message));
1054
  i::Vector<const char*> args = data->BuildArgs();
1055
  i::Handle<i::JSArray> args_array = factory->NewJSArray(args.length());
1056
  for (int i = 0; i < args.length(); i++) {
1057
    i::JSArray::SetElement(args_array,
1058
                           i,
1059
                           v8::Utils::OpenHandle(*v8::String::New(args[i])),
1060
                           NONE,
1061
                           i::kNonStrictMode);
1062
  }
1063
  i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
1064
  i::Handle<i::Object> format_fun =
1065
      i::GetProperty(builtins, "FormatMessage");
1066
  i::Handle<i::Object> arg_handles[] = { format, args_array };
1067
  bool has_exception = false;
1068
  i::Handle<i::Object> result = i::Execution::Call(
1069
      isolate, format_fun, builtins, 2, arg_handles, &has_exception);
1070
  CHECK(!has_exception);
1071
  CHECK(result->IsString());
1072
  for (int i = 0; i < args.length(); i++) {
1073
    i::DeleteArray(args[i]);
1074
  }
1075
  i::DeleteArray(args.start());
1076
  i::DeleteArray(message);
1077
  return i::Handle<i::String>::cast(result);
1078
}
1079

    
1080

    
1081
enum ParserFlag {
1082
  kAllowLazy,
1083
  kAllowNativesSyntax,
1084
  kAllowHarmonyScoping,
1085
  kAllowModules,
1086
  kAllowGenerators,
1087
  kAllowForOf,
1088
  kAllowHarmonyNumericLiterals
1089
};
1090

    
1091

    
1092
void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
1093
  parser->set_allow_lazy(flags.Contains(kAllowLazy));
1094
  parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
1095
  parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
1096
  parser->set_allow_modules(flags.Contains(kAllowModules));
1097
  parser->set_allow_generators(flags.Contains(kAllowGenerators));
1098
  parser->set_allow_for_of(flags.Contains(kAllowForOf));
1099
  parser->set_allow_harmony_numeric_literals(
1100
      flags.Contains(kAllowHarmonyNumericLiterals));
1101
}
1102

    
1103

    
1104
void TestParserSyncWithFlags(i::Handle<i::String> source,
1105
                             i::EnumSet<ParserFlag> flags) {
1106
  i::Isolate* isolate = CcTest::i_isolate();
1107
  i::Factory* factory = isolate->factory();
1108

    
1109
  uintptr_t stack_limit = isolate->stack_guard()->real_climit();
1110

    
1111
  // Preparse the data.
1112
  i::CompleteParserRecorder log;
1113
  {
1114
    i::Scanner scanner(isolate->unicode_cache());
1115
    i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1116
    i::PreParser preparser(&scanner, &log, stack_limit);
1117
    SetParserFlags(&preparser, flags);
1118
    scanner.Initialize(&stream);
1119
    i::PreParser::PreParseResult result = preparser.PreParseProgram();
1120
    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
1121
  }
1122
  i::ScriptDataImpl data(log.ExtractData());
1123

    
1124
  // Parse the data
1125
  i::FunctionLiteral* function;
1126
  {
1127
    i::Handle<i::Script> script = factory->NewScript(source);
1128
    i::CompilationInfoWithZone info(script);
1129
    i::Parser parser(&info);
1130
    SetParserFlags(&parser, flags);
1131
    info.MarkAsGlobal();
1132
    parser.Parse();
1133
    function = info.function();
1134
  }
1135

    
1136
  // Check that preparsing fails iff parsing fails.
1137
  if (function == NULL) {
1138
    // Extract exception from the parser.
1139
    CHECK(isolate->has_pending_exception());
1140
    i::MaybeObject* maybe_object = isolate->pending_exception();
1141
    i::JSObject* exception = NULL;
1142
    CHECK(maybe_object->To(&exception));
1143
    i::Handle<i::JSObject> exception_handle(exception);
1144
    i::Handle<i::String> message_string =
1145
        i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
1146

    
1147
    if (!data.has_error()) {
1148
      i::OS::Print(
1149
          "Parser failed on:\n"
1150
          "\t%s\n"
1151
          "with error:\n"
1152
          "\t%s\n"
1153
          "However, the preparser succeeded",
1154
          *source->ToCString(), *message_string->ToCString());
1155
      CHECK(false);
1156
    }
1157
    // Check that preparser and parser produce the same error.
1158
    i::Handle<i::String> preparser_message = FormatMessage(&data);
1159
    if (!message_string->Equals(*preparser_message)) {
1160
      i::OS::Print(
1161
          "Expected parser and preparser to produce the same error on:\n"
1162
          "\t%s\n"
1163
          "However, found the following error messages\n"
1164
          "\tparser:    %s\n"
1165
          "\tpreparser: %s\n",
1166
          *source->ToCString(),
1167
          *message_string->ToCString(),
1168
          *preparser_message->ToCString());
1169
      CHECK(false);
1170
    }
1171
  } else if (data.has_error()) {
1172
    i::OS::Print(
1173
        "Preparser failed on:\n"
1174
        "\t%s\n"
1175
        "with error:\n"
1176
        "\t%s\n"
1177
        "However, the parser succeeded",
1178
        *source->ToCString(), *FormatMessage(&data)->ToCString());
1179
    CHECK(false);
1180
  }
1181
}
1182

    
1183

    
1184
void TestParserSync(const char* source,
1185
                    const ParserFlag* flag_list,
1186
                    size_t flag_list_length) {
1187
  i::Handle<i::String> str =
1188
      CcTest::i_isolate()->factory()->NewStringFromAscii(i::CStrVector(source));
1189
  for (int bits = 0; bits < (1 << flag_list_length); bits++) {
1190
    i::EnumSet<ParserFlag> flags;
1191
    for (size_t flag_index = 0; flag_index < flag_list_length; flag_index++) {
1192
      if ((bits & (1 << flag_index)) != 0) flags.Add(flag_list[flag_index]);
1193
    }
1194
    TestParserSyncWithFlags(str, flags);
1195
  }
1196
}
1197

    
1198

    
1199
TEST(ParserSync) {
1200
  const char* context_data[][2] = {
1201
    { "", "" },
1202
    { "{", "}" },
1203
    { "if (true) ", " else {}" },
1204
    { "if (true) {} else ", "" },
1205
    { "if (true) ", "" },
1206
    { "do ", " while (false)" },
1207
    { "while (false) ", "" },
1208
    { "for (;;) ", "" },
1209
    { "with ({})", "" },
1210
    { "switch (12) { case 12: ", "}" },
1211
    { "switch (12) { default: ", "}" },
1212
    { "switch (12) { ", "case 12: }" },
1213
    { "label2: ", "" },
1214
    { NULL, NULL }
1215
  };
1216

    
1217
  const char* statement_data[] = {
1218
    "{}",
1219
    "var x",
1220
    "var x = 1",
1221
    "const x",
1222
    "const x = 1",
1223
    ";",
1224
    "12",
1225
    "if (false) {} else ;",
1226
    "if (false) {} else {}",
1227
    "if (false) {} else 12",
1228
    "if (false) ;"
1229
    "if (false) {}",
1230
    "if (false) 12",
1231
    "do {} while (false)",
1232
    "for (;;) ;",
1233
    "for (;;) {}",
1234
    "for (;;) 12",
1235
    "continue",
1236
    "continue label",
1237
    "continue\nlabel",
1238
    "break",
1239
    "break label",
1240
    "break\nlabel",
1241
    "return",
1242
    "return  12",
1243
    "return\n12",
1244
    "with ({}) ;",
1245
    "with ({}) {}",
1246
    "with ({}) 12",
1247
    "switch ({}) { default: }"
1248
    "label3: "
1249
    "throw",
1250
    "throw  12",
1251
    "throw\n12",
1252
    "try {} catch(e) {}",
1253
    "try {} finally {}",
1254
    "try {} catch(e) {} finally {}",
1255
    "debugger",
1256
    NULL
1257
  };
1258

    
1259
  const char* termination_data[] = {
1260
    "",
1261
    ";",
1262
    "\n",
1263
    ";\n",
1264
    "\n;",
1265
    NULL
1266
  };
1267

    
1268
  v8::HandleScope handles(CcTest::isolate());
1269
  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
1270
  v8::Context::Scope context_scope(context);
1271

    
1272
  int marker;
1273
  CcTest::i_isolate()->stack_guard()->SetStackLimit(
1274
      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1275

    
1276
  static const ParserFlag flags1[] = {
1277
    kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
1278
    kAllowForOf
1279
  };
1280
  for (int i = 0; context_data[i][0] != NULL; ++i) {
1281
    for (int j = 0; statement_data[j] != NULL; ++j) {
1282
      for (int k = 0; termination_data[k] != NULL; ++k) {
1283
        int kPrefixLen = i::StrLength(context_data[i][0]);
1284
        int kStatementLen = i::StrLength(statement_data[j]);
1285
        int kTerminationLen = i::StrLength(termination_data[k]);
1286
        int kSuffixLen = i::StrLength(context_data[i][1]);
1287
        int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1288
            + kSuffixLen + i::StrLength("label: for (;;) {  }");
1289

    
1290
        // Plug the source code pieces together.
1291
        i::ScopedVector<char> program(kProgramSize + 1);
1292
        int length = i::OS::SNPrintF(program,
1293
            "label: for (;;) { %s%s%s%s }",
1294
            context_data[i][0],
1295
            statement_data[j],
1296
            termination_data[k],
1297
            context_data[i][1]);
1298
        CHECK(length == kProgramSize);
1299
        TestParserSync(program.start(), flags1, ARRAY_SIZE(flags1));
1300
      }
1301
    }
1302
  }
1303

    
1304
  // Neither Harmony numeric literals nor our natives syntax have any
1305
  // interaction with the flags above, so test these separately to reduce
1306
  // the combinatorial explosion.
1307
  static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
1308
  TestParserSync("0o1234", flags2, ARRAY_SIZE(flags2));
1309
  TestParserSync("0b1011", flags2, ARRAY_SIZE(flags2));
1310

    
1311
  static const ParserFlag flags3[] = { kAllowNativesSyntax };
1312
  TestParserSync("%DebugPrint(123)", flags3, ARRAY_SIZE(flags3));
1313
}
1314

    
1315

    
1316
TEST(PreparserStrictOctal) {
1317
  // Test that syntax error caused by octal literal is reported correctly as
1318
  // such (issue 2220).
1319
  v8::internal::FLAG_min_preparse_length = 1;  // Force preparsing.
1320
  v8::V8::Initialize();
1321
  v8::HandleScope scope(CcTest::isolate());
1322
  v8::Context::Scope context_scope(
1323
      v8::Context::New(CcTest::isolate()));
1324
  v8::TryCatch try_catch;
1325
  const char* script =
1326
      "\"use strict\";       \n"
1327
      "a = function() {      \n"
1328
      "  b = function() {    \n"
1329
      "    01;               \n"
1330
      "  };                  \n"
1331
      "};                    \n";
1332
  v8::Script::Compile(v8::String::New(script));
1333
  CHECK(try_catch.HasCaught());
1334
  v8::String::Utf8Value exception(try_catch.Exception());
1335
  CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
1336
           *exception);
1337
}