Upgrade to 3.29

Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.

Bug: 17370214

Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
old mode 100755
new mode 100644
index 6bcae7c..72f2298
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -25,21 +25,25 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
-#include "v8.h"
+#include "src/v8.h"
 
-#include "cctest.h"
-#include "compiler.h"
-#include "execution.h"
-#include "isolate.h"
-#include "parser.h"
-#include "preparser.h"
-#include "scanner-character-streams.h"
-#include "token.h"
-#include "utils.h"
+#include "src/ast-value-factory.h"
+#include "src/compiler.h"
+#include "src/execution.h"
+#include "src/isolate.h"
+#include "src/objects.h"
+#include "src/parser.h"
+#include "src/preparser.h"
+#include "src/rewriter.h"
+#include "src/scanner-character-streams.h"
+#include "src/token.h"
+#include "src/utils.h"
+
+#include "test/cctest/cctest.h"
 
 TEST(ScanKeywords) {
   struct KeywordToken {
@@ -68,6 +72,7 @@
       // The scanner should parse Harmony keywords for this test.
       scanner.SetHarmonyScoping(true);
       scanner.SetHarmonyModules(true);
+      scanner.SetHarmonyClasses(true);
       scanner.Initialize(&stream);
       CHECK_EQ(key_token.token, scanner.Next());
       CHECK_EQ(i::Token::EOS, scanner.Next());
@@ -82,8 +87,8 @@
     }
     // Adding characters will make keyword matching fail.
     static const char chars_to_append[] = { 'z', '0', '_' };
-    for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) {
-      memmove(buffer, keyword, length);
+    for (int j = 0; j < static_cast<int>(arraysize(chars_to_append)); ++j) {
+      i::MemMove(buffer, keyword, length);
       buffer[length] = chars_to_append[j];
       i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
       i::Scanner scanner(&unicode_cache);
@@ -93,7 +98,7 @@
     }
     // Replacing characters will make keyword matching fail.
     {
-      memmove(buffer, keyword, length);
+      i::MemMove(buffer, keyword, length);
       buffer[length - 1] = '_';
       i::Utf8ToUtf16CharacterStream stream(buffer, length);
       i::Scanner scanner(&unicode_cache);
@@ -107,6 +112,8 @@
 
 TEST(ScanHTMLEndComments) {
   v8::V8::Initialize();
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handles(isolate);
 
   // Regression test. See:
   //    http://code.google.com/p/chromium/issues/detail?id=53548
@@ -138,27 +145,41 @@
   };
 
   // Parser/Scanner needs a stack limit.
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
-
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
+  uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
   for (int i = 0; tests[i]; i++) {
-    v8::ScriptData* data =
-        v8::ScriptData::PreCompile(tests[i], i::StrLength(tests[i]));
-    CHECK(data != NULL && !data->HasError());
-    delete data;
+    const i::byte* source =
+        reinterpret_cast<const i::byte*>(tests[i]);
+    i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(tests[i]));
+    i::CompleteParserRecorder log;
+    i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+    scanner.Initialize(&stream);
+    i::PreParser preparser(&scanner, &log, stack_limit);
+    preparser.set_allow_lazy(true);
+    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+    CHECK(!log.HasError());
   }
 
   for (int i = 0; fail_tests[i]; i++) {
-    v8::ScriptData* data =
-        v8::ScriptData::PreCompile(fail_tests[i], i::StrLength(fail_tests[i]));
-    CHECK(data == NULL || data->HasError());
-    delete data;
+    const i::byte* source =
+        reinterpret_cast<const i::byte*>(fail_tests[i]);
+    i::Utf8ToUtf16CharacterStream stream(source, i::StrLength(fail_tests[i]));
+    i::CompleteParserRecorder log;
+    i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+    scanner.Initialize(&stream);
+    i::PreParser preparser(&scanner, &log, stack_limit);
+    preparser.set_allow_lazy(true);
+    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    // Even in the case of a syntax error, kPreParseSuccess is returned.
+    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+    CHECK(log.HasError());
   }
 }
 
 
-class ScriptResource : public v8::String::ExternalAsciiStringResource {
+class ScriptResource : public v8::String::ExternalOneByteStringResource {
  public:
   ScriptResource(const char* data, size_t length)
       : data_(data), length_(length) { }
@@ -172,13 +193,13 @@
 };
 
 
-TEST(Preparsing) {
-  v8::HandleScope handles;
-  v8::Persistent<v8::Context> context = v8::Context::New();
+TEST(UsingCachedData) {
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handles(isolate);
+  v8::Local<v8::Context> context = v8::Context::New(isolate);
   v8::Context::Scope context_scope(context);
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
 
   // Source containing functions that might be lazily compiled  and all types
   // of symbols (string, propertyName, regexp).
@@ -192,56 +213,87 @@
       "var v = /RegExp Literal/;"
       "var w = /RegExp Literal\\u0020With Escape/gin;"
       "var y = { get getter() { return 42; }, "
-      "          set setter(v) { this.value = v; }};";
+      "          set setter(v) { this.value = v; }};"
+      "var f = a => function (b) { return a + b; };"
+      "var g = a => b => a + b;";
   int source_length = i::StrLength(source);
-  const char* error_source = "var x = y z;";
-  int error_source_length = i::StrLength(error_source);
 
-  v8::ScriptData* preparse =
-      v8::ScriptData::PreCompile(source, source_length);
-  CHECK(!preparse->HasError());
+  // ScriptResource will be deleted when the corresponding String is GCd.
+  v8::ScriptCompiler::Source script_source(v8::String::NewExternal(
+      isolate, new ScriptResource(source, source_length)));
+  i::FLAG_harmony_arrow_functions = true;
+  i::FLAG_min_preparse_length = 0;
+  v8::ScriptCompiler::Compile(isolate, &script_source,
+                              v8::ScriptCompiler::kProduceParserCache);
+  CHECK(script_source.GetCachedData());
+
+  // Compile the script again, using the cached data.
   bool lazy_flag = i::FLAG_lazy;
-  {
-    i::FLAG_lazy = true;
-    ScriptResource* resource = new ScriptResource(source, source_length);
-    v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
-    v8::Script::Compile(script_source, NULL, preparse);
-  }
-
-  {
-    i::FLAG_lazy = false;
-
-    ScriptResource* resource = new ScriptResource(source, source_length);
-    v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
-    v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
-  }
-  delete preparse;
+  i::FLAG_lazy = true;
+  v8::ScriptCompiler::Compile(isolate, &script_source,
+                              v8::ScriptCompiler::kConsumeParserCache);
+  i::FLAG_lazy = false;
+  v8::ScriptCompiler::CompileUnbound(isolate, &script_source,
+                                     v8::ScriptCompiler::kConsumeParserCache);
   i::FLAG_lazy = lazy_flag;
+}
 
-  // Syntax error.
-  v8::ScriptData* error_preparse =
-      v8::ScriptData::PreCompile(error_source, error_source_length);
-  CHECK(error_preparse->HasError());
-  i::ScriptDataImpl *pre_impl =
-      reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
-  i::Scanner::Location error_location =
-      pre_impl->MessageLocation();
-  // Error is at "z" in source, location 10..11.
-  CHECK_EQ(10, error_location.beg_pos);
-  CHECK_EQ(11, error_location.end_pos);
-  // Should not crash.
-  const char* message = pre_impl->BuildMessage();
-  pre_impl->BuildArgs();
-  CHECK_GT(strlen(message), 0);
+
+TEST(PreparseFunctionDataIsUsed) {
+  // This tests that we actually do use the function data generated by the
+  // preparser.
+
+  // Make preparsing work for short scripts.
+  i::FLAG_min_preparse_length = 0;
+  i::FLAG_harmony_arrow_functions = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handles(isolate);
+  v8::Local<v8::Context> context = v8::Context::New(isolate);
+  v8::Context::Scope context_scope(context);
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
+
+  const char* good_code[] = {
+      "function this_is_lazy() { var a; } function foo() { return 25; } foo();",
+      "var this_is_lazy = () => { var a; }; var foo = () => 25; foo();",
+  };
+
+  // Insert a syntax error inside the lazy function.
+  const char* bad_code[] = {
+      "function this_is_lazy() { if (   } function foo() { return 25; } foo();",
+      "var this_is_lazy = () => { if (   }; var foo = () => 25; foo();",
+  };
+
+  for (unsigned i = 0; i < arraysize(good_code); i++) {
+    v8::ScriptCompiler::Source good_source(v8_str(good_code[i]));
+    v8::ScriptCompiler::Compile(isolate, &good_source,
+                                v8::ScriptCompiler::kProduceDataToCache);
+
+    const v8::ScriptCompiler::CachedData* cached_data =
+        good_source.GetCachedData();
+    CHECK(cached_data->data != NULL);
+    CHECK_GT(cached_data->length, 0);
+
+    // Now compile the erroneous code with the good preparse data. If the
+    // preparse data is used, the lazy function is skipped and it should
+    // compile fine.
+    v8::ScriptCompiler::Source bad_source(
+        v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData(
+                                 cached_data->data, cached_data->length));
+    v8::Local<v8::Value> result =
+        v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
+    CHECK(result->IsInt32());
+    CHECK_EQ(25, result->Int32Value());
+  }
 }
 
 
 TEST(StandAlonePreParser) {
   v8::V8::Initialize();
 
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
 
   const char* programs[] = {
       "{label: 42}",
@@ -249,28 +301,27 @@
       "function foo(x, y) { return x + y; }",
       "%ArgleBargle(glop);",
       "var x = new new Function('this.x = 42');",
+      "var f = (x, y) => x + y;",
       NULL
   };
 
-  uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
+  uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
   for (int i = 0; programs[i]; i++) {
     const char* program = programs[i];
     i::Utf8ToUtf16CharacterStream stream(
         reinterpret_cast<const i::byte*>(program),
         static_cast<unsigned>(strlen(program)));
     i::CompleteParserRecorder log;
-    i::Scanner scanner(i::Isolate::Current()->unicode_cache());
+    i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
     scanner.Initialize(&stream);
 
-    int flags = i::kAllowLazy | i::kAllowNativesSyntax;
-    v8::preparser::PreParser::PreParseResult result =
-        v8::preparser::PreParser::PreParseProgram(&scanner,
-                                                  &log,
-                                                  flags,
-                                                  stack_limit);
-    CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
-    i::ScriptDataImpl data(log.ExtractData());
-    CHECK(!data.has_error());
+    i::PreParser preparser(&scanner, &log, stack_limit);
+    preparser.set_allow_lazy(true);
+    preparser.set_allow_natives_syntax(true);
+    preparser.set_allow_arrow_functions(true);
+    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+    CHECK(!log.HasError());
   }
 }
 
@@ -278,9 +329,8 @@
 TEST(StandAlonePreParserNoNatives) {
   v8::V8::Initialize();
 
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
 
   const char* programs[] = {
       "%ArgleBargle(glop);",
@@ -288,36 +338,68 @@
       NULL
   };
 
-  uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
+  uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
   for (int i = 0; programs[i]; i++) {
     const char* program = programs[i];
     i::Utf8ToUtf16CharacterStream stream(
         reinterpret_cast<const i::byte*>(program),
         static_cast<unsigned>(strlen(program)));
     i::CompleteParserRecorder log;
-    i::Scanner scanner(i::Isolate::Current()->unicode_cache());
+    i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
     scanner.Initialize(&stream);
 
-    // Flags don't allow natives syntax.
-    v8::preparser::PreParser::PreParseResult result =
-        v8::preparser::PreParser::PreParseProgram(&scanner,
-                                                  &log,
-                                                  i::kAllowLazy,
-                                                  stack_limit);
-    CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
-    i::ScriptDataImpl data(log.ExtractData());
-    // Data contains syntax error.
-    CHECK(data.has_error());
+    // Preparser defaults to disallowing natives syntax.
+    i::PreParser preparser(&scanner, &log, stack_limit);
+    preparser.set_allow_lazy(true);
+    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+    CHECK(log.HasError());
+  }
+}
+
+
+TEST(PreparsingObjectLiterals) {
+  // Regression test for a bug where the symbol stream produced by PreParser
+  // didn't match what Parser wanted to consume.
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handles(isolate);
+  v8::Local<v8::Context> context = v8::Context::New(isolate);
+  v8::Context::Scope context_scope(context);
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
+
+  {
+    const char* source = "var myo = {if: \"foo\"}; myo.if;";
+    v8::Local<v8::Value> result = ParserCacheCompileRun(source);
+    CHECK(result->IsString());
+    v8::String::Utf8Value utf8(result);
+    CHECK_EQ("foo", *utf8);
+  }
+
+  {
+    const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
+    v8::Local<v8::Value> result = ParserCacheCompileRun(source);
+    CHECK(result->IsString());
+    v8::String::Utf8Value utf8(result);
+    CHECK_EQ("foo", *utf8);
+  }
+
+  {
+    const char* source = "var myo = {1: \"foo\"}; myo[1];";
+    v8::Local<v8::Value> result = ParserCacheCompileRun(source);
+    CHECK(result->IsString());
+    v8::String::Utf8Value utf8(result);
+    CHECK_EQ("foo", *utf8);
   }
 }
 
 
 TEST(RegressChromium62639) {
   v8::V8::Initialize();
+  i::Isolate* isolate = CcTest::i_isolate();
 
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+  isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
+                                        128 * 1024);
 
   const char* program = "var x = 'something';\n"
                         "escape: function() {}";
@@ -329,41 +411,55 @@
   i::Utf8ToUtf16CharacterStream stream(
       reinterpret_cast<const i::byte*>(program),
       static_cast<unsigned>(strlen(program)));
-  i::ScriptDataImpl* data =
-      i::ParserApi::PreParse(&stream, NULL, false);
-  CHECK(data->HasError());
-  delete data;
+  i::CompleteParserRecorder log;
+  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+  scanner.Initialize(&stream);
+  i::PreParser preparser(&scanner, &log,
+                         CcTest::i_isolate()->stack_guard()->real_climit());
+  preparser.set_allow_lazy(true);
+  i::PreParser::PreParseResult result = preparser.PreParseProgram();
+  // Even in the case of a syntax error, kPreParseSuccess is returned.
+  CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+  CHECK(log.HasError());
 }
 
 
 TEST(Regress928) {
   v8::V8::Initialize();
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
 
   // Preparsing didn't consider the catch clause of a try statement
   // as with-content, which made it assume that a function inside
   // the block could be lazily compiled, and an extra, unexpected,
   // entry was added to the data.
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+  isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
+                                        128 * 1024);
 
   const char* program =
       "try { } catch (e) { var foo = function () { /* first */ } }"
       "var bar = function () { /* second */ }";
 
-  v8::HandleScope handles;
-  i::Handle<i::String> source(
-      FACTORY->NewStringFromAscii(i::CStrVector(program)));
-  i::ScriptDataImpl* data = i::ParserApi::PartialPreParse(source, NULL, false);
-  CHECK(!data->HasError());
-
-  data->Initialize();
+  v8::HandleScope handles(CcTest::isolate());
+  i::Handle<i::String> source = factory->NewStringFromAsciiChecked(program);
+  i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
+  i::CompleteParserRecorder log;
+  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+  scanner.Initialize(&stream);
+  i::PreParser preparser(&scanner, &log,
+                         CcTest::i_isolate()->stack_guard()->real_climit());
+  preparser.set_allow_lazy(true);
+  i::PreParser::PreParseResult result = preparser.PreParseProgram();
+  CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+  i::ScriptData* sd = log.GetScriptData();
+  i::ParseData pd(sd);
+  pd.Initialize();
 
   int first_function =
       static_cast<int>(strstr(program, "function") - program);
   int first_lbrace = first_function + i::StrLength("function () ");
   CHECK_EQ('{', program[first_lbrace]);
-  i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
+  i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
   CHECK(!entry1.is_valid());
 
   int second_function =
@@ -371,42 +467,38 @@
   int second_lbrace =
       second_function + i::StrLength("function () ");
   CHECK_EQ('{', program[second_lbrace]);
-  i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
+  i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
   CHECK(entry2.is_valid());
   CHECK_EQ('}', program[entry2.end_pos() - 1]);
-  delete data;
+  delete sd;
 }
 
 
 TEST(PreParseOverflow) {
   v8::V8::Initialize();
 
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
 
   size_t kProgramSize = 1024 * 1024;
-  i::SmartArrayPointer<char> program(
-      reinterpret_cast<char*>(malloc(kProgramSize + 1)));
-  memset(*program, '(', kProgramSize);
+  i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1));
+  memset(program.get(), '(', kProgramSize);
   program[kProgramSize] = '\0';
 
-  uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
+  uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
 
   i::Utf8ToUtf16CharacterStream stream(
-      reinterpret_cast<const i::byte*>(*program),
+      reinterpret_cast<const i::byte*>(program.get()),
       static_cast<unsigned>(kProgramSize));
   i::CompleteParserRecorder log;
-  i::Scanner scanner(i::Isolate::Current()->unicode_cache());
+  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
   scanner.Initialize(&stream);
 
-
-  v8::preparser::PreParser::PreParseResult result =
-      v8::preparser::PreParser::PreParseProgram(&scanner,
-                                                &log,
-                                                true,
-                                                stack_limit);
-  CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
+  i::PreParser preparser(&scanner, &log, stack_limit);
+  preparser.set_allow_lazy(true);
+  preparser.set_allow_arrow_functions(true);
+  i::PreParser::PreParseResult result = preparser.PreParseProgram();
+  CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
 }
 
 
@@ -432,29 +524,31 @@
 
 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
 
-void TestCharacterStream(const char* ascii_source,
-                         unsigned length,
-                         unsigned start = 0,
-                         unsigned end = 0) {
+void TestCharacterStream(const char* one_byte_source, unsigned length,
+                         unsigned start = 0, unsigned end = 0) {
   if (end == 0) end = length;
   unsigned sub_length = end - start;
-  i::HandleScope test_scope;
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope test_scope(isolate);
   i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
   for (unsigned i = 0; i < length; i++) {
-    uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
+    uc16_buffer[i] = static_cast<i::uc16>(one_byte_source[i]);
   }
-  i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
-  i::Handle<i::String> ascii_string(
-      FACTORY->NewStringFromAscii(ascii_vector));
-  TestExternalResource resource(*uc16_buffer, length);
+  i::Vector<const char> one_byte_vector(one_byte_source,
+                                        static_cast<int>(length));
+  i::Handle<i::String> one_byte_string =
+      factory->NewStringFromAscii(one_byte_vector).ToHandleChecked();
+  TestExternalResource resource(uc16_buffer.get(), length);
   i::Handle<i::String> uc16_string(
-      FACTORY->NewExternalStringFromTwoByte(&resource));
+      factory->NewExternalStringFromTwoByte(&resource).ToHandleChecked());
 
   i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
       i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
-  i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
+  i::GenericStringUtf16CharacterStream string_stream(one_byte_string, start,
+                                                     end);
   i::Utf8ToUtf16CharacterStream utf8_stream(
-      reinterpret_cast<const i::byte*>(ascii_source), end);
+      reinterpret_cast<const i::byte*>(one_byte_source), end);
   utf8_stream.SeekForward(start);
 
   unsigned i = start;
@@ -463,7 +557,7 @@
     CHECK_EQU(i, uc16_stream.pos());
     CHECK_EQU(i, string_stream.pos());
     CHECK_EQU(i, utf8_stream.pos());
-    int32_t c0 = ascii_source[i];
+    int32_t c0 = one_byte_source[i];
     int32_t c1 = uc16_stream.Advance();
     int32_t c2 = string_stream.Advance();
     int32_t c3 = utf8_stream.Advance();
@@ -477,7 +571,7 @@
   }
   while (i > start + sub_length / 4) {
     // Pushback, re-read, pushback again.
-    int32_t c0 = ascii_source[i - 1];
+    int32_t c0 = one_byte_source[i - 1];
     CHECK_EQU(i, uc16_stream.pos());
     CHECK_EQU(i, string_stream.pos());
     CHECK_EQU(i, utf8_stream.pos());
@@ -520,7 +614,7 @@
     CHECK_EQU(i, uc16_stream.pos());
     CHECK_EQU(i, string_stream.pos());
     CHECK_EQU(i, utf8_stream.pos());
-    int32_t c0 = ascii_source[i];
+    int32_t c0 = one_byte_source[i];
     int32_t c1 = uc16_stream.Advance();
     int32_t c2 = string_stream.Advance();
     int32_t c3 = utf8_stream.Advance();
@@ -543,8 +637,9 @@
 
 
 TEST(CharacterStreams) {
-  v8::HandleScope handles;
-  v8::Persistent<v8::Context> context = v8::Context::New();
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handles(isolate);
+  v8::Local<v8::Context> context = v8::Context::New(isolate);
   v8::Context::Scope context_scope(context);
 
   TestCharacterStream("abc\0\n\r\x7f", 7);
@@ -580,7 +675,7 @@
                                     i,
                                     unibrow::Utf16::kNoPreviousCharacter);
   }
-  ASSERT(cursor == kAllUtf8CharsSizeU);
+  DCHECK(cursor == kAllUtf8CharsSizeU);
 
   i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
                                        kAllUtf8CharsSizeU);
@@ -617,7 +712,7 @@
                        i::Token::Value* expected_tokens,
                        int skip_pos = 0,  // Zero means not skipping.
                        int skip_to = 0) {
-  i::Scanner scanner(i::Isolate::Current()->unicode_cache());
+  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
   scanner.Initialize(stream);
 
   int i = 0;
@@ -632,6 +727,7 @@
   } while (expected_tokens[i] != i::Token::ILLEGAL);
 }
 
+
 TEST(StreamScanner) {
   v8::V8::Initialize();
 
@@ -668,8 +764,8 @@
       i::Token::EOS,
       i::Token::ILLEGAL
   };
-  ASSERT_EQ('{', str2[19]);
-  ASSERT_EQ('}', str2[37]);
+  DCHECK_EQ('{', str2[19]);
+  DCHECK_EQ('}', str2[37]);
   TestStreamScanner(&stream2, expectations2, 20, 37);
 
   const char* str3 = "{}}}}";
@@ -698,15 +794,24 @@
   i::Utf8ToUtf16CharacterStream stream(
        reinterpret_cast<const i::byte*>(re_source),
        static_cast<unsigned>(strlen(re_source)));
-  i::Scanner scanner(i::Isolate::Current()->unicode_cache());
+  i::HandleScope scope(CcTest::i_isolate());
+  i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
   scanner.Initialize(&stream);
 
   i::Token::Value start = scanner.peek();
   CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
   CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
   scanner.Next();  // Current token is now the regexp literal.
-  CHECK(scanner.is_literal_ascii());
-  i::Vector<const char> actual = scanner.literal_ascii_string();
+  i::Zone zone(CcTest::i_isolate());
+  i::AstValueFactory ast_value_factory(&zone,
+                                       CcTest::i_isolate()->heap()->HashSeed());
+  ast_value_factory.Internalize(CcTest::i_isolate());
+  i::Handle<i::String> val =
+      scanner.CurrentSymbol(&ast_value_factory)->string();
+  i::DisallowHeapAllocation no_alloc;
+  i::String::FlatContent content = val->GetFlatContent();
+  CHECK(content.IsOneByte());
+  i::Vector<const uint8_t> actual = content.ToOneByteVector();
   for (int i = 0; i < actual.length(); i++) {
     CHECK_NE('\0', expected[i]);
     CHECK_EQ(expected[i], actual[i]);
@@ -813,6 +918,8 @@
 
 
 TEST(ScopePositions) {
+  v8::internal::FLAG_harmony_scoping = true;
+
   // Test the parser for correctly setting the start and end positions
   // of a scope. We check the scope positions of exactly one scope
   // nested in the global scope of a program. 'inner source' is the
@@ -824,177 +931,184 @@
     const char* inner_source;
     const char* outer_suffix;
     i::ScopeType scope_type;
-    i::LanguageMode language_mode;
+    i::StrictMode strict_mode;
   };
 
   const SourceData source_data[] = {
-    { "  with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
-    { "  with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+    { "  with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::SLOPPY },
+    { "  with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::SLOPPY },
     { "  with ({}) ", "{\n"
       "    block;\n"
       "  }", "\n"
-      "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
-    { "  with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+      "  more;", i::WITH_SCOPE, i::SLOPPY },
+    { "  with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::SLOPPY },
     { "  with ({}) ", "statement", "\n"
-      "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+      "  more;", i::WITH_SCOPE, i::SLOPPY },
     { "  with ({})\n"
       "    ", "statement;", "\n"
-      "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
+      "  more;", i::WITH_SCOPE, i::SLOPPY },
     { "  try {} catch ", "(e) { block; }", " more;",
-      i::CATCH_SCOPE, i::CLASSIC_MODE },
+      i::CATCH_SCOPE, i::SLOPPY },
     { "  try {} catch ", "(e) { block; }", "; more;",
-      i::CATCH_SCOPE, i::CLASSIC_MODE },
+      i::CATCH_SCOPE, i::SLOPPY },
     { "  try {} catch ", "(e) {\n"
       "    block;\n"
       "  }", "\n"
-      "  more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
+      "  more;", i::CATCH_SCOPE, i::SLOPPY },
     { "  try {} catch ", "(e) { block; }", " finally { block; } more;",
-      i::CATCH_SCOPE, i::CLASSIC_MODE },
+      i::CATCH_SCOPE, i::SLOPPY },
     { "  start;\n"
-      "  ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::STRICT },
     { "  start;\n"
-      "  ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::STRICT },
     { "  start;\n"
       "  ", "{\n"
       "    let block;\n"
       "  }", "\n"
-      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  more;", i::BLOCK_SCOPE, i::STRICT },
     { "  start;\n"
       "  function fun", "(a,b) { infunction; }", " more;",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     { "  start;\n"
       "  function fun", "(a,b) {\n"
       "    infunction;\n"
       "  }", "\n"
-      "  more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
-    { "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      "  more;", i::FUNCTION_SCOPE, i::SLOPPY },
+    // TODO(aperez): Change to use i::ARROW_SCOPE when implemented
+    { "  start;\n", "(a,b) => a + b", "; more;",
+      i::FUNCTION_SCOPE, i::SLOPPY },
+    { "  start;\n", "(a,b) => { return a+b; }", "\nmore;",
+      i::FUNCTION_SCOPE, i::SLOPPY },
+    { "  start;\n"
+      "  (function fun", "(a,b) { infunction; }", ")();",
+      i::FUNCTION_SCOPE, i::SLOPPY },
     { "  for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
-      i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
-      i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x = 1 ; x < 10; ++ x) {\n"
       "    block;\n"
       "  }", "\n"
-      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  more;", i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
-      i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
-      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  more;", i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x = 1 ; x < 10; ++ x)\n"
       "    statement;", "\n"
-      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  more;", i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x in {}) { block; }", " more;",
-      i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x in {}) { block; }", "; more;",
-      i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x in {}) {\n"
       "    block;\n"
       "  }", "\n"
-      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  more;", i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x in {}) statement;", " more;",
-      i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x in {}) statement", "\n"
-      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  more;", i::BLOCK_SCOPE, i::STRICT },
     { "  for ", "(let x in {})\n"
       "    statement;", "\n"
-      "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+      "  more;", i::BLOCK_SCOPE, i::STRICT },
     // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
     // the preparser off in terms of byte offsets.
     // 6 byte encoding.
     { "  'foo\355\240\201\355\260\211';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // 4 byte encoding.
     { "  'foo\360\220\220\212';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // 3 byte encoding of \u0fff.
     { "  'foo\340\277\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Broken 6 byte encoding with missing last byte.
     { "  'foo\355\240\201\355\211';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Broken 3 byte encoding of \u0fff with missing last byte.
     { "  'foo\340\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
     { "  'foo\340';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
     { "  'foo\340\203\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
     { "  'foo\340\201\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Unpaired lead surrogate.
     { "  'foo\355\240\201';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Unpaired lead surrogate where following code point is a 3 byte sequence.
     { "  'foo\355\240\201\340\277\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Unpaired lead surrogate where following code point is a 4 byte encoding
     // of a trail surrogate.
     { "  'foo\355\240\201\360\215\260\211';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Unpaired trail surrogate.
     { "  'foo\355\260\211';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // 2 byte encoding of \u00ff.
     { "  'foo\303\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Broken 2 byte encoding of \u00ff with missing last byte.
     { "  'foo\303';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
     { "  'foo\301\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Illegal 5 byte encoding.
     { "  'foo\370\277\277\277\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Illegal 6 byte encoding.
     { "  'foo\374\277\277\277\277\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Illegal 0xfe byte
     { "  'foo\376\277\277\277\277\277\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     // Illegal 0xff byte
     { "  'foo\377\277\277\277\277\277\277\277';\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     { "  'foo';\n"
       "  (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+      i::FUNCTION_SCOPE, i::SLOPPY },
     { "  'foo';\n"
       "  (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
-      i::FUNCTION_SCOPE, i::CLASSIC_MODE },
-    { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
+      i::FUNCTION_SCOPE, i::SLOPPY },
+    { NULL, NULL, NULL, i::EVAL_SCOPE, i::SLOPPY }
   };
 
-  v8::HandleScope handles;
-  v8::Persistent<v8::Context> context = v8::Context::New();
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+
+  v8::HandleScope handles(CcTest::isolate());
+  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
   v8::Context::Scope context_scope(context);
 
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
-  i::FLAG_harmony_scoping = true;
+  isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
+                                        128 * 1024);
 
   for (int i = 0; source_data[i].outer_prefix; i++) {
     int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
@@ -1005,33 +1119,39 @@
     int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
     int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
     int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
-    i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
-    i::OS::SNPrintF(program, "%s%s%s",
-                             source_data[i].outer_prefix,
-                             source_data[i].inner_source,
-                             source_data[i].outer_suffix);
+    i::ScopedVector<char> program(kProgramByteSize + 1);
+    i::SNPrintF(program, "%s%s%s",
+                         source_data[i].outer_prefix,
+                         source_data[i].inner_source,
+                         source_data[i].outer_suffix);
 
     // Parse program source.
-    i::Handle<i::String> source(
-        FACTORY->NewStringFromUtf8(i::CStrVector(program.start())));
+    i::Handle<i::String> source = factory->NewStringFromUtf8(
+        i::CStrVector(program.start())).ToHandleChecked();
     CHECK_EQ(source->length(), kProgramSize);
-    i::Handle<i::Script> script = FACTORY->NewScript(source);
-    i::Parser parser(script, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
-    i::CompilationInfo info(script);
+    i::Handle<i::Script> script = factory->NewScript(source);
+    i::CompilationInfoWithZone info(script);
+    i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
+                                       isolate->heap()->HashSeed(),
+                                       isolate->unicode_cache()};
+    i::Parser parser(&info, &parse_info);
+    parser.set_allow_lazy(true);
+    parser.set_allow_harmony_scoping(true);
+    parser.set_allow_arrow_functions(true);
     info.MarkAsGlobal();
-    info.SetLanguageMode(source_data[i].language_mode);
-    i::FunctionLiteral* function = parser.ParseProgram(&info);
-    CHECK(function != NULL);
+    info.SetStrictMode(source_data[i].strict_mode);
+    parser.Parse();
+    CHECK(info.function() != NULL);
 
     // Check scope types and positions.
-    i::Scope* scope = function->scope();
+    i::Scope* scope = info.function()->scope();
     CHECK(scope->is_global_scope());
     CHECK_EQ(scope->start_position(), 0);
     CHECK_EQ(scope->end_position(), kProgramSize);
     CHECK_EQ(scope->inner_scopes()->length(), 1);
 
     i::Scope* inner_scope = scope->inner_scopes()->at(0);
-    CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
+    CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
     CHECK_EQ(inner_scope->start_position(), kPrefixLen);
     // The end position of a token is one position after the last
     // character belonging to that token.
@@ -1040,96 +1160,212 @@
 }
 
 
-void TestParserSync(i::Handle<i::String> source, int flags) {
-  uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
-  bool harmony_scoping = ((i::kLanguageModeMask & flags) == i::EXTENDED_MODE);
+const char* ReadString(unsigned* start) {
+  int length = start[0];
+  char* result = i::NewArray<char>(length + 1);
+  for (int i = 0; i < length; i++) {
+    result[i] = start[i + 1];
+  }
+  result[length] = '\0';
+  return result;
+}
+
+
+i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  const char* message =
+      ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
+  i::Handle<i::String> format = v8::Utils::OpenHandle(
+      *v8::String::NewFromUtf8(CcTest::isolate(), message));
+  int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
+  const char* arg = NULL;
+  i::Handle<i::JSArray> args_array;
+  if (arg_count == 1) {
+    // Position after text found by skipping past length field and
+    // length field content words.
+    int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
+              data[i::PreparseDataConstants::kMessageTextPos];
+    arg = ReadString(&data[pos]);
+    args_array = factory->NewJSArray(1);
+    i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
+                           NONE, i::SLOPPY).Check();
+  } else {
+    CHECK_EQ(0, arg_count);
+    args_array = factory->NewJSArray(0);
+  }
+
+  i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
+  i::Handle<i::Object> format_fun = i::Object::GetProperty(
+      isolate, builtins, "FormatMessage").ToHandleChecked();
+  i::Handle<i::Object> arg_handles[] = { format, args_array };
+  i::Handle<i::Object> result = i::Execution::Call(
+      isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked();
+  CHECK(result->IsString());
+  i::DeleteArray(message);
+  i::DeleteArray(arg);
+  data.Dispose();
+  return i::Handle<i::String>::cast(result);
+}
+
+
+enum ParserFlag {
+  kAllowLazy,
+  kAllowNativesSyntax,
+  kAllowHarmonyScoping,
+  kAllowModules,
+  kAllowHarmonyNumericLiterals,
+  kAllowArrowFunctions,
+  kAllowClasses,
+  kAllowHarmonyObjectLiterals
+};
+
+
+enum ParserSyncTestResult {
+  kSuccessOrError,
+  kSuccess,
+  kError
+};
+
+template <typename Traits>
+void SetParserFlags(i::ParserBase<Traits>* parser,
+                    i::EnumSet<ParserFlag> flags) {
+  parser->set_allow_lazy(flags.Contains(kAllowLazy));
+  parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
+  parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
+  parser->set_allow_modules(flags.Contains(kAllowModules));
+  parser->set_allow_harmony_numeric_literals(
+      flags.Contains(kAllowHarmonyNumericLiterals));
+  parser->set_allow_harmony_object_literals(
+      flags.Contains(kAllowHarmonyObjectLiterals));
+  parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions));
+  parser->set_allow_classes(flags.Contains(kAllowClasses));
+}
+
+
+void TestParserSyncWithFlags(i::Handle<i::String> source,
+                             i::EnumSet<ParserFlag> flags,
+                             ParserSyncTestResult result) {
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+
+  uintptr_t stack_limit = isolate->stack_guard()->real_climit();
 
   // Preparse the data.
   i::CompleteParserRecorder log;
-  i::Scanner scanner(i::Isolate::Current()->unicode_cache());
-  i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
-  scanner.SetHarmonyScoping(harmony_scoping);
-  scanner.Initialize(&stream);
-  v8::preparser::PreParser::PreParseResult result =
-      v8::preparser::PreParser::PreParseProgram(
-          &scanner, &log, flags, stack_limit);
-  CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
-  i::ScriptDataImpl data(log.ExtractData());
+  {
+    i::Scanner scanner(isolate->unicode_cache());
+    i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
+    i::PreParser preparser(&scanner, &log, stack_limit);
+    SetParserFlags(&preparser, flags);
+    scanner.Initialize(&stream);
+    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+  }
+
+  bool preparse_error = log.HasError();
 
   // Parse the data
-  i::Handle<i::Script> script = FACTORY->NewScript(source);
-  bool save_harmony_scoping = i::FLAG_harmony_scoping;
-  i::FLAG_harmony_scoping = harmony_scoping;
-  i::Parser parser(script, flags, NULL, NULL);
-  i::CompilationInfo info(script);
-  info.MarkAsGlobal();
-  i::FunctionLiteral* function = parser.ParseProgram(&info);
-  i::FLAG_harmony_scoping = save_harmony_scoping;
-
-  i::String* type_string = NULL;
-  if (function == NULL) {
-    // Extract exception from the parser.
-    i::Handle<i::String> type_symbol = FACTORY->LookupAsciiSymbol("type");
-    CHECK(i::Isolate::Current()->has_pending_exception());
-    i::MaybeObject* maybe_object = i::Isolate::Current()->pending_exception();
-    i::JSObject* exception = NULL;
-    CHECK(maybe_object->To(&exception));
-
-    // Get the type string.
-    maybe_object = exception->GetProperty(*type_symbol);
-    CHECK(maybe_object->To(&type_string));
+  i::FunctionLiteral* function;
+  {
+    i::Handle<i::Script> script = factory->NewScript(source);
+    i::CompilationInfoWithZone info(script);
+    i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
+                                       isolate->heap()->HashSeed(),
+                                       isolate->unicode_cache()};
+    i::Parser parser(&info, &parse_info);
+    SetParserFlags(&parser, flags);
+    info.MarkAsGlobal();
+    parser.Parse();
+    function = info.function();
   }
 
   // Check that preparsing fails iff parsing fails.
-  if (data.has_error() && function != NULL) {
-    i::OS::Print(
-        "Preparser failed on:\n"
-        "\t%s\n"
-        "with error:\n"
-        "\t%s\n"
-        "However, the parser succeeded",
-        *source->ToCString(), data.BuildMessage());
-    CHECK(false);
-  } else if (!data.has_error() && function == NULL) {
-    i::OS::Print(
-        "Parser failed on:\n"
-        "\t%s\n"
-        "with error:\n"
-        "\t%s\n"
-        "However, the preparser succeeded",
-        *source->ToCString(), *type_string->ToCString());
-    CHECK(false);
-  }
-
-  // Check that preparser and parser produce the same error.
   if (function == NULL) {
-    if (!type_string->IsEqualTo(i::CStrVector(data.BuildMessage()))) {
-      i::OS::Print(
+    // Extract exception from the parser.
+    CHECK(isolate->has_pending_exception());
+    i::Handle<i::JSObject> exception_handle(
+        i::JSObject::cast(isolate->pending_exception()));
+    i::Handle<i::String> message_string =
+        i::Handle<i::String>::cast(i::Object::GetProperty(
+            isolate, exception_handle, "message").ToHandleChecked());
+
+    if (result == kSuccess) {
+      v8::base::OS::Print(
+          "Parser failed on:\n"
+          "\t%s\n"
+          "with error:\n"
+          "\t%s\n"
+          "However, we expected no error.",
+          source->ToCString().get(), message_string->ToCString().get());
+      CHECK(false);
+    }
+
+    if (!preparse_error) {
+      v8::base::OS::Print(
+          "Parser failed on:\n"
+          "\t%s\n"
+          "with error:\n"
+          "\t%s\n"
+          "However, the preparser succeeded",
+          source->ToCString().get(), message_string->ToCString().get());
+      CHECK(false);
+    }
+    // Check that preparser and parser produce the same error.
+    i::Handle<i::String> preparser_message =
+        FormatMessage(log.ErrorMessageData());
+    if (!i::String::Equals(message_string, preparser_message)) {
+      v8::base::OS::Print(
           "Expected parser and preparser to produce the same error on:\n"
           "\t%s\n"
           "However, found the following error messages\n"
           "\tparser:    %s\n"
           "\tpreparser: %s\n",
-          *source->ToCString(), *type_string->ToCString(), data.BuildMessage());
+          source->ToCString().get(),
+          message_string->ToCString().get(),
+          preparser_message->ToCString().get());
       CHECK(false);
     }
+  } else if (preparse_error) {
+    v8::base::OS::Print(
+        "Preparser failed on:\n"
+        "\t%s\n"
+        "with error:\n"
+        "\t%s\n"
+        "However, the parser succeeded",
+        source->ToCString().get(),
+        FormatMessage(log.ErrorMessageData())->ToCString().get());
+    CHECK(false);
+  } else if (result == kError) {
+    v8::base::OS::Print(
+        "Expected error on:\n"
+        "\t%s\n"
+        "However, parser and preparser succeeded",
+        source->ToCString().get());
+    CHECK(false);
   }
 }
 
 
-void TestParserSyncWithFlags(i::Handle<i::String> source) {
-  static const int kFlagsCount = 6;
-  const int flags[kFlagsCount] = {
-    i::kNoParsingFlags | i::CLASSIC_MODE,
-    i::kNoParsingFlags | i::STRICT_MODE,
-    i::kNoParsingFlags | i::EXTENDED_MODE,
-    i::kAllowLazy | i::CLASSIC_MODE,
-    i::kAllowLazy | i::STRICT_MODE,
-    i::kAllowLazy | i::EXTENDED_MODE
-  };
-
-  for (int k = 0; k < kFlagsCount; ++k) {
-    TestParserSync(source, flags[k]);
+void TestParserSync(const char* source,
+                    const ParserFlag* varying_flags,
+                    size_t varying_flags_length,
+                    ParserSyncTestResult result = kSuccessOrError,
+                    const ParserFlag* always_true_flags = NULL,
+                    size_t always_true_flags_length = 0) {
+  i::Handle<i::String> str =
+      CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
+  for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
+    i::EnumSet<ParserFlag> flags;
+    for (size_t flag_index = 0; flag_index < varying_flags_length;
+         ++flag_index) {
+      if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]);
+    }
+    for (size_t flag_index = 0; flag_index < always_true_flags_length;
+         ++flag_index) {
+      flags.Add(always_true_flags[flag_index]);
+    }
+    TestParserSyncWithFlags(str, flags, result);
   }
 }
 
@@ -1147,6 +1383,7 @@
     { "with ({})", "" },
     { "switch (12) { case 12: ", "}" },
     { "switch (12) { default: ", "}" },
+    { "switch (12) { ", "case 12: }" },
     { "label2: ", "" },
     { NULL, NULL }
   };
@@ -1175,9 +1412,10 @@
     "break",
     "break label",
     "break\nlabel",
-    "return",
-    "return  12",
-    "return\n12",
+    // TODO(marja): activate once parsing 'return' is merged into ParserBase.
+    // "return",
+    // "return  12",
+    // "return\n12",
     "with ({}) ;",
     "with ({}) {}",
     "with ({}) 12",
@@ -1202,13 +1440,22 @@
     NULL
   };
 
-  v8::HandleScope handles;
-  v8::Persistent<v8::Context> context = v8::Context::New();
+  v8::HandleScope handles(CcTest::isolate());
+  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
   v8::Context::Scope context_scope(context);
 
-  int marker;
-  i::Isolate::Current()->stack_guard()->SetStackLimit(
-      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
+
+  static const ParserFlag flags1[] = {
+    kAllowArrowFunctions,
+    kAllowClasses,
+    kAllowHarmonyNumericLiterals,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonyScoping,
+    kAllowLazy,
+    kAllowModules,
+  };
 
   for (int i = 0; context_data[i][0] != NULL; ++i) {
     for (int j = 0; statement_data[j] != NULL; ++j) {
@@ -1221,18 +1468,2504 @@
             + kSuffixLen + i::StrLength("label: for (;;) {  }");
 
         // Plug the source code pieces together.
-        i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
-        int length = i::OS::SNPrintF(program,
+        i::ScopedVector<char> program(kProgramSize + 1);
+        int length = i::SNPrintF(program,
             "label: for (;;) { %s%s%s%s }",
             context_data[i][0],
             statement_data[j],
             termination_data[k],
             context_data[i][1]);
         CHECK(length == kProgramSize);
-        i::Handle<i::String> source =
-            FACTORY->NewStringFromAscii(i::CStrVector(program.start()));
-        TestParserSyncWithFlags(source);
+        TestParserSync(program.start(), flags1, arraysize(flags1));
       }
     }
   }
+
+  // Neither Harmony numeric literals nor our natives syntax have any
+  // interaction with the flags above, so test these separately to reduce
+  // the combinatorial explosion.
+  static const ParserFlag flags2[] = { kAllowHarmonyNumericLiterals };
+  TestParserSync("0o1234", flags2, arraysize(flags2));
+  TestParserSync("0b1011", flags2, arraysize(flags2));
+
+  static const ParserFlag flags3[] = { kAllowNativesSyntax };
+  TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
+}
+
+
+TEST(StrictOctal) {
+  // Test that syntax error caused by octal literal is reported correctly as
+  // such (issue 2220).
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Context::Scope context_scope(
+      v8::Context::New(CcTest::isolate()));
+  v8::TryCatch try_catch;
+  const char* script =
+      "\"use strict\";       \n"
+      "a = function() {      \n"
+      "  b = function() {    \n"
+      "    01;               \n"
+      "  };                  \n"
+      "};                    \n";
+  v8::Script::Compile(v8::String::NewFromUtf8(CcTest::isolate(), script));
+  CHECK(try_catch.HasCaught());
+  v8::String::Utf8Value exception(try_catch.Exception());
+  CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
+           *exception);
+}
+
+
+void RunParserSyncTest(const char* context_data[][2],
+                       const char* statement_data[],
+                       ParserSyncTestResult result,
+                       const ParserFlag* flags = NULL,
+                       int flags_len = 0,
+                       const ParserFlag* always_true_flags = NULL,
+                       int always_true_flags_len = 0) {
+  v8::HandleScope handles(CcTest::isolate());
+  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
+  v8::Context::Scope context_scope(context);
+
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
+
+  static const ParserFlag default_flags[] = {
+    kAllowArrowFunctions,
+    kAllowClasses,
+    kAllowHarmonyNumericLiterals,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonyScoping,
+    kAllowLazy,
+    kAllowModules,
+    kAllowNativesSyntax,
+  };
+  ParserFlag* generated_flags = NULL;
+  if (flags == NULL) {
+    flags = default_flags;
+    flags_len = arraysize(default_flags);
+    if (always_true_flags != NULL) {
+      // Remove always_true_flags from default_flags.
+      CHECK(always_true_flags_len < flags_len);
+      generated_flags = new ParserFlag[flags_len - always_true_flags_len];
+      int flag_index = 0;
+      for (int i = 0; i < flags_len; ++i) {
+        bool use_flag = true;
+        for (int j = 0; j < always_true_flags_len; ++j) {
+          if (flags[i] == always_true_flags[j]) {
+            use_flag = false;
+            break;
+          }
+        }
+        if (use_flag) generated_flags[flag_index++] = flags[i];
+      }
+      CHECK(flag_index == flags_len - always_true_flags_len);
+      flags_len = flag_index;
+      flags = generated_flags;
+    }
+  }
+  for (int i = 0; context_data[i][0] != NULL; ++i) {
+    for (int j = 0; statement_data[j] != NULL; ++j) {
+      int kPrefixLen = i::StrLength(context_data[i][0]);
+      int kStatementLen = i::StrLength(statement_data[j]);
+      int kSuffixLen = i::StrLength(context_data[i][1]);
+      int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
+
+      // Plug the source code pieces together.
+      i::ScopedVector<char> program(kProgramSize + 1);
+      int length = i::SNPrintF(program,
+                               "%s%s%s",
+                               context_data[i][0],
+                               statement_data[j],
+                               context_data[i][1]);
+      CHECK(length == kProgramSize);
+      TestParserSync(program.start(),
+                     flags,
+                     flags_len,
+                     result,
+                     always_true_flags,
+                     always_true_flags_len);
+    }
+  }
+  delete[] generated_flags;
+}
+
+
+TEST(ErrorsEvalAndArguments) {
+  // Tests that both preparsing and parsing produce the right kind of errors for
+  // using "eval" and "arguments" as identifiers. Without the strict mode, it's
+  // ok to use "eval" or "arguments" as identifiers. With the strict mode, it
+  // isn't.
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "var eval; function test_func() {\"use strict\"; ", "}"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var eval;",
+    "var arguments",
+    "var foo, eval;",
+    "var foo, arguments;",
+    "try { } catch (eval) { }",
+    "try { } catch (arguments) { }",
+    "function eval() { }",
+    "function arguments() { }",
+    "function foo(eval) { }",
+    "function foo(arguments) { }",
+    "function foo(bar, eval) { }",
+    "function foo(bar, arguments) { }",
+    "(eval) => { }",
+    "(arguments) => { }",
+    "(foo, eval) => { }",
+    "(foo, arguments) => { }",
+    "eval = 1;",
+    "arguments = 1;",
+    "var foo = eval = 1;",
+    "var foo = arguments = 1;",
+    "++eval;",
+    "++arguments;",
+    "eval++;",
+    "arguments++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsEvalAndArgumentsSloppy) {
+  // Tests that both preparsing and parsing accept "eval" and "arguments" as
+  // identifiers when needed.
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function test_func() {", "}"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var eval;",
+    "var arguments",
+    "var foo, eval;",
+    "var foo, arguments;",
+    "try { } catch (eval) { }",
+    "try { } catch (arguments) { }",
+    "function eval() { }",
+    "function arguments() { }",
+    "function foo(eval) { }",
+    "function foo(arguments) { }",
+    "function foo(bar, eval) { }",
+    "function foo(bar, arguments) { }",
+    "eval = 1;",
+    "arguments = 1;",
+    "var foo = eval = 1;",
+    "var foo = arguments = 1;",
+    "++eval;",
+    "++arguments;",
+    "eval++;",
+    "arguments++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(NoErrorsEvalAndArgumentsStrict) {
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "function test_func() { \"use strict\";", "}" },
+    { "() => { \"use strict\"; ", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "eval;",
+    "arguments;",
+    "var foo = eval;",
+    "var foo = arguments;",
+    "var foo = { eval: 1 };",
+    "var foo = { arguments: 1 };",
+    "var foo = { }; foo.eval = {};",
+    "var foo = { }; foo.arguments = {};",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ErrorsFutureStrictReservedWords) {
+  // Tests that both preparsing and parsing produce the right kind of errors for
+  // using future strict reserved words as identifiers. Without the strict mode,
+  // it's ok to use future strict reserved words as identifiers. With the strict
+  // mode, it isn't.
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "function test_func() {\"use strict\"; ", "}"},
+    { "() => { \"use strict\"; ", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var interface;",
+    "var foo, interface;",
+    "try { } catch (interface) { }",
+    "function interface() { }",
+    "function foo(interface) { }",
+    "function foo(bar, interface) { }",
+    "interface = 1;",
+    "var foo = interface = 1;",
+    "++interface;",
+    "interface++;",
+    "var yield = 13;",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(NoErrorsFutureStrictReservedWords) {
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function test_func() {", "}"},
+    { "() => {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var interface;",
+    "var foo, interface;",
+    "try { } catch (interface) { }",
+    "function interface() { }",
+    "function foo(interface) { }",
+    "function foo(bar, interface) { }",
+    "interface = 1;",
+    "var foo = interface = 1;",
+    "++interface;",
+    "interface++;",
+    "var yield = 13;",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ErrorsReservedWords) {
+  // Tests that both preparsing and parsing produce the right kind of errors for
+  // using future reserved words as identifiers. These tests don't depend on the
+  // strict mode.
+  const char* context_data[][2] = {
+    { "", "" },
+    { "\"use strict\";", "" },
+    { "var eval; function test_func() {", "}"},
+    { "var eval; function test_func() {\"use strict\"; ", "}"},
+    { "var eval; () => {", "}"},
+    { "var eval; () => {\"use strict\"; ", "}"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var super;",
+    "var foo, super;",
+    "try { } catch (super) { }",
+    "function super() { }",
+    "function foo(super) { }",
+    "function foo(bar, super) { }",
+    "(super) => { }",
+    "(bar, super) => { }",
+    "super = 1;",
+    "var foo = super = 1;",
+    "++super;",
+    "super++;",
+    "function foo super",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsLetSloppyAllModes) {
+  // In sloppy mode, it's okay to use "let" as identifier.
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function f() {", "}" },
+    { "(function f() {", "})" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var let;",
+    "var foo, let;",
+    "try { } catch (let) { }",
+    "function let() { }",
+    "(function let() { })",
+    "function foo(let) { }",
+    "function foo(bar, let) { }",
+    "let = 1;",
+    "var foo = let = 1;",
+    "let * 2;",
+    "++let;",
+    "let++;",
+    "let: 34",
+    "function let(let) { let: let(let + let(0)); }",
+    "({ let: 1 })",
+    "({ get let() { 1 } })",
+    "let(100)",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(NoErrorsYieldSloppyAllModes) {
+  // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
+  // generator (see other test).
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function not_gen() {", "}" },
+    { "(function not_gen() {", "})" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var yield;",
+    "var foo, yield;",
+    "try { } catch (yield) { }",
+    "function yield() { }",
+    "(function yield() { })",
+    "function foo(yield) { }",
+    "function foo(bar, yield) { }",
+    "yield = 1;",
+    "var foo = yield = 1;",
+    "yield * 2;",
+    "++yield;",
+    "yield++;",
+    "yield: 34",
+    "function yield(yield) { yield: yield (yield + yield(0)); }",
+    "({ yield: 1 })",
+    "({ get yield() { 1 } })",
+    "yield(100)",
+    "yield[100]",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(NoErrorsYieldSloppyGeneratorsEnabled) {
+  // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a
+  // generator (see next test).
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function not_gen() {", "}" },
+    { "function * gen() { function not_gen() {", "} }" },
+    { "(function not_gen() {", "})" },
+    { "(function * gen() { (function not_gen() {", "}) })" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var yield;",
+    "var foo, yield;",
+    "try { } catch (yield) { }",
+    "function yield() { }",
+    "(function yield() { })",
+    "function foo(yield) { }",
+    "function foo(bar, yield) { }",
+    "function * yield() { }",
+    "(function * yield() { })",
+    "yield = 1;",
+    "var foo = yield = 1;",
+    "yield * 2;",
+    "++yield;",
+    "yield++;",
+    "yield: 34",
+    "function yield(yield) { yield: yield (yield + yield(0)); }",
+    "({ yield: 1 })",
+    "({ get yield() { 1 } })",
+    "yield(100)",
+    "yield[100]",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsYieldStrict) {
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "\"use strict\"; function not_gen() {", "}" },
+    { "function test_func() {\"use strict\"; ", "}"},
+    { "\"use strict\"; function * gen() { function not_gen() {", "} }" },
+    { "\"use strict\"; (function not_gen() {", "})" },
+    { "\"use strict\"; (function * gen() { (function not_gen() {", "}) })" },
+    { "() => {\"use strict\"; ", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var yield;",
+    "var foo, yield;",
+    "try { } catch (yield) { }",
+    "function yield() { }",
+    "(function yield() { })",
+    "function foo(yield) { }",
+    "function foo(bar, yield) { }",
+    "function * yield() { }",
+    "(function * yield() { })",
+    "yield = 1;",
+    "var foo = yield = 1;",
+    "++yield;",
+    "yield++;",
+    "yield: 34;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsGenerator) {
+  const char* context_data[][2] = {
+    { "function * gen() {", "}" },
+    { "(function * gen() {", "})" },
+    { "(function * () {", "})" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    // A generator without a body is valid.
+    ""
+    // Valid yield expressions inside generators.
+    "yield 2;",
+    "yield * 2;",
+    "yield * \n 2;",
+    "yield yield 1;",
+    "yield * yield * 1;",
+    "yield 3 + (yield 4);",
+    "yield * 3 + (yield * 4);",
+    "(yield * 3) + (yield * 4);",
+    "yield 3; yield 4;",
+    "yield * 3; yield * 4;",
+    "(function (yield) { })",
+    "yield { yield: 12 }",
+    "yield /* comment */ { yield: 12 }",
+    "yield * \n { yield: 12 }",
+    "yield /* comment */ * \n { yield: 12 }",
+    // You can return in a generator.
+    "yield 1; return",
+    "yield * 1; return",
+    "yield 1; return 37",
+    "yield * 1; return 37",
+    "yield 1; return 37; yield 'dead';",
+    "yield * 1; return 37; yield * 'dead';",
+    // Yield is still a valid key in object literals.
+    "({ yield: 1 })",
+    "({ get yield() { } })",
+    // Yield without RHS.
+    "yield;",
+    "yield",
+    "yield\n",
+    "yield /* comment */"
+    "yield // comment\n"
+    "(yield)",
+    "[yield]",
+    "{yield}",
+    "yield, yield",
+    "yield; yield",
+    "(yield) ? yield : yield",
+    "(yield) \n ? yield : yield",
+    // If there is a newline before the next token, we don't look for RHS.
+    "yield\nfor (;;) {}",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsYieldGenerator) {
+  const char* context_data[][2] = {
+    { "function * gen() {", "}" },
+    { "\"use strict\"; function * gen() {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    // Invalid yield expressions inside generators.
+    "var yield;",
+    "var foo, yield;",
+    "try { } catch (yield) { }",
+    "function yield() { }",
+    // The name of the NFE is let-bound in the generator, which does not permit
+    // yield to be an identifier.
+    "(function yield() { })",
+    "(function * yield() { })",
+    // Yield isn't valid as a formal parameter for generators.
+    "function * foo(yield) { }",
+    "(function * foo(yield) { })",
+    "yield = 1;",
+    "var foo = yield = 1;",
+    "++yield;",
+    "yield++;",
+    "yield *",
+    "(yield *)",
+    // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which
+    // is invalid.
+    "yield 3 + yield 4;",
+    "yield: 34",
+    "yield ? 1 : 2",
+    // Parses as yield (/ yield): invalid.
+    "yield / yield",
+    "+ yield",
+    "+ yield 3",
+    // Invalid (no newline allowed between yield and *).
+    "yield\n*3",
+    // Invalid (we see a newline, so we parse {yield:42} as a statement, not an
+    // object literal, and yield is not a valid label).
+    "yield\n{yield: 42}",
+    "yield /* comment */\n {yield: 42}",
+    "yield //comment\n {yield: 42}",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsNameOfStrictFunction) {
+  // Tests that illegal tokens as names of a strict function produce the correct
+  // errors.
+  const char* context_data[][2] = {
+    { "function ", ""},
+    { "\"use strict\"; function", ""},
+    { "function * ", ""},
+    { "\"use strict\"; function * ", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "eval() {\"use strict\";}",
+    "arguments() {\"use strict\";}",
+    "interface() {\"use strict\";}",
+    "yield() {\"use strict\";}",
+    // Future reserved words are always illegal
+    "function super() { }",
+    "function super() {\"use strict\";}",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsNameOfStrictFunction) {
+  const char* context_data[][2] = {
+    { "function ", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "eval() { }",
+    "arguments() { }",
+    "interface() { }",
+    "yield() { }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(NoErrorsNameOfStrictGenerator) {
+  const char* context_data[][2] = {
+    { "function * ", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "eval() { }",
+    "arguments() { }",
+    "interface() { }",
+    "yield() { }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsIllegalWordsAsLabelsSloppy) {
+  // Using future reserved words as labels is always an error.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { "() => {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "super: while(true) { break super; }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsIllegalWordsAsLabelsStrict) {
+  // Tests that illegal tokens as labels produce the correct errors.
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "function test_func() {\"use strict\"; ", "}"},
+    { "() => {\"use strict\"; ", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "super: while(true) { break super; }",
+    "interface: while(true) { break interface; }",
+    "yield: while(true) { break yield; }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsIllegalWordsAsLabels) {
+  // Using eval and arguments as labels is legal even in strict mode.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { "() => {", "}" },
+    { "\"use strict\";", "" },
+    { "\"use strict\"; function test_func() {", "}" },
+    { "\"use strict\"; () => {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "mylabel: while(true) { break mylabel; }",
+    "eval: while(true) { break eval; }",
+    "arguments: while(true) { break arguments; }",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ErrorsParenthesizedLabels) {
+  // Parenthesized identifiers shouldn't be recognized as labels.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { "() => {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "(mylabel): while(true) { break mylabel; }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsParenthesizedDirectivePrologue) {
+  // Parenthesized directive prologue shouldn't be recognized.
+  const char* context_data[][2] = {
+    { "", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "(\"use strict\"); var eval;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsNotAnIdentifierName) {
+  const char* context_data[][2] = {
+    { "", ""},
+    { "\"use strict\";", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var foo = {}; foo.{;",
+    "var foo = {}; foo.};",
+    "var foo = {}; foo.=;",
+    "var foo = {}; foo.888;",
+    "var foo = {}; foo.-;",
+    "var foo = {}; foo.--;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsIdentifierNames) {
+  // Keywords etc. are valid as property names.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "\"use strict\";", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var foo = {}; foo.if;",
+    "var foo = {}; foo.yield;",
+    "var foo = {}; foo.super;",
+    "var foo = {}; foo.interface;",
+    "var foo = {}; foo.eval;",
+    "var foo = {}; foo.arguments;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(DontRegressPreParserDataSizes) {
+  // These tests make sure that Parser doesn't start producing less "preparse
+  // data" (data which the embedder can cache).
+  v8::V8::Initialize();
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handles(isolate);
+
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      i::GetCurrentStackPosition() - 128 * 1024);
+
+  struct TestCase {
+    const char* program;
+    int functions;
+  } test_cases[] = {
+    // No functions.
+    {"var x = 42;", 0},
+    // Functions.
+    {"function foo() {}", 1}, {"function foo() {} function bar() {}", 2},
+    // Getter / setter functions are recorded as functions if they're on the top
+    // level.
+    {"var x = {get foo(){} };", 1},
+    // Functions insize lazy functions are not recorded.
+    {"function lazy() { function a() {} function b() {} function c() {} }", 1},
+    {"function lazy() { var x = {get foo(){} } }", 1},
+    {NULL, 0}
+  };
+
+  for (int i = 0; test_cases[i].program; i++) {
+    const char* program = test_cases[i].program;
+    i::Factory* factory = CcTest::i_isolate()->factory();
+    i::Handle<i::String> source =
+        factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
+    i::Handle<i::Script> script = factory->NewScript(source);
+    i::CompilationInfoWithZone info(script);
+    i::ScriptData* sd = NULL;
+    info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
+    i::Parser::Parse(&info, true);
+    i::ParseData pd(sd);
+
+    if (pd.FunctionCount() != test_cases[i].functions) {
+      v8::base::OS::Print(
+          "Expected preparse data for program:\n"
+          "\t%s\n"
+          "to contain %d functions, however, received %d functions.\n",
+          program, test_cases[i].functions, pd.FunctionCount());
+      CHECK(false);
+    }
+    delete sd;
+  }
+}
+
+
+TEST(FunctionDeclaresItselfStrict) {
+  // Tests that we produce the right kinds of errors when a function declares
+  // itself strict (we cannot produce there errors as soon as we see the
+  // offending identifiers, because we don't know at that point whether the
+  // function is strict or not).
+  const char* context_data[][2] = {
+    {"function eval() {", "}"},
+    {"function arguments() {", "}"},
+    {"function yield() {", "}"},
+    {"function interface() {", "}"},
+    {"function foo(eval) {", "}"},
+    {"function foo(arguments) {", "}"},
+    {"function foo(yield) {", "}"},
+    {"function foo(interface) {", "}"},
+    {"function foo(bar, eval) {", "}"},
+    {"function foo(bar, arguments) {", "}"},
+    {"function foo(bar, yield) {", "}"},
+    {"function foo(bar, interface) {", "}"},
+    {"function foo(bar, bar) {", "}"},
+    { NULL, NULL }
+  };
+
+  const char* strict_statement_data[] = {
+    "\"use strict\";",
+    NULL
+  };
+
+  const char* non_strict_statement_data[] = {
+    ";",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, strict_statement_data, kError);
+  RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
+}
+
+
+TEST(ErrorsTryWithoutCatchOrFinally) {
+  const char* context_data[][2] = {
+    {"", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "try { }",
+    "try { } foo();",
+    "try { } catch (e) foo();",
+    "try { } catch { }",
+    "try { } finally foo();",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsTryCatchFinally) {
+  const char* context_data[][2] = {
+    {"", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "try { } catch (e) { }",
+    "try { } catch (e) { } finally { }",
+    "try { } finally { }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsRegexpLiteral) {
+  const char* context_data[][2] = {
+    {"var r = ", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "/unterminated",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsRegexpLiteral) {
+  const char* context_data[][2] = {
+    {"var r = ", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "/foo/",
+    "/foo/g",
+    "/foo/whatever",  // This is an error but not detected by the parser.
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(Intrinsics) {
+  const char* context_data[][2] = {
+    {"", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "%someintrinsic(arg)",
+    NULL
+  };
+
+  // This test requires kAllowNativesSyntax to succeed.
+  static const ParserFlag always_true_flags[] = {
+    kAllowNativesSyntax
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_true_flags, 1);
+}
+
+
+TEST(NoErrorsNewExpression) {
+  const char* context_data[][2] = {
+    {"", ""},
+    {"var f =", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "new foo",
+    "new foo();",
+    "new foo(1);",
+    "new foo(1, 2);",
+    // The first () will be processed as a part of the NewExpression and the
+    // second () will be processed as part of LeftHandSideExpression.
+    "new foo()();",
+    // The first () will be processed as a part of the inner NewExpression and
+    // the second () will be processed as a part of the outer NewExpression.
+    "new new foo()();",
+    "new foo.bar;",
+    "new foo.bar();",
+    "new foo.bar.baz;",
+    "new foo.bar().baz;",
+    "new foo[bar];",
+    "new foo[bar]();",
+    "new foo[bar][baz];",
+    "new foo[bar]()[baz];",
+    "new foo[bar].baz(baz)()[bar].baz;",
+    "new \"foo\"",  // Runtime error
+    "new 1",  // Runtime error
+    // This even runs:
+    "(new new Function(\"this.x = 1\")).x;",
+    "new new Test_Two(String, 2).v(0123).length;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsNewExpression) {
+  const char* context_data[][2] = {
+    {"", ""},
+    {"var f =", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "new foo bar",
+    "new ) foo",
+    "new ++foo",
+    "new foo ++",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(StrictObjectLiteralChecking) {
+  const char* strict_context_data[][2] = {
+    {"\"use strict\"; var myobject = {", "};"},
+    {"\"use strict\"; var myobject = {", ",};"},
+    { NULL, NULL }
+  };
+  const char* non_strict_context_data[][2] = {
+    {"var myobject = {", "};"},
+    {"var myobject = {", ",};"},
+    { NULL, NULL }
+  };
+
+  // These are only errors in strict mode.
+  const char* statement_data[] = {
+    "foo: 1, foo: 2",
+    "\"foo\": 1, \"foo\": 2",
+    "foo: 1, \"foo\": 2",
+    "1: 1, 1: 2",
+    "1: 1, \"1\": 2",
+    "get: 1, get: 2",  // Not a getter for real, just a property called get.
+    "set: 1, set: 2",  // Not a setter for real, just a property called set.
+    NULL
+  };
+
+  RunParserSyncTest(non_strict_context_data, statement_data, kSuccess);
+  RunParserSyncTest(strict_context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsObjectLiteralChecking) {
+  const char* context_data[][2] = {
+    {"\"use strict\"; var myobject = {", "};"},
+    {"var myobject = {", "};"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+      ",",
+      "foo: 1, get foo() {}",
+      "foo: 1, set foo(v) {}",
+      "\"foo\": 1, get \"foo\"() {}",
+      "\"foo\": 1, set \"foo\"(v) {}",
+      "1: 1, get 1() {}",
+      "1: 1, set 1() {}",
+      "get foo() {}, get foo() {}",
+      "set foo(_) {}, set foo(_) {}",
+      // It's counter-intuitive, but these collide too (even in classic
+      // mode). Note that we can have "foo" and foo as properties in classic
+      // mode,
+      // but we cannot have "foo" and get foo, or foo and get "foo".
+      "foo: 1, get \"foo\"() {}",
+      "foo: 1, set \"foo\"(v) {}",
+      "\"foo\": 1, get foo() {}",
+      "\"foo\": 1, set foo(v) {}",
+      "1: 1, get \"1\"() {}",
+      "1: 1, set \"1\"() {}",
+      "\"1\": 1, get 1() {}"
+      "\"1\": 1, set 1(v) {}"
+      // Wrong number of parameters
+      "get bar(x) {}",
+      "get bar(x, y) {}",
+      "set bar() {}",
+      "set bar(x, y) {}",
+      // Parsing FunctionLiteral for getter or setter fails
+      "get foo( +",
+      "get foo() \"error\"",
+      NULL};
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsObjectLiteralChecking) {
+  const char* context_data[][2] = {
+    {"var myobject = {", "};"},
+    {"var myobject = {", ",};"},
+    {"\"use strict\"; var myobject = {", "};"},
+    {"\"use strict\"; var myobject = {", ",};"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "foo: 1, bar: 2",
+    "\"foo\": 1, \"bar\": 2",
+    "1: 1, 2: 2",
+    // Syntax: IdentifierName ':' AssignmentExpression
+    "foo: bar = 5 + baz",
+    // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}'
+    "get foo() {}",
+    "get \"foo\"() {}",
+    "get 1() {}",
+    // Syntax: 'set' PropertyName '(' PropertySetParameterList ')'
+    //     '{' FunctionBody '}'
+    "set foo(v) {}",
+    "set \"foo\"(v) {}",
+    "set 1(v) {}",
+    // Non-colliding getters and setters -> no errors
+    "foo: 1, get bar() {}",
+    "foo: 1, set bar(v) {}",
+    "\"foo\": 1, get \"bar\"() {}",
+    "\"foo\": 1, set \"bar\"(v) {}",
+    "1: 1, get 2() {}",
+    "1: 1, set 2(v) {}",
+    "get: 1, get foo() {}",
+    "set: 1, set foo(_) {}",
+    // Keywords, future reserved and strict future reserved are also allowed as
+    // property names.
+    "if: 4",
+    "interface: 5",
+    "super: 6",
+    "eval: 7",
+    "arguments: 8",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(TooManyArguments) {
+  const char* context_data[][2] = {
+    {"foo(", "0)"},
+    { NULL, NULL }
+  };
+
+  using v8::internal::Code;
+  char statement[Code::kMaxArguments * 2 + 1];
+  for (int i = 0; i < Code::kMaxArguments; ++i) {
+    statement[2 * i] = '0';
+    statement[2 * i + 1] = ',';
+  }
+  statement[Code::kMaxArguments * 2] = 0;
+
+  const char* statement_data[] = {
+    statement,
+    NULL
+  };
+
+  // The test is quite slow, so run it with a reduced set of flags.
+  static const ParserFlag empty_flags[] = {kAllowLazy};
+  RunParserSyncTest(context_data, statement_data, kError, empty_flags, 1);
+}
+
+
+TEST(StrictDelete) {
+  // "delete <Identifier>" is not allowed in strict mode.
+  const char* strict_context_data[][2] = {
+    {"\"use strict\"; ", ""},
+    { NULL, NULL }
+  };
+
+  const char* sloppy_context_data[][2] = {
+    {"", ""},
+    { NULL, NULL }
+  };
+
+  // These are errors in the strict mode.
+  const char* sloppy_statement_data[] = {
+    "delete foo;",
+    "delete foo + 1;",
+    "delete (foo);",
+    "delete eval;",
+    "delete interface;",
+    NULL
+  };
+
+  // These are always OK
+  const char* good_statement_data[] = {
+    "delete this;",
+    "delete 1;",
+    "delete 1 + 2;",
+    "delete foo();",
+    "delete foo.bar;",
+    "delete foo[bar];",
+    "delete foo--;",
+    "delete --foo;",
+    "delete new foo();",
+    "delete new foo(bar);",
+    NULL
+  };
+
+  // These are always errors
+  const char* bad_statement_data[] = {
+    "delete if;",
+    NULL
+  };
+
+  RunParserSyncTest(strict_context_data, sloppy_statement_data, kError);
+  RunParserSyncTest(sloppy_context_data, sloppy_statement_data, kSuccess);
+
+  RunParserSyncTest(strict_context_data, good_statement_data, kSuccess);
+  RunParserSyncTest(sloppy_context_data, good_statement_data, kSuccess);
+
+  RunParserSyncTest(strict_context_data, bad_statement_data, kError);
+  RunParserSyncTest(sloppy_context_data, bad_statement_data, kError);
+}
+
+
+TEST(InvalidLeftHandSide) {
+  const char* assignment_context_data[][2] = {
+    {"", " = 1;"},
+    {"\"use strict\"; ", " = 1;"},
+    { NULL, NULL }
+  };
+
+  const char* prefix_context_data[][2] = {
+    {"++", ";"},
+    {"\"use strict\"; ++", ";"},
+    {NULL, NULL},
+  };
+
+  const char* postfix_context_data[][2] = {
+    {"", "++;"},
+    {"\"use strict\"; ", "++;"},
+    { NULL, NULL }
+  };
+
+  // Good left hand sides for assigment or prefix / postfix operations.
+  const char* good_statement_data[] = {
+    "foo",
+    "foo.bar",
+    "foo[bar]",
+    "foo()[bar]",
+    "foo().bar",
+    "this.foo",
+    "this[foo]",
+    "new foo()[bar]",
+    "new foo().bar",
+    "foo()",
+    "foo(bar)",
+    "foo[bar]()",
+    "foo.bar()",
+    "this()",
+    "this.foo()",
+    "this[foo].bar()",
+    "this.foo[foo].bar(this)(bar)[foo]()",
+    NULL
+  };
+
+  // Bad left hand sides for assigment or prefix / postfix operations.
+  const char* bad_statement_data_common[] = {
+    "2",
+    "new foo",
+    "new foo()",
+    "null",
+    "if",  // Unexpected token
+    "{x: 1}",  // Unexpected token
+    "this",
+    "\"bar\"",
+    "(foo + bar)",
+    "new new foo()[bar]",  // means: new (new foo()[bar])
+    "new new foo().bar",  // means: new (new foo()[bar])
+    NULL
+  };
+
+  // These are not okay for assignment, but okay for prefix / postix.
+  const char* bad_statement_data_for_assignment[] = {
+    "++foo",
+    "foo++",
+    "foo + bar",
+    NULL
+  };
+
+  RunParserSyncTest(assignment_context_data, good_statement_data, kSuccess);
+  RunParserSyncTest(assignment_context_data, bad_statement_data_common, kError);
+  RunParserSyncTest(assignment_context_data, bad_statement_data_for_assignment,
+                    kError);
+
+  RunParserSyncTest(prefix_context_data, good_statement_data, kSuccess);
+  RunParserSyncTest(prefix_context_data, bad_statement_data_common, kError);
+
+  RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess);
+  RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError);
+}
+
+
+TEST(FuncNameInferrerBasic) {
+  // Tests that function names are inferred properly.
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  LocalContext env;
+  CompileRun("var foo1 = function() {}; "
+             "var foo2 = function foo3() {}; "
+             "function not_ctor() { "
+             "  var foo4 = function() {}; "
+             "  return %FunctionGetInferredName(foo4); "
+             "} "
+             "function Ctor() { "
+             "  var foo5 = function() {}; "
+             "  return %FunctionGetInferredName(foo5); "
+             "} "
+             "var obj1 = { foo6: function() {} }; "
+             "var obj2 = { 'foo7': function() {} }; "
+             "var obj3 = {}; "
+             "obj3[1] = function() {}; "
+             "var obj4 = {}; "
+             "obj4[1] = function foo8() {}; "
+             "var obj5 = {}; "
+             "obj5['foo9'] = function() {}; "
+             "var obj6 = { obj7 : { foo10: function() {} } };");
+  ExpectString("%FunctionGetInferredName(foo1)", "foo1");
+  // foo2 is not unnamed -> its name is not inferred.
+  ExpectString("%FunctionGetInferredName(foo2)", "");
+  ExpectString("not_ctor()", "foo4");
+  ExpectString("Ctor()", "Ctor.foo5");
+  ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6");
+  ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7");
+  ExpectString("%FunctionGetInferredName(obj3[1])",
+               "obj3.(anonymous function)");
+  ExpectString("%FunctionGetInferredName(obj4[1])", "");
+  ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9");
+  ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10");
+}
+
+
+TEST(FuncNameInferrerTwoByte) {
+  // Tests function name inferring in cases where some parts of the inferred
+  // function name are two-byte strings.
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  LocalContext env;
+  uint16_t* two_byte_source = AsciiToTwoByteString(
+      "var obj1 = { oXj2 : { foo1: function() {} } }; "
+      "%FunctionGetInferredName(obj1.oXj2.foo1)");
+  uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
+  // Make it really non-Latin1 (replace the Xs with a non-Latin1 character).
+  two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d;
+  v8::Local<v8::String> source =
+      v8::String::NewFromTwoByte(isolate, two_byte_source);
+  v8::Local<v8::Value> result = CompileRun(source);
+  CHECK(result->IsString());
+  v8::Local<v8::String> expected_name =
+      v8::String::NewFromTwoByte(isolate, two_byte_name);
+  CHECK(result->Equals(expected_name));
+  i::DeleteArray(two_byte_source);
+  i::DeleteArray(two_byte_name);
+}
+
+
+TEST(FuncNameInferrerEscaped) {
+  // The same as FuncNameInferrerTwoByte, except that we express the two-byte
+  // character as a unicode escape.
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  LocalContext env;
+  uint16_t* two_byte_source = AsciiToTwoByteString(
+      "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; "
+      "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)");
+  uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1");
+  // Fix to correspond to the non-ASCII name in two_byte_source.
+  two_byte_name[6] = 0x010d;
+  v8::Local<v8::String> source =
+      v8::String::NewFromTwoByte(isolate, two_byte_source);
+  v8::Local<v8::Value> result = CompileRun(source);
+  CHECK(result->IsString());
+  v8::Local<v8::String> expected_name =
+      v8::String::NewFromTwoByte(isolate, two_byte_name);
+  CHECK(result->Equals(expected_name));
+  i::DeleteArray(two_byte_source);
+  i::DeleteArray(two_byte_name);
+}
+
+
+TEST(RegressionLazyFunctionWithErrorWithArg) {
+  // The bug occurred when a lazy function had an error which requires a
+  // parameter (such as "unknown label" here). The error message was processed
+  // before the AstValueFactory containing the error message string was
+  // internalized.
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  LocalContext env;
+  i::FLAG_lazy = true;
+  i::FLAG_min_preparse_length = 0;
+  CompileRun("function this_is_lazy() {\n"
+             "  break p;\n"
+             "}\n"
+             "this_is_lazy();\n");
+}
+
+
+TEST(SerializationOfMaybeAssignmentFlag) {
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope scope(isolate);
+  LocalContext env;
+
+  const char* src =
+      "function h() {"
+      "  var result = [];"
+      "  function f() {"
+      "    result.push(2);"
+      "  }"
+      "  function assertResult(r) {"
+      "    f();"
+      "    result = [];"
+      "  }"
+      "  assertResult([2]);"
+      "  assertResult([2]);"
+      "  return f;"
+      "};"
+      "h();";
+
+  i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
+  i::SNPrintF(program, "%s", src);
+  i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
+  source->PrintOn(stdout);
+  printf("\n");
+  i::Zone zone(isolate);
+  v8::Local<v8::Value> v = CompileRun(src);
+  i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
+  i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
+  i::Context* context = f->context();
+  i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
+  avf.Internalize(isolate);
+  const i::AstRawString* name = avf.GetOneByteString("result");
+  i::Handle<i::String> str = name->string();
+  CHECK(str->IsInternalizedString());
+  i::Scope* global_scope =
+      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
+  global_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
+  DCHECK(s != global_scope);
+  DCHECK(name != NULL);
+
+  // Get result from h's function context (that is f's context)
+  i::Variable* var = s->Lookup(name);
+
+  CHECK(var != NULL);
+  // Maybe assigned should survive deserialization
+  CHECK(var->maybe_assigned() == i::kMaybeAssigned);
+  // TODO(sigurds) Figure out if is_used should survive context serialization.
+}
+
+
+TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) {
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope scope(isolate);
+  LocalContext env;
+
+
+  const char* src =
+      "function f(x) {"
+      "    var a = arguments;"
+      "    function g(i) {"
+      "      ++a[0];"
+      "    };"
+      "    return g;"
+      "  }"
+      "f(0);";
+
+  i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
+  i::SNPrintF(program, "%s", src);
+  i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
+  source->PrintOn(stdout);
+  printf("\n");
+  i::Zone zone(isolate);
+  v8::Local<v8::Value> v = CompileRun(src);
+  i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
+  i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
+  i::Context* context = f->context();
+  i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
+  avf.Internalize(isolate);
+
+  i::Scope* global_scope =
+      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
+  global_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
+  DCHECK(s != global_scope);
+  const i::AstRawString* name_x = avf.GetOneByteString("x");
+
+  // Get result from f's function context (that is g's outer context)
+  i::Variable* var_x = s->Lookup(name_x);
+  CHECK(var_x != NULL);
+  CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
+}
+
+
+TEST(ExportsMaybeAssigned) {
+  i::FLAG_use_strict = true;
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_harmony_modules = true;
+
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope scope(isolate);
+  LocalContext env;
+
+  const char* src =
+      "module A {"
+      "  export var x = 1;"
+      "  export function f() { return x };"
+      "  export const y = 2;"
+      "  module B {}"
+      "  export module C {}"
+      "};"
+      "A.f";
+
+  i::ScopedVector<char> program(Utf8LengthHelper(src) + 1);
+  i::SNPrintF(program, "%s", src);
+  i::Handle<i::String> source = factory->InternalizeUtf8String(program.start());
+  source->PrintOn(stdout);
+  printf("\n");
+  i::Zone zone(isolate);
+  v8::Local<v8::Value> v = CompileRun(src);
+  i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
+  i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
+  i::Context* context = f->context();
+  i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
+  avf.Internalize(isolate);
+
+  i::Scope* global_scope =
+      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
+  global_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
+  DCHECK(s != global_scope);
+  const i::AstRawString* name_x = avf.GetOneByteString("x");
+  const i::AstRawString* name_f = avf.GetOneByteString("f");
+  const i::AstRawString* name_y = avf.GetOneByteString("y");
+  const i::AstRawString* name_B = avf.GetOneByteString("B");
+  const i::AstRawString* name_C = avf.GetOneByteString("C");
+
+  // Get result from h's function context (that is f's context)
+  i::Variable* var_x = s->Lookup(name_x);
+  CHECK(var_x != NULL);
+  CHECK(var_x->maybe_assigned() == i::kMaybeAssigned);
+  i::Variable* var_f = s->Lookup(name_f);
+  CHECK(var_f != NULL);
+  CHECK(var_f->maybe_assigned() == i::kMaybeAssigned);
+  i::Variable* var_y = s->Lookup(name_y);
+  CHECK(var_y != NULL);
+  CHECK(var_y->maybe_assigned() == i::kNotAssigned);
+  i::Variable* var_B = s->Lookup(name_B);
+  CHECK(var_B != NULL);
+  CHECK(var_B->maybe_assigned() == i::kNotAssigned);
+  i::Variable* var_C = s->Lookup(name_C);
+  CHECK(var_C != NULL);
+  CHECK(var_C->maybe_assigned() == i::kNotAssigned);
+}
+
+
+TEST(InnerAssignment) {
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope scope(isolate);
+  LocalContext env;
+
+  const char* prefix = "function f() {";
+  const char* midfix = " function g() {";
+  const char* suffix = "}}";
+  struct { const char* source; bool assigned; bool strict; } outers[] = {
+    // Actual assignments.
+    { "var x; var x = 5;", true, false },
+    { "var x; { var x = 5; }", true, false },
+    { "'use strict'; let x; x = 6;", true, true },
+    { "var x = 5; function x() {}", true, false },
+    // Actual non-assignments.
+    { "var x;", false, false },
+    { "var x = 5;", false, false },
+    { "'use strict'; let x;", false, true },
+    { "'use strict'; let x = 6;", false, true },
+    { "'use strict'; var x = 0; { let x = 6; }", false, true },
+    { "'use strict'; var x = 0; { let x; x = 6; }", false, true },
+    { "'use strict'; let x = 0; { let x = 6; }", false, true },
+    { "'use strict'; let x = 0; { let x; x = 6; }", false, true },
+    { "var x; try {} catch (x) { x = 5; }", false, false },
+    { "function x() {}", false, false },
+    // Eval approximation.
+    { "var x; eval('');", true, false },
+    { "eval(''); var x;", true, false },
+    { "'use strict'; let x; eval('');", true, true },
+    { "'use strict'; eval(''); let x;", true, true },
+    // Non-assignments not recognized, because the analysis is approximative.
+    { "var x; var x;", true, false },
+    { "var x = 5; var x;", true, false },
+    { "var x; { var x; }", true, false },
+    { "var x; function x() {}", true, false },
+    { "function x() {}; var x;", true, false },
+    { "var x; try {} catch (x) { var x = 5; }", true, false },
+  };
+  struct { const char* source; bool assigned; bool with; } inners[] = {
+    // Actual assignments.
+    { "x = 1;", true, false },
+    { "x++;", true, false },
+    { "++x;", true, false },
+    { "x--;", true, false },
+    { "--x;", true, false },
+    { "{ x = 1; }", true, false },
+    { "'use strict'; { let x; }; x = 0;", true, false },
+    { "'use strict'; { const x = 1; }; x = 0;", true, false },
+    { "'use strict'; { function x() {} }; x = 0;", true, false },
+    { "with ({}) { x = 1; }", true, true },
+    { "eval('');", true, false },
+    { "'use strict'; { let y; eval('') }", true, false },
+    { "function h() { x = 0; }", true, false },
+    { "(function() { x = 0; })", true, false },
+    { "(function() { x = 0; })", true, false },
+    { "with ({}) (function() { x = 0; })", true, true },
+    // Actual non-assignments.
+    { "", false, false },
+    { "x;", false, false },
+    { "var x;", false, false },
+    { "var x = 8;", false, false },
+    { "var x; x = 8;", false, false },
+    { "'use strict'; let x;", false, false },
+    { "'use strict'; let x = 8;", false, false },
+    { "'use strict'; let x; x = 8;", false, false },
+    { "'use strict'; const x = 8;", false, false },
+    { "function x() {}", false, false },
+    { "function x() { x = 0; }", false, false },
+    { "function h(x) { x = 0; }", false, false },
+    { "'use strict'; { let x; x = 0; }", false, false },
+    { "{ var x; }; x = 0;", false, false },
+    { "with ({}) {}", false, true },
+    { "var x; { with ({}) { x = 1; } }", false, true },
+    { "try {} catch(x) { x = 0; }", false, false },
+    { "try {} catch(x) { with ({}) { x = 1; } }", false, true },
+    // Eval approximation.
+    { "eval('');", true, false },
+    { "function h() { eval(''); }", true, false },
+    { "(function() { eval(''); })", true, false },
+    // Shadowing not recognized because of eval approximation.
+    { "var x; eval('');", true, false },
+    { "'use strict'; let x; eval('');", true, false },
+    { "try {} catch(x) { eval(''); }", true, false },
+    { "function x() { eval(''); }", true, false },
+    { "(function(x) { eval(''); })", true, false },
+  };
+
+  // Used to trigger lazy compilation of function
+  int comment_len = 2048;
+  i::ScopedVector<char> comment(comment_len + 1);
+  i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0);
+  int prefix_len = Utf8LengthHelper(prefix);
+  int midfix_len = Utf8LengthHelper(midfix);
+  int suffix_len = Utf8LengthHelper(suffix);
+  for (unsigned i = 0; i < arraysize(outers); ++i) {
+    const char* outer = outers[i].source;
+    int outer_len = Utf8LengthHelper(outer);
+    for (unsigned j = 0; j < arraysize(inners); ++j) {
+      for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) {
+        for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) {
+          if (outers[i].strict && inners[j].with) continue;
+          const char* inner = inners[j].source;
+          int inner_len = Utf8LengthHelper(inner);
+
+          int outer_comment_len = outer_lazy ? comment_len : 0;
+          int inner_comment_len = inner_lazy ? comment_len : 0;
+          const char* outer_comment = outer_lazy ? comment.start() : "";
+          const char* inner_comment = inner_lazy ? comment.start() : "";
+          int len = prefix_len + outer_comment_len + outer_len + midfix_len +
+                    inner_comment_len + inner_len + suffix_len;
+          i::ScopedVector<char> program(len + 1);
+
+          i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer,
+                      midfix, inner_comment, inner, suffix);
+          i::Handle<i::String> source =
+              factory->InternalizeUtf8String(program.start());
+          source->PrintOn(stdout);
+          printf("\n");
+
+          i::Handle<i::Script> script = factory->NewScript(source);
+          i::CompilationInfoWithZone info(script);
+          i::Parser::ParseInfo parse_info = {
+              isolate->stack_guard()->real_climit(),
+              isolate->heap()->HashSeed(), isolate->unicode_cache()};
+          i::Parser parser(&info, &parse_info);
+          parser.set_allow_harmony_scoping(true);
+          CHECK(parser.Parse());
+          CHECK(i::Rewriter::Rewrite(&info));
+          CHECK(i::Scope::Analyze(&info));
+          CHECK(info.function() != NULL);
+
+          i::Scope* scope = info.function()->scope();
+          CHECK_EQ(scope->inner_scopes()->length(), 1);
+          i::Scope* inner_scope = scope->inner_scopes()->at(0);
+          const i::AstRawString* var_name =
+              info.ast_value_factory()->GetOneByteString("x");
+          i::Variable* var = inner_scope->Lookup(var_name);
+          bool expected = outers[i].assigned || inners[j].assigned;
+          CHECK(var != NULL);
+          CHECK(var->is_used() || !expected);
+          CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected);
+        }
+      }
+    }
+  }
+}
+
+namespace {
+
+int* global_use_counts = NULL;
+
+void MockUseCounterCallback(v8::Isolate* isolate,
+                            v8::Isolate::UseCounterFeature feature) {
+  ++global_use_counts[feature];
+}
+
+}
+
+
+TEST(UseAsmUseCount) {
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::HandleScope scope(isolate);
+  LocalContext env;
+  int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
+  global_use_counts = use_counts;
+  CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
+  CompileRun("\"use asm\";\n"
+             "var foo = 1;\n"
+             "\"use asm\";\n"  // Only the first one counts.
+             "function bar() { \"use asm\"; var baz = 1; }");
+  CHECK_EQ(2, use_counts[v8::Isolate::kUseAsm]);
+}
+
+
+TEST(ErrorsArrowFunctions) {
+  // Tests that parser and preparser generate the same kind of errors
+  // on invalid arrow function syntax.
+  const char* context_data[][2] = {
+    {"", ";"},
+    {"v = ", ";"},
+    {"bar ? (", ") : baz;"},
+    {"bar ? baz : (", ");"},
+    {"bar[", "];"},
+    {"bar, ", ";"},
+    {"", ", bar;"},
+    {NULL, NULL}
+  };
+
+  const char* statement_data[] = {
+    "=> 0",
+    "=>",
+    "() =>",
+    "=> {}",
+    ") => {}",
+    ", => {}",
+    "(,) => {}",
+    "return => {}",
+    "() => {'value': 42}",
+
+    // Check that the early return introduced in ParsePrimaryExpression
+    // does not accept stray closing parentheses.
+    ")",
+    ") => 0",
+    "foo[()]",
+    "()",
+
+    // Parameter lists with extra parens should be recognized as errors.
+    "(()) => 0",
+    "((x)) => 0",
+    "((x, y)) => 0",
+    "(x, (y)) => 0",
+    "((x, y, z)) => 0",
+    "(x, (y, z)) => 0",
+    "((x, y), z) => 0",
+
+    // Parameter lists are always validated as strict, so those are errors.
+    "eval => {}",
+    "arguments => {}",
+    "yield => {}",
+    "interface => {}",
+    "(eval) => {}",
+    "(arguments) => {}",
+    "(yield) => {}",
+    "(interface) => {}",
+    "(eval, bar) => {}",
+    "(bar, eval) => {}",
+    "(bar, arguments) => {}",
+    "(bar, yield) => {}",
+    "(bar, interface) => {}",
+    // TODO(aperez): Detecting duplicates does not work in PreParser.
+    // "(bar, bar) => {}",
+
+    // The parameter list is parsed as an expression, but only
+    // a comma-separated list of identifier is valid.
+    "32 => {}",
+    "(32) => {}",
+    "(a, 32) => {}",
+    "if => {}",
+    "(if) => {}",
+    "(a, if) => {}",
+    "a + b => {}",
+    "(a + b) => {}",
+    "(a + b, c) => {}",
+    "(a, b - c) => {}",
+    "\"a\" => {}",
+    "(\"a\") => {}",
+    "(\"a\", b) => {}",
+    "(a, \"b\") => {}",
+    "-a => {}",
+    "(-a) => {}",
+    "(-a, b) => {}",
+    "(a, -b) => {}",
+    "{} => {}",
+    "({}) => {}",
+    "(a, {}) => {}",
+    "({}, a) => {}",
+    "a++ => {}",
+    "(a++) => {}",
+    "(a++, b) => {}",
+    "(a, b++) => {}",
+    "[] => {}",
+    "([]) => {}",
+    "(a, []) => {}",
+    "([], a) => {}",
+    "(a = b) => {}",
+    "(a = b, c) => {}",
+    "(a, b = c) => {}",
+    "(foo ? bar : baz) => {}",
+    "(a, foo ? bar : baz) => {}",
+    "(foo ? bar : baz, a) => {}",
+    NULL
+  };
+
+  // The test is quite slow, so run it with a reduced set of flags.
+  static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
+  static const ParserFlag always_flags[] = { kAllowArrowFunctions };
+  RunParserSyncTest(context_data, statement_data, kError, flags,
+                    arraysize(flags), always_flags, arraysize(always_flags));
+}
+
+
+TEST(NoErrorsArrowFunctions) {
+  // Tests that parser and preparser accept valid arrow functions syntax.
+  const char* context_data[][2] = {
+    {"", ";"},
+    {"bar ? (", ") : baz;"},
+    {"bar ? baz : (", ");"},
+    {"bar, ", ";"},
+    {"", ", bar;"},
+    {NULL, NULL}
+  };
+
+  const char* statement_data[] = {
+    "() => {}",
+    "() => { return 42 }",
+    "x => { return x; }",
+    "(x) => { return x; }",
+    "(x, y) => { return x + y; }",
+    "(x, y, z) => { return x + y + z; }",
+    "(x, y) => { x.a = y; }",
+    "() => 42",
+    "x => x",
+    "x => x * x",
+    "(x) => x",
+    "(x) => x * x",
+    "(x, y) => x + y",
+    "(x, y, z) => x, y, z",
+    "(x, y) => x.a = y",
+    "() => ({'value': 42})",
+    "x => y => x + y",
+    "(x, y) => (u, v) => x*u + y*v",
+    "(x, y) => z => z * (x + y)",
+    "x => (y, z) => z * (x + y)",
+
+    // Those are comma-separated expressions, with arrow functions as items.
+    // They stress the code for validating arrow function parameter lists.
+    "a, b => 0",
+    "a, b, (c, d) => 0",
+    "(a, b, (c, d) => 0)",
+    "(a, b) => 0, (c, d) => 1",
+    "(a, b => {}, a => a + 1)",
+    "((a, b) => {}, (a => a + 1))",
+    "(a, (a, (b, c) => 0))",
+
+    // Arrow has more precedence, this is the same as: foo ? bar : (baz = {})
+    "foo ? bar : baz => {}",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(NoErrorsSuper) {
+  // Tests that parser and preparser accept 'super' keyword in right places.
+  const char* context_data[][2] = {{"", ";"},
+                                   {"k = ", ";"},
+                                   {"foo(", ");"},
+                                   {NULL, NULL}};
+
+  const char* statement_data[] = {
+    "super.x",
+    "super[27]",
+    "new super",
+    "new super()",
+    "new super(12, 45)",
+    "new new super",
+    "new new super()",
+    "new new super()()",
+    "z.super",  // Ok, property lookup.
+    NULL};
+
+  static const ParserFlag always_flags[] = {kAllowClasses};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ErrorsSuper) {
+  // Tests that parser and preparser generate same errors for 'super'.
+  const char* context_data[][2] = {{"", ";"},
+                                   {"k = ", ";"},
+                                   {"foo(", ");"},
+                                   {NULL, NULL}};
+
+  const char* statement_data[] = {
+    "super = x",
+    "y = super",
+    "f(super)",
+    NULL};
+
+  static const ParserFlag always_flags[] = {kAllowClasses};
+  RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(NoErrorsMethodDefinition) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {"'use strict'; ({", "});"},
+                                   {"({*", "});"},
+                                   {"'use strict'; ({*", "});"},
+                                   {NULL, NULL}};
+
+  const char* object_literal_body_data[] = {
+    "m() {}",
+    "m(x) { return x; }",
+    "m(x, y) {}, n() {}",
+    "set(x, y) {}",
+    "get(x, y) {}",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(MethodDefinitionNames) {
+  const char* context_data[][2] = {{"({", "(x, y) {}});"},
+                                   {"'use strict'; ({", "(x, y) {}});"},
+                                   {"({*", "(x, y) {}});"},
+                                   {"'use strict'; ({*", "(x, y) {}});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "m",
+    "'m'",
+    "\"m\"",
+    "\"m n\"",
+    "true",
+    "false",
+    "null",
+    "0",
+    "1.2",
+    "1e1",
+    "1E1",
+    "1e+1",
+    "1e-1",
+
+    // Keywords
+    "async",
+    "await",
+    "break",
+    "case",
+    "catch",
+    "class",
+    "const",
+    "continue",
+    "debugger",
+    "default",
+    "delete",
+    "do",
+    "else",
+    "enum",
+    "export",
+    "extends",
+    "finally",
+    "for",
+    "function",
+    "if",
+    "implements",
+    "import",
+    "in",
+    "instanceof",
+    "interface",
+    "let",
+    "new",
+    "package",
+    "private",
+    "protected",
+    "public",
+    "return",
+    "static",
+    "super",
+    "switch",
+    "this",
+    "throw",
+    "try",
+    "typeof",
+    "var",
+    "void",
+    "while",
+    "with",
+    "yield",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(MethodDefinitionStrictFormalParamereters) {
+  const char* context_data[][2] = {{"({method(", "){}});"},
+                                   {"'use strict'; ({method(", "){}});"},
+                                   {"({*method(", "){}});"},
+                                   {"'use strict'; ({*method(", "){}});"},
+                                   {NULL, NULL}};
+
+  const char* params_data[] = {
+    "x, x",
+    "x, y, x",
+    "eval",
+    "arguments",
+    "var",
+    "const",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, params_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(MethodDefinitionDuplicateProperty) {
+  // Duplicate properties are allowed in ES6 but we haven't removed that check
+  // yet.
+  const char* context_data[][2] = {{"'use strict'; ({", "});"},
+                                   {NULL, NULL}};
+
+  const char* params_data[] = {
+    "x: 1, x() {}",
+    "x() {}, x: 1",
+    "x() {}, get x() {}",
+    "x() {}, set x(_) {}",
+    "x() {}, x() {}",
+    "x() {}, y() {}, x() {}",
+    "x() {}, \"x\"() {}",
+    "x() {}, 'x'() {}",
+    "0() {}, '0'() {}",
+    "1.0() {}, 1: 1",
+
+    "x: 1, *x() {}",
+    "*x() {}, x: 1",
+    "*x() {}, get x() {}",
+    "*x() {}, set x(_) {}",
+    "*x() {}, *x() {}",
+    "*x() {}, y() {}, *x() {}",
+    "*x() {}, *\"x\"() {}",
+    "*x() {}, *'x'() {}",
+    "*0() {}, *'0'() {}",
+    "*1.0() {}, 1: 1",
+
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, params_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassExpressionNoErrors) {
+  const char* context_data[][2] = {{"(", ");"},
+                                   {"var C = ", ";"},
+                                   {"bar, ", ";"},
+                                   {NULL, NULL}};
+  const char* class_data[] = {
+    "class {}",
+    "class name {}",
+    "class extends F {}",
+    "class name extends F {}",
+    "class extends (F, G) {}",
+    "class name extends (F, G) {}",
+    "class extends class {} {}",
+    "class name extends class {} {}",
+    "class extends class base {} {}",
+    "class name extends class base {} {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {kAllowClasses};
+  RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassDeclarationNoErrors) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"{", "}"},
+                                   {"if (true) {", "}"},
+                                   {NULL, NULL}};
+  const char* statement_data[] = {
+    "class name {}",
+    "class name extends F {}",
+    "class name extends (F, G) {}",
+    "class name extends class {} {}",
+    "class name extends class base {} {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {kAllowClasses};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassBodyNoErrors) {
+  // Tests that parser and preparser accept valid class syntax.
+  const char* context_data[][2] = {{"(class {", "});"},
+                                   {"(class extends Base {", "});"},
+                                   {"class C {", "}"},
+                                   {"class C extends Base {", "}"},
+                                   {NULL, NULL}};
+  const char* class_body_data[] = {
+    ";",
+    ";;",
+    "m() {}",
+    "m() {};",
+    "; m() {}",
+    "m() {}; n(x) {}",
+    "get x() {}",
+    "set x(v) {}",
+    "get() {}",
+    "set() {}",
+    "*g() {}",
+    "*g() {};",
+    "; *g() {}",
+    "*g() {}; *h(x) {}",
+    "static() {}",
+    "static m() {}",
+    "static get x() {}",
+    "static set x(v) {}",
+    "static get() {}",
+    "static set() {}",
+    "static static() {}",
+    "static get static() {}",
+    "static set static(v) {}",
+    "*static() {}",
+    "*get() {}",
+    "*set() {}",
+    "static *g() {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassPropertyNameNoErrors) {
+  const char* context_data[][2] = {{"(class {", "() {}});"},
+                                   {"(class { get ", "() {}});"},
+                                   {"(class { set ", "(v) {}});"},
+                                   {"(class { static ", "() {}});"},
+                                   {"(class { static get ", "() {}});"},
+                                   {"(class { static set ", "(v) {}});"},
+                                   {"(class { *", "() {}});"},
+                                   {"(class { static *", "() {}});"},
+                                   {"class C {", "() {}}"},
+                                   {"class C { get ", "() {}}"},
+                                   {"class C { set ", "(v) {}}"},
+                                   {"class C { static ", "() {}}"},
+                                   {"class C { static get ", "() {}}"},
+                                   {"class C { static set ", "(v) {}}"},
+                                   {"class C { *", "() {}}"},
+                                   {"class C { static *", "() {}}"},
+                                   {NULL, NULL}};
+  const char* name_data[] = {
+    "42",
+    "42.5",
+    "42e2",
+    "42e+2",
+    "42e-2",
+    "null",
+    "false",
+    "true",
+    "'str'",
+    "\"str\"",
+    "static",
+    "get",
+    "set",
+    "var",
+    "const",
+    "let",
+    "this",
+    "class",
+    "function",
+    "yield",
+    "if",
+    "else",
+    "for",
+    "while",
+    "do",
+    "try",
+    "catch",
+    "finally",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassExpressionErrors) {
+  const char* context_data[][2] = {{"(", ");"},
+                                   {"var C = ", ";"},
+                                   {"bar, ", ";"},
+                                   {NULL, NULL}};
+  const char* class_data[] = {
+    "class",
+    "class name",
+    "class name extends",
+    "class extends",
+    "class {",
+    "class { m }",
+    "class { m; n }",
+    "class { m: 1 }",
+    "class { m(); n() }",
+    "class { get m }",
+    "class { get m() }",
+    "class { get m() { }",
+    "class { set m() {} }",  // Missing required parameter.
+    "class { m() {}, n() {} }",  // No commas allowed.
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassDeclarationErrors) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"{", "}"},
+                                   {"if (true) {", "}"},
+                                   {NULL, NULL}};
+  const char* class_data[] = {
+    "class",
+    "class name",
+    "class name extends",
+    "class extends",
+    "class name {",
+    "class name { m }",
+    "class name { m; n }",
+    "class name { m: 1 }",
+    "class name { m(); n() }",
+    "class name { get x }",
+    "class name { get x() }",
+    "class name { set x() {) }",  // missing required param
+    "class {}",  // Name is required for declaration
+    "class extends base {}",
+    "class name { *",
+    "class name { * }",
+    "class name { *; }",
+    "class name { *get x() {} }",
+    "class name { *set x(_) {} }",
+    "class name { *static m() {} }",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyNumericLiterals
+  };
+  RunParserSyncTest(context_data, class_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassNameErrors) {
+  const char* context_data[][2] = {{"class ", "{}"},
+                                   {"(class ", "{});"},
+                                   {"'use strict'; class ", "{}"},
+                                   {"'use strict'; (class ", "{});"},
+                                   {NULL, NULL}};
+  const char* class_name[] = {
+    "arguments",
+    "eval",
+    "implements",
+    "interface",
+    "let",
+    "package",
+    "private",
+    "protected",
+    "public",
+    "static",
+    "var",
+    "yield",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_name, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassGetterParamNameErrors) {
+  const char* context_data[][2] = {
+    {"class C { get name(", ") {} }"},
+    {"(class { get name(", ") {} });"},
+    {"'use strict'; class C { get name(", ") {} }"},
+    {"'use strict'; (class { get name(", ") {} })"},
+    {NULL, NULL}
+  };
+
+  const char* class_name[] = {
+    "arguments",
+    "eval",
+    "implements",
+    "interface",
+    "let",
+    "package",
+    "private",
+    "protected",
+    "public",
+    "static",
+    "var",
+    "yield",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_name, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassStaticPrototypeErrors) {
+  const char* context_data[][2] = {{"class C {", "}"},
+                                   {"(class {", "});"},
+                                   {NULL, NULL}};
+
+  const char* class_body_data[] = {
+    "static prototype() {}",
+    "static get prototype() {}",
+    "static set prototype(_) {}",
+    "static *prototype() {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassSpecialConstructorErrors) {
+  const char* context_data[][2] = {{"class C {", "}"},
+                                   {"(class {", "});"},
+                                   {NULL, NULL}};
+
+  const char* class_body_data[] = {
+    "get constructor() {}",
+    "get constructor(_) {}",
+    "*constructor() {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassConstructorNoErrors) {
+  const char* context_data[][2] = {{"class C {", "}"},
+                                   {"(class {", "});"},
+                                   {NULL, NULL}};
+
+  const char* class_body_data[] = {
+    "constructor() {}",
+    "static constructor() {}",
+    "static get constructor() {}",
+    "static set constructor(_) {}",
+    "static *constructor() {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassMultipleConstructorErrors) {
+  // We currently do not allow any duplicate properties in class bodies. This
+  // test ensures that when we change that we still throw on duplicate
+  // constructors.
+  const char* context_data[][2] = {{"class C {", "}"},
+                                   {"(class {", "});"},
+                                   {NULL, NULL}};
+
+  const char* class_body_data[] = {
+    "constructor() {}; constructor() {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+// TODO(arv): We should allow duplicate property names.
+// https://code.google.com/p/v8/issues/detail?id=3570
+DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
+  const char* context_data[][2] = {{"class C {", "}"},
+                                   {"(class {", "});"},
+                                   {NULL, NULL}};
+
+  const char* class_body_data[] = {
+    "constructor() {}; static constructor() {}",
+    "m() {}; static m() {}",
+    "m() {}; m() {}",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ClassesAreStrictErrors) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"(", ");"},
+                                   {NULL, NULL}};
+
+  const char* class_body_data[] = {
+    "class C { method() { with ({}) {} } }",
+    "class C extends function() { with ({}) {} } {}",
+    "class C { *method() { with ({}) {} } }",
+    NULL};
+
+  static const ParserFlag always_flags[] = {
+    kAllowClasses,
+    kAllowHarmonyObjectLiterals
+  };
+  RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
 }