Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/parsing/OWNERS b/src/parsing/OWNERS
new file mode 100644
index 0000000..a5daeb3
--- /dev/null
+++ b/src/parsing/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+adamk@chromium.org
+littledan@chromium.org
+marja@chromium.org
+rossberg@chromium.org
+
diff --git a/src/parsing/expression-classifier.h b/src/parsing/expression-classifier.h
new file mode 100644
index 0000000..96ccf87
--- /dev/null
+++ b/src/parsing/expression-classifier.h
@@ -0,0 +1,356 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_EXPRESSION_CLASSIFIER_H
+#define V8_PARSING_EXPRESSION_CLASSIFIER_H
+
+#include "src/messages.h"
+#include "src/parsing/scanner.h"
+#include "src/parsing/token.h"
+
+namespace v8 {
+namespace internal {
+
+
+class ExpressionClassifier {
+ public:
+  struct Error {
+    Error()
+        : location(Scanner::Location::invalid()),
+          message(MessageTemplate::kNone),
+          type(kSyntaxError),
+          arg(nullptr) {}
+
+    Scanner::Location location;
+    MessageTemplate::Template message : 30;
+    ParseErrorType type : 2;
+    const char* arg;
+  };
+
+  enum TargetProduction {
+    ExpressionProduction = 1 << 0,
+    FormalParameterInitializerProduction = 1 << 1,
+    BindingPatternProduction = 1 << 2,
+    AssignmentPatternProduction = 1 << 3,
+    DistinctFormalParametersProduction = 1 << 4,
+    StrictModeFormalParametersProduction = 1 << 5,
+    StrongModeFormalParametersProduction = 1 << 6,
+    ArrowFormalParametersProduction = 1 << 7,
+    LetPatternProduction = 1 << 8,
+    CoverInitializedNameProduction = 1 << 9,
+
+    ExpressionProductions =
+        (ExpressionProduction | FormalParameterInitializerProduction),
+    PatternProductions = (BindingPatternProduction |
+                          AssignmentPatternProduction | LetPatternProduction),
+    FormalParametersProductions = (DistinctFormalParametersProduction |
+                                   StrictModeFormalParametersProduction |
+                                   StrongModeFormalParametersProduction),
+    StandardProductions = ExpressionProductions | PatternProductions,
+    AllProductions =
+        (StandardProductions | FormalParametersProductions |
+         ArrowFormalParametersProduction | CoverInitializedNameProduction)
+  };
+
+  enum FunctionProperties { NonSimpleParameter = 1 << 0 };
+
+  ExpressionClassifier()
+      : invalid_productions_(0),
+        function_properties_(0),
+        duplicate_finder_(nullptr) {}
+
+  explicit ExpressionClassifier(DuplicateFinder* duplicate_finder)
+      : invalid_productions_(0),
+        function_properties_(0),
+        duplicate_finder_(duplicate_finder) {}
+
+  bool is_valid(unsigned productions) const {
+    return (invalid_productions_ & productions) == 0;
+  }
+
+  DuplicateFinder* duplicate_finder() const { return duplicate_finder_; }
+
+  bool is_valid_expression() const { return is_valid(ExpressionProduction); }
+
+  bool is_valid_formal_parameter_initializer() const {
+    return is_valid(FormalParameterInitializerProduction);
+  }
+
+  bool is_valid_binding_pattern() const {
+    return is_valid(BindingPatternProduction);
+  }
+
+  bool is_valid_assignment_pattern() const {
+    return is_valid(AssignmentPatternProduction);
+  }
+
+  bool is_valid_arrow_formal_parameters() const {
+    return is_valid(ArrowFormalParametersProduction);
+  }
+
+  bool is_valid_formal_parameter_list_without_duplicates() const {
+    return is_valid(DistinctFormalParametersProduction);
+  }
+
+  // Note: callers should also check
+  // is_valid_formal_parameter_list_without_duplicates().
+  bool is_valid_strict_mode_formal_parameters() const {
+    return is_valid(StrictModeFormalParametersProduction);
+  }
+
+  // Note: callers should also check is_valid_strict_mode_formal_parameters()
+  // and is_valid_formal_parameter_list_without_duplicates().
+  bool is_valid_strong_mode_formal_parameters() const {
+    return is_valid(StrongModeFormalParametersProduction);
+  }
+
+  bool is_valid_let_pattern() const { return is_valid(LetPatternProduction); }
+
+  const Error& expression_error() const { return expression_error_; }
+
+  const Error& formal_parameter_initializer_error() const {
+    return formal_parameter_initializer_error_;
+  }
+
+  const Error& binding_pattern_error() const { return binding_pattern_error_; }
+
+  const Error& assignment_pattern_error() const {
+    return assignment_pattern_error_;
+  }
+
+  const Error& arrow_formal_parameters_error() const {
+    return arrow_formal_parameters_error_;
+  }
+
+  const Error& duplicate_formal_parameter_error() const {
+    return duplicate_formal_parameter_error_;
+  }
+
+  const Error& strict_mode_formal_parameter_error() const {
+    return strict_mode_formal_parameter_error_;
+  }
+
+  const Error& strong_mode_formal_parameter_error() const {
+    return strong_mode_formal_parameter_error_;
+  }
+
+  const Error& let_pattern_error() const { return let_pattern_error_; }
+
+  bool has_cover_initialized_name() const {
+    return !is_valid(CoverInitializedNameProduction);
+  }
+  const Error& cover_initialized_name_error() const {
+    return cover_initialized_name_error_;
+  }
+
+  bool is_simple_parameter_list() const {
+    return !(function_properties_ & NonSimpleParameter);
+  }
+
+  void RecordNonSimpleParameter() {
+    function_properties_ |= NonSimpleParameter;
+  }
+
+  void RecordExpressionError(const Scanner::Location& loc,
+                             MessageTemplate::Template message,
+                             const char* arg = nullptr) {
+    if (!is_valid_expression()) return;
+    invalid_productions_ |= ExpressionProduction;
+    expression_error_.location = loc;
+    expression_error_.message = message;
+    expression_error_.arg = arg;
+  }
+
+  void RecordExpressionError(const Scanner::Location& loc,
+                             MessageTemplate::Template message,
+                             ParseErrorType type, const char* arg = nullptr) {
+    if (!is_valid_expression()) return;
+    invalid_productions_ |= ExpressionProduction;
+    expression_error_.location = loc;
+    expression_error_.message = message;
+    expression_error_.arg = arg;
+    expression_error_.type = type;
+  }
+
+  void RecordFormalParameterInitializerError(const Scanner::Location& loc,
+                                             MessageTemplate::Template message,
+                                             const char* arg = nullptr) {
+    if (!is_valid_formal_parameter_initializer()) return;
+    invalid_productions_ |= FormalParameterInitializerProduction;
+    formal_parameter_initializer_error_.location = loc;
+    formal_parameter_initializer_error_.message = message;
+    formal_parameter_initializer_error_.arg = arg;
+  }
+
+  void RecordBindingPatternError(const Scanner::Location& loc,
+                                 MessageTemplate::Template message,
+                                 const char* arg = nullptr) {
+    if (!is_valid_binding_pattern()) return;
+    invalid_productions_ |= BindingPatternProduction;
+    binding_pattern_error_.location = loc;
+    binding_pattern_error_.message = message;
+    binding_pattern_error_.arg = arg;
+  }
+
+  void RecordAssignmentPatternError(const Scanner::Location& loc,
+                                    MessageTemplate::Template message,
+                                    const char* arg = nullptr) {
+    if (!is_valid_assignment_pattern()) return;
+    invalid_productions_ |= AssignmentPatternProduction;
+    assignment_pattern_error_.location = loc;
+    assignment_pattern_error_.message = message;
+    assignment_pattern_error_.arg = arg;
+  }
+
+  void RecordPatternError(const Scanner::Location& loc,
+                          MessageTemplate::Template message,
+                          const char* arg = nullptr) {
+    RecordBindingPatternError(loc, message, arg);
+    RecordAssignmentPatternError(loc, message, arg);
+  }
+
+  void RecordArrowFormalParametersError(const Scanner::Location& loc,
+                                        MessageTemplate::Template message,
+                                        const char* arg = nullptr) {
+    if (!is_valid_arrow_formal_parameters()) return;
+    invalid_productions_ |= ArrowFormalParametersProduction;
+    arrow_formal_parameters_error_.location = loc;
+    arrow_formal_parameters_error_.message = message;
+    arrow_formal_parameters_error_.arg = arg;
+  }
+
+  void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
+    if (!is_valid_formal_parameter_list_without_duplicates()) return;
+    invalid_productions_ |= DistinctFormalParametersProduction;
+    duplicate_formal_parameter_error_.location = loc;
+    duplicate_formal_parameter_error_.message = MessageTemplate::kParamDupe;
+    duplicate_formal_parameter_error_.arg = nullptr;
+  }
+
+  // Record a binding that would be invalid in strict mode.  Confusingly this
+  // is not the same as StrictFormalParameterList, which simply forbids
+  // duplicate bindings.
+  void RecordStrictModeFormalParameterError(const Scanner::Location& loc,
+                                            MessageTemplate::Template message,
+                                            const char* arg = nullptr) {
+    if (!is_valid_strict_mode_formal_parameters()) return;
+    invalid_productions_ |= StrictModeFormalParametersProduction;
+    strict_mode_formal_parameter_error_.location = loc;
+    strict_mode_formal_parameter_error_.message = message;
+    strict_mode_formal_parameter_error_.arg = arg;
+  }
+
+  void RecordStrongModeFormalParameterError(const Scanner::Location& loc,
+                                            MessageTemplate::Template message,
+                                            const char* arg = nullptr) {
+    if (!is_valid_strong_mode_formal_parameters()) return;
+    invalid_productions_ |= StrongModeFormalParametersProduction;
+    strong_mode_formal_parameter_error_.location = loc;
+    strong_mode_formal_parameter_error_.message = message;
+    strong_mode_formal_parameter_error_.arg = arg;
+  }
+
+  void RecordLetPatternError(const Scanner::Location& loc,
+                             MessageTemplate::Template message,
+                             const char* arg = nullptr) {
+    if (!is_valid_let_pattern()) return;
+    invalid_productions_ |= LetPatternProduction;
+    let_pattern_error_.location = loc;
+    let_pattern_error_.message = message;
+    let_pattern_error_.arg = arg;
+  }
+
+  void RecordCoverInitializedNameError(const Scanner::Location& loc,
+                                       MessageTemplate::Template message,
+                                       const char* arg = nullptr) {
+    if (has_cover_initialized_name()) return;
+    invalid_productions_ |= CoverInitializedNameProduction;
+    cover_initialized_name_error_.location = loc;
+    cover_initialized_name_error_.message = message;
+    cover_initialized_name_error_.arg = arg;
+  }
+
+  void ForgiveCoverInitializedNameError() {
+    invalid_productions_ &= ~CoverInitializedNameProduction;
+    cover_initialized_name_error_ = Error();
+  }
+
+  void ForgiveAssignmentPatternError() {
+    invalid_productions_ &= ~AssignmentPatternProduction;
+    assignment_pattern_error_ = Error();
+  }
+
+  void Accumulate(const ExpressionClassifier& inner,
+                  unsigned productions = StandardProductions) {
+    // Propagate errors from inner, but don't overwrite already recorded
+    // errors.
+    unsigned non_arrow_inner_invalid_productions =
+        inner.invalid_productions_ & ~ArrowFormalParametersProduction;
+    if (non_arrow_inner_invalid_productions == 0) return;
+    unsigned non_arrow_productions =
+        productions & ~ArrowFormalParametersProduction;
+    unsigned errors =
+        non_arrow_productions & non_arrow_inner_invalid_productions;
+    errors &= ~invalid_productions_;
+    if (errors != 0) {
+      invalid_productions_ |= errors;
+      if (errors & ExpressionProduction)
+        expression_error_ = inner.expression_error_;
+      if (errors & FormalParameterInitializerProduction)
+        formal_parameter_initializer_error_ =
+            inner.formal_parameter_initializer_error_;
+      if (errors & BindingPatternProduction)
+        binding_pattern_error_ = inner.binding_pattern_error_;
+      if (errors & AssignmentPatternProduction)
+        assignment_pattern_error_ = inner.assignment_pattern_error_;
+      if (errors & DistinctFormalParametersProduction)
+        duplicate_formal_parameter_error_ =
+            inner.duplicate_formal_parameter_error_;
+      if (errors & StrictModeFormalParametersProduction)
+        strict_mode_formal_parameter_error_ =
+            inner.strict_mode_formal_parameter_error_;
+      if (errors & StrongModeFormalParametersProduction)
+        strong_mode_formal_parameter_error_ =
+            inner.strong_mode_formal_parameter_error_;
+      if (errors & LetPatternProduction)
+        let_pattern_error_ = inner.let_pattern_error_;
+      if (errors & CoverInitializedNameProduction)
+        cover_initialized_name_error_ = inner.cover_initialized_name_error_;
+    }
+
+    // As an exception to the above, the result continues to be a valid arrow
+    // formal parameters if the inner expression is a valid binding pattern.
+    if (productions & ArrowFormalParametersProduction &&
+        is_valid_arrow_formal_parameters()) {
+      // Also copy function properties if expecting an arrow function
+      // parameter.
+      function_properties_ |= inner.function_properties_;
+
+      if (!inner.is_valid_binding_pattern()) {
+        invalid_productions_ |= ArrowFormalParametersProduction;
+        arrow_formal_parameters_error_ = inner.binding_pattern_error_;
+      }
+    }
+  }
+
+ private:
+  unsigned invalid_productions_;
+  unsigned function_properties_;
+  Error expression_error_;
+  Error formal_parameter_initializer_error_;
+  Error binding_pattern_error_;
+  Error assignment_pattern_error_;
+  Error arrow_formal_parameters_error_;
+  Error duplicate_formal_parameter_error_;
+  Error strict_mode_formal_parameter_error_;
+  Error strong_mode_formal_parameter_error_;
+  Error let_pattern_error_;
+  Error cover_initialized_name_error_;
+  DuplicateFinder* duplicate_finder_;
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_EXPRESSION_CLASSIFIER_H
diff --git a/src/parsing/func-name-inferrer.cc b/src/parsing/func-name-inferrer.cc
new file mode 100644
index 0000000..12013af
--- /dev/null
+++ b/src/parsing/func-name-inferrer.cc
@@ -0,0 +1,85 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/parsing/func-name-inferrer.h"
+
+#include "src/ast/ast.h"
+#include "src/ast/ast-value-factory.h"
+#include "src/list-inl.h"
+
+namespace v8 {
+namespace internal {
+
+FuncNameInferrer::FuncNameInferrer(AstValueFactory* ast_value_factory,
+                                   Zone* zone)
+    : ast_value_factory_(ast_value_factory),
+      entries_stack_(10, zone),
+      names_stack_(5, zone),
+      funcs_to_infer_(4, zone),
+      zone_(zone) {
+}
+
+
+void FuncNameInferrer::PushEnclosingName(const AstRawString* name) {
+  // Enclosing name is a name of a constructor function. To check
+  // that it is really a constructor, we check that it is not empty
+  // and starts with a capital letter.
+  if (!name->IsEmpty() && unibrow::Uppercase::Is(name->FirstCharacter())) {
+    names_stack_.Add(Name(name, kEnclosingConstructorName), zone());
+  }
+}
+
+
+void FuncNameInferrer::PushLiteralName(const AstRawString* name) {
+  if (IsOpen() && name != ast_value_factory_->prototype_string()) {
+    names_stack_.Add(Name(name, kLiteralName), zone());
+  }
+}
+
+
+void FuncNameInferrer::PushVariableName(const AstRawString* name) {
+  if (IsOpen() && name != ast_value_factory_->dot_result_string()) {
+    names_stack_.Add(Name(name, kVariableName), zone());
+  }
+}
+
+
+const AstString* FuncNameInferrer::MakeNameFromStack() {
+  return MakeNameFromStackHelper(0, ast_value_factory_->empty_string());
+}
+
+const AstString* FuncNameInferrer::MakeNameFromStackHelper(
+    int pos, const AstString* prev) {
+  if (pos >= names_stack_.length()) return prev;
+  if (pos < names_stack_.length() - 1 &&
+      names_stack_.at(pos).type == kVariableName &&
+      names_stack_.at(pos + 1).type == kVariableName) {
+    // Skip consecutive variable declarations.
+    return MakeNameFromStackHelper(pos + 1, prev);
+  } else {
+    if (prev->length() > 0) {
+      const AstRawString* name = names_stack_.at(pos).name;
+      if (prev->length() + name->length() + 1 > String::kMaxLength) return prev;
+      const AstConsString* curr = ast_value_factory_->NewConsString(
+          ast_value_factory_->dot_string(), name);
+      curr = ast_value_factory_->NewConsString(prev, curr);
+      return MakeNameFromStackHelper(pos + 1, curr);
+    } else {
+      return MakeNameFromStackHelper(pos + 1, names_stack_.at(pos).name);
+    }
+  }
+}
+
+
+void FuncNameInferrer::InferFunctionsNames() {
+  const AstString* func_name = MakeNameFromStack();
+  for (int i = 0; i < funcs_to_infer_.length(); ++i) {
+    funcs_to_infer_[i]->set_raw_inferred_name(func_name);
+  }
+  funcs_to_infer_.Rewind(0);
+}
+
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/func-name-inferrer.h b/src/parsing/func-name-inferrer.h
new file mode 100644
index 0000000..ba38ffe
--- /dev/null
+++ b/src/parsing/func-name-inferrer.h
@@ -0,0 +1,127 @@
+// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_FUNC_NAME_INFERRER_H_
+#define V8_PARSING_FUNC_NAME_INFERRER_H_
+
+#include "src/handles.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+class AstRawString;
+class AstString;
+class AstValueFactory;
+class FunctionLiteral;
+
+// FuncNameInferrer is a stateful class that is used to perform name
+// inference for anonymous functions during static analysis of source code.
+// Inference is performed in cases when an anonymous function is assigned
+// to a variable or a property (see test-func-name-inference.cc for examples.)
+//
+// The basic idea is that during parsing of LHSs of certain expressions
+// (assignments, declarations, object literals) we collect name strings,
+// and during parsing of the RHS, a function literal can be collected. After
+// parsing the RHS we can infer a name for function literals that do not have
+// a name.
+class FuncNameInferrer : public ZoneObject {
+ public:
+  FuncNameInferrer(AstValueFactory* ast_value_factory, Zone* zone);
+
+  // To enter function name inference state, put a FuncNameInferrer::State
+  // on the stack.
+  class State {
+   public:
+    explicit State(FuncNameInferrer* fni) : fni_(fni) {
+      if (fni_ != nullptr) fni_->Enter();
+    }
+    ~State() {
+      if (fni_ != nullptr) fni_->Leave();
+    }
+
+   private:
+    FuncNameInferrer* fni_;
+
+    DISALLOW_COPY_AND_ASSIGN(State);
+  };
+
+  // Returns whether we have entered name collection state.
+  bool IsOpen() const { return !entries_stack_.is_empty(); }
+
+  // Pushes an enclosing the name of enclosing function onto names stack.
+  void PushEnclosingName(const AstRawString* name);
+
+  // Pushes an encountered name onto names stack when in collection state.
+  void PushLiteralName(const AstRawString* name);
+
+  void PushVariableName(const AstRawString* name);
+
+  // Adds a function to infer name for.
+  void AddFunction(FunctionLiteral* func_to_infer) {
+    if (IsOpen()) {
+      funcs_to_infer_.Add(func_to_infer, zone());
+    }
+  }
+
+  void RemoveLastFunction() {
+    if (IsOpen() && !funcs_to_infer_.is_empty()) {
+      funcs_to_infer_.RemoveLast();
+    }
+  }
+
+  // Infers a function name and leaves names collection state.
+  void Infer() {
+    DCHECK(IsOpen());
+    if (!funcs_to_infer_.is_empty()) {
+      InferFunctionsNames();
+    }
+  }
+
+ private:
+  enum NameType {
+    kEnclosingConstructorName,
+    kLiteralName,
+    kVariableName
+  };
+  struct Name {
+    Name(const AstRawString* name, NameType type) : name(name), type(type) {}
+    const AstRawString* name;
+    NameType type;
+  };
+
+  void Enter() { entries_stack_.Add(names_stack_.length(), zone()); }
+
+  void Leave() {
+    DCHECK(IsOpen());
+    names_stack_.Rewind(entries_stack_.RemoveLast());
+    if (entries_stack_.is_empty()) funcs_to_infer_.Clear();
+  }
+
+  Zone* zone() const { return zone_; }
+
+  // Constructs a full name in dotted notation from gathered names.
+  const AstString* MakeNameFromStack();
+
+  // A helper function for MakeNameFromStack.
+  const AstString* MakeNameFromStackHelper(int pos,
+                                               const AstString* prev);
+
+  // Performs name inferring for added functions.
+  void InferFunctionsNames();
+
+  AstValueFactory* ast_value_factory_;
+  ZoneList<int> entries_stack_;
+  ZoneList<Name> names_stack_;
+  ZoneList<FunctionLiteral*> funcs_to_infer_;
+  Zone* zone_;
+
+  DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
+};
+
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_FUNC_NAME_INFERRER_H_
diff --git a/src/parsing/json-parser.h b/src/parsing/json-parser.h
new file mode 100644
index 0000000..e23c733
--- /dev/null
+++ b/src/parsing/json-parser.h
@@ -0,0 +1,842 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_JSON_PARSER_H_
+#define V8_PARSING_JSON_PARSER_H_
+
+#include "src/char-predicates.h"
+#include "src/conversions.h"
+#include "src/debug/debug.h"
+#include "src/factory.h"
+#include "src/messages.h"
+#include "src/parsing/scanner.h"
+#include "src/parsing/token.h"
+#include "src/transitions.h"
+#include "src/types.h"
+
+namespace v8 {
+namespace internal {
+
+enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle };
+
+
+// A simple json parser.
+template <bool seq_one_byte>
+class JsonParser BASE_EMBEDDED {
+ public:
+  MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) {
+    return JsonParser(source).ParseJson();
+  }
+
+  static const int kEndOfString = -1;
+
+ private:
+  explicit JsonParser(Handle<String> source)
+      : source_(source),
+        source_length_(source->length()),
+        isolate_(source->map()->GetHeap()->isolate()),
+        factory_(isolate_->factory()),
+        object_constructor_(isolate_->native_context()->object_function(),
+                            isolate_),
+        position_(-1) {
+    source_ = String::Flatten(source_);
+    pretenure_ = (source_length_ >= kPretenureTreshold) ? TENURED : NOT_TENURED;
+
+    // Optimized fast case where we only have Latin1 characters.
+    if (seq_one_byte) {
+      seq_source_ = Handle<SeqOneByteString>::cast(source_);
+    }
+  }
+
+  // Parse a string containing a single JSON value.
+  MaybeHandle<Object> ParseJson();
+
+  inline void Advance() {
+    position_++;
+    if (position_ >= source_length_) {
+      c0_ = kEndOfString;
+    } else if (seq_one_byte) {
+      c0_ = seq_source_->SeqOneByteStringGet(position_);
+    } else {
+      c0_ = source_->Get(position_);
+    }
+  }
+
+  // The JSON lexical grammar is specified in the ECMAScript 5 standard,
+  // section 15.12.1.1. The only allowed whitespace characters between tokens
+  // are tab, carriage-return, newline and space.
+
+  inline void AdvanceSkipWhitespace() {
+    do {
+      Advance();
+    } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r');
+  }
+
+  inline void SkipWhitespace() {
+    while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') {
+      Advance();
+    }
+  }
+
+  inline uc32 AdvanceGetChar() {
+    Advance();
+    return c0_;
+  }
+
+  // Checks that current charater is c.
+  // If so, then consume c and skip whitespace.
+  inline bool MatchSkipWhiteSpace(uc32 c) {
+    if (c0_ == c) {
+      AdvanceSkipWhitespace();
+      return true;
+    }
+    return false;
+  }
+
+  // A JSON string (production JSONString) is subset of valid JavaScript string
+  // literals. The string must only be double-quoted (not single-quoted), and
+  // the only allowed backslash-escapes are ", /, \, b, f, n, r, t and
+  // four-digit hex escapes (uXXXX). Any other use of backslashes is invalid.
+  Handle<String> ParseJsonString() {
+    return ScanJsonString<false>();
+  }
+
+  bool ParseJsonString(Handle<String> expected) {
+    int length = expected->length();
+    if (source_->length() - position_ - 1 > length) {
+      DisallowHeapAllocation no_gc;
+      String::FlatContent content = expected->GetFlatContent();
+      if (content.IsOneByte()) {
+        DCHECK_EQ('"', c0_);
+        const uint8_t* input_chars = seq_source_->GetChars() + position_ + 1;
+        const uint8_t* expected_chars = content.ToOneByteVector().start();
+        for (int i = 0; i < length; i++) {
+          uint8_t c0 = input_chars[i];
+          if (c0 != expected_chars[i] || c0 == '"' || c0 < 0x20 || c0 == '\\') {
+            return false;
+          }
+        }
+        if (input_chars[length] == '"') {
+          position_ = position_ + length + 1;
+          AdvanceSkipWhitespace();
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  Handle<String> ParseJsonInternalizedString() {
+    return ScanJsonString<true>();
+  }
+
+  template <bool is_internalized>
+  Handle<String> ScanJsonString();
+  // Creates a new string and copies prefix[start..end] into the beginning
+  // of it. Then scans the rest of the string, adding characters after the
+  // prefix. Called by ScanJsonString when reaching a '\' or non-Latin1 char.
+  template <typename StringType, typename SinkChar>
+  Handle<String> SlowScanJsonString(Handle<String> prefix, int start, int end);
+
+  // A JSON number (production JSONNumber) is a subset of the valid JavaScript
+  // decimal number literals.
+  // It includes an optional minus sign, must have at least one
+  // digit before and after a decimal point, may not have prefixed zeros (unless
+  // the integer part is zero), and may include an exponent part (e.g., "e-10").
+  // Hexadecimal and octal numbers are not allowed.
+  Handle<Object> ParseJsonNumber();
+
+  // Parse a single JSON value from input (grammar production JSONValue).
+  // A JSON value is either a (double-quoted) string literal, a number literal,
+  // one of "true", "false", or "null", or an object or array literal.
+  Handle<Object> ParseJsonValue();
+
+  // Parse a JSON object literal (grammar production JSONObject).
+  // An object literal is a squiggly-braced and comma separated sequence
+  // (possibly empty) of key/value pairs, where the key is a JSON string
+  // literal, the value is a JSON value, and the two are separated by a colon.
+  // A JSON array doesn't allow numbers and identifiers as keys, like a
+  // JavaScript array.
+  Handle<Object> ParseJsonObject();
+
+  // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded
+  // as an element, not a property.
+  ParseElementResult ParseElement(Handle<JSObject> json_object);
+
+  // Parses a JSON array literal (grammar production JSONArray). An array
+  // literal is a square-bracketed and comma separated sequence (possibly empty)
+  // of JSON values.
+  // A JSON array doesn't allow leaving out values from the sequence, nor does
+  // it allow a terminal comma, like a JavaScript array does.
+  Handle<Object> ParseJsonArray();
+
+
+  // Mark that a parsing error has happened at the current token, and
+  // return a null handle. Primarily for readability.
+  inline Handle<Object> ReportUnexpectedCharacter() {
+    return Handle<Object>::null();
+  }
+
+  inline Isolate* isolate() { return isolate_; }
+  inline Factory* factory() { return factory_; }
+  inline Handle<JSFunction> object_constructor() { return object_constructor_; }
+
+  static const int kInitialSpecialStringLength = 32;
+  static const int kPretenureTreshold = 100 * 1024;
+
+
+ private:
+  Zone* zone() { return &zone_; }
+
+  void CommitStateToJsonObject(Handle<JSObject> json_object, Handle<Map> map,
+                               ZoneList<Handle<Object> >* properties);
+
+  Handle<String> source_;
+  int source_length_;
+  Handle<SeqOneByteString> seq_source_;
+
+  PretenureFlag pretenure_;
+  Isolate* isolate_;
+  Factory* factory_;
+  Zone zone_;
+  Handle<JSFunction> object_constructor_;
+  uc32 c0_;
+  int position_;
+};
+
+template <bool seq_one_byte>
+MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() {
+  // Advance to the first character (possibly EOS)
+  AdvanceSkipWhitespace();
+  Handle<Object> result = ParseJsonValue();
+  if (result.is_null() || c0_ != kEndOfString) {
+    // Some exception (for example stack overflow) is already pending.
+    if (isolate_->has_pending_exception()) return Handle<Object>::null();
+
+    // Parse failed. Current character is the unexpected token.
+    Factory* factory = this->factory();
+    MessageTemplate::Template message;
+    Handle<String> argument;
+
+    switch (c0_) {
+      case kEndOfString:
+        message = MessageTemplate::kUnexpectedEOS;
+        break;
+      case '-':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        message = MessageTemplate::kUnexpectedTokenNumber;
+        break;
+      case '"':
+        message = MessageTemplate::kUnexpectedTokenString;
+        break;
+      default:
+        message = MessageTemplate::kUnexpectedToken;
+        argument = factory->LookupSingleCharacterStringFromCode(c0_);
+        break;
+    }
+
+    Handle<Script> script(factory->NewScript(source_));
+    // We should sent compile error event because we compile JSON object in
+    // separated source file.
+    isolate()->debug()->OnCompileError(script);
+    MessageLocation location(script, position_, position_ + 1);
+    Handle<Object> error = factory->NewSyntaxError(message, argument);
+    return isolate()->template Throw<Object>(error, &location);
+  }
+  return result;
+}
+
+
+// Parse any JSON value.
+template <bool seq_one_byte>
+Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() {
+  StackLimitCheck stack_check(isolate_);
+  if (stack_check.HasOverflowed()) {
+    isolate_->StackOverflow();
+    return Handle<Object>::null();
+  }
+
+  if (stack_check.InterruptRequested()) {
+    ExecutionAccess access(isolate_);
+    // Avoid blocking GC in long running parser (v8:3974).
+    isolate_->stack_guard()->HandleGCInterrupt();
+  }
+
+  if (c0_ == '"') return ParseJsonString();
+  if ((c0_ >= '0' && c0_ <= '9') || c0_ == '-') return ParseJsonNumber();
+  if (c0_ == '{') return ParseJsonObject();
+  if (c0_ == '[') return ParseJsonArray();
+  if (c0_ == 'f') {
+    if (AdvanceGetChar() == 'a' && AdvanceGetChar() == 'l' &&
+        AdvanceGetChar() == 's' && AdvanceGetChar() == 'e') {
+      AdvanceSkipWhitespace();
+      return factory()->false_value();
+    }
+    return ReportUnexpectedCharacter();
+  }
+  if (c0_ == 't') {
+    if (AdvanceGetChar() == 'r' && AdvanceGetChar() == 'u' &&
+        AdvanceGetChar() == 'e') {
+      AdvanceSkipWhitespace();
+      return factory()->true_value();
+    }
+    return ReportUnexpectedCharacter();
+  }
+  if (c0_ == 'n') {
+    if (AdvanceGetChar() == 'u' && AdvanceGetChar() == 'l' &&
+        AdvanceGetChar() == 'l') {
+      AdvanceSkipWhitespace();
+      return factory()->null_value();
+    }
+    return ReportUnexpectedCharacter();
+  }
+  return ReportUnexpectedCharacter();
+}
+
+
+template <bool seq_one_byte>
+ParseElementResult JsonParser<seq_one_byte>::ParseElement(
+    Handle<JSObject> json_object) {
+  uint32_t index = 0;
+  // Maybe an array index, try to parse it.
+  if (c0_ == '0') {
+    // With a leading zero, the string has to be "0" only to be an index.
+    Advance();
+  } else {
+    do {
+      int d = c0_ - '0';
+      if (index > 429496729U - ((d + 3) >> 3)) break;
+      index = (index * 10) + d;
+      Advance();
+    } while (IsDecimalDigit(c0_));
+  }
+
+  if (c0_ == '"') {
+    // Successfully parsed index, parse and store element.
+    AdvanceSkipWhitespace();
+
+    if (c0_ == ':') {
+      AdvanceSkipWhitespace();
+      Handle<Object> value = ParseJsonValue();
+      if (!value.is_null()) {
+        JSObject::SetOwnElementIgnoreAttributes(json_object, index, value, NONE)
+            .Assert();
+        return kElementFound;
+      } else {
+        return kNullHandle;
+      }
+    }
+  }
+  return kElementNotFound;
+}
+
+// Parse a JSON object. Position must be right at '{'.
+template <bool seq_one_byte>
+Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
+  HandleScope scope(isolate());
+  Handle<JSObject> json_object =
+      factory()->NewJSObject(object_constructor(), pretenure_);
+  Handle<Map> map(json_object->map());
+  int descriptor = 0;
+  ZoneList<Handle<Object> > properties(8, zone());
+  DCHECK_EQ(c0_, '{');
+
+  bool transitioning = true;
+
+  AdvanceSkipWhitespace();
+  if (c0_ != '}') {
+    do {
+      if (c0_ != '"') return ReportUnexpectedCharacter();
+
+      int start_position = position_;
+      Advance();
+
+      if (IsDecimalDigit(c0_)) {
+        ParseElementResult element_result = ParseElement(json_object);
+        if (element_result == kNullHandle) return Handle<Object>::null();
+        if (element_result == kElementFound) continue;
+      }
+      // Not an index, fallback to the slow path.
+
+      position_ = start_position;
+#ifdef DEBUG
+      c0_ = '"';
+#endif
+
+      Handle<String> key;
+      Handle<Object> value;
+
+      // Try to follow existing transitions as long as possible. Once we stop
+      // transitioning, no transition can be found anymore.
+      DCHECK(transitioning);
+      // First check whether there is a single expected transition. If so, try
+      // to parse it first.
+      bool follow_expected = false;
+      Handle<Map> target;
+      if (seq_one_byte) {
+        key = TransitionArray::ExpectedTransitionKey(map);
+        follow_expected = !key.is_null() && ParseJsonString(key);
+      }
+      // If the expected transition hits, follow it.
+      if (follow_expected) {
+        target = TransitionArray::ExpectedTransitionTarget(map);
+      } else {
+        // If the expected transition failed, parse an internalized string and
+        // try to find a matching transition.
+        key = ParseJsonInternalizedString();
+        if (key.is_null()) return ReportUnexpectedCharacter();
+
+        target = TransitionArray::FindTransitionToField(map, key);
+        // If a transition was found, follow it and continue.
+        transitioning = !target.is_null();
+      }
+      if (c0_ != ':') return ReportUnexpectedCharacter();
+
+      AdvanceSkipWhitespace();
+      value = ParseJsonValue();
+      if (value.is_null()) return ReportUnexpectedCharacter();
+
+      if (transitioning) {
+        PropertyDetails details =
+            target->instance_descriptors()->GetDetails(descriptor);
+        Representation expected_representation = details.representation();
+
+        if (value->FitsRepresentation(expected_representation)) {
+          if (expected_representation.IsHeapObject() &&
+              !target->instance_descriptors()
+                   ->GetFieldType(descriptor)
+                   ->NowContains(value)) {
+            Handle<HeapType> value_type(
+                value->OptimalType(isolate(), expected_representation));
+            Map::GeneralizeFieldType(target, descriptor,
+                                     expected_representation, value_type);
+          }
+          DCHECK(target->instance_descriptors()
+                     ->GetFieldType(descriptor)
+                     ->NowContains(value));
+          properties.Add(value, zone());
+          map = target;
+          descriptor++;
+          continue;
+        } else {
+          transitioning = false;
+        }
+      }
+
+      DCHECK(!transitioning);
+
+      // Commit the intermediate state to the object and stop transitioning.
+      CommitStateToJsonObject(json_object, map, &properties);
+
+      JSObject::DefinePropertyOrElementIgnoreAttributes(json_object, key, value)
+          .Check();
+    } while (transitioning && MatchSkipWhiteSpace(','));
+
+    // If we transitioned until the very end, transition the map now.
+    if (transitioning) {
+      CommitStateToJsonObject(json_object, map, &properties);
+    } else {
+      while (MatchSkipWhiteSpace(',')) {
+        HandleScope local_scope(isolate());
+        if (c0_ != '"') return ReportUnexpectedCharacter();
+
+        int start_position = position_;
+        Advance();
+
+        if (IsDecimalDigit(c0_)) {
+          ParseElementResult element_result = ParseElement(json_object);
+          if (element_result == kNullHandle) return Handle<Object>::null();
+          if (element_result == kElementFound) continue;
+        }
+        // Not an index, fallback to the slow path.
+
+        position_ = start_position;
+#ifdef DEBUG
+        c0_ = '"';
+#endif
+
+        Handle<String> key;
+        Handle<Object> value;
+
+        key = ParseJsonInternalizedString();
+        if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
+
+        AdvanceSkipWhitespace();
+        value = ParseJsonValue();
+        if (value.is_null()) return ReportUnexpectedCharacter();
+
+        JSObject::DefinePropertyOrElementIgnoreAttributes(json_object, key,
+                                                          value).Check();
+      }
+    }
+
+    if (c0_ != '}') {
+      return ReportUnexpectedCharacter();
+    }
+  }
+  AdvanceSkipWhitespace();
+  return scope.CloseAndEscape(json_object);
+}
+
+
+template <bool seq_one_byte>
+void JsonParser<seq_one_byte>::CommitStateToJsonObject(
+    Handle<JSObject> json_object, Handle<Map> map,
+    ZoneList<Handle<Object> >* properties) {
+  JSObject::AllocateStorageForMap(json_object, map);
+  DCHECK(!json_object->map()->is_dictionary_map());
+
+  DisallowHeapAllocation no_gc;
+
+  int length = properties->length();
+  for (int i = 0; i < length; i++) {
+    Handle<Object> value = (*properties)[i];
+    json_object->WriteToField(i, *value);
+  }
+}
+
+
+// Parse a JSON array. Position must be right at '['.
+template <bool seq_one_byte>
+Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() {
+  HandleScope scope(isolate());
+  ZoneList<Handle<Object> > elements(4, zone());
+  DCHECK_EQ(c0_, '[');
+
+  AdvanceSkipWhitespace();
+  if (c0_ != ']') {
+    do {
+      Handle<Object> element = ParseJsonValue();
+      if (element.is_null()) return ReportUnexpectedCharacter();
+      elements.Add(element, zone());
+    } while (MatchSkipWhiteSpace(','));
+    if (c0_ != ']') {
+      return ReportUnexpectedCharacter();
+    }
+  }
+  AdvanceSkipWhitespace();
+  // Allocate a fixed array with all the elements.
+  Handle<FixedArray> fast_elements =
+      factory()->NewFixedArray(elements.length(), pretenure_);
+  for (int i = 0, n = elements.length(); i < n; i++) {
+    fast_elements->set(i, *elements[i]);
+  }
+  Handle<Object> json_array = factory()->NewJSArrayWithElements(
+      fast_elements, FAST_ELEMENTS, Strength::WEAK, pretenure_);
+  return scope.CloseAndEscape(json_array);
+}
+
+
+template <bool seq_one_byte>
+Handle<Object> JsonParser<seq_one_byte>::ParseJsonNumber() {
+  bool negative = false;
+  int beg_pos = position_;
+  if (c0_ == '-') {
+    Advance();
+    negative = true;
+  }
+  if (c0_ == '0') {
+    Advance();
+    // Prefix zero is only allowed if it's the only digit before
+    // a decimal point or exponent.
+    if (IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
+  } else {
+    int i = 0;
+    int digits = 0;
+    if (c0_ < '1' || c0_ > '9') return ReportUnexpectedCharacter();
+    do {
+      i = i * 10 + c0_ - '0';
+      digits++;
+      Advance();
+    } while (IsDecimalDigit(c0_));
+    if (c0_ != '.' && c0_ != 'e' && c0_ != 'E' && digits < 10) {
+      SkipWhitespace();
+      return Handle<Smi>(Smi::FromInt((negative ? -i : i)), isolate());
+    }
+  }
+  if (c0_ == '.') {
+    Advance();
+    if (!IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
+    do {
+      Advance();
+    } while (IsDecimalDigit(c0_));
+  }
+  if (AsciiAlphaToLower(c0_) == 'e') {
+    Advance();
+    if (c0_ == '-' || c0_ == '+') Advance();
+    if (!IsDecimalDigit(c0_)) return ReportUnexpectedCharacter();
+    do {
+      Advance();
+    } while (IsDecimalDigit(c0_));
+  }
+  int length = position_ - beg_pos;
+  double number;
+  if (seq_one_byte) {
+    Vector<const uint8_t> chars(seq_source_->GetChars() +  beg_pos, length);
+    number = StringToDouble(isolate()->unicode_cache(), chars,
+                            NO_FLAGS,  // Hex, octal or trailing junk.
+                            std::numeric_limits<double>::quiet_NaN());
+  } else {
+    Vector<uint8_t> buffer = Vector<uint8_t>::New(length);
+    String::WriteToFlat(*source_, buffer.start(), beg_pos, position_);
+    Vector<const uint8_t> result =
+        Vector<const uint8_t>(buffer.start(), length);
+    number = StringToDouble(isolate()->unicode_cache(),
+                            result,
+                            NO_FLAGS,  // Hex, octal or trailing junk.
+                            0.0);
+    buffer.Dispose();
+  }
+  SkipWhitespace();
+  return factory()->NewNumber(number, pretenure_);
+}
+
+
+template <typename StringType>
+inline void SeqStringSet(Handle<StringType> seq_str, int i, uc32 c);
+
+template <>
+inline void SeqStringSet(Handle<SeqTwoByteString> seq_str, int i, uc32 c) {
+  seq_str->SeqTwoByteStringSet(i, c);
+}
+
+template <>
+inline void SeqStringSet(Handle<SeqOneByteString> seq_str, int i, uc32 c) {
+  seq_str->SeqOneByteStringSet(i, c);
+}
+
+template <typename StringType>
+inline Handle<StringType> NewRawString(Factory* factory,
+                                       int length,
+                                       PretenureFlag pretenure);
+
+template <>
+inline Handle<SeqTwoByteString> NewRawString(Factory* factory,
+                                             int length,
+                                             PretenureFlag pretenure) {
+  return factory->NewRawTwoByteString(length, pretenure).ToHandleChecked();
+}
+
+template <>
+inline Handle<SeqOneByteString> NewRawString(Factory* factory,
+                                           int length,
+                                           PretenureFlag pretenure) {
+  return factory->NewRawOneByteString(length, pretenure).ToHandleChecked();
+}
+
+
+// Scans the rest of a JSON string starting from position_ and writes
+// prefix[start..end] along with the scanned characters into a
+// sequential string of type StringType.
+template <bool seq_one_byte>
+template <typename StringType, typename SinkChar>
+Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString(
+    Handle<String> prefix, int start, int end) {
+  int count = end - start;
+  int max_length = count + source_length_ - position_;
+  int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count));
+  Handle<StringType> seq_string =
+      NewRawString<StringType>(factory(), length, pretenure_);
+  // Copy prefix into seq_str.
+  SinkChar* dest = seq_string->GetChars();
+  String::WriteToFlat(*prefix, dest, start, end);
+
+  while (c0_ != '"') {
+    // Check for control character (0x00-0x1f) or unterminated string (<0).
+    if (c0_ < 0x20) return Handle<String>::null();
+    if (count >= length) {
+      // We need to create a longer sequential string for the result.
+      return SlowScanJsonString<StringType, SinkChar>(seq_string, 0, count);
+    }
+    if (c0_ != '\\') {
+      // If the sink can contain UC16 characters, or source_ contains only
+      // Latin1 characters, there's no need to test whether we can store the
+      // character. Otherwise check whether the UC16 source character can fit
+      // in the Latin1 sink.
+      if (sizeof(SinkChar) == kUC16Size || seq_one_byte ||
+          c0_ <= String::kMaxOneByteCharCode) {
+        SeqStringSet(seq_string, count++, c0_);
+        Advance();
+      } else {
+        // StringType is SeqOneByteString and we just read a non-Latin1 char.
+        return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string, 0, count);
+      }
+    } else {
+      Advance();  // Advance past the \.
+      switch (c0_) {
+        case '"':
+        case '\\':
+        case '/':
+          SeqStringSet(seq_string, count++, c0_);
+          break;
+        case 'b':
+          SeqStringSet(seq_string, count++, '\x08');
+          break;
+        case 'f':
+          SeqStringSet(seq_string, count++, '\x0c');
+          break;
+        case 'n':
+          SeqStringSet(seq_string, count++, '\x0a');
+          break;
+        case 'r':
+          SeqStringSet(seq_string, count++, '\x0d');
+          break;
+        case 't':
+          SeqStringSet(seq_string, count++, '\x09');
+          break;
+        case 'u': {
+          uc32 value = 0;
+          for (int i = 0; i < 4; i++) {
+            Advance();
+            int digit = HexValue(c0_);
+            if (digit < 0) {
+              return Handle<String>::null();
+            }
+            value = value * 16 + digit;
+          }
+          if (sizeof(SinkChar) == kUC16Size ||
+              value <= String::kMaxOneByteCharCode) {
+            SeqStringSet(seq_string, count++, value);
+            break;
+          } else {
+            // StringType is SeqOneByteString and we just read a non-Latin1
+            // char.
+            position_ -= 6;  // Rewind position_ to \ in \uxxxx.
+            Advance();
+            return SlowScanJsonString<SeqTwoByteString, uc16>(seq_string,
+                                                              0,
+                                                              count);
+          }
+        }
+        default:
+          return Handle<String>::null();
+      }
+      Advance();
+    }
+  }
+
+  DCHECK_EQ('"', c0_);
+  // Advance past the last '"'.
+  AdvanceSkipWhitespace();
+
+  // Shrink seq_string length to count and return.
+  return SeqString::Truncate(seq_string, count);
+}
+
+
+template <bool seq_one_byte>
+template <bool is_internalized>
+Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
+  DCHECK_EQ('"', c0_);
+  Advance();
+  if (c0_ == '"') {
+    AdvanceSkipWhitespace();
+    return factory()->empty_string();
+  }
+
+  if (seq_one_byte && is_internalized) {
+    // Fast path for existing internalized strings.  If the the string being
+    // parsed is not a known internalized string, contains backslashes or
+    // unexpectedly reaches the end of string, return with an empty handle.
+    uint32_t running_hash = isolate()->heap()->HashSeed();
+    int position = position_;
+    uc32 c0 = c0_;
+    do {
+      if (c0 == '\\') {
+        c0_ = c0;
+        int beg_pos = position_;
+        position_ = position;
+        return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
+                                                             beg_pos,
+                                                             position_);
+      }
+      if (c0 < 0x20) return Handle<String>::null();
+      running_hash = StringHasher::AddCharacterCore(running_hash,
+                                                    static_cast<uint16_t>(c0));
+      position++;
+      if (position >= source_length_) return Handle<String>::null();
+      c0 = seq_source_->SeqOneByteStringGet(position);
+    } while (c0 != '"');
+    int length = position - position_;
+    uint32_t hash = (length <= String::kMaxHashCalcLength)
+                        ? StringHasher::GetHashCore(running_hash)
+                        : static_cast<uint32_t>(length);
+    Vector<const uint8_t> string_vector(
+        seq_source_->GetChars() + position_, length);
+    StringTable* string_table = isolate()->heap()->string_table();
+    uint32_t capacity = string_table->Capacity();
+    uint32_t entry = StringTable::FirstProbe(hash, capacity);
+    uint32_t count = 1;
+    Handle<String> result;
+    while (true) {
+      Object* element = string_table->KeyAt(entry);
+      if (element == isolate()->heap()->undefined_value()) {
+        // Lookup failure.
+        result = factory()->InternalizeOneByteString(
+            seq_source_, position_, length);
+        break;
+      }
+      if (element != isolate()->heap()->the_hole_value() &&
+          String::cast(element)->IsOneByteEqualTo(string_vector)) {
+        result = Handle<String>(String::cast(element), isolate());
+#ifdef DEBUG
+        uint32_t hash_field =
+            (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
+        DCHECK_EQ(static_cast<int>(result->Hash()),
+                  static_cast<int>(hash_field >> String::kHashShift));
+#endif
+        break;
+      }
+      entry = StringTable::NextProbe(entry, count++, capacity);
+    }
+    position_ = position;
+    // Advance past the last '"'.
+    AdvanceSkipWhitespace();
+    return result;
+  }
+
+  int beg_pos = position_;
+  // Fast case for Latin1 only without escape characters.
+  do {
+    // Check for control character (0x00-0x1f) or unterminated string (<0).
+    if (c0_ < 0x20) return Handle<String>::null();
+    if (c0_ != '\\') {
+      if (seq_one_byte || c0_ <= String::kMaxOneByteCharCode) {
+        Advance();
+      } else {
+        return SlowScanJsonString<SeqTwoByteString, uc16>(source_,
+                                                          beg_pos,
+                                                          position_);
+      }
+    } else {
+      return SlowScanJsonString<SeqOneByteString, uint8_t>(source_,
+                                                           beg_pos,
+                                                           position_);
+    }
+  } while (c0_ != '"');
+  int length = position_ - beg_pos;
+  Handle<String> result =
+      factory()->NewRawOneByteString(length, pretenure_).ToHandleChecked();
+  uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
+  String::WriteToFlat(*source_, dest, beg_pos, position_);
+
+  DCHECK_EQ('"', c0_);
+  // Advance past the last '"'.
+  AdvanceSkipWhitespace();
+  return result;
+}
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_JSON_PARSER_H_
diff --git a/src/parsing/parameter-initializer-rewriter.cc b/src/parsing/parameter-initializer-rewriter.cc
new file mode 100644
index 0000000..003bbeb
--- /dev/null
+++ b/src/parsing/parameter-initializer-rewriter.cc
@@ -0,0 +1,88 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/parsing/parameter-initializer-rewriter.h"
+
+#include "src/ast/ast.h"
+#include "src/ast/ast-expression-visitor.h"
+#include "src/ast/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+
+class Rewriter final : public AstExpressionVisitor {
+ public:
+  Rewriter(uintptr_t stack_limit, Expression* initializer, Scope* old_scope,
+           Scope* new_scope)
+      : AstExpressionVisitor(stack_limit, initializer),
+        old_scope_(old_scope),
+        new_scope_(new_scope) {}
+
+ private:
+  void VisitExpression(Expression* expr) override {}
+
+  void VisitFunctionLiteral(FunctionLiteral* expr) override;
+  void VisitClassLiteral(ClassLiteral* expr) override;
+  void VisitVariableProxy(VariableProxy* expr) override;
+
+  Scope* old_scope_;
+  Scope* new_scope_;
+};
+
+
+void Rewriter::VisitFunctionLiteral(FunctionLiteral* function_literal) {
+  function_literal->scope()->ReplaceOuterScope(new_scope_);
+}
+
+
+void Rewriter::VisitClassLiteral(ClassLiteral* class_literal) {
+  class_literal->scope()->ReplaceOuterScope(new_scope_);
+  if (class_literal->extends() != nullptr) {
+    Visit(class_literal->extends());
+  }
+  // No need to visit the constructor since it will have the class
+  // scope on its scope chain.
+  ZoneList<ObjectLiteralProperty*>* props = class_literal->properties();
+  for (int i = 0; i < props->length(); ++i) {
+    ObjectLiteralProperty* prop = props->at(i);
+    if (!prop->key()->IsLiteral()) {
+      Visit(prop->key());
+    }
+    // No need to visit the values, since all values are functions with
+    // the class scope on their scope chain.
+    DCHECK(prop->value()->IsFunctionLiteral());
+  }
+}
+
+
+void Rewriter::VisitVariableProxy(VariableProxy* proxy) {
+  if (proxy->is_resolved()) {
+    Variable* var = proxy->var();
+    DCHECK_EQ(var->mode(), TEMPORARY);
+    if (old_scope_->RemoveTemporary(var)) {
+      var->set_scope(new_scope_);
+      new_scope_->AddTemporary(var);
+    }
+  } else if (old_scope_->RemoveUnresolved(proxy)) {
+    new_scope_->AddUnresolved(proxy);
+  }
+}
+
+
+}  // anonymous namespace
+
+
+void RewriteParameterInitializerScope(uintptr_t stack_limit,
+                                      Expression* initializer, Scope* old_scope,
+                                      Scope* new_scope) {
+  Rewriter rewriter(stack_limit, initializer, old_scope, new_scope);
+  rewriter.Run();
+}
+
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/parameter-initializer-rewriter.h b/src/parsing/parameter-initializer-rewriter.h
new file mode 100644
index 0000000..255534c
--- /dev/null
+++ b/src/parsing/parameter-initializer-rewriter.h
@@ -0,0 +1,22 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_PARAMETER_EXPRESSION_REWRITER_H_
+#define V8_PARSING_PARAMETER_EXPRESSION_REWRITER_H_
+
+#include "src/ast/ast.h"
+
+namespace v8 {
+namespace internal {
+
+
+void RewriteParameterInitializerScope(uintptr_t stack_limit,
+                                      Expression* initializer, Scope* old_scope,
+                                      Scope* new_scope);
+
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_PARAMETER_EXPRESSION_REWRITER_H_
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
new file mode 100644
index 0000000..d9da445
--- /dev/null
+++ b/src/parsing/parser-base.h
@@ -0,0 +1,3381 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_PARSER_BASE_H
+#define V8_PARSING_PARSER_BASE_H
+
+#include "src/ast/scopes.h"
+#include "src/bailout-reason.h"
+#include "src/hashmap.h"
+#include "src/messages.h"
+#include "src/parsing/expression-classifier.h"
+#include "src/parsing/func-name-inferrer.h"
+#include "src/parsing/scanner.h"
+#include "src/parsing/token.h"
+
+namespace v8 {
+namespace internal {
+
+
+enum FunctionNameValidity {
+  kFunctionNameIsStrictReserved,
+  kSkipFunctionNameCheck,
+  kFunctionNameValidityUnknown
+};
+
+
+struct FormalParametersBase {
+  explicit FormalParametersBase(Scope* scope) : scope(scope) {}
+  Scope* scope;
+  bool has_rest = false;
+  bool is_simple = true;
+  int materialized_literals_count = 0;
+};
+
+
+// Common base class shared between parser and pre-parser. Traits encapsulate
+// the differences between Parser and PreParser:
+
+// - Return types: For example, Parser functions return Expression* and
+// PreParser functions return PreParserExpression.
+
+// - Creating parse tree nodes: Parser generates an AST during the recursive
+// descent. PreParser doesn't create a tree. Instead, it passes around minimal
+// data objects (PreParserExpression, PreParserIdentifier etc.) which contain
+// just enough data for the upper layer functions. PreParserFactory is
+// responsible for creating these dummy objects. It provides a similar kind of
+// interface as AstNodeFactory, so ParserBase doesn't need to care which one is
+// used.
+
+// - Miscellaneous other tasks interleaved with the recursive descent. For
+// example, Parser keeps track of which function literals should be marked as
+// pretenured, and PreParser doesn't care.
+
+// The traits are expected to contain the following typedefs:
+// struct Traits {
+//   // In particular...
+//   struct Type {
+//     // Used by FunctionState and BlockState.
+//     typedef Scope;
+//     typedef GeneratorVariable;
+//     // Return types for traversing functions.
+//     typedef Identifier;
+//     typedef Expression;
+//     typedef FunctionLiteral;
+//     typedef ClassLiteral;
+//     typedef ObjectLiteralProperty;
+//     typedef Literal;
+//     typedef ExpressionList;
+//     typedef PropertyList;
+//     typedef FormalParameter;
+//     typedef FormalParameters;
+//     // For constructing objects returned by the traversing functions.
+//     typedef Factory;
+//   };
+//   // ...
+// };
+
+template <typename Traits>
+class ParserBase : public Traits {
+ public:
+  // Shorten type names defined by Traits.
+  typedef typename Traits::Type::Expression ExpressionT;
+  typedef typename Traits::Type::Identifier IdentifierT;
+  typedef typename Traits::Type::FormalParameter FormalParameterT;
+  typedef typename Traits::Type::FormalParameters FormalParametersT;
+  typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
+  typedef typename Traits::Type::Literal LiteralT;
+  typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
+  typedef typename Traits::Type::StatementList StatementListT;
+
+  ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
+             v8::Extension* extension, AstValueFactory* ast_value_factory,
+             ParserRecorder* log, typename Traits::Type::Parser this_object)
+      : Traits(this_object),
+        parenthesized_function_(false),
+        scope_(NULL),
+        function_state_(NULL),
+        extension_(extension),
+        fni_(NULL),
+        ast_value_factory_(ast_value_factory),
+        log_(log),
+        mode_(PARSE_EAGERLY),  // Lazy mode must be set explicitly.
+        stack_limit_(stack_limit),
+        zone_(zone),
+        scanner_(scanner),
+        stack_overflow_(false),
+        allow_lazy_(false),
+        allow_natives_(false),
+        allow_harmony_sloppy_(false),
+        allow_harmony_sloppy_function_(false),
+        allow_harmony_sloppy_let_(false),
+        allow_harmony_default_parameters_(false),
+        allow_harmony_destructuring_bind_(false),
+        allow_harmony_destructuring_assignment_(false),
+        allow_strong_mode_(false),
+        allow_legacy_const_(true),
+        allow_harmony_do_expressions_(false),
+        allow_harmony_function_name_(false) {}
+
+#define ALLOW_ACCESSORS(name)                           \
+  bool allow_##name() const { return allow_##name##_; } \
+  void set_allow_##name(bool allow) { allow_##name##_ = allow; }
+
+  ALLOW_ACCESSORS(lazy);
+  ALLOW_ACCESSORS(natives);
+  ALLOW_ACCESSORS(harmony_sloppy);
+  ALLOW_ACCESSORS(harmony_sloppy_function);
+  ALLOW_ACCESSORS(harmony_sloppy_let);
+  ALLOW_ACCESSORS(harmony_default_parameters);
+  ALLOW_ACCESSORS(harmony_destructuring_bind);
+  ALLOW_ACCESSORS(harmony_destructuring_assignment);
+  ALLOW_ACCESSORS(strong_mode);
+  ALLOW_ACCESSORS(legacy_const);
+  ALLOW_ACCESSORS(harmony_do_expressions);
+  ALLOW_ACCESSORS(harmony_function_name);
+#undef ALLOW_ACCESSORS
+
+  uintptr_t stack_limit() const { return stack_limit_; }
+
+ protected:
+  enum AllowRestrictedIdentifiers {
+    kAllowRestrictedIdentifiers,
+    kDontAllowRestrictedIdentifiers
+  };
+
+  enum Mode {
+    PARSE_LAZILY,
+    PARSE_EAGERLY
+  };
+
+  enum VariableDeclarationContext {
+    kStatementListItem,
+    kStatement,
+    kForStatement
+  };
+
+  class Checkpoint;
+  class ObjectLiteralCheckerBase;
+
+  // ---------------------------------------------------------------------------
+  // FunctionState and BlockState together implement the parser's scope stack.
+  // The parser's current scope is in scope_. BlockState and FunctionState
+  // constructors push on the scope stack and the destructors pop. They are also
+  // used to hold the parser's per-function and per-block state.
+  class BlockState BASE_EMBEDDED {
+   public:
+    BlockState(Scope** scope_stack, Scope* scope)
+        : scope_stack_(scope_stack), outer_scope_(*scope_stack) {
+      *scope_stack_ = scope;
+    }
+    ~BlockState() { *scope_stack_ = outer_scope_; }
+
+   private:
+    Scope** scope_stack_;
+    Scope* outer_scope_;
+  };
+
+  struct DestructuringAssignment {
+   public:
+    DestructuringAssignment(ExpressionT expression, Scope* scope)
+        : assignment(expression), scope(scope) {}
+
+    ExpressionT assignment;
+    Scope* scope;
+  };
+
+  class FunctionState BASE_EMBEDDED {
+   public:
+    FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
+                  Scope* scope, FunctionKind kind,
+                  typename Traits::Type::Factory* factory);
+    ~FunctionState();
+
+    int NextMaterializedLiteralIndex() {
+      return next_materialized_literal_index_++;
+    }
+    int materialized_literal_count() {
+      return next_materialized_literal_index_;
+    }
+
+    void SkipMaterializedLiterals(int count) {
+      next_materialized_literal_index_ += count;
+    }
+
+    void AddProperty() { expected_property_count_++; }
+    int expected_property_count() { return expected_property_count_; }
+
+    Scanner::Location this_location() const { return this_location_; }
+    Scanner::Location super_location() const { return super_location_; }
+    Scanner::Location return_location() const { return return_location_; }
+    void set_this_location(Scanner::Location location) {
+      this_location_ = location;
+    }
+    void set_super_location(Scanner::Location location) {
+      super_location_ = location;
+    }
+    void set_return_location(Scanner::Location location) {
+      return_location_ = location;
+    }
+
+    bool is_generator() const { return IsGeneratorFunction(kind_); }
+
+    FunctionKind kind() const { return kind_; }
+    FunctionState* outer() const { return outer_function_state_; }
+
+    void set_generator_object_variable(
+        typename Traits::Type::GeneratorVariable* variable) {
+      DCHECK(variable != NULL);
+      DCHECK(is_generator());
+      generator_object_variable_ = variable;
+    }
+    typename Traits::Type::GeneratorVariable* generator_object_variable()
+        const {
+      return generator_object_variable_;
+    }
+
+    typename Traits::Type::Factory* factory() { return factory_; }
+
+    const List<DestructuringAssignment>& destructuring_assignments_to_rewrite()
+        const {
+      return destructuring_assignments_to_rewrite_;
+    }
+
+    void AddDestructuringAssignment(DestructuringAssignment pair) {
+      destructuring_assignments_to_rewrite_.Add(pair);
+    }
+
+   private:
+    // Used to assign an index to each literal that needs materialization in
+    // the function.  Includes regexp literals, and boilerplate for object and
+    // array literals.
+    int next_materialized_literal_index_;
+
+    // Properties count estimation.
+    int expected_property_count_;
+
+    // Location of most recent use of 'this' (invalid if none).
+    Scanner::Location this_location_;
+
+    // Location of most recent 'return' statement (invalid if none).
+    Scanner::Location return_location_;
+
+    // Location of call to the "super" constructor (invalid if none).
+    Scanner::Location super_location_;
+
+    FunctionKind kind_;
+    // For generators, this variable may hold the generator object. It variable
+    // is used by yield expressions and return statements. It is not necessary
+    // for generator functions to have this variable set.
+    Variable* generator_object_variable_;
+
+    FunctionState** function_state_stack_;
+    FunctionState* outer_function_state_;
+    Scope** scope_stack_;
+    Scope* outer_scope_;
+
+    List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
+
+    void RewriteDestructuringAssignments();
+
+    typename Traits::Type::Factory* factory_;
+
+    friend class ParserTraits;
+    friend class Checkpoint;
+  };
+
+  // Annoyingly, arrow functions first parse as comma expressions, then when we
+  // see the => we have to go back and reinterpret the arguments as being formal
+  // parameters.  To do so we need to reset some of the parser state back to
+  // what it was before the arguments were first seen.
+  class Checkpoint BASE_EMBEDDED {
+   public:
+    explicit Checkpoint(ParserBase* parser) {
+      function_state_ = parser->function_state_;
+      next_materialized_literal_index_ =
+          function_state_->next_materialized_literal_index_;
+      expected_property_count_ = function_state_->expected_property_count_;
+    }
+
+    void Restore(int* materialized_literal_index_delta) {
+      *materialized_literal_index_delta =
+          function_state_->next_materialized_literal_index_ -
+          next_materialized_literal_index_;
+      function_state_->next_materialized_literal_index_ =
+          next_materialized_literal_index_;
+      function_state_->expected_property_count_ = expected_property_count_;
+    }
+
+   private:
+    FunctionState* function_state_;
+    int next_materialized_literal_index_;
+    int expected_property_count_;
+  };
+
+  class ParsingModeScope BASE_EMBEDDED {
+   public:
+    ParsingModeScope(ParserBase* parser, Mode mode)
+        : parser_(parser),
+          old_mode_(parser->mode()) {
+      parser_->mode_ = mode;
+    }
+    ~ParsingModeScope() {
+      parser_->mode_ = old_mode_;
+    }
+
+   private:
+    ParserBase* parser_;
+    Mode old_mode_;
+  };
+
+  Scope* NewScope(Scope* parent, ScopeType scope_type) {
+    // Must always pass the function kind for FUNCTION_SCOPE.
+    DCHECK(scope_type != FUNCTION_SCOPE);
+    return NewScope(parent, scope_type, kNormalFunction);
+  }
+
+  Scope* NewScope(Scope* parent, ScopeType scope_type, FunctionKind kind) {
+    DCHECK(ast_value_factory());
+    DCHECK(scope_type != MODULE_SCOPE || FLAG_harmony_modules);
+    Scope* result = new (zone())
+        Scope(zone(), parent, scope_type, ast_value_factory(), kind);
+    result->Initialize();
+    return result;
+  }
+
+  Scanner* scanner() const { return scanner_; }
+  AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
+  int position() { return scanner_->location().beg_pos; }
+  int peek_position() { return scanner_->peek_location().beg_pos; }
+  bool stack_overflow() const { return stack_overflow_; }
+  void set_stack_overflow() { stack_overflow_ = true; }
+  Mode mode() const { return mode_; }
+  Zone* zone() const { return zone_; }
+
+  INLINE(Token::Value peek()) {
+    if (stack_overflow_) return Token::ILLEGAL;
+    return scanner()->peek();
+  }
+
+  INLINE(Token::Value PeekAhead()) {
+    if (stack_overflow_) return Token::ILLEGAL;
+    return scanner()->PeekAhead();
+  }
+
+  INLINE(Token::Value Next()) {
+    if (stack_overflow_) return Token::ILLEGAL;
+    {
+      if (GetCurrentStackPosition() < stack_limit_) {
+        // Any further calls to Next or peek will return the illegal token.
+        // The current call must return the next token, which might already
+        // have been peek'ed.
+        stack_overflow_ = true;
+      }
+    }
+    return scanner()->Next();
+  }
+
+  void Consume(Token::Value token) {
+    Token::Value next = Next();
+    USE(next);
+    USE(token);
+    DCHECK(next == token);
+  }
+
+  bool Check(Token::Value token) {
+    Token::Value next = peek();
+    if (next == token) {
+      Consume(next);
+      return true;
+    }
+    return false;
+  }
+
+  void Expect(Token::Value token, bool* ok) {
+    Token::Value next = Next();
+    if (next != token) {
+      ReportUnexpectedToken(next);
+      *ok = false;
+    }
+  }
+
+  void ExpectSemicolon(bool* ok) {
+    // Check for automatic semicolon insertion according to
+    // the rules given in ECMA-262, section 7.9, page 21.
+    Token::Value tok = peek();
+    if (tok == Token::SEMICOLON) {
+      Next();
+      return;
+    }
+    if (scanner()->HasAnyLineTerminatorBeforeNext() ||
+        tok == Token::RBRACE ||
+        tok == Token::EOS) {
+      return;
+    }
+    Expect(Token::SEMICOLON, ok);
+  }
+
+  bool peek_any_identifier() {
+    Token::Value next = peek();
+    return next == Token::IDENTIFIER || next == Token::FUTURE_RESERVED_WORD ||
+           next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
+           next == Token::STATIC || next == Token::YIELD;
+  }
+
+  bool CheckContextualKeyword(Vector<const char> keyword) {
+    if (PeekContextualKeyword(keyword)) {
+      Consume(Token::IDENTIFIER);
+      return true;
+    }
+    return false;
+  }
+
+  bool PeekContextualKeyword(Vector<const char> keyword) {
+    return peek() == Token::IDENTIFIER &&
+           scanner()->is_next_contextual_keyword(keyword);
+  }
+
+  void ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
+    Expect(Token::IDENTIFIER, ok);
+    if (!*ok) return;
+    if (!scanner()->is_literal_contextual_keyword(keyword)) {
+      ReportUnexpectedToken(scanner()->current_token());
+      *ok = false;
+    }
+  }
+
+  bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode, bool* ok) {
+    if (Check(Token::IN)) {
+      if (is_strong(language_mode())) {
+        ReportMessageAt(scanner()->location(), MessageTemplate::kStrongForIn);
+        *ok = false;
+      } else {
+        *visit_mode = ForEachStatement::ENUMERATE;
+      }
+      return true;
+    } else if (CheckContextualKeyword(CStrVector("of"))) {
+      *visit_mode = ForEachStatement::ITERATE;
+      return true;
+    }
+    return false;
+  }
+
+  // Checks whether an octal literal was last seen between beg_pos and end_pos.
+  // If so, reports an error. Only called for strict mode and template strings.
+  void CheckOctalLiteral(int beg_pos, int end_pos,
+                         MessageTemplate::Template message, bool* ok) {
+    Scanner::Location octal = scanner()->octal_position();
+    if (octal.IsValid() && beg_pos <= octal.beg_pos &&
+        octal.end_pos <= end_pos) {
+      ReportMessageAt(octal, message);
+      scanner()->clear_octal_position();
+      *ok = false;
+    }
+  }
+
+  inline void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+    CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kStrictOctalLiteral,
+                      ok);
+  }
+
+  inline void CheckTemplateOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+    CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kTemplateOctalLiteral,
+                      ok);
+  }
+
+  void CheckDestructuringElement(ExpressionT element,
+                                 ExpressionClassifier* classifier, int beg_pos,
+                                 int end_pos);
+
+  // Checking the name of a function literal. This has to be done after parsing
+  // the function, since the function can declare itself strict.
+  void CheckFunctionName(LanguageMode language_mode, IdentifierT function_name,
+                         FunctionNameValidity function_name_validity,
+                         const Scanner::Location& function_name_loc, bool* ok) {
+    if (function_name_validity == kSkipFunctionNameCheck) return;
+    // The function name needs to be checked in strict mode.
+    if (is_sloppy(language_mode)) return;
+
+    if (this->IsEvalOrArguments(function_name)) {
+      Traits::ReportMessageAt(function_name_loc,
+                              MessageTemplate::kStrictEvalArguments);
+      *ok = false;
+      return;
+    }
+    if (function_name_validity == kFunctionNameIsStrictReserved) {
+      Traits::ReportMessageAt(function_name_loc,
+                              MessageTemplate::kUnexpectedStrictReserved);
+      *ok = false;
+      return;
+    }
+    if (is_strong(language_mode) && this->IsUndefined(function_name)) {
+      Traits::ReportMessageAt(function_name_loc,
+                              MessageTemplate::kStrongUndefined);
+      *ok = false;
+      return;
+    }
+  }
+
+  // Determine precedence of given token.
+  static int Precedence(Token::Value token, bool accept_IN) {
+    if (token == Token::IN && !accept_IN)
+      return 0;  // 0 precedence will terminate binary expression parsing
+    return Token::Precedence(token);
+  }
+
+  typename Traits::Type::Factory* factory() {
+    return function_state_->factory();
+  }
+
+  LanguageMode language_mode() { return scope_->language_mode(); }
+  bool is_generator() const { return function_state_->is_generator(); }
+
+  bool allow_const() {
+    return is_strict(language_mode()) || allow_harmony_sloppy() ||
+           allow_legacy_const();
+  }
+
+  bool allow_let() {
+    return is_strict(language_mode()) || allow_harmony_sloppy_let();
+  }
+
+  // Report syntax errors.
+  void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
+                     ParseErrorType error_type = kSyntaxError) {
+    Scanner::Location source_location = scanner()->location();
+    Traits::ReportMessageAt(source_location, message, arg, error_type);
+  }
+
+  void ReportMessageAt(Scanner::Location location,
+                       MessageTemplate::Template message,
+                       ParseErrorType error_type = kSyntaxError) {
+    Traits::ReportMessageAt(location, message, reinterpret_cast<const char*>(0),
+                            error_type);
+  }
+
+  void GetUnexpectedTokenMessage(
+      Token::Value token, MessageTemplate::Template* message, const char** arg,
+      MessageTemplate::Template default_ = MessageTemplate::kUnexpectedToken);
+
+  void ReportUnexpectedToken(Token::Value token);
+  void ReportUnexpectedTokenAt(
+      Scanner::Location location, Token::Value token,
+      MessageTemplate::Template message = MessageTemplate::kUnexpectedToken);
+
+
+  void ReportClassifierError(const ExpressionClassifier::Error& error) {
+    Traits::ReportMessageAt(error.location, error.message, error.arg,
+                            error.type);
+  }
+
+  void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) {
+    if (!classifier->is_valid_expression() ||
+        classifier->has_cover_initialized_name()) {
+      const Scanner::Location& a = classifier->expression_error().location;
+      const Scanner::Location& b =
+          classifier->cover_initialized_name_error().location;
+      if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) {
+        ReportClassifierError(classifier->cover_initialized_name_error());
+      } else {
+        ReportClassifierError(classifier->expression_error());
+      }
+      *ok = false;
+    }
+  }
+
+  void ValidateFormalParameterInitializer(
+      const ExpressionClassifier* classifier, bool* ok) {
+    if (!classifier->is_valid_formal_parameter_initializer()) {
+      ReportClassifierError(classifier->formal_parameter_initializer_error());
+      *ok = false;
+    }
+  }
+
+  void ValidateBindingPattern(const ExpressionClassifier* classifier,
+                              bool* ok) {
+    if (!classifier->is_valid_binding_pattern()) {
+      ReportClassifierError(classifier->binding_pattern_error());
+      *ok = false;
+    }
+  }
+
+  void ValidateAssignmentPattern(const ExpressionClassifier* classifier,
+                                 bool* ok) {
+    if (!classifier->is_valid_assignment_pattern()) {
+      ReportClassifierError(classifier->assignment_pattern_error());
+      *ok = false;
+    }
+  }
+
+  void ValidateFormalParameters(const ExpressionClassifier* classifier,
+                                LanguageMode language_mode,
+                                bool allow_duplicates, bool* ok) {
+    if (!allow_duplicates &&
+        !classifier->is_valid_formal_parameter_list_without_duplicates()) {
+      ReportClassifierError(classifier->duplicate_formal_parameter_error());
+      *ok = false;
+    } else if (is_strict(language_mode) &&
+               !classifier->is_valid_strict_mode_formal_parameters()) {
+      ReportClassifierError(classifier->strict_mode_formal_parameter_error());
+      *ok = false;
+    } else if (is_strong(language_mode) &&
+               !classifier->is_valid_strong_mode_formal_parameters()) {
+      ReportClassifierError(classifier->strong_mode_formal_parameter_error());
+      *ok = false;
+    }
+  }
+
+  void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
+                                     ExpressionT expr,
+                                     bool parenthesized_formals, bool* ok) {
+    if (classifier->is_valid_binding_pattern()) {
+      // A simple arrow formal parameter: IDENTIFIER => BODY.
+      if (!this->IsIdentifier(expr)) {
+        Traits::ReportMessageAt(scanner()->location(),
+                                MessageTemplate::kUnexpectedToken,
+                                Token::String(scanner()->current_token()));
+        *ok = false;
+      }
+    } else if (!classifier->is_valid_arrow_formal_parameters()) {
+      // If after parsing the expr, we see an error but the expression is
+      // neither a valid binding pattern nor a valid parenthesized formal
+      // parameter list, show the "arrow formal parameters" error if the formals
+      // started with a parenthesis, and the binding pattern error otherwise.
+      const ExpressionClassifier::Error& error =
+          parenthesized_formals ? classifier->arrow_formal_parameters_error()
+                                : classifier->binding_pattern_error();
+      ReportClassifierError(error);
+      *ok = false;
+    }
+  }
+
+  void ValidateLetPattern(const ExpressionClassifier* classifier, bool* ok) {
+    if (!classifier->is_valid_let_pattern()) {
+      ReportClassifierError(classifier->let_pattern_error());
+      *ok = false;
+    }
+  }
+
+  void ExpressionUnexpectedToken(ExpressionClassifier* classifier) {
+    MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
+    const char* arg;
+    GetUnexpectedTokenMessage(peek(), &message, &arg);
+    classifier->RecordExpressionError(scanner()->peek_location(), message, arg);
+  }
+
+  void BindingPatternUnexpectedToken(ExpressionClassifier* classifier) {
+    MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
+    const char* arg;
+    GetUnexpectedTokenMessage(peek(), &message, &arg);
+    classifier->RecordBindingPatternError(scanner()->peek_location(), message,
+                                          arg);
+  }
+
+  void ArrowFormalParametersUnexpectedToken(ExpressionClassifier* classifier) {
+    MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
+    const char* arg;
+    GetUnexpectedTokenMessage(peek(), &message, &arg);
+    classifier->RecordArrowFormalParametersError(scanner()->peek_location(),
+                                                 message, arg);
+  }
+
+  void FormalParameterInitializerUnexpectedToken(
+      ExpressionClassifier* classifier) {
+    MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
+    const char* arg;
+    GetUnexpectedTokenMessage(peek(), &message, &arg);
+    classifier->RecordFormalParameterInitializerError(
+        scanner()->peek_location(), message, arg);
+  }
+
+  // Recursive descent functions:
+
+  // Parses an identifier that is valid for the current scope, in particular it
+  // fails on strict mode future reserved keywords in a strict scope. If
+  // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
+  // "arguments" as identifier even in strict mode (this is needed in cases like
+  // "var foo = eval;").
+  IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok);
+  IdentifierT ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
+                                         bool* ok);
+  // Parses an identifier or a strict mode future reserved word, and indicate
+  // whether it is strict mode future reserved. Allows passing in is_generator
+  // for the case of parsing the identifier in a function expression, where the
+  // relevant "is_generator" bit is of the function being parsed, not the
+  // containing
+  // function.
+  IdentifierT ParseIdentifierOrStrictReservedWord(bool is_generator,
+                                                  bool* is_strict_reserved,
+                                                  bool* ok);
+  IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
+                                                  bool* ok) {
+    return ParseIdentifierOrStrictReservedWord(this->is_generator(),
+                                               is_strict_reserved, ok);
+  }
+
+  IdentifierT ParseIdentifierName(bool* ok);
+  // Parses an identifier and determines whether or not it is 'get' or 'set'.
+  IdentifierT ParseIdentifierNameOrGetOrSet(bool* is_get, bool* is_set,
+                                            bool* ok);
+
+
+  ExpressionT ParseRegExpLiteral(bool seen_equal,
+                                 ExpressionClassifier* classifier, bool* ok);
+
+  ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
+                                     bool* ok);
+  ExpressionT ParseExpression(bool accept_IN, bool* ok);
+  ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier,
+                              bool* ok);
+  ExpressionT ParseExpression(bool accept_IN, int flags,
+                              ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
+                                bool* is_static, bool* is_computed_name,
+                                bool* is_identifier, bool* is_escaped_keyword,
+                                ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
+  ObjectLiteralPropertyT ParsePropertyDefinition(
+      ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
+      bool is_static, bool* is_computed_name, bool* has_seen_constructor,
+      ExpressionClassifier* classifier, IdentifierT* name, bool* ok);
+  typename Traits::Type::ExpressionList ParseArguments(
+      Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
+      bool* ok);
+
+  enum AssignmentExpressionFlags {
+    kIsNormalAssignment = 0,
+    kIsPossiblePatternElement = 1 << 0,
+    kIsPossibleArrowFormals = 1 << 1
+  };
+
+  ExpressionT ParseAssignmentExpression(bool accept_IN, int flags,
+                                        ExpressionClassifier* classifier,
+                                        bool* ok);
+  ExpressionT ParseAssignmentExpression(bool accept_IN,
+                                        ExpressionClassifier* classifier,
+                                        bool* ok) {
+    return ParseAssignmentExpression(accept_IN, kIsNormalAssignment, classifier,
+                                     ok);
+  }
+  ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseConditionalExpression(bool accept_IN,
+                                         ExpressionClassifier* classifier,
+                                         bool* ok);
+  ExpressionT ParseBinaryExpression(int prec, bool accept_IN,
+                                    ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseUnaryExpression(ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParsePostfixExpression(ExpressionClassifier* classifier,
+                                     bool* ok);
+  ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier,
+                                          bool* ok);
+  ExpressionT ParseMemberWithNewPrefixesExpression(
+      ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseMemberExpressionContinuation(
+      ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
+                                        const FormalParametersT& parameters,
+                                        const ExpressionClassifier& classifier,
+                                        bool* ok);
+  ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
+                                   ExpressionClassifier* classifier, bool* ok);
+  void AddTemplateExpression(ExpressionT);
+  ExpressionT ParseSuperExpression(bool is_new,
+                                   ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseNewTargetExpression(bool* ok);
+  ExpressionT ParseStrongInitializationExpression(
+      ExpressionClassifier* classifier, bool* ok);
+  ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
+                                             bool* ok);
+
+  void ParseFormalParameter(FormalParametersT* parameters,
+                            ExpressionClassifier* classifier, bool* ok);
+  void ParseFormalParameterList(FormalParametersT* parameters,
+                                ExpressionClassifier* classifier, bool* ok);
+  void CheckArityRestrictions(
+      int param_count, FunctionLiteral::ArityRestriction arity_restriction,
+      bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok);
+
+  bool IsNextLetKeyword();
+
+  // Checks if the expression is a valid reference expression (e.g., on the
+  // left-hand side of assignments). Although ruled out by ECMA as early errors,
+  // we allow calls for web compatibility and rewrite them to a runtime throw.
+  ExpressionT CheckAndRewriteReferenceExpression(
+      ExpressionT expression, int beg_pos, int end_pos,
+      MessageTemplate::Template message, bool* ok);
+  ExpressionT ClassifyAndRewriteReferenceExpression(
+      ExpressionClassifier* classifier, ExpressionT expression, int beg_pos,
+      int end_pos, MessageTemplate::Template message,
+      ParseErrorType type = kSyntaxError);
+  ExpressionT CheckAndRewriteReferenceExpression(
+      ExpressionT expression, int beg_pos, int end_pos,
+      MessageTemplate::Template message, ParseErrorType type, bool* ok);
+
+  bool IsValidReferenceExpression(ExpressionT expression);
+
+  bool IsAssignableIdentifier(ExpressionT expression) {
+    if (!Traits::IsIdentifier(expression)) return false;
+    if (is_strict(language_mode()) &&
+        Traits::IsEvalOrArguments(Traits::AsIdentifier(expression))) {
+      return false;
+    }
+    if (is_strong(language_mode()) &&
+        Traits::IsUndefined(Traits::AsIdentifier(expression))) {
+      return false;
+    }
+    return true;
+  }
+
+  // Keep track of eval() calls since they disable all local variable
+  // optimizations. This checks if expression is an eval call, and if yes,
+  // forwards the information to scope.
+  void CheckPossibleEvalCall(ExpressionT expression, Scope* scope) {
+    if (Traits::IsIdentifier(expression) &&
+        Traits::IsEval(Traits::AsIdentifier(expression))) {
+      scope->DeclarationScope()->RecordEvalCall();
+      scope->RecordEvalCall();
+    }
+  }
+
+  // Used to validate property names in object literals and class literals
+  enum PropertyKind {
+    kAccessorProperty,
+    kValueProperty,
+    kMethodProperty
+  };
+
+  class ObjectLiteralCheckerBase {
+   public:
+    explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
+
+    virtual void CheckProperty(Token::Value property, PropertyKind type,
+                               bool is_static, bool is_generator, bool* ok) = 0;
+
+    virtual ~ObjectLiteralCheckerBase() {}
+
+   protected:
+    ParserBase* parser() const { return parser_; }
+    Scanner* scanner() const { return parser_->scanner(); }
+
+   private:
+    ParserBase* parser_;
+  };
+
+  // Validation per ES6 object literals.
+  class ObjectLiteralChecker : public ObjectLiteralCheckerBase {
+   public:
+    explicit ObjectLiteralChecker(ParserBase* parser)
+        : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
+
+    void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
+                       bool is_generator, bool* ok) override;
+
+   private:
+    bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
+
+    bool has_seen_proto_;
+  };
+
+  // Validation per ES6 class literals.
+  class ClassLiteralChecker : public ObjectLiteralCheckerBase {
+   public:
+    explicit ClassLiteralChecker(ParserBase* parser)
+        : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
+
+    void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
+                       bool is_generator, bool* ok) override;
+
+   private:
+    bool IsConstructor() {
+      return this->scanner()->LiteralMatches("constructor", 11);
+    }
+    bool IsPrototype() {
+      return this->scanner()->LiteralMatches("prototype", 9);
+    }
+
+    bool has_seen_constructor_;
+  };
+
+  // If true, the next (and immediately following) function literal is
+  // preceded by a parenthesis.
+  // Heuristically that means that the function will be called immediately,
+  // so never lazily compile it.
+  bool parenthesized_function_;
+
+  Scope* scope_;                   // Scope stack.
+  FunctionState* function_state_;  // Function state stack.
+  v8::Extension* extension_;
+  FuncNameInferrer* fni_;
+  AstValueFactory* ast_value_factory_;  // Not owned.
+  ParserRecorder* log_;
+  Mode mode_;
+  uintptr_t stack_limit_;
+
+ private:
+  Zone* zone_;
+
+  Scanner* scanner_;
+  bool stack_overflow_;
+
+  bool allow_lazy_;
+  bool allow_natives_;
+  bool allow_harmony_sloppy_;
+  bool allow_harmony_sloppy_function_;
+  bool allow_harmony_sloppy_let_;
+  bool allow_harmony_default_parameters_;
+  bool allow_harmony_destructuring_bind_;
+  bool allow_harmony_destructuring_assignment_;
+  bool allow_strong_mode_;
+  bool allow_legacy_const_;
+  bool allow_harmony_do_expressions_;
+  bool allow_harmony_function_name_;
+};
+
+
+template <class Traits>
+ParserBase<Traits>::FunctionState::FunctionState(
+    FunctionState** function_state_stack, Scope** scope_stack, Scope* scope,
+    FunctionKind kind, typename Traits::Type::Factory* factory)
+    : next_materialized_literal_index_(0),
+      expected_property_count_(0),
+      this_location_(Scanner::Location::invalid()),
+      return_location_(Scanner::Location::invalid()),
+      super_location_(Scanner::Location::invalid()),
+      kind_(kind),
+      generator_object_variable_(NULL),
+      function_state_stack_(function_state_stack),
+      outer_function_state_(*function_state_stack),
+      scope_stack_(scope_stack),
+      outer_scope_(*scope_stack),
+      factory_(factory) {
+  *scope_stack_ = scope;
+  *function_state_stack = this;
+}
+
+
+template <class Traits>
+ParserBase<Traits>::FunctionState::~FunctionState() {
+  *scope_stack_ = outer_scope_;
+  *function_state_stack_ = outer_function_state_;
+}
+
+
+template <class Traits>
+void ParserBase<Traits>::GetUnexpectedTokenMessage(
+    Token::Value token, MessageTemplate::Template* message, const char** arg,
+    MessageTemplate::Template default_) {
+  // Four of the tokens are treated specially
+  switch (token) {
+    case Token::EOS:
+      *message = MessageTemplate::kUnexpectedEOS;
+      *arg = nullptr;
+      break;
+    case Token::SMI:
+    case Token::NUMBER:
+      *message = MessageTemplate::kUnexpectedTokenNumber;
+      *arg = nullptr;
+      break;
+    case Token::STRING:
+      *message = MessageTemplate::kUnexpectedTokenString;
+      *arg = nullptr;
+      break;
+    case Token::IDENTIFIER:
+      *message = MessageTemplate::kUnexpectedTokenIdentifier;
+      *arg = nullptr;
+      break;
+    case Token::FUTURE_RESERVED_WORD:
+      *message = MessageTemplate::kUnexpectedReserved;
+      *arg = nullptr;
+      break;
+    case Token::LET:
+    case Token::STATIC:
+    case Token::YIELD:
+    case Token::FUTURE_STRICT_RESERVED_WORD:
+      *message = is_strict(language_mode())
+                     ? MessageTemplate::kUnexpectedStrictReserved
+                     : MessageTemplate::kUnexpectedTokenIdentifier;
+      *arg = nullptr;
+      break;
+    case Token::TEMPLATE_SPAN:
+    case Token::TEMPLATE_TAIL:
+      *message = MessageTemplate::kUnexpectedTemplateString;
+      *arg = nullptr;
+      break;
+    case Token::ESCAPED_STRICT_RESERVED_WORD:
+    case Token::ESCAPED_KEYWORD:
+      *message = MessageTemplate::kInvalidEscapedReservedWord;
+      *arg = nullptr;
+      break;
+    default:
+      const char* name = Token::String(token);
+      DCHECK(name != NULL);
+      *arg = name;
+      break;
+  }
+}
+
+
+template <class Traits>
+void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
+  return ReportUnexpectedTokenAt(scanner_->location(), token);
+}
+
+
+template <class Traits>
+void ParserBase<Traits>::ReportUnexpectedTokenAt(
+    Scanner::Location source_location, Token::Value token,
+    MessageTemplate::Template message) {
+  const char* arg;
+  GetUnexpectedTokenMessage(token, &message, &arg);
+  Traits::ReportMessageAt(source_location, message, arg);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParseIdentifier(
+    AllowRestrictedIdentifiers allow_restricted_identifiers, bool* ok) {
+  ExpressionClassifier classifier;
+  auto result = ParseAndClassifyIdentifier(&classifier, ok);
+  if (!*ok) return Traits::EmptyIdentifier();
+
+  if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) {
+    ValidateAssignmentPattern(&classifier, ok);
+    if (!*ok) return Traits::EmptyIdentifier();
+    ValidateBindingPattern(&classifier, ok);
+    if (!*ok) return Traits::EmptyIdentifier();
+  }
+
+  return result;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::IdentifierT
+ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
+                                               bool* ok) {
+  Token::Value next = Next();
+  if (next == Token::IDENTIFIER) {
+    IdentifierT name = this->GetSymbol(scanner());
+    // When this function is used to read a formal parameter, we don't always
+    // know whether the function is going to be strict or sloppy.  Indeed for
+    // arrow functions we don't always know that the identifier we are reading
+    // is actually a formal parameter.  Therefore besides the errors that we
+    // must detect because we know we're in strict mode, we also record any
+    // error that we might make in the future once we know the language mode.
+    if (this->IsEval(name)) {
+      classifier->RecordStrictModeFormalParameterError(
+          scanner()->location(), MessageTemplate::kStrictEvalArguments);
+      if (is_strict(language_mode())) {
+        classifier->RecordBindingPatternError(
+            scanner()->location(), MessageTemplate::kStrictEvalArguments);
+      }
+    }
+    if (this->IsArguments(name)) {
+      scope_->RecordArgumentsUsage();
+      classifier->RecordStrictModeFormalParameterError(
+          scanner()->location(), MessageTemplate::kStrictEvalArguments);
+      if (is_strict(language_mode())) {
+        classifier->RecordBindingPatternError(
+            scanner()->location(), MessageTemplate::kStrictEvalArguments);
+      }
+      if (is_strong(language_mode())) {
+        classifier->RecordExpressionError(scanner()->location(),
+                                          MessageTemplate::kStrongArguments);
+      }
+    }
+    if (this->IsUndefined(name)) {
+      classifier->RecordStrongModeFormalParameterError(
+          scanner()->location(), MessageTemplate::kStrongUndefined);
+      if (is_strong(language_mode())) {
+        // TODO(dslomov): allow 'undefined' in nested patterns.
+        classifier->RecordBindingPatternError(
+            scanner()->location(), MessageTemplate::kStrongUndefined);
+        classifier->RecordAssignmentPatternError(
+            scanner()->location(), MessageTemplate::kStrongUndefined);
+      }
+    }
+
+    if (classifier->duplicate_finder() != nullptr &&
+        scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
+      classifier->RecordDuplicateFormalParameterError(scanner()->location());
+    }
+    return name;
+  } else if (is_sloppy(language_mode()) &&
+             (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+              next == Token::ESCAPED_STRICT_RESERVED_WORD ||
+              next == Token::LET || next == Token::STATIC ||
+              (next == Token::YIELD && !is_generator()))) {
+    classifier->RecordStrictModeFormalParameterError(
+        scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
+    if (next == Token::ESCAPED_STRICT_RESERVED_WORD &&
+        is_strict(language_mode())) {
+      ReportUnexpectedToken(next);
+      *ok = false;
+      return Traits::EmptyIdentifier();
+    }
+    if (next == Token::LET) {
+      classifier->RecordLetPatternError(scanner()->location(),
+                                        MessageTemplate::kLetInLexicalBinding);
+    }
+    return this->GetSymbol(scanner());
+  } else {
+    this->ReportUnexpectedToken(next);
+    *ok = false;
+    return Traits::EmptyIdentifier();
+  }
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::IdentifierT
+ParserBase<Traits>::ParseIdentifierOrStrictReservedWord(
+    bool is_generator, bool* is_strict_reserved, bool* ok) {
+  Token::Value next = Next();
+  if (next == Token::IDENTIFIER) {
+    *is_strict_reserved = false;
+  } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
+             next == Token::STATIC || (next == Token::YIELD && !is_generator)) {
+    *is_strict_reserved = true;
+  } else {
+    ReportUnexpectedToken(next);
+    *ok = false;
+    return Traits::EmptyIdentifier();
+  }
+
+  IdentifierT name = this->GetSymbol(scanner());
+  if (this->IsArguments(name)) scope_->RecordArgumentsUsage();
+  return name;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::IdentifierT
+ParserBase<Traits>::ParseIdentifierName(bool* ok) {
+  Token::Value next = Next();
+  if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
+      next != Token::LET && next != Token::STATIC && next != Token::YIELD &&
+      next != Token::FUTURE_STRICT_RESERVED_WORD &&
+      next != Token::ESCAPED_KEYWORD &&
+      next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
+    this->ReportUnexpectedToken(next);
+    *ok = false;
+    return Traits::EmptyIdentifier();
+  }
+
+  IdentifierT name = this->GetSymbol(scanner());
+  if (this->IsArguments(name)) scope_->RecordArgumentsUsage();
+  return name;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::IdentifierT
+ParserBase<Traits>::ParseIdentifierNameOrGetOrSet(bool* is_get,
+                                                  bool* is_set,
+                                                  bool* ok) {
+  IdentifierT result = ParseIdentifierName(ok);
+  if (!*ok) return Traits::EmptyIdentifier();
+  scanner()->IsGetOrSet(is_get, is_set);
+  return result;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseRegExpLiteral(
+    bool seen_equal, ExpressionClassifier* classifier, bool* ok) {
+  int pos = peek_position();
+  if (!scanner()->ScanRegExpPattern(seen_equal)) {
+    Next();
+    ReportMessage(MessageTemplate::kUnterminatedRegExp);
+    *ok = false;
+    return Traits::EmptyExpression();
+  }
+
+  int literal_index = function_state_->NextMaterializedLiteralIndex();
+
+  IdentifierT js_pattern = this->GetNextSymbol(scanner());
+  Maybe<RegExp::Flags> flags = scanner()->ScanRegExpFlags();
+  if (flags.IsNothing()) {
+    Next();
+    ReportMessage(MessageTemplate::kMalformedRegExpFlags);
+    *ok = false;
+    return Traits::EmptyExpression();
+  }
+  int js_flags = flags.FromJust();
+  Next();
+  return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index,
+                                     is_strong(language_mode()), pos);
+}
+
+
+#define CHECK_OK  ok); \
+  if (!*ok) return this->EmptyExpression(); \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+// Used in functions where the return type is not ExpressionT.
+#define CHECK_OK_CUSTOM(x) ok); \
+  if (!*ok) return this->x(); \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
+                                           bool* ok) {
+  // PrimaryExpression ::
+  //   'this'
+  //   'null'
+  //   'true'
+  //   'false'
+  //   Identifier
+  //   Number
+  //   String
+  //   ArrayLiteral
+  //   ObjectLiteral
+  //   RegExpLiteral
+  //   ClassLiteral
+  //   '(' Expression ')'
+  //   TemplateLiteral
+  //   do Block
+
+  int beg_pos = peek_position();
+  switch (peek()) {
+    case Token::THIS: {
+      BindingPatternUnexpectedToken(classifier);
+      Consume(Token::THIS);
+      if (FLAG_strong_this && is_strong(language_mode())) {
+        // Constructors' usages of 'this' in strong mode are parsed separately.
+        // TODO(rossberg): this does not work with arrow functions yet.
+        if (IsClassConstructor(function_state_->kind())) {
+          ReportMessage(MessageTemplate::kStrongConstructorThis);
+          *ok = false;
+          return this->EmptyExpression();
+        }
+      }
+      return this->ThisExpression(scope_, factory(), beg_pos);
+    }
+
+    case Token::NULL_LITERAL:
+    case Token::TRUE_LITERAL:
+    case Token::FALSE_LITERAL:
+      BindingPatternUnexpectedToken(classifier);
+      return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
+    case Token::SMI:
+    case Token::NUMBER:
+      classifier->RecordBindingPatternError(
+          scanner()->peek_location(), MessageTemplate::kUnexpectedTokenNumber);
+      return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
+
+    case Token::IDENTIFIER:
+    case Token::LET:
+    case Token::STATIC:
+    case Token::YIELD:
+    case Token::ESCAPED_STRICT_RESERVED_WORD:
+    case Token::FUTURE_STRICT_RESERVED_WORD: {
+      // Using eval or arguments in this context is OK even in strict mode.
+      IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK);
+      return this->ExpressionFromIdentifier(
+          name, beg_pos, scanner()->location().end_pos, scope_, factory());
+    }
+
+    case Token::STRING: {
+      classifier->RecordBindingPatternError(
+          scanner()->peek_location(), MessageTemplate::kUnexpectedTokenString);
+      Consume(Token::STRING);
+      return this->ExpressionFromString(beg_pos, scanner(), factory());
+    }
+
+    case Token::ASSIGN_DIV:
+      classifier->RecordBindingPatternError(
+          scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp);
+      return this->ParseRegExpLiteral(true, classifier, ok);
+
+    case Token::DIV:
+      classifier->RecordBindingPatternError(
+          scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp);
+      return this->ParseRegExpLiteral(false, classifier, ok);
+
+    case Token::LBRACK:
+      if (!allow_harmony_destructuring_bind()) {
+        BindingPatternUnexpectedToken(classifier);
+      }
+      return this->ParseArrayLiteral(classifier, ok);
+
+    case Token::LBRACE:
+      if (!allow_harmony_destructuring_bind()) {
+        BindingPatternUnexpectedToken(classifier);
+      }
+      return this->ParseObjectLiteral(classifier, ok);
+
+    case Token::LPAREN: {
+      // Arrow function formal parameters are either a single identifier or a
+      // list of BindingPattern productions enclosed in parentheses.
+      // Parentheses are not valid on the LHS of a BindingPattern, so we use the
+      // is_valid_binding_pattern() check to detect multiple levels of
+      // parenthesization.
+      if (!classifier->is_valid_binding_pattern()) {
+        ArrowFormalParametersUnexpectedToken(classifier);
+      }
+      BindingPatternUnexpectedToken(classifier);
+      Consume(Token::LPAREN);
+      if (Check(Token::RPAREN)) {
+        // ()=>x.  The continuation that looks for the => is in
+        // ParseAssignmentExpression.
+        classifier->RecordExpressionError(scanner()->location(),
+                                          MessageTemplate::kUnexpectedToken,
+                                          Token::String(Token::RPAREN));
+        classifier->RecordBindingPatternError(scanner()->location(),
+                                              MessageTemplate::kUnexpectedToken,
+                                              Token::String(Token::RPAREN));
+        return factory()->NewEmptyParentheses(beg_pos);
+      } else if (Check(Token::ELLIPSIS)) {
+        // (...x)=>x.  The continuation that looks for the => is in
+        // ParseAssignmentExpression.
+        int ellipsis_pos = position();
+        classifier->RecordExpressionError(scanner()->location(),
+                                          MessageTemplate::kUnexpectedToken,
+                                          Token::String(Token::ELLIPSIS));
+        classifier->RecordNonSimpleParameter();
+        ExpressionT expr =
+            this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+        if (peek() == Token::COMMA) {
+          ReportMessageAt(scanner()->peek_location(),
+                          MessageTemplate::kParamAfterRest);
+          *ok = false;
+          return this->EmptyExpression();
+        }
+        Expect(Token::RPAREN, CHECK_OK);
+        return factory()->NewSpread(expr, ellipsis_pos);
+      }
+      // Heuristically try to detect immediately called functions before
+      // seeing the call parentheses.
+      parenthesized_function_ = (peek() == Token::FUNCTION);
+      ExpressionT expr = this->ParseExpression(true, kIsPossibleArrowFormals,
+                                               classifier, CHECK_OK);
+      Expect(Token::RPAREN, CHECK_OK);
+      if (peek() != Token::ARROW) {
+        expr->set_is_parenthesized();
+      }
+      return expr;
+    }
+
+    case Token::CLASS: {
+      BindingPatternUnexpectedToken(classifier);
+      Consume(Token::CLASS);
+      if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
+        ReportMessage(MessageTemplate::kSloppyLexical);
+        *ok = false;
+        return this->EmptyExpression();
+      }
+      int class_token_position = position();
+      IdentifierT name = this->EmptyIdentifier();
+      bool is_strict_reserved_name = false;
+      Scanner::Location class_name_location = Scanner::Location::invalid();
+      if (peek_any_identifier()) {
+        name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
+                                                   CHECK_OK);
+        class_name_location = scanner()->location();
+      }
+      return this->ParseClassLiteral(name, class_name_location,
+                                     is_strict_reserved_name,
+                                     class_token_position, ok);
+    }
+
+    case Token::TEMPLATE_SPAN:
+    case Token::TEMPLATE_TAIL:
+      classifier->RecordBindingPatternError(
+          scanner()->peek_location(),
+          MessageTemplate::kUnexpectedTemplateString);
+      return this->ParseTemplateLiteral(Traits::NoTemplateTag(), beg_pos,
+                                        classifier, ok);
+
+    case Token::MOD:
+      if (allow_natives() || extension_ != NULL) {
+        BindingPatternUnexpectedToken(classifier);
+        return this->ParseV8Intrinsic(ok);
+      }
+      break;
+
+    case Token::DO:
+      if (allow_harmony_do_expressions()) {
+        BindingPatternUnexpectedToken(classifier);
+        return Traits::ParseDoExpression(ok);
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  ReportUnexpectedToken(Next());
+  *ok = false;
+  return this->EmptyExpression();
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
+    bool accept_IN, bool* ok) {
+  ExpressionClassifier classifier;
+  ExpressionT result = ParseExpression(accept_IN, &classifier, CHECK_OK);
+  result = Traits::RewriteNonPattern(result, &classifier, CHECK_OK);
+  return result;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
+    bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
+  return ParseExpression(accept_IN, kIsNormalAssignment, classifier, ok);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
+    bool accept_IN, int flags, ExpressionClassifier* classifier, bool* ok) {
+  // Expression ::
+  //   AssignmentExpression
+  //   Expression ',' AssignmentExpression
+
+  ExpressionClassifier binding_classifier;
+  ExpressionT result = this->ParseAssignmentExpression(
+      accept_IN, flags, &binding_classifier, CHECK_OK);
+  classifier->Accumulate(binding_classifier,
+                         ExpressionClassifier::AllProductions);
+  bool is_simple_parameter_list = this->IsIdentifier(result);
+  bool seen_rest = false;
+  while (peek() == Token::COMMA) {
+    if (seen_rest) {
+      // At this point the production can't possibly be valid, but we don't know
+      // which error to signal.
+      classifier->RecordArrowFormalParametersError(
+          scanner()->peek_location(), MessageTemplate::kParamAfterRest);
+    }
+    Consume(Token::COMMA);
+    bool is_rest = false;
+    if (peek() == Token::ELLIPSIS) {
+      // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
+      // as the formal parameters of'(x, y, ...z) => foo', and is not itself a
+      // valid expression or binding pattern.
+      ExpressionUnexpectedToken(classifier);
+      BindingPatternUnexpectedToken(classifier);
+      Consume(Token::ELLIPSIS);
+      seen_rest = is_rest = true;
+    }
+    int pos = position();
+    ExpressionT right = this->ParseAssignmentExpression(
+        accept_IN, flags, &binding_classifier, CHECK_OK);
+    if (is_rest) right = factory()->NewSpread(right, pos);
+    is_simple_parameter_list =
+        is_simple_parameter_list && this->IsIdentifier(right);
+    classifier->Accumulate(binding_classifier,
+                           ExpressionClassifier::AllProductions);
+    result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
+  }
+  if (!is_simple_parameter_list || seen_rest) {
+    classifier->RecordNonSimpleParameter();
+  }
+
+  return result;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
+    ExpressionClassifier* classifier, bool* ok) {
+  // ArrayLiteral ::
+  //   '[' Expression? (',' Expression?)* ']'
+
+  int pos = peek_position();
+  typename Traits::Type::ExpressionList values =
+      this->NewExpressionList(4, zone_);
+  int first_spread_index = -1;
+  Expect(Token::LBRACK, CHECK_OK);
+  while (peek() != Token::RBRACK) {
+    ExpressionT elem = this->EmptyExpression();
+    if (peek() == Token::COMMA) {
+      if (is_strong(language_mode())) {
+        ReportMessageAt(scanner()->peek_location(),
+                        MessageTemplate::kStrongEllision);
+        *ok = false;
+        return this->EmptyExpression();
+      }
+      elem = this->GetLiteralTheHole(peek_position(), factory());
+    } else if (peek() == Token::ELLIPSIS) {
+      int start_pos = peek_position();
+      Consume(Token::ELLIPSIS);
+      ExpressionT argument =
+          this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+      elem = factory()->NewSpread(argument, start_pos);
+
+      if (first_spread_index < 0) {
+        first_spread_index = values->length();
+      }
+
+      if (argument->IsAssignment()) {
+        classifier->RecordPatternError(
+            Scanner::Location(start_pos, scanner()->location().end_pos),
+            MessageTemplate::kInvalidDestructuringTarget);
+      } else {
+        CheckDestructuringElement(argument, classifier, start_pos,
+                                  scanner()->location().end_pos);
+      }
+
+      if (peek() == Token::COMMA) {
+        classifier->RecordPatternError(
+            Scanner::Location(start_pos, scanner()->location().end_pos),
+            MessageTemplate::kElementAfterRest);
+      }
+    } else {
+      elem = this->ParseAssignmentExpression(true, kIsPossiblePatternElement,
+                                             classifier, CHECK_OK);
+    }
+    values->Add(elem, zone_);
+    if (peek() != Token::RBRACK) {
+      Expect(Token::COMMA, CHECK_OK);
+    }
+  }
+  Expect(Token::RBRACK, CHECK_OK);
+
+  // Update the scope information before the pre-parsing bailout.
+  int literal_index = function_state_->NextMaterializedLiteralIndex();
+
+  return factory()->NewArrayLiteral(values, first_spread_index, literal_index,
+                                    is_strong(language_mode()), pos);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
+    IdentifierT* name, bool* is_get, bool* is_set, bool* is_static,
+    bool* is_computed_name, bool* is_identifier, bool* is_escaped_keyword,
+    ExpressionClassifier* classifier, bool* ok) {
+  Token::Value token = peek();
+  int pos = peek_position();
+
+  // For non computed property names we normalize the name a bit:
+  //
+  //   "12" -> 12
+  //   12.3 -> "12.3"
+  //   12.30 -> "12.3"
+  //   identifier -> "identifier"
+  //
+  // This is important because we use the property name as a key in a hash
+  // table when we compute constant properties.
+  switch (token) {
+    case Token::STRING:
+      Consume(Token::STRING);
+      *name = this->GetSymbol(scanner());
+      break;
+
+    case Token::SMI:
+      Consume(Token::SMI);
+      *name = this->GetNumberAsSymbol(scanner());
+      break;
+
+    case Token::NUMBER:
+      Consume(Token::NUMBER);
+      *name = this->GetNumberAsSymbol(scanner());
+      break;
+
+    case Token::LBRACK: {
+      *is_computed_name = true;
+      Consume(Token::LBRACK);
+      ExpressionClassifier computed_name_classifier;
+      ExpressionT expression =
+          ParseAssignmentExpression(true, &computed_name_classifier, CHECK_OK);
+      expression = Traits::RewriteNonPattern(
+          expression, &computed_name_classifier, CHECK_OK);
+      classifier->Accumulate(computed_name_classifier,
+                             ExpressionClassifier::ExpressionProductions);
+      Expect(Token::RBRACK, CHECK_OK);
+      return expression;
+    }
+
+    case Token::ESCAPED_KEYWORD:
+      *is_escaped_keyword = true;
+      *name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
+      break;
+
+    case Token::STATIC:
+      *is_static = true;
+
+    // Fall through.
+    default:
+      *is_identifier = true;
+      *name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
+      break;
+  }
+
+  uint32_t index;
+  return this->IsArrayIndex(*name, &index)
+             ? factory()->NewNumberLiteral(index, pos)
+             : factory()->NewStringLiteral(*name, pos);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ObjectLiteralPropertyT
+ParserBase<Traits>::ParsePropertyDefinition(
+    ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
+    bool is_static, bool* is_computed_name, bool* has_seen_constructor,
+    ExpressionClassifier* classifier, IdentifierT* name, bool* ok) {
+  DCHECK(!in_class || is_static || has_seen_constructor != nullptr);
+  ExpressionT value = this->EmptyExpression();
+  bool is_get = false;
+  bool is_set = false;
+  bool name_is_static = false;
+  bool is_generator = Check(Token::MUL);
+
+  Token::Value name_token = peek();
+  int next_beg_pos = scanner()->peek_location().beg_pos;
+  int next_end_pos = scanner()->peek_location().end_pos;
+  bool is_identifier = false;
+  bool is_escaped_keyword = false;
+  ExpressionT name_expression = ParsePropertyName(
+      name, &is_get, &is_set, &name_is_static, is_computed_name, &is_identifier,
+      &is_escaped_keyword, classifier,
+      CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
+  if (fni_ != nullptr && !*is_computed_name) {
+    this->PushLiteralName(fni_, *name);
+  }
+
+  bool escaped_static =
+      is_escaped_keyword &&
+      scanner()->is_literal_contextual_keyword(CStrVector("static"));
+
+  if (!in_class && !is_generator) {
+    DCHECK(!is_static);
+
+    if (peek() == Token::COLON) {
+      // PropertyDefinition
+      //    PropertyName ':' AssignmentExpression
+      if (!*is_computed_name) {
+        checker->CheckProperty(name_token, kValueProperty, false, false,
+                               CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+      }
+      Consume(Token::COLON);
+      value = this->ParseAssignmentExpression(
+          true, kIsPossiblePatternElement, classifier,
+          CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
+      return factory()->NewObjectLiteralProperty(name_expression, value, false,
+                                                 *is_computed_name);
+    }
+
+    if ((is_identifier || is_escaped_keyword) &&
+        (peek() == Token::COMMA || peek() == Token::RBRACE ||
+         peek() == Token::ASSIGN)) {
+      // PropertyDefinition
+      //    IdentifierReference
+      //    CoverInitializedName
+      //
+      // CoverInitializedName
+      //    IdentifierReference Initializer?
+      if (!Token::IsIdentifier(name_token, language_mode(),
+                               this->is_generator())) {
+        if (!escaped_static) {
+          ReportUnexpectedTokenAt(scanner()->location(), name_token);
+          *ok = false;
+          return this->EmptyObjectLiteralProperty();
+        }
+      }
+      if (classifier->duplicate_finder() != nullptr &&
+          scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
+        classifier->RecordDuplicateFormalParameterError(scanner()->location());
+      }
+      if (name_token == Token::LET) {
+        classifier->RecordLetPatternError(
+            scanner()->location(), MessageTemplate::kLetInLexicalBinding);
+      }
+
+      ExpressionT lhs = this->ExpressionFromIdentifier(
+          *name, next_beg_pos, next_end_pos, scope_, factory());
+      CheckDestructuringElement(lhs, classifier, next_beg_pos, next_end_pos);
+
+      if (peek() == Token::ASSIGN) {
+        Consume(Token::ASSIGN);
+        ExpressionClassifier rhs_classifier;
+        ExpressionT rhs = this->ParseAssignmentExpression(
+            true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+        rhs = Traits::RewriteNonPattern(
+            rhs, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+        classifier->Accumulate(rhs_classifier,
+                               ExpressionClassifier::ExpressionProductions);
+        value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
+                                         RelocInfo::kNoPosition);
+        classifier->RecordCoverInitializedNameError(
+            Scanner::Location(next_beg_pos, scanner()->location().end_pos),
+            MessageTemplate::kInvalidCoverInitializedName);
+      } else {
+        value = lhs;
+      }
+
+      return factory()->NewObjectLiteralProperty(
+          name_expression, value, ObjectLiteralProperty::COMPUTED, false,
+          false);
+    }
+  }
+
+  if (in_class && escaped_static && !is_static) {
+    ReportUnexpectedTokenAt(scanner()->location(), name_token);
+    *ok = false;
+    return this->EmptyObjectLiteralProperty();
+  }
+
+  // Method definitions are never valid in patterns.
+  classifier->RecordPatternError(
+      Scanner::Location(next_beg_pos, scanner()->location().end_pos),
+      MessageTemplate::kInvalidDestructuringTarget);
+
+  if (is_generator || peek() == Token::LPAREN) {
+    // MethodDefinition
+    //    PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
+    //    '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
+    if (!*is_computed_name) {
+      checker->CheckProperty(name_token, kMethodProperty, is_static,
+                             is_generator,
+                             CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+    }
+
+    FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
+                                     : FunctionKind::kConciseMethod;
+
+    if (in_class && !is_static && this->IsConstructor(*name)) {
+      *has_seen_constructor = true;
+      kind = has_extends ? FunctionKind::kSubclassConstructor
+                         : FunctionKind::kBaseConstructor;
+    }
+
+    if (!in_class) kind = WithObjectLiteralBit(kind);
+
+    value = this->ParseFunctionLiteral(
+        *name, scanner()->location(), kSkipFunctionNameCheck, kind,
+        RelocInfo::kNoPosition, FunctionLiteral::kAnonymousExpression,
+        FunctionLiteral::kNormalArity, language_mode(),
+        CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
+    return factory()->NewObjectLiteralProperty(name_expression, value,
+                                               ObjectLiteralProperty::COMPUTED,
+                                               is_static, *is_computed_name);
+  }
+
+  if (in_class && name_is_static && !is_static) {
+    // ClassElement (static)
+    //    'static' MethodDefinition
+    *name = this->EmptyIdentifier();
+    ObjectLiteralPropertyT property = ParsePropertyDefinition(
+        checker, true, has_extends, true, is_computed_name, nullptr, classifier,
+        name, ok);
+    property = Traits::RewriteNonPatternObjectLiteralProperty(property,
+                                                              classifier, ok);
+    return property;
+  }
+
+  if (is_get || is_set) {
+    // MethodDefinition (Accessors)
+    //    get PropertyName '(' ')' '{' FunctionBody '}'
+    //    set PropertyName '(' PropertySetParameterList ')' '{' FunctionBody '}'
+    *name = this->EmptyIdentifier();
+    bool dont_care = false;
+    name_token = peek();
+
+    name_expression = ParsePropertyName(
+        name, &dont_care, &dont_care, &dont_care, is_computed_name, &dont_care,
+        &dont_care, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
+    if (!*is_computed_name) {
+      checker->CheckProperty(name_token, kAccessorProperty, is_static,
+                             is_generator,
+                             CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+    }
+
+    FunctionKind kind = FunctionKind::kAccessorFunction;
+    if (!in_class) kind = WithObjectLiteralBit(kind);
+    typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral(
+        *name, scanner()->location(), kSkipFunctionNameCheck, kind,
+        RelocInfo::kNoPosition, FunctionLiteral::kAnonymousExpression,
+        is_get ? FunctionLiteral::kGetterArity : FunctionLiteral::kSetterArity,
+        language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
+    // Make sure the name expression is a string since we need a Name for
+    // Runtime_DefineAccessorPropertyUnchecked and since we can determine this
+    // statically we can skip the extra runtime check.
+    if (!*is_computed_name) {
+      name_expression =
+          factory()->NewStringLiteral(*name, name_expression->position());
+    }
+
+    return factory()->NewObjectLiteralProperty(
+        name_expression, value,
+        is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER,
+        is_static, *is_computed_name);
+  }
+
+  Token::Value next = Next();
+  ReportUnexpectedToken(next);
+  *ok = false;
+  return this->EmptyObjectLiteralProperty();
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
+    ExpressionClassifier* classifier, bool* ok) {
+  // ObjectLiteral ::
+  // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
+
+  int pos = peek_position();
+  typename Traits::Type::PropertyList properties =
+      this->NewPropertyList(4, zone_);
+  int number_of_boilerplate_properties = 0;
+  bool has_function = false;
+  bool has_computed_names = false;
+  ObjectLiteralChecker checker(this);
+
+  Expect(Token::LBRACE, CHECK_OK);
+
+  while (peek() != Token::RBRACE) {
+    FuncNameInferrer::State fni_state(fni_);
+
+    const bool in_class = false;
+    const bool is_static = false;
+    const bool has_extends = false;
+    bool is_computed_name = false;
+    IdentifierT name = this->EmptyIdentifier();
+    ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
+        &checker, in_class, has_extends, is_static, &is_computed_name, NULL,
+        classifier, &name, CHECK_OK);
+
+    if (is_computed_name) {
+      has_computed_names = true;
+    }
+
+    // Mark top-level object literals that contain function literals and
+    // pretenure the literal so it can be added as a constant function
+    // property. (Parser only.)
+    this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, property,
+                                                          &has_function);
+
+    // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
+    if (!has_computed_names && this->IsBoilerplateProperty(property)) {
+      number_of_boilerplate_properties++;
+    }
+    properties->Add(property, zone());
+
+    if (peek() != Token::RBRACE) {
+      // Need {} because of the CHECK_OK macro.
+      Expect(Token::COMMA, CHECK_OK);
+    }
+
+    if (fni_ != nullptr) fni_->Infer();
+
+    if (allow_harmony_function_name()) {
+      Traits::SetFunctionNameFromPropertyName(property, name);
+    }
+  }
+  Expect(Token::RBRACE, CHECK_OK);
+
+  // Computation of literal_index must happen before pre parse bailout.
+  int literal_index = function_state_->NextMaterializedLiteralIndex();
+
+  return factory()->NewObjectLiteral(properties,
+                                     literal_index,
+                                     number_of_boilerplate_properties,
+                                     has_function,
+                                     is_strong(language_mode()),
+                                     pos);
+}
+
+
+template <class Traits>
+typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
+    Scanner::Location* first_spread_arg_loc, ExpressionClassifier* classifier,
+    bool* ok) {
+  // Arguments ::
+  //   '(' (AssignmentExpression)*[','] ')'
+
+  Scanner::Location spread_arg = Scanner::Location::invalid();
+  typename Traits::Type::ExpressionList result =
+      this->NewExpressionList(4, zone_);
+  Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList));
+  bool done = (peek() == Token::RPAREN);
+  bool was_unspread = false;
+  int unspread_sequences_count = 0;
+  while (!done) {
+    int start_pos = peek_position();
+    bool is_spread = Check(Token::ELLIPSIS);
+
+    ExpressionT argument = this->ParseAssignmentExpression(
+        true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
+    argument = Traits::RewriteNonPattern(argument, classifier,
+                                         CHECK_OK_CUSTOM(NullExpressionList));
+    if (is_spread) {
+      if (!spread_arg.IsValid()) {
+        spread_arg.beg_pos = start_pos;
+        spread_arg.end_pos = peek_position();
+      }
+      argument = factory()->NewSpread(argument, start_pos);
+    }
+    result->Add(argument, zone_);
+
+    // unspread_sequences_count is the number of sequences of parameters which
+    // are not prefixed with a spread '...' operator.
+    if (is_spread) {
+      was_unspread = false;
+    } else if (!was_unspread) {
+      was_unspread = true;
+      unspread_sequences_count++;
+    }
+
+    if (result->length() > Code::kMaxArguments) {
+      ReportMessage(MessageTemplate::kTooManyArguments);
+      *ok = false;
+      return this->NullExpressionList();
+    }
+    done = (peek() != Token::COMMA);
+    if (!done) {
+      Next();
+    }
+  }
+  Scanner::Location location = scanner_->location();
+  if (Token::RPAREN != Next()) {
+    ReportMessageAt(location, MessageTemplate::kUnterminatedArgList);
+    *ok = false;
+    return this->NullExpressionList();
+  }
+  *first_spread_arg_loc = spread_arg;
+
+  if (spread_arg.IsValid()) {
+    // Unspread parameter sequences are translated into array literals in the
+    // parser. Ensure that the number of materialized literals matches between
+    // the parser and preparser
+    Traits::MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
+  }
+
+  return result;
+}
+
+// Precedence = 2
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, int flags,
+                                              ExpressionClassifier* classifier,
+                                              bool* ok) {
+  // AssignmentExpression ::
+  //   ConditionalExpression
+  //   ArrowFunction
+  //   YieldExpression
+  //   LeftHandSideExpression AssignmentOperator AssignmentExpression
+  bool maybe_pattern_element = flags & kIsPossiblePatternElement;
+  bool maybe_arrow_formals = flags & kIsPossibleArrowFormals;
+  bool is_destructuring_assignment = false;
+  int lhs_beg_pos = peek_position();
+
+  if (peek() == Token::YIELD && is_generator()) {
+    return this->ParseYieldExpression(classifier, ok);
+  }
+
+  FuncNameInferrer::State fni_state(fni_);
+  ParserBase<Traits>::Checkpoint checkpoint(this);
+  ExpressionClassifier arrow_formals_classifier(classifier->duplicate_finder());
+  bool parenthesized_formals = peek() == Token::LPAREN;
+  if (!parenthesized_formals) {
+    ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
+  }
+  ExpressionT expression = this->ParseConditionalExpression(
+      accept_IN, &arrow_formals_classifier, CHECK_OK);
+  if (peek() == Token::ARROW) {
+    BindingPatternUnexpectedToken(classifier);
+    ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
+                                  parenthesized_formals, CHECK_OK);
+    Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
+    Scope* scope =
+        this->NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
+    // Because the arrow's parameters were parsed in the outer scope, any
+    // usage flags that might have been triggered there need to be copied
+    // to the arrow scope.
+    scope_->PropagateUsageFlagsToScope(scope);
+    FormalParametersT parameters(scope);
+    if (!arrow_formals_classifier.is_simple_parameter_list()) {
+      scope->SetHasNonSimpleParameters();
+      parameters.is_simple = false;
+    }
+
+    checkpoint.Restore(&parameters.materialized_literals_count);
+
+    scope->set_start_position(lhs_beg_pos);
+    Scanner::Location duplicate_loc = Scanner::Location::invalid();
+    this->ParseArrowFunctionFormalParameterList(&parameters, expression, loc,
+                                                &duplicate_loc, CHECK_OK);
+    if (duplicate_loc.IsValid()) {
+      arrow_formals_classifier.RecordDuplicateFormalParameterError(
+          duplicate_loc);
+    }
+    expression = this->ParseArrowFunctionLiteral(
+        accept_IN, parameters, arrow_formals_classifier, CHECK_OK);
+    if (maybe_pattern_element) {
+      classifier->RecordPatternError(
+          Scanner::Location(lhs_beg_pos, scanner()->location().end_pos),
+          MessageTemplate::kInvalidDestructuringTarget);
+    }
+
+    if (fni_ != nullptr) fni_->Infer();
+
+    return expression;
+  }
+
+  if (this->IsValidReferenceExpression(expression)) {
+    arrow_formals_classifier.ForgiveAssignmentPatternError();
+  }
+
+  // "expression" was not itself an arrow function parameter list, but it might
+  // form part of one.  Propagate speculative formal parameter error locations.
+  classifier->Accumulate(
+      arrow_formals_classifier,
+      ExpressionClassifier::StandardProductions |
+          ExpressionClassifier::FormalParametersProductions |
+          ExpressionClassifier::CoverInitializedNameProduction);
+
+  bool maybe_pattern =
+      (expression->IsObjectLiteral() || expression->IsArrayLiteral()) &&
+      !expression->is_parenthesized();
+
+  if (!Token::IsAssignmentOp(peek())) {
+    // Parsed conditional expression only (no assignment).
+    if (maybe_pattern_element) {
+      CheckDestructuringElement(expression, classifier, lhs_beg_pos,
+                                scanner()->location().end_pos);
+    }
+    return expression;
+  }
+
+  if (!(allow_harmony_destructuring_bind() ||
+        allow_harmony_default_parameters())) {
+    BindingPatternUnexpectedToken(classifier);
+  }
+
+  if (allow_harmony_destructuring_assignment() && maybe_pattern &&
+      peek() == Token::ASSIGN) {
+    classifier->ForgiveCoverInitializedNameError();
+    ValidateAssignmentPattern(classifier, CHECK_OK);
+    is_destructuring_assignment = true;
+  } else if (maybe_arrow_formals) {
+    expression = this->ClassifyAndRewriteReferenceExpression(
+        classifier, expression, lhs_beg_pos, scanner()->location().end_pos,
+        MessageTemplate::kInvalidLhsInAssignment);
+  } else {
+    if (maybe_pattern_element) {
+      CheckDestructuringElement(expression, classifier, lhs_beg_pos,
+                                scanner()->location().end_pos);
+    }
+    expression = this->CheckAndRewriteReferenceExpression(
+        expression, lhs_beg_pos, scanner()->location().end_pos,
+        MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
+  }
+
+  expression = this->MarkExpressionAsAssigned(expression);
+
+  Token::Value op = Next();  // Get assignment operator.
+  if (op != Token::ASSIGN) {
+    classifier->RecordBindingPatternError(scanner()->location(),
+                                          MessageTemplate::kUnexpectedToken,
+                                          Token::String(op));
+  }
+  int pos = position();
+
+  ExpressionClassifier rhs_classifier;
+
+  ExpressionT right =
+      this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK);
+  right = Traits::RewriteNonPattern(right, &rhs_classifier, CHECK_OK);
+  classifier->Accumulate(
+      rhs_classifier, ExpressionClassifier::ExpressionProductions |
+                          ExpressionClassifier::CoverInitializedNameProduction);
+
+  // TODO(1231235): We try to estimate the set of properties set by
+  // constructors. We define a new property whenever there is an
+  // assignment to a property of 'this'. We should probably only add
+  // properties if we haven't seen them before. Otherwise we'll
+  // probably overestimate the number of properties.
+  if (op == Token::ASSIGN && this->IsThisProperty(expression)) {
+    function_state_->AddProperty();
+  }
+
+  if (op != Token::ASSIGN && maybe_pattern_element) {
+    classifier->RecordAssignmentPatternError(
+        Scanner::Location(lhs_beg_pos, scanner()->location().end_pos),
+        MessageTemplate::kInvalidDestructuringTarget);
+  }
+
+  this->CheckAssigningFunctionLiteralToProperty(expression, right);
+
+  if (fni_ != NULL) {
+    // Check if the right hand side is a call to avoid inferring a
+    // name if we're dealing with "a = function(){...}();"-like
+    // expression.
+    if ((op == Token::INIT || op == Token::ASSIGN) &&
+        (!right->IsCall() && !right->IsCallNew())) {
+      fni_->Infer();
+    } else {
+      fni_->RemoveLastFunction();
+    }
+  }
+
+  if (op == Token::ASSIGN && allow_harmony_function_name()) {
+    Traits::SetFunctionNameFromIdentifierRef(right, expression);
+  }
+
+  ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
+
+  if (is_destructuring_assignment) {
+    result = factory()->NewRewritableAssignmentExpression(result);
+    Traits::QueueDestructuringAssignmentForRewriting(result);
+  }
+
+  return result;
+}
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
+                                         bool* ok) {
+  // YieldExpression ::
+  //   'yield' ([no line terminator] '*'? AssignmentExpression)?
+  int pos = peek_position();
+  classifier->RecordPatternError(scanner()->peek_location(),
+                                 MessageTemplate::kInvalidDestructuringTarget);
+  FormalParameterInitializerUnexpectedToken(classifier);
+  Expect(Token::YIELD, CHECK_OK);
+  ExpressionT generator_object =
+      factory()->NewVariableProxy(function_state_->generator_object_variable());
+  ExpressionT expression = Traits::EmptyExpression();
+  Yield::Kind kind = Yield::kSuspend;
+  if (!scanner()->HasAnyLineTerminatorBeforeNext()) {
+    if (Check(Token::MUL)) kind = Yield::kDelegating;
+    switch (peek()) {
+      case Token::EOS:
+      case Token::SEMICOLON:
+      case Token::RBRACE:
+      case Token::RBRACK:
+      case Token::RPAREN:
+      case Token::COLON:
+      case Token::COMMA:
+        // The above set of tokens is the complete set of tokens that can appear
+        // after an AssignmentExpression, and none of them can start an
+        // AssignmentExpression.  This allows us to avoid looking for an RHS for
+        // a Yield::kSuspend operation, given only one look-ahead token.
+        if (kind == Yield::kSuspend)
+          break;
+        DCHECK_EQ(Yield::kDelegating, kind);
+        // Delegating yields require an RHS; fall through.
+      default:
+        expression = ParseAssignmentExpression(false, classifier, CHECK_OK);
+        expression =
+            Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+        break;
+    }
+  }
+  if (kind == Yield::kDelegating) {
+    // var iterator = subject[Symbol.iterator]();
+    // Hackily disambiguate o from o.next and o [Symbol.iterator]().
+    // TODO(verwaest): Come up with a better solution.
+    expression = this->GetIterator(expression, factory(), pos + 1);
+  }
+  // Hackily disambiguate o from o.next and o [Symbol.iterator]().
+  // TODO(verwaest): Come up with a better solution.
+  typename Traits::Type::YieldExpression yield =
+      factory()->NewYield(generator_object, expression, kind, pos);
+  return yield;
+}
+
+
+// Precedence = 3
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseConditionalExpression(bool accept_IN,
+                                               ExpressionClassifier* classifier,
+                                               bool* ok) {
+  // ConditionalExpression ::
+  //   LogicalOrExpression
+  //   LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
+
+  int pos = peek_position();
+  // We start using the binary expression parser for prec >= 4 only!
+  ExpressionT expression =
+      this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
+  if (peek() != Token::CONDITIONAL) return expression;
+  expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+  ArrowFormalParametersUnexpectedToken(classifier);
+  BindingPatternUnexpectedToken(classifier);
+  Consume(Token::CONDITIONAL);
+  // In parsing the first assignment expression in conditional
+  // expressions we always accept the 'in' keyword; see ECMA-262,
+  // section 11.12, page 58.
+  ExpressionT left = ParseAssignmentExpression(true, classifier, CHECK_OK);
+  left = Traits::RewriteNonPattern(left, classifier, CHECK_OK);
+  Expect(Token::COLON, CHECK_OK);
+  ExpressionT right =
+      ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
+  right = Traits::RewriteNonPattern(right, classifier, CHECK_OK);
+  return factory()->NewConditional(expression, left, right, pos);
+}
+
+
+// Precedence >= 4
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN,
+                                          ExpressionClassifier* classifier,
+                                          bool* ok) {
+  DCHECK(prec >= 4);
+  ExpressionT x = this->ParseUnaryExpression(classifier, CHECK_OK);
+  for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
+    // prec1 >= 4
+    while (Precedence(peek(), accept_IN) == prec1) {
+      x = Traits::RewriteNonPattern(x, classifier, CHECK_OK);
+      BindingPatternUnexpectedToken(classifier);
+      ArrowFormalParametersUnexpectedToken(classifier);
+      Token::Value op = Next();
+      Scanner::Location op_location = scanner()->location();
+      int pos = position();
+      ExpressionT y =
+          ParseBinaryExpression(prec1 + 1, accept_IN, classifier, CHECK_OK);
+      y = Traits::RewriteNonPattern(y, classifier, CHECK_OK);
+
+      if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos,
+                                                       factory())) {
+        continue;
+      }
+
+      // For now we distinguish between comparisons and other binary
+      // operations.  (We could combine the two and get rid of this
+      // code and AST node eventually.)
+      if (Token::IsCompareOp(op)) {
+        // We have a comparison.
+        Token::Value cmp = op;
+        switch (op) {
+          case Token::NE: cmp = Token::EQ; break;
+          case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
+          default: break;
+        }
+        if (cmp == Token::EQ && is_strong(language_mode())) {
+          ReportMessageAt(op_location, MessageTemplate::kStrongEqual);
+          *ok = false;
+          return this->EmptyExpression();
+        }
+        x = factory()->NewCompareOperation(cmp, x, y, pos);
+        if (cmp != op) {
+          // The comparison was negated - add a NOT.
+          x = factory()->NewUnaryOperation(Token::NOT, x, pos);
+        }
+
+      } else {
+        // We have a "normal" binary operation.
+        x = factory()->NewBinaryOperation(op, x, y, pos);
+      }
+    }
+  }
+  return x;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
+                                         bool* ok) {
+  // UnaryExpression ::
+  //   PostfixExpression
+  //   'delete' UnaryExpression
+  //   'void' UnaryExpression
+  //   'typeof' UnaryExpression
+  //   '++' UnaryExpression
+  //   '--' UnaryExpression
+  //   '+' UnaryExpression
+  //   '-' UnaryExpression
+  //   '~' UnaryExpression
+  //   '!' UnaryExpression
+
+  Token::Value op = peek();
+  if (Token::IsUnaryOp(op)) {
+    BindingPatternUnexpectedToken(classifier);
+    ArrowFormalParametersUnexpectedToken(classifier);
+
+    op = Next();
+    int pos = position();
+    ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK);
+    expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+
+    if (op == Token::DELETE && is_strict(language_mode())) {
+      if (is_strong(language_mode())) {
+        ReportMessage(MessageTemplate::kStrongDelete);
+        *ok = false;
+        return this->EmptyExpression();
+      } else if (this->IsIdentifier(expression)) {
+        // "delete identifier" is a syntax error in strict mode.
+        ReportMessage(MessageTemplate::kStrictDelete);
+        *ok = false;
+        return this->EmptyExpression();
+      }
+    }
+
+    // Allow Traits do rewrite the expression.
+    return this->BuildUnaryExpression(expression, op, pos, factory());
+  } else if (Token::IsCountOp(op)) {
+    BindingPatternUnexpectedToken(classifier);
+    ArrowFormalParametersUnexpectedToken(classifier);
+    op = Next();
+    int beg_pos = peek_position();
+    ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
+    expression = this->CheckAndRewriteReferenceExpression(
+        expression, beg_pos, scanner()->location().end_pos,
+        MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
+    this->MarkExpressionAsAssigned(expression);
+    expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+
+    return factory()->NewCountOperation(op,
+                                        true /* prefix */,
+                                        expression,
+                                        position());
+
+  } else {
+    return this->ParsePostfixExpression(classifier, ok);
+  }
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier,
+                                           bool* ok) {
+  // PostfixExpression ::
+  //   LeftHandSideExpression ('++' | '--')?
+
+  int lhs_beg_pos = peek_position();
+  ExpressionT expression =
+      this->ParseLeftHandSideExpression(classifier, CHECK_OK);
+  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
+      Token::IsCountOp(peek())) {
+    BindingPatternUnexpectedToken(classifier);
+    ArrowFormalParametersUnexpectedToken(classifier);
+
+    expression = this->CheckAndRewriteReferenceExpression(
+        expression, lhs_beg_pos, scanner()->location().end_pos,
+        MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
+    expression = this->MarkExpressionAsAssigned(expression);
+    expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+
+    Token::Value next = Next();
+    expression =
+        factory()->NewCountOperation(next,
+                                     false /* postfix */,
+                                     expression,
+                                     position());
+  }
+  return expression;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseLeftHandSideExpression(
+    ExpressionClassifier* classifier, bool* ok) {
+  // LeftHandSideExpression ::
+  //   (NewExpression | MemberExpression) ...
+
+  ExpressionT result =
+      this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
+
+  while (true) {
+    switch (peek()) {
+      case Token::LBRACK: {
+        BindingPatternUnexpectedToken(classifier);
+        ArrowFormalParametersUnexpectedToken(classifier);
+        Consume(Token::LBRACK);
+        int pos = position();
+        ExpressionT index = ParseExpression(true, classifier, CHECK_OK);
+        index = Traits::RewriteNonPattern(index, classifier, CHECK_OK);
+        result = factory()->NewProperty(result, index, pos);
+        Expect(Token::RBRACK, CHECK_OK);
+        break;
+      }
+
+      case Token::LPAREN: {
+        result = Traits::RewriteNonPattern(result, classifier, CHECK_OK);
+        BindingPatternUnexpectedToken(classifier);
+        ArrowFormalParametersUnexpectedToken(classifier);
+
+        if (is_strong(language_mode()) && this->IsIdentifier(result) &&
+            this->IsEval(this->AsIdentifier(result))) {
+          ReportMessage(MessageTemplate::kStrongDirectEval);
+          *ok = false;
+          return this->EmptyExpression();
+        }
+        int pos;
+        if (scanner()->current_token() == Token::IDENTIFIER ||
+            scanner()->current_token() == Token::SUPER) {
+          // For call of an identifier we want to report position of
+          // the identifier as position of the call in the stack trace.
+          pos = position();
+        } else {
+          // For other kinds of calls we record position of the parenthesis as
+          // position of the call. Note that this is extremely important for
+          // expressions of the form function(){...}() for which call position
+          // should not point to the closing brace otherwise it will intersect
+          // with positions recorded for function literal and confuse debugger.
+          pos = peek_position();
+          // Also the trailing parenthesis are a hint that the function will
+          // be called immediately. If we happen to have parsed a preceding
+          // function literal eagerly, we can also compile it eagerly.
+          if (result->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
+            result->AsFunctionLiteral()->set_should_eager_compile();
+          }
+        }
+        Scanner::Location spread_pos;
+        typename Traits::Type::ExpressionList args =
+            ParseArguments(&spread_pos, classifier, CHECK_OK);
+
+        // Keep track of eval() calls since they disable all local variable
+        // optimizations.
+        // The calls that need special treatment are the
+        // direct eval calls. These calls are all of the form eval(...), with
+        // no explicit receiver.
+        // These calls are marked as potentially direct eval calls. Whether
+        // they are actually direct calls to eval is determined at run time.
+        this->CheckPossibleEvalCall(result, scope_);
+
+        bool is_super_call = result->IsSuperCallReference();
+        if (spread_pos.IsValid()) {
+          args = Traits::PrepareSpreadArguments(args);
+          result = Traits::SpreadCall(result, args, pos);
+        } else {
+          result = factory()->NewCall(result, args, pos);
+        }
+
+        // Explicit calls to the super constructor using super() perform an
+        // implicit binding assignment to the 'this' variable.
+        if (is_super_call) {
+          ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
+          result =
+              factory()->NewAssignment(Token::INIT, this_expr, result, pos);
+        }
+
+        if (fni_ != NULL) fni_->RemoveLastFunction();
+        break;
+      }
+
+      case Token::PERIOD: {
+        BindingPatternUnexpectedToken(classifier);
+        ArrowFormalParametersUnexpectedToken(classifier);
+        Consume(Token::PERIOD);
+        int pos = position();
+        IdentifierT name = ParseIdentifierName(CHECK_OK);
+        result = factory()->NewProperty(
+            result, factory()->NewStringLiteral(name, pos), pos);
+        if (fni_ != NULL) this->PushLiteralName(fni_, name);
+        break;
+      }
+
+      case Token::TEMPLATE_SPAN:
+      case Token::TEMPLATE_TAIL: {
+        BindingPatternUnexpectedToken(classifier);
+        ArrowFormalParametersUnexpectedToken(classifier);
+        result = ParseTemplateLiteral(result, position(), classifier, CHECK_OK);
+        break;
+      }
+
+      default:
+        return result;
+    }
+  }
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
+    ExpressionClassifier* classifier, bool* ok) {
+  // NewExpression ::
+  //   ('new')+ MemberExpression
+  //
+  // NewTarget ::
+  //   'new' '.' 'target'
+
+  // The grammar for new expressions is pretty warped. We can have several 'new'
+  // keywords following each other, and then a MemberExpression. When we see '('
+  // after the MemberExpression, it's associated with the rightmost unassociated
+  // 'new' to create a NewExpression with arguments. However, a NewExpression
+  // can also occur without arguments.
+
+  // Examples of new expression:
+  // new foo.bar().baz means (new (foo.bar)()).baz
+  // new foo()() means (new foo())()
+  // new new foo()() means (new (new foo())())
+  // new new foo means new (new foo)
+  // new new foo() means new (new foo())
+  // new new foo().bar().baz means (new (new foo()).bar()).baz
+
+  if (peek() == Token::NEW) {
+    BindingPatternUnexpectedToken(classifier);
+    ArrowFormalParametersUnexpectedToken(classifier);
+    Consume(Token::NEW);
+    int new_pos = position();
+    ExpressionT result = this->EmptyExpression();
+    if (peek() == Token::SUPER) {
+      const bool is_new = true;
+      result = ParseSuperExpression(is_new, classifier, CHECK_OK);
+    } else if (peek() == Token::PERIOD) {
+      return ParseNewTargetExpression(CHECK_OK);
+    } else {
+      result = this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
+    }
+    result = Traits::RewriteNonPattern(result, classifier, CHECK_OK);
+    if (peek() == Token::LPAREN) {
+      // NewExpression with arguments.
+      Scanner::Location spread_pos;
+      typename Traits::Type::ExpressionList args =
+          this->ParseArguments(&spread_pos, classifier, CHECK_OK);
+
+      if (spread_pos.IsValid()) {
+        args = Traits::PrepareSpreadArguments(args);
+        result = Traits::SpreadCallNew(result, args, new_pos);
+      } else {
+        result = factory()->NewCallNew(result, args, new_pos);
+      }
+      // The expression can still continue with . or [ after the arguments.
+      result =
+          this->ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
+      return result;
+    }
+    // NewExpression without arguments.
+    return factory()->NewCallNew(result, this->NewExpressionList(0, zone_),
+                                 new_pos);
+  }
+  // No 'new' or 'super' keyword.
+  return this->ParseMemberExpression(classifier, ok);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
+                                          bool* ok) {
+  // MemberExpression ::
+  //   (PrimaryExpression | FunctionLiteral | ClassLiteral)
+  //     ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
+
+  // The '[' Expression ']' and '.' Identifier parts are parsed by
+  // ParseMemberExpressionContinuation, and the Arguments part is parsed by the
+  // caller.
+
+  // Parse the initial primary or function expression.
+  ExpressionT result = this->EmptyExpression();
+  if (peek() == Token::FUNCTION) {
+    BindingPatternUnexpectedToken(classifier);
+    ArrowFormalParametersUnexpectedToken(classifier);
+
+    Consume(Token::FUNCTION);
+    int function_token_position = position();
+    bool is_generator = Check(Token::MUL);
+    IdentifierT name = this->EmptyIdentifier();
+    bool is_strict_reserved_name = false;
+    Scanner::Location function_name_location = Scanner::Location::invalid();
+    FunctionLiteral::FunctionType function_type =
+        FunctionLiteral::kAnonymousExpression;
+    if (peek_any_identifier()) {
+      name = ParseIdentifierOrStrictReservedWord(
+          is_generator, &is_strict_reserved_name, CHECK_OK);
+      function_name_location = scanner()->location();
+      function_type = FunctionLiteral::kNamedExpression;
+    }
+    result = this->ParseFunctionLiteral(
+        name, function_name_location,
+        is_strict_reserved_name ? kFunctionNameIsStrictReserved
+                                : kFunctionNameValidityUnknown,
+        is_generator ? FunctionKind::kGeneratorFunction
+                     : FunctionKind::kNormalFunction,
+        function_token_position, function_type, FunctionLiteral::kNormalArity,
+        language_mode(), CHECK_OK);
+  } else if (peek() == Token::SUPER) {
+    const bool is_new = false;
+    result = ParseSuperExpression(is_new, classifier, CHECK_OK);
+  } else {
+    result = ParsePrimaryExpression(classifier, CHECK_OK);
+  }
+
+  result = ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
+  return result;
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseStrongInitializationExpression(
+    ExpressionClassifier* classifier, bool* ok) {
+  // InitializationExpression ::  (strong mode)
+  //  'this' '.' IdentifierName '=' AssignmentExpression
+  //  'this' '[' Expression ']' '=' AssignmentExpression
+
+  FuncNameInferrer::State fni_state(fni_);
+
+  Consume(Token::THIS);
+  int pos = position();
+  function_state_->set_this_location(scanner()->location());
+  ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
+
+  ExpressionT left = this->EmptyExpression();
+  switch (peek()) {
+    case Token::LBRACK: {
+      Consume(Token::LBRACK);
+      int pos = position();
+      ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
+      index = Traits::RewriteNonPattern(index, classifier, CHECK_OK);
+      left = factory()->NewProperty(this_expr, index, pos);
+      if (fni_ != NULL) {
+        this->PushPropertyName(fni_, index);
+      }
+      Expect(Token::RBRACK, CHECK_OK);
+      break;
+    }
+    case Token::PERIOD: {
+      Consume(Token::PERIOD);
+      int pos = position();
+      IdentifierT name = ParseIdentifierName(CHECK_OK);
+      left = factory()->NewProperty(
+          this_expr, factory()->NewStringLiteral(name, pos), pos);
+      if (fni_ != NULL) {
+        this->PushLiteralName(fni_, name);
+      }
+      break;
+    }
+    default:
+      ReportMessage(MessageTemplate::kStrongConstructorThis);
+      *ok = false;
+      return this->EmptyExpression();
+  }
+
+  if (peek() != Token::ASSIGN) {
+    ReportMessageAt(function_state_->this_location(),
+                    MessageTemplate::kStrongConstructorThis);
+    *ok = false;
+    return this->EmptyExpression();
+  }
+  Consume(Token::ASSIGN);
+  left = this->MarkExpressionAsAssigned(left);
+
+  ExpressionT right =
+      this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+  right = Traits::RewriteNonPattern(right, classifier, CHECK_OK);
+  this->CheckAssigningFunctionLiteralToProperty(left, right);
+  function_state_->AddProperty();
+  if (fni_ != NULL) {
+    // Check if the right hand side is a call to avoid inferring a
+    // name if we're dealing with "this.a = function(){...}();"-like
+    // expression.
+    if (!right->IsCall() && !right->IsCallNew()) {
+      fni_->Infer();
+    } else {
+      fni_->RemoveLastFunction();
+    }
+  }
+
+  if (function_state_->return_location().IsValid()) {
+    ReportMessageAt(function_state_->return_location(),
+                    MessageTemplate::kStrongConstructorReturnMisplaced);
+    *ok = false;
+    return this->EmptyExpression();
+  }
+
+  return factory()->NewAssignment(Token::ASSIGN, left, right, pos);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseStrongSuperCallExpression(
+    ExpressionClassifier* classifier, bool* ok) {
+  // SuperCallExpression ::  (strong mode)
+  //  'super' '(' ExpressionList ')'
+  BindingPatternUnexpectedToken(classifier);
+
+  Consume(Token::SUPER);
+  int pos = position();
+  Scanner::Location super_loc = scanner()->location();
+  ExpressionT expr = this->SuperCallReference(scope_, factory(), pos);
+
+  if (peek() != Token::LPAREN) {
+    ReportMessage(MessageTemplate::kStrongConstructorSuper);
+    *ok = false;
+    return this->EmptyExpression();
+  }
+
+  Scanner::Location spread_pos;
+  typename Traits::Type::ExpressionList args =
+      ParseArguments(&spread_pos, classifier, CHECK_OK);
+
+  // TODO(rossberg): This doesn't work with arrow functions yet.
+  if (!IsSubclassConstructor(function_state_->kind())) {
+    ReportMessage(MessageTemplate::kUnexpectedSuper);
+    *ok = false;
+    return this->EmptyExpression();
+  } else if (function_state_->super_location().IsValid()) {
+    ReportMessageAt(scanner()->location(),
+                    MessageTemplate::kStrongSuperCallDuplicate);
+    *ok = false;
+    return this->EmptyExpression();
+  } else if (function_state_->this_location().IsValid()) {
+    ReportMessageAt(scanner()->location(),
+                    MessageTemplate::kStrongSuperCallMisplaced);
+    *ok = false;
+    return this->EmptyExpression();
+  } else if (function_state_->return_location().IsValid()) {
+    ReportMessageAt(function_state_->return_location(),
+                    MessageTemplate::kStrongConstructorReturnMisplaced);
+    *ok = false;
+    return this->EmptyExpression();
+  }
+
+  function_state_->set_super_location(super_loc);
+  if (spread_pos.IsValid()) {
+    args = Traits::PrepareSpreadArguments(args);
+    expr = Traits::SpreadCall(expr, args, pos);
+  } else {
+    expr = factory()->NewCall(expr, args, pos);
+  }
+
+  // Explicit calls to the super constructor using super() perform an implicit
+  // binding assignment to the 'this' variable.
+  ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
+  return factory()->NewAssignment(Token::INIT, this_expr, expr, pos);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseSuperExpression(bool is_new,
+                                         ExpressionClassifier* classifier,
+                                         bool* ok) {
+  Expect(Token::SUPER, CHECK_OK);
+  int pos = position();
+
+  Scope* scope = scope_->ReceiverScope();
+  FunctionKind kind = scope->function_kind();
+  if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
+      IsClassConstructor(kind)) {
+    if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
+      scope->RecordSuperPropertyUsage();
+      return this->SuperPropertyReference(scope_, factory(), pos);
+    }
+    // new super() is never allowed.
+    // super() is only allowed in derived constructor
+    if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) {
+      if (is_strong(language_mode())) {
+        // Super calls in strong mode are parsed separately.
+        ReportMessageAt(scanner()->location(),
+                        MessageTemplate::kStrongConstructorSuper);
+        *ok = false;
+        return this->EmptyExpression();
+      }
+      // TODO(rossberg): This might not be the correct FunctionState for the
+      // method here.
+      function_state_->set_super_location(scanner()->location());
+      return this->SuperCallReference(scope_, factory(), pos);
+    }
+  }
+
+  ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedSuper);
+  *ok = false;
+  return this->EmptyExpression();
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseNewTargetExpression(bool* ok) {
+  int pos = position();
+  Consume(Token::PERIOD);
+  ExpectContextualKeyword(CStrVector("target"), CHECK_OK);
+
+  if (!scope_->ReceiverScope()->is_function_scope()) {
+    ReportMessageAt(scanner()->location(),
+                    MessageTemplate::kUnexpectedNewTarget);
+    *ok = false;
+    return this->EmptyExpression();
+  }
+
+  return this->NewTargetExpression(scope_, factory(), pos);
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseMemberExpressionContinuation(
+    ExpressionT expression, ExpressionClassifier* classifier, bool* ok) {
+  // Parses this part of MemberExpression:
+  // ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
+  while (true) {
+    switch (peek()) {
+      case Token::LBRACK: {
+        BindingPatternUnexpectedToken(classifier);
+        ArrowFormalParametersUnexpectedToken(classifier);
+
+        Consume(Token::LBRACK);
+        int pos = position();
+        ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
+        index = Traits::RewriteNonPattern(index, classifier, CHECK_OK);
+        expression = factory()->NewProperty(expression, index, pos);
+        if (fni_ != NULL) {
+          this->PushPropertyName(fni_, index);
+        }
+        Expect(Token::RBRACK, CHECK_OK);
+        break;
+      }
+      case Token::PERIOD: {
+        BindingPatternUnexpectedToken(classifier);
+        ArrowFormalParametersUnexpectedToken(classifier);
+
+        Consume(Token::PERIOD);
+        int pos = position();
+        IdentifierT name = ParseIdentifierName(CHECK_OK);
+        expression = factory()->NewProperty(
+            expression, factory()->NewStringLiteral(name, pos), pos);
+        if (fni_ != NULL) {
+          this->PushLiteralName(fni_, name);
+        }
+        break;
+      }
+      case Token::TEMPLATE_SPAN:
+      case Token::TEMPLATE_TAIL: {
+        BindingPatternUnexpectedToken(classifier);
+        ArrowFormalParametersUnexpectedToken(classifier);
+        int pos;
+        if (scanner()->current_token() == Token::IDENTIFIER) {
+          pos = position();
+        } else {
+          pos = peek_position();
+          if (expression->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
+            // If the tag function looks like an IIFE, set_parenthesized() to
+            // force eager compilation.
+            expression->AsFunctionLiteral()->set_should_eager_compile();
+          }
+        }
+        expression =
+            ParseTemplateLiteral(expression, pos, classifier, CHECK_OK);
+        break;
+      }
+      default:
+        return expression;
+    }
+  }
+  DCHECK(false);
+  return this->EmptyExpression();
+}
+
+
+template <class Traits>
+void ParserBase<Traits>::ParseFormalParameter(
+    FormalParametersT* parameters, ExpressionClassifier* classifier, bool* ok) {
+  // FormalParameter[Yield,GeneratorParameter] :
+  //   BindingElement[?Yield, ?GeneratorParameter]
+  bool is_rest = parameters->has_rest;
+
+  Token::Value next = peek();
+  ExpressionT pattern = ParsePrimaryExpression(classifier, ok);
+  if (!*ok) return;
+
+  ValidateBindingPattern(classifier, ok);
+  if (!*ok) return;
+
+  if (!Traits::IsIdentifier(pattern)) {
+    if (!allow_harmony_destructuring_bind()) {
+      ReportUnexpectedToken(next);
+      *ok = false;
+      return;
+    }
+    parameters->is_simple = false;
+    ValidateFormalParameterInitializer(classifier, ok);
+    if (!*ok) return;
+    classifier->RecordNonSimpleParameter();
+  }
+
+  ExpressionT initializer = Traits::EmptyExpression();
+  if (!is_rest && allow_harmony_default_parameters() && Check(Token::ASSIGN)) {
+    ExpressionClassifier init_classifier;
+    initializer = ParseAssignmentExpression(true, &init_classifier, ok);
+    if (!*ok) return;
+    initializer = Traits::RewriteNonPattern(initializer, &init_classifier, ok);
+    ValidateFormalParameterInitializer(&init_classifier, ok);
+    if (!*ok) return;
+    parameters->is_simple = false;
+    classifier->RecordNonSimpleParameter();
+  }
+
+  Traits::AddFormalParameter(parameters, pattern, initializer,
+                             scanner()->location().end_pos, is_rest);
+}
+
+
+template <class Traits>
+void ParserBase<Traits>::ParseFormalParameterList(
+    FormalParametersT* parameters, ExpressionClassifier* classifier, bool* ok) {
+  // FormalParameters[Yield,GeneratorParameter] :
+  //   [empty]
+  //   FormalParameterList[?Yield, ?GeneratorParameter]
+  //
+  // FormalParameterList[Yield,GeneratorParameter] :
+  //   FunctionRestParameter[?Yield]
+  //   FormalsList[?Yield, ?GeneratorParameter]
+  //   FormalsList[?Yield, ?GeneratorParameter] , FunctionRestParameter[?Yield]
+  //
+  // FormalsList[Yield,GeneratorParameter] :
+  //   FormalParameter[?Yield, ?GeneratorParameter]
+  //   FormalsList[?Yield, ?GeneratorParameter] ,
+  //     FormalParameter[?Yield,?GeneratorParameter]
+
+  DCHECK_EQ(0, parameters->Arity());
+
+  if (peek() != Token::RPAREN) {
+    do {
+      if (parameters->Arity() > Code::kMaxArguments) {
+        ReportMessage(MessageTemplate::kTooManyParameters);
+        *ok = false;
+        return;
+      }
+      parameters->has_rest = Check(Token::ELLIPSIS);
+      ParseFormalParameter(parameters, classifier, ok);
+      if (!*ok) return;
+    } while (!parameters->has_rest && Check(Token::COMMA));
+
+    if (parameters->has_rest) {
+      parameters->is_simple = false;
+      classifier->RecordNonSimpleParameter();
+      if (peek() == Token::COMMA) {
+        ReportMessageAt(scanner()->peek_location(),
+                      MessageTemplate::kParamAfterRest);
+        *ok = false;
+        return;
+      }
+    }
+  }
+
+  for (int i = 0; i < parameters->Arity(); ++i) {
+    auto parameter = parameters->at(i);
+    Traits::DeclareFormalParameter(parameters->scope, parameter, classifier);
+  }
+}
+
+
+template <class Traits>
+void ParserBase<Traits>::CheckArityRestrictions(
+    int param_count, FunctionLiteral::ArityRestriction arity_restriction,
+    bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok) {
+  switch (arity_restriction) {
+    case FunctionLiteral::kGetterArity:
+      if (param_count != 0) {
+        ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
+                        MessageTemplate::kBadGetterArity);
+        *ok = false;
+      }
+      break;
+    case FunctionLiteral::kSetterArity:
+      if (param_count != 1) {
+        ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
+                        MessageTemplate::kBadSetterArity);
+        *ok = false;
+      }
+      if (has_rest) {
+        ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
+                        MessageTemplate::kBadSetterRestParameter);
+        *ok = false;
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+
+template <class Traits>
+bool ParserBase<Traits>::IsNextLetKeyword() {
+  DCHECK(peek() == Token::LET);
+  if (!allow_let()) {
+    return false;
+  }
+  Token::Value next_next = PeekAhead();
+  switch (next_next) {
+    case Token::LBRACE:
+    case Token::LBRACK:
+    case Token::IDENTIFIER:
+    case Token::STATIC:
+    case Token::LET:  // Yes, you can do let let = ... in sloppy mode
+    case Token::YIELD:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseArrowFunctionLiteral(
+    bool accept_IN, const FormalParametersT& formal_parameters,
+    const ExpressionClassifier& formals_classifier, bool* ok) {
+  if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
+    // ASI inserts `;` after arrow parameters if a line terminator is found.
+    // `=> ...` is never a valid expression, so report as syntax error.
+    // If next token is not `=>`, it's a syntax error anyways.
+    ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW);
+    *ok = false;
+    return this->EmptyExpression();
+  }
+
+  typename Traits::Type::StatementList body;
+  int num_parameters = formal_parameters.scope->num_parameters();
+  int materialized_literal_count = -1;
+  int expected_property_count = -1;
+  Scanner::Location super_loc;
+
+  {
+    typename Traits::Type::Factory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_,
+                                 formal_parameters.scope, kArrowFunction,
+                                 &function_factory);
+
+    function_state.SkipMaterializedLiterals(
+        formal_parameters.materialized_literals_count);
+
+    this->ReindexLiterals(formal_parameters);
+
+    Expect(Token::ARROW, CHECK_OK);
+
+    if (peek() == Token::LBRACE) {
+      // Multiple statement body
+      Consume(Token::LBRACE);
+      bool is_lazily_parsed =
+          (mode() == PARSE_LAZILY && scope_->AllowsLazyParsing());
+      if (is_lazily_parsed) {
+        body = this->NewStatementList(0, zone());
+        this->SkipLazyFunctionBody(&materialized_literal_count,
+                                   &expected_property_count, CHECK_OK);
+        if (formal_parameters.materialized_literals_count > 0) {
+          materialized_literal_count +=
+              formal_parameters.materialized_literals_count;
+        }
+      } else {
+        body = this->ParseEagerFunctionBody(
+            this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
+            kArrowFunction, FunctionLiteral::kAnonymousExpression, CHECK_OK);
+        materialized_literal_count =
+            function_state.materialized_literal_count();
+        expected_property_count = function_state.expected_property_count();
+      }
+    } else {
+      // Single-expression body
+      int pos = position();
+      parenthesized_function_ = false;
+      ExpressionClassifier classifier;
+      ExpressionT expression =
+          ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
+      expression = Traits::RewriteNonPattern(expression, &classifier, CHECK_OK);
+      body = this->NewStatementList(1, zone());
+      this->AddParameterInitializationBlock(formal_parameters, body, CHECK_OK);
+      body->Add(factory()->NewReturnStatement(expression, pos), zone());
+      materialized_literal_count = function_state.materialized_literal_count();
+      expected_property_count = function_state.expected_property_count();
+    }
+    super_loc = function_state.super_location();
+
+    formal_parameters.scope->set_end_position(scanner()->location().end_pos);
+
+    // Arrow function formal parameters are parsed as StrictFormalParameterList,
+    // which is not the same as "parameters of a strict function"; it only means
+    // that duplicates are not allowed.  Of course, the arrow function may
+    // itself be strict as well.
+    const bool allow_duplicate_parameters = false;
+    this->ValidateFormalParameters(&formals_classifier, language_mode(),
+                                   allow_duplicate_parameters, CHECK_OK);
+
+    // Validate strict mode.
+    if (is_strict(language_mode())) {
+      CheckStrictOctalLiteral(formal_parameters.scope->start_position(),
+                              scanner()->location().end_pos, CHECK_OK);
+    }
+    if (is_strict(language_mode()) || allow_harmony_sloppy()) {
+      this->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
+    }
+
+    Traits::RewriteDestructuringAssignments();
+  }
+
+  FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
+      this->EmptyIdentifierString(), formal_parameters.scope, body,
+      materialized_literal_count, expected_property_count, num_parameters,
+      FunctionLiteral::kNoDuplicateParameters,
+      FunctionLiteral::kAnonymousExpression,
+      FunctionLiteral::kShouldLazyCompile, FunctionKind::kArrowFunction,
+      formal_parameters.scope->start_position());
+
+  function_literal->set_function_token_position(
+      formal_parameters.scope->start_position());
+  if (super_loc.IsValid()) function_state_->set_super_location(super_loc);
+
+  if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
+
+  return function_literal;
+}
+
+
+template <typename Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start,
+                                         ExpressionClassifier* classifier,
+                                         bool* ok) {
+  // A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal
+  // text followed by a substitution expression), finalized by a single
+  // TEMPLATE_TAIL.
+  //
+  // In terms of draft language, TEMPLATE_SPAN may be either the TemplateHead or
+  // TemplateMiddle productions, while TEMPLATE_TAIL is either TemplateTail, or
+  // NoSubstitutionTemplate.
+  //
+  // When parsing a TemplateLiteral, we must have scanned either an initial
+  // TEMPLATE_SPAN, or a TEMPLATE_TAIL.
+  CHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL);
+
+  // If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate.
+  // In this case we may simply consume the token and build a template with a
+  // single TEMPLATE_SPAN and no expressions.
+  if (peek() == Token::TEMPLATE_TAIL) {
+    Consume(Token::TEMPLATE_TAIL);
+    int pos = position();
+    CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
+    typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
+    Traits::AddTemplateSpan(&ts, true);
+    return Traits::CloseTemplateLiteral(&ts, start, tag);
+  }
+
+  Consume(Token::TEMPLATE_SPAN);
+  int pos = position();
+  typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
+  Traits::AddTemplateSpan(&ts, false);
+  Token::Value next;
+
+  // If we open with a TEMPLATE_SPAN, we must scan the subsequent expression,
+  // and repeat if the following token is a TEMPLATE_SPAN as well (in this
+  // case, representing a TemplateMiddle).
+
+  do {
+    CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
+    next = peek();
+    if (next == Token::EOS) {
+      ReportMessageAt(Scanner::Location(start, peek_position()),
+                      MessageTemplate::kUnterminatedTemplate);
+      *ok = false;
+      return Traits::EmptyExpression();
+    } else if (next == Token::ILLEGAL) {
+      Traits::ReportMessageAt(
+          Scanner::Location(position() + 1, peek_position()),
+          MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
+      *ok = false;
+      return Traits::EmptyExpression();
+    }
+
+    int expr_pos = peek_position();
+    ExpressionT expression = this->ParseExpression(true, classifier, CHECK_OK);
+    expression = Traits::RewriteNonPattern(expression, classifier, CHECK_OK);
+    Traits::AddTemplateExpression(&ts, expression);
+
+    if (peek() != Token::RBRACE) {
+      ReportMessageAt(Scanner::Location(expr_pos, peek_position()),
+                      MessageTemplate::kUnterminatedTemplateExpr);
+      *ok = false;
+      return Traits::EmptyExpression();
+    }
+
+    // If we didn't die parsing that expression, our next token should be a
+    // TEMPLATE_SPAN or TEMPLATE_TAIL.
+    next = scanner()->ScanTemplateContinuation();
+    Next();
+    pos = position();
+
+    if (next == Token::EOS) {
+      ReportMessageAt(Scanner::Location(start, pos),
+                      MessageTemplate::kUnterminatedTemplate);
+      *ok = false;
+      return Traits::EmptyExpression();
+    } else if (next == Token::ILLEGAL) {
+      Traits::ReportMessageAt(
+          Scanner::Location(position() + 1, peek_position()),
+          MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
+      *ok = false;
+      return Traits::EmptyExpression();
+    }
+
+    Traits::AddTemplateSpan(&ts, next == Token::TEMPLATE_TAIL);
+  } while (next == Token::TEMPLATE_SPAN);
+
+  DCHECK_EQ(next, Token::TEMPLATE_TAIL);
+  CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
+  // Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
+  return Traits::CloseTemplateLiteral(&ts, start, tag);
+}
+
+
+template <typename Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::CheckAndRewriteReferenceExpression(
+    ExpressionT expression, int beg_pos, int end_pos,
+    MessageTemplate::Template message, bool* ok) {
+  return this->CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos,
+                                                  message, kReferenceError, ok);
+}
+
+
+template <typename Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::CheckAndRewriteReferenceExpression(
+    ExpressionT expression, int beg_pos, int end_pos,
+    MessageTemplate::Template message, ParseErrorType type, bool* ok) {
+  ExpressionClassifier classifier;
+  ExpressionT result = ClassifyAndRewriteReferenceExpression(
+      &classifier, expression, beg_pos, end_pos, message, type);
+  ValidateExpression(&classifier, ok);
+  if (!*ok) return this->EmptyExpression();
+  return result;
+}
+
+
+template <typename Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ClassifyAndRewriteReferenceExpression(
+    ExpressionClassifier* classifier, ExpressionT expression, int beg_pos,
+    int end_pos, MessageTemplate::Template message, ParseErrorType type) {
+  Scanner::Location location(beg_pos, end_pos);
+  if (this->IsIdentifier(expression)) {
+    if (is_strict(language_mode()) &&
+        this->IsEvalOrArguments(this->AsIdentifier(expression))) {
+      classifier->RecordExpressionError(
+          location, MessageTemplate::kStrictEvalArguments, kSyntaxError);
+      return expression;
+    }
+    if (is_strong(language_mode()) &&
+        this->IsUndefined(this->AsIdentifier(expression))) {
+      classifier->RecordExpressionError(
+          location, MessageTemplate::kStrongUndefined, kSyntaxError);
+      return expression;
+    }
+  }
+  if (expression->IsValidReferenceExpression()) {
+    return expression;
+  } else if (expression->IsCall()) {
+    // If it is a call, make it a runtime error for legacy web compatibility.
+    // Rewrite `expr' to `expr[throw ReferenceError]'.
+    int pos = location.beg_pos;
+    ExpressionT error = this->NewThrowReferenceError(message, pos);
+    return factory()->NewProperty(expression, error, pos);
+  } else {
+    classifier->RecordExpressionError(location, message, type);
+    return expression;
+  }
+}
+
+
+template <typename Traits>
+bool ParserBase<Traits>::IsValidReferenceExpression(ExpressionT expression) {
+  return this->IsAssignableIdentifier(expression) || expression->IsProperty();
+}
+
+
+template <typename Traits>
+void ParserBase<Traits>::CheckDestructuringElement(
+    ExpressionT expression, ExpressionClassifier* classifier, int begin,
+    int end) {
+  static const MessageTemplate::Template message =
+      MessageTemplate::kInvalidDestructuringTarget;
+  const Scanner::Location location(begin, end);
+  if (expression->IsArrayLiteral() || expression->IsObjectLiteral() ||
+      expression->IsAssignment()) {
+    if (expression->is_parenthesized()) {
+      classifier->RecordPatternError(location, message);
+    }
+    return;
+  }
+
+  if (expression->IsProperty()) {
+    classifier->RecordBindingPatternError(location, message);
+  } else if (!this->IsAssignableIdentifier(expression)) {
+    classifier->RecordPatternError(location, message);
+  }
+}
+
+
+#undef CHECK_OK
+#undef CHECK_OK_CUSTOM
+
+
+template <typename Traits>
+void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
+    Token::Value property, PropertyKind type, bool is_static, bool is_generator,
+    bool* ok) {
+  DCHECK(!is_static);
+  DCHECK(!is_generator || type == kMethodProperty);
+
+  if (property == Token::SMI || property == Token::NUMBER) return;
+
+  if (type == kValueProperty && IsProto()) {
+    if (has_seen_proto_) {
+      this->parser()->ReportMessage(MessageTemplate::kDuplicateProto);
+      *ok = false;
+      return;
+    }
+    has_seen_proto_ = true;
+    return;
+  }
+}
+
+
+template <typename Traits>
+void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
+    Token::Value property, PropertyKind type, bool is_static, bool is_generator,
+    bool* ok) {
+  DCHECK(type == kMethodProperty || type == kAccessorProperty);
+
+  if (property == Token::SMI || property == Token::NUMBER) return;
+
+  if (is_static) {
+    if (IsPrototype()) {
+      this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
+      *ok = false;
+      return;
+    }
+  } else if (IsConstructor()) {
+    if (is_generator || type == kAccessorProperty) {
+      MessageTemplate::Template msg =
+          is_generator ? MessageTemplate::kConstructorIsGenerator
+                       : MessageTemplate::kConstructorIsAccessor;
+      this->parser()->ReportMessage(msg);
+      *ok = false;
+      return;
+    }
+    if (has_seen_constructor_) {
+      this->parser()->ReportMessage(MessageTemplate::kDuplicateConstructor);
+      *ok = false;
+      return;
+    }
+    has_seen_constructor_ = true;
+    return;
+  }
+}
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_PARSER_BASE_H
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
new file mode 100644
index 0000000..b1b8c13
--- /dev/null
+++ b/src/parsing/parser.cc
@@ -0,0 +1,5548 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/parsing/parser.h"
+
+#include "src/api.h"
+#include "src/ast/ast.h"
+#include "src/ast/ast-expression-visitor.h"
+#include "src/ast/ast-literal-reindexer.h"
+#include "src/ast/scopeinfo.h"
+#include "src/bailout-reason.h"
+#include "src/base/platform/platform.h"
+#include "src/bootstrapper.h"
+#include "src/char-predicates-inl.h"
+#include "src/codegen.h"
+#include "src/compiler.h"
+#include "src/messages.h"
+#include "src/parsing/parameter-initializer-rewriter.h"
+#include "src/parsing/parser-base.h"
+#include "src/parsing/rewriter.h"
+#include "src/parsing/scanner-character-streams.h"
+#include "src/runtime/runtime.h"
+#include "src/string-stream.h"
+
+namespace v8 {
+namespace internal {
+
+ScriptData::ScriptData(const byte* data, int length)
+    : owns_data_(false), rejected_(false), data_(data), length_(length) {
+  if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
+    byte* copy = NewArray<byte>(length);
+    DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment));
+    CopyBytes(copy, data, length);
+    data_ = copy;
+    AcquireDataOwnership();
+  }
+}
+
+
+ParseInfo::ParseInfo(Zone* zone)
+    : zone_(zone),
+      flags_(0),
+      source_stream_(nullptr),
+      source_stream_encoding_(ScriptCompiler::StreamedSource::ONE_BYTE),
+      extension_(nullptr),
+      compile_options_(ScriptCompiler::kNoCompileOptions),
+      script_scope_(nullptr),
+      unicode_cache_(nullptr),
+      stack_limit_(0),
+      hash_seed_(0),
+      cached_data_(nullptr),
+      ast_value_factory_(nullptr),
+      literal_(nullptr),
+      scope_(nullptr) {}
+
+
+ParseInfo::ParseInfo(Zone* zone, Handle<JSFunction> function)
+    : ParseInfo(zone, Handle<SharedFunctionInfo>(function->shared())) {
+  set_closure(function);
+  set_context(Handle<Context>(function->context()));
+}
+
+
+ParseInfo::ParseInfo(Zone* zone, Handle<SharedFunctionInfo> shared)
+    : ParseInfo(zone) {
+  isolate_ = shared->GetIsolate();
+
+  set_lazy();
+  set_hash_seed(isolate_->heap()->HashSeed());
+  set_stack_limit(isolate_->stack_guard()->real_climit());
+  set_unicode_cache(isolate_->unicode_cache());
+  set_language_mode(shared->language_mode());
+  set_shared_info(shared);
+
+  Handle<Script> script(Script::cast(shared->script()));
+  set_script(script);
+  if (!script.is_null() && script->type() == Script::TYPE_NATIVE) {
+    set_native();
+  }
+}
+
+
+ParseInfo::ParseInfo(Zone* zone, Handle<Script> script) : ParseInfo(zone) {
+  isolate_ = script->GetIsolate();
+
+  set_hash_seed(isolate_->heap()->HashSeed());
+  set_stack_limit(isolate_->stack_guard()->real_climit());
+  set_unicode_cache(isolate_->unicode_cache());
+  set_script(script);
+
+  if (script->type() == Script::TYPE_NATIVE) {
+    set_native();
+  }
+}
+
+
+FunctionEntry ParseData::GetFunctionEntry(int start) {
+  // The current pre-data entry must be a FunctionEntry with the given
+  // start position.
+  if ((function_index_ + FunctionEntry::kSize <= Length()) &&
+      (static_cast<int>(Data()[function_index_]) == start)) {
+    int index = function_index_;
+    function_index_ += FunctionEntry::kSize;
+    Vector<unsigned> subvector(&(Data()[index]), FunctionEntry::kSize);
+    return FunctionEntry(subvector);
+  }
+  return FunctionEntry();
+}
+
+
+int ParseData::FunctionCount() {
+  int functions_size = FunctionsSize();
+  if (functions_size < 0) return 0;
+  if (functions_size % FunctionEntry::kSize != 0) return 0;
+  return functions_size / FunctionEntry::kSize;
+}
+
+
+bool ParseData::IsSane() {
+  if (!IsAligned(script_data_->length(), sizeof(unsigned))) return false;
+  // Check that the header data is valid and doesn't specify
+  // point to positions outside the store.
+  int data_length = Length();
+  if (data_length < PreparseDataConstants::kHeaderSize) return false;
+  if (Magic() != PreparseDataConstants::kMagicNumber) return false;
+  if (Version() != PreparseDataConstants::kCurrentVersion) return false;
+  if (HasError()) return false;
+  // Check that the space allocated for function entries is sane.
+  int functions_size = FunctionsSize();
+  if (functions_size < 0) return false;
+  if (functions_size % FunctionEntry::kSize != 0) return false;
+  // Check that the total size has room for header and function entries.
+  int minimum_size =
+      PreparseDataConstants::kHeaderSize + functions_size;
+  if (data_length < minimum_size) return false;
+  return true;
+}
+
+
+void ParseData::Initialize() {
+  // Prepares state for use.
+  int data_length = Length();
+  if (data_length >= PreparseDataConstants::kHeaderSize) {
+    function_index_ = PreparseDataConstants::kHeaderSize;
+  }
+}
+
+
+bool ParseData::HasError() {
+  return Data()[PreparseDataConstants::kHasErrorOffset];
+}
+
+
+unsigned ParseData::Magic() {
+  return Data()[PreparseDataConstants::kMagicOffset];
+}
+
+
+unsigned ParseData::Version() {
+  return Data()[PreparseDataConstants::kVersionOffset];
+}
+
+
+int ParseData::FunctionsSize() {
+  return static_cast<int>(Data()[PreparseDataConstants::kFunctionsSizeOffset]);
+}
+
+
+void Parser::SetCachedData(ParseInfo* info) {
+  if (compile_options_ == ScriptCompiler::kNoCompileOptions) {
+    cached_parse_data_ = NULL;
+  } else {
+    DCHECK(info->cached_data() != NULL);
+    if (compile_options_ == ScriptCompiler::kConsumeParserCache) {
+      cached_parse_data_ = ParseData::FromCachedData(*info->cached_data());
+    }
+  }
+}
+
+
+FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
+                                            int pos, int end_pos,
+                                            LanguageMode language_mode) {
+  int materialized_literal_count = -1;
+  int expected_property_count = -1;
+  int parameter_count = 0;
+  const AstRawString* name = ast_value_factory()->empty_string();
+
+
+  FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor
+                                 : FunctionKind::kDefaultBaseConstructor;
+  Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind);
+  SetLanguageMode(function_scope,
+                  static_cast<LanguageMode>(language_mode | STRICT));
+  // Set start and end position to the same value
+  function_scope->set_start_position(pos);
+  function_scope->set_end_position(pos);
+  ZoneList<Statement*>* body = NULL;
+
+  {
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, function_scope,
+                                 kind, &function_factory);
+
+    body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone());
+    if (call_super) {
+      // $super_constructor = %_GetSuperConstructor(<this-function>)
+      // %reflect_construct($super_constructor, arguments, new.target)
+      ZoneList<Expression*>* args =
+          new (zone()) ZoneList<Expression*>(2, zone());
+      VariableProxy* this_function_proxy = scope_->NewUnresolved(
+          factory(), ast_value_factory()->this_function_string(),
+          Variable::NORMAL, pos);
+      ZoneList<Expression*>* tmp =
+          new (zone()) ZoneList<Expression*>(1, zone());
+      tmp->Add(this_function_proxy, zone());
+      Expression* super_constructor = factory()->NewCallRuntime(
+          Runtime::kInlineGetSuperConstructor, tmp, pos);
+      args->Add(super_constructor, zone());
+      VariableProxy* arguments_proxy = scope_->NewUnresolved(
+          factory(), ast_value_factory()->arguments_string(), Variable::NORMAL,
+          pos);
+      args->Add(arguments_proxy, zone());
+      VariableProxy* new_target_proxy = scope_->NewUnresolved(
+          factory(), ast_value_factory()->new_target_string(), Variable::NORMAL,
+          pos);
+      args->Add(new_target_proxy, zone());
+      CallRuntime* call = factory()->NewCallRuntime(
+          Context::REFLECT_CONSTRUCT_INDEX, args, pos);
+      body->Add(factory()->NewReturnStatement(call, pos), zone());
+    }
+
+    materialized_literal_count = function_state.materialized_literal_count();
+    expected_property_count = function_state.expected_property_count();
+  }
+
+  FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
+      name, function_scope, body, materialized_literal_count,
+      expected_property_count, parameter_count,
+      FunctionLiteral::kNoDuplicateParameters,
+      FunctionLiteral::kAnonymousExpression,
+      FunctionLiteral::kShouldLazyCompile, kind, pos);
+
+  return function_literal;
+}
+
+
+// ----------------------------------------------------------------------------
+// Target is a support class to facilitate manipulation of the
+// Parser's target_stack_ (the stack of potential 'break' and
+// 'continue' statement targets). Upon construction, a new target is
+// added; it is removed upon destruction.
+
+class Target BASE_EMBEDDED {
+ public:
+  Target(Target** variable, BreakableStatement* statement)
+      : variable_(variable), statement_(statement), previous_(*variable) {
+    *variable = this;
+  }
+
+  ~Target() {
+    *variable_ = previous_;
+  }
+
+  Target* previous() { return previous_; }
+  BreakableStatement* statement() { return statement_; }
+
+ private:
+  Target** variable_;
+  BreakableStatement* statement_;
+  Target* previous_;
+};
+
+
+class TargetScope BASE_EMBEDDED {
+ public:
+  explicit TargetScope(Target** variable)
+      : variable_(variable), previous_(*variable) {
+    *variable = NULL;
+  }
+
+  ~TargetScope() {
+    *variable_ = previous_;
+  }
+
+ private:
+  Target** variable_;
+  Target* previous_;
+};
+
+
+// ----------------------------------------------------------------------------
+// The CHECK_OK macro is a convenient macro to enforce error
+// handling for functions that may fail (by returning !*ok).
+//
+// CAUTION: This macro appends extra statements after a call,
+// thus it must never be used where only a single statement
+// is correct (e.g. an if statement branch w/o braces)!
+
+#define CHECK_OK  ok);   \
+  if (!*ok) return NULL; \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+#define CHECK_FAILED  /**/);   \
+  if (failed_) return NULL; \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+// ----------------------------------------------------------------------------
+// Implementation of Parser
+
+bool ParserTraits::IsEval(const AstRawString* identifier) const {
+  return identifier == parser_->ast_value_factory()->eval_string();
+}
+
+
+bool ParserTraits::IsArguments(const AstRawString* identifier) const {
+  return identifier == parser_->ast_value_factory()->arguments_string();
+}
+
+
+bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const {
+  return IsEval(identifier) || IsArguments(identifier);
+}
+
+bool ParserTraits::IsUndefined(const AstRawString* identifier) const {
+  return identifier == parser_->ast_value_factory()->undefined_string();
+}
+
+bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
+  return identifier == parser_->ast_value_factory()->prototype_string();
+}
+
+
+bool ParserTraits::IsConstructor(const AstRawString* identifier) const {
+  return identifier == parser_->ast_value_factory()->constructor_string();
+}
+
+
+bool ParserTraits::IsThisProperty(Expression* expression) {
+  DCHECK(expression != NULL);
+  Property* property = expression->AsProperty();
+  return property != NULL && property->obj()->IsVariableProxy() &&
+         property->obj()->AsVariableProxy()->is_this();
+}
+
+
+bool ParserTraits::IsIdentifier(Expression* expression) {
+  VariableProxy* operand = expression->AsVariableProxy();
+  return operand != NULL && !operand->is_this();
+}
+
+
+void ParserTraits::PushPropertyName(FuncNameInferrer* fni,
+                                    Expression* expression) {
+  if (expression->IsPropertyName()) {
+    fni->PushLiteralName(expression->AsLiteral()->AsRawPropertyName());
+  } else {
+    fni->PushLiteralName(
+        parser_->ast_value_factory()->anonymous_function_string());
+  }
+}
+
+
+void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
+                                                           Expression* right) {
+  DCHECK(left != NULL);
+  if (left->IsProperty() && right->IsFunctionLiteral()) {
+    right->AsFunctionLiteral()->set_pretenure();
+  }
+}
+
+
+Expression* ParserTraits::MarkExpressionAsAssigned(Expression* expression) {
+  VariableProxy* proxy =
+      expression != NULL ? expression->AsVariableProxy() : NULL;
+  if (proxy != NULL) proxy->set_is_assigned();
+  return expression;
+}
+
+
+bool ParserTraits::ShortcutNumericLiteralBinaryExpression(
+    Expression** x, Expression* y, Token::Value op, int pos,
+    AstNodeFactory* factory) {
+  if ((*x)->AsLiteral() && (*x)->AsLiteral()->raw_value()->IsNumber() &&
+      y->AsLiteral() && y->AsLiteral()->raw_value()->IsNumber()) {
+    double x_val = (*x)->AsLiteral()->raw_value()->AsNumber();
+    double y_val = y->AsLiteral()->raw_value()->AsNumber();
+    bool x_has_dot = (*x)->AsLiteral()->raw_value()->ContainsDot();
+    bool y_has_dot = y->AsLiteral()->raw_value()->ContainsDot();
+    bool has_dot = x_has_dot || y_has_dot;
+    switch (op) {
+      case Token::ADD:
+        *x = factory->NewNumberLiteral(x_val + y_val, pos, has_dot);
+        return true;
+      case Token::SUB:
+        *x = factory->NewNumberLiteral(x_val - y_val, pos, has_dot);
+        return true;
+      case Token::MUL:
+        *x = factory->NewNumberLiteral(x_val * y_val, pos, has_dot);
+        return true;
+      case Token::DIV:
+        *x = factory->NewNumberLiteral(x_val / y_val, pos, has_dot);
+        return true;
+      case Token::BIT_OR: {
+        int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
+        *x = factory->NewNumberLiteral(value, pos, has_dot);
+        return true;
+      }
+      case Token::BIT_AND: {
+        int value = DoubleToInt32(x_val) & DoubleToInt32(y_val);
+        *x = factory->NewNumberLiteral(value, pos, has_dot);
+        return true;
+      }
+      case Token::BIT_XOR: {
+        int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val);
+        *x = factory->NewNumberLiteral(value, pos, has_dot);
+        return true;
+      }
+      case Token::SHL: {
+        int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f);
+        *x = factory->NewNumberLiteral(value, pos, has_dot);
+        return true;
+      }
+      case Token::SHR: {
+        uint32_t shift = DoubleToInt32(y_val) & 0x1f;
+        uint32_t value = DoubleToUint32(x_val) >> shift;
+        *x = factory->NewNumberLiteral(value, pos, has_dot);
+        return true;
+      }
+      case Token::SAR: {
+        uint32_t shift = DoubleToInt32(y_val) & 0x1f;
+        int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift);
+        *x = factory->NewNumberLiteral(value, pos, has_dot);
+        return true;
+      }
+      default:
+        break;
+    }
+  }
+  return false;
+}
+
+
+Expression* ParserTraits::BuildUnaryExpression(Expression* expression,
+                                               Token::Value op, int pos,
+                                               AstNodeFactory* factory) {
+  DCHECK(expression != NULL);
+  if (expression->IsLiteral()) {
+    const AstValue* literal = expression->AsLiteral()->raw_value();
+    if (op == Token::NOT) {
+      // Convert the literal to a boolean condition and negate it.
+      bool condition = literal->BooleanValue();
+      return factory->NewBooleanLiteral(!condition, pos);
+    } else if (literal->IsNumber()) {
+      // Compute some expressions involving only number literals.
+      double value = literal->AsNumber();
+      bool has_dot = literal->ContainsDot();
+      switch (op) {
+        case Token::ADD:
+          return expression;
+        case Token::SUB:
+          return factory->NewNumberLiteral(-value, pos, has_dot);
+        case Token::BIT_NOT:
+          return factory->NewNumberLiteral(~DoubleToInt32(value), pos, has_dot);
+        default:
+          break;
+      }
+    }
+  }
+  // Desugar '+foo' => 'foo*1'
+  if (op == Token::ADD) {
+    return factory->NewBinaryOperation(
+        Token::MUL, expression, factory->NewNumberLiteral(1, pos, true), pos);
+  }
+  // The same idea for '-foo' => 'foo*(-1)'.
+  if (op == Token::SUB) {
+    return factory->NewBinaryOperation(
+        Token::MUL, expression, factory->NewNumberLiteral(-1, pos), pos);
+  }
+  // ...and one more time for '~foo' => 'foo^(~0)'.
+  if (op == Token::BIT_NOT) {
+    return factory->NewBinaryOperation(
+        Token::BIT_XOR, expression, factory->NewNumberLiteral(~0, pos), pos);
+  }
+  return factory->NewUnaryOperation(op, expression, pos);
+}
+
+
+Expression* ParserTraits::NewThrowReferenceError(
+    MessageTemplate::Template message, int pos) {
+  return NewThrowError(Runtime::kNewReferenceError, message,
+                       parser_->ast_value_factory()->empty_string(), pos);
+}
+
+
+Expression* ParserTraits::NewThrowSyntaxError(MessageTemplate::Template message,
+                                              const AstRawString* arg,
+                                              int pos) {
+  return NewThrowError(Runtime::kNewSyntaxError, message, arg, pos);
+}
+
+
+Expression* ParserTraits::NewThrowTypeError(MessageTemplate::Template message,
+                                            const AstRawString* arg, int pos) {
+  return NewThrowError(Runtime::kNewTypeError, message, arg, pos);
+}
+
+
+Expression* ParserTraits::NewThrowError(Runtime::FunctionId id,
+                                        MessageTemplate::Template message,
+                                        const AstRawString* arg, int pos) {
+  Zone* zone = parser_->zone();
+  ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone);
+  args->Add(parser_->factory()->NewSmiLiteral(message, pos), zone);
+  args->Add(parser_->factory()->NewStringLiteral(arg, pos), zone);
+  CallRuntime* call_constructor =
+      parser_->factory()->NewCallRuntime(id, args, pos);
+  return parser_->factory()->NewThrow(call_constructor, pos);
+}
+
+
+void ParserTraits::ReportMessageAt(Scanner::Location source_location,
+                                   MessageTemplate::Template message,
+                                   const char* arg, ParseErrorType error_type) {
+  if (parser_->stack_overflow()) {
+    // Suppress the error message (syntax error or such) in the presence of a
+    // stack overflow. The isolate allows only one pending exception at at time
+    // and we want to report the stack overflow later.
+    return;
+  }
+  parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
+                                                  source_location.end_pos,
+                                                  message, arg, error_type);
+}
+
+
+void ParserTraits::ReportMessage(MessageTemplate::Template message,
+                                 const char* arg, ParseErrorType error_type) {
+  Scanner::Location source_location = parser_->scanner()->location();
+  ReportMessageAt(source_location, message, arg, error_type);
+}
+
+
+void ParserTraits::ReportMessage(MessageTemplate::Template message,
+                                 const AstRawString* arg,
+                                 ParseErrorType error_type) {
+  Scanner::Location source_location = parser_->scanner()->location();
+  ReportMessageAt(source_location, message, arg, error_type);
+}
+
+
+void ParserTraits::ReportMessageAt(Scanner::Location source_location,
+                                   MessageTemplate::Template message,
+                                   const AstRawString* arg,
+                                   ParseErrorType error_type) {
+  if (parser_->stack_overflow()) {
+    // Suppress the error message (syntax error or such) in the presence of a
+    // stack overflow. The isolate allows only one pending exception at at time
+    // and we want to report the stack overflow later.
+    return;
+  }
+  parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
+                                                  source_location.end_pos,
+                                                  message, arg, error_type);
+}
+
+
+const AstRawString* ParserTraits::GetSymbol(Scanner* scanner) {
+  const AstRawString* result =
+      parser_->scanner()->CurrentSymbol(parser_->ast_value_factory());
+  DCHECK(result != NULL);
+  return result;
+}
+
+
+const AstRawString* ParserTraits::GetNumberAsSymbol(Scanner* scanner) {
+  double double_value = parser_->scanner()->DoubleValue();
+  char array[100];
+  const char* string =
+      DoubleToCString(double_value, Vector<char>(array, arraysize(array)));
+  return parser_->ast_value_factory()->GetOneByteString(string);
+}
+
+
+const AstRawString* ParserTraits::GetNextSymbol(Scanner* scanner) {
+  return parser_->scanner()->NextSymbol(parser_->ast_value_factory());
+}
+
+
+Expression* ParserTraits::ThisExpression(Scope* scope, AstNodeFactory* factory,
+                                         int pos) {
+  return scope->NewUnresolved(factory,
+                              parser_->ast_value_factory()->this_string(),
+                              Variable::THIS, pos, pos + 4);
+}
+
+
+Expression* ParserTraits::SuperPropertyReference(Scope* scope,
+                                                 AstNodeFactory* factory,
+                                                 int pos) {
+  // this_function[home_object_symbol]
+  VariableProxy* this_function_proxy = scope->NewUnresolved(
+      factory, parser_->ast_value_factory()->this_function_string(),
+      Variable::NORMAL, pos);
+  Expression* home_object_symbol_literal =
+      factory->NewSymbolLiteral("home_object_symbol", RelocInfo::kNoPosition);
+  Expression* home_object = factory->NewProperty(
+      this_function_proxy, home_object_symbol_literal, pos);
+  return factory->NewSuperPropertyReference(
+      ThisExpression(scope, factory, pos)->AsVariableProxy(), home_object, pos);
+}
+
+
+Expression* ParserTraits::SuperCallReference(Scope* scope,
+                                             AstNodeFactory* factory, int pos) {
+  VariableProxy* new_target_proxy = scope->NewUnresolved(
+      factory, parser_->ast_value_factory()->new_target_string(),
+      Variable::NORMAL, pos);
+  VariableProxy* this_function_proxy = scope->NewUnresolved(
+      factory, parser_->ast_value_factory()->this_function_string(),
+      Variable::NORMAL, pos);
+  return factory->NewSuperCallReference(
+      ThisExpression(scope, factory, pos)->AsVariableProxy(), new_target_proxy,
+      this_function_proxy, pos);
+}
+
+
+Expression* ParserTraits::NewTargetExpression(Scope* scope,
+                                              AstNodeFactory* factory,
+                                              int pos) {
+  static const int kNewTargetStringLength = 10;
+  auto proxy = scope->NewUnresolved(
+      factory, parser_->ast_value_factory()->new_target_string(),
+      Variable::NORMAL, pos, pos + kNewTargetStringLength);
+  proxy->set_is_new_target();
+  return proxy;
+}
+
+
+Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope,
+                                             int pos, int end_pos,
+                                             LanguageMode mode) {
+  return parser_->DefaultConstructor(call_super, scope, pos, end_pos, mode);
+}
+
+
+Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
+                                             Scanner* scanner,
+                                             AstNodeFactory* factory) {
+  switch (token) {
+    case Token::NULL_LITERAL:
+      return factory->NewNullLiteral(pos);
+    case Token::TRUE_LITERAL:
+      return factory->NewBooleanLiteral(true, pos);
+    case Token::FALSE_LITERAL:
+      return factory->NewBooleanLiteral(false, pos);
+    case Token::SMI: {
+      int value = scanner->smi_value();
+      return factory->NewSmiLiteral(value, pos);
+    }
+    case Token::NUMBER: {
+      bool has_dot = scanner->ContainsDot();
+      double value = scanner->DoubleValue();
+      return factory->NewNumberLiteral(value, pos, has_dot);
+    }
+    default:
+      DCHECK(false);
+  }
+  return NULL;
+}
+
+
+Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
+                                                   int start_position,
+                                                   int end_position,
+                                                   Scope* scope,
+                                                   AstNodeFactory* factory) {
+  if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
+  return scope->NewUnresolved(factory, name, Variable::NORMAL, start_position,
+                              end_position);
+}
+
+
+Expression* ParserTraits::ExpressionFromString(int pos, Scanner* scanner,
+                                               AstNodeFactory* factory) {
+  const AstRawString* symbol = GetSymbol(scanner);
+  if (parser_->fni_ != NULL) parser_->fni_->PushLiteralName(symbol);
+  return factory->NewStringLiteral(symbol, pos);
+}
+
+
+Expression* ParserTraits::GetIterator(Expression* iterable,
+                                      AstNodeFactory* factory, int pos) {
+  Expression* iterator_symbol_literal =
+      factory->NewSymbolLiteral("iterator_symbol", RelocInfo::kNoPosition);
+  Expression* prop =
+      factory->NewProperty(iterable, iterator_symbol_literal, pos);
+  Zone* zone = parser_->zone();
+  ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(0, zone);
+  return factory->NewCall(prop, args, pos);
+}
+
+
+Literal* ParserTraits::GetLiteralTheHole(int position,
+                                         AstNodeFactory* factory) {
+  return factory->NewTheHoleLiteral(RelocInfo::kNoPosition);
+}
+
+
+Expression* ParserTraits::ParseV8Intrinsic(bool* ok) {
+  return parser_->ParseV8Intrinsic(ok);
+}
+
+
+FunctionLiteral* ParserTraits::ParseFunctionLiteral(
+    const AstRawString* name, Scanner::Location function_name_location,
+    FunctionNameValidity function_name_validity, FunctionKind kind,
+    int function_token_position, FunctionLiteral::FunctionType type,
+    FunctionLiteral::ArityRestriction arity_restriction,
+    LanguageMode language_mode, bool* ok) {
+  return parser_->ParseFunctionLiteral(
+      name, function_name_location, function_name_validity, kind,
+      function_token_position, type, arity_restriction, language_mode, ok);
+}
+
+
+ClassLiteral* ParserTraits::ParseClassLiteral(
+    const AstRawString* name, Scanner::Location class_name_location,
+    bool name_is_strict_reserved, int pos, bool* ok) {
+  return parser_->ParseClassLiteral(name, class_name_location,
+                                    name_is_strict_reserved, pos, ok);
+}
+
+
+Parser::Parser(ParseInfo* info)
+    : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(),
+                               info->extension(), info->ast_value_factory(),
+                               NULL, this),
+      scanner_(info->unicode_cache()),
+      reusable_preparser_(NULL),
+      original_scope_(NULL),
+      target_stack_(NULL),
+      compile_options_(info->compile_options()),
+      cached_parse_data_(NULL),
+      total_preparse_skipped_(0),
+      pre_parse_timer_(NULL),
+      parsing_on_main_thread_(true) {
+  // Even though we were passed ParseInfo, we should not store it in
+  // Parser - this makes sure that Isolate is not accidentally accessed via
+  // ParseInfo during background parsing.
+  DCHECK(!info->script().is_null() || info->source_stream() != NULL);
+  set_allow_lazy(info->allow_lazy_parsing());
+  set_allow_natives(FLAG_allow_natives_syntax || info->is_native());
+  set_allow_harmony_sloppy(FLAG_harmony_sloppy);
+  set_allow_harmony_sloppy_function(FLAG_harmony_sloppy_function);
+  set_allow_harmony_sloppy_let(FLAG_harmony_sloppy_let);
+  set_allow_harmony_default_parameters(FLAG_harmony_default_parameters);
+  set_allow_harmony_destructuring_bind(FLAG_harmony_destructuring_bind);
+  set_allow_harmony_destructuring_assignment(
+      FLAG_harmony_destructuring_assignment);
+  set_allow_strong_mode(FLAG_strong_mode);
+  set_allow_legacy_const(FLAG_legacy_const);
+  set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
+  set_allow_harmony_function_name(FLAG_harmony_function_name);
+  for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
+       ++feature) {
+    use_counts_[feature] = 0;
+  }
+  if (info->ast_value_factory() == NULL) {
+    // info takes ownership of AstValueFactory.
+    info->set_ast_value_factory(new AstValueFactory(zone(), info->hash_seed()));
+    info->set_ast_value_factory_owned();
+    ast_value_factory_ = info->ast_value_factory();
+  }
+}
+
+
+FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
+  // TODO(bmeurer): We temporarily need to pass allow_nesting = true here,
+  // see comment for HistogramTimerScope class.
+
+  // It's OK to use the Isolate & counters here, since this function is only
+  // called in the main thread.
+  DCHECK(parsing_on_main_thread_);
+
+  HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
+  Handle<String> source(String::cast(info->script()->source()));
+  isolate->counters()->total_parse_size()->Increment(source->length());
+  base::ElapsedTimer timer;
+  if (FLAG_trace_parse) {
+    timer.Start();
+  }
+  fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
+
+  // Initialize parser state.
+  CompleteParserRecorder recorder;
+
+  if (produce_cached_parse_data()) {
+    log_ = &recorder;
+  } else if (consume_cached_parse_data()) {
+    cached_parse_data_->Initialize();
+  }
+
+  source = String::Flatten(source);
+  FunctionLiteral* result;
+
+  if (source->IsExternalTwoByteString()) {
+    // Notice that the stream is destroyed at the end of the branch block.
+    // The last line of the blocks can't be moved outside, even though they're
+    // identical calls.
+    ExternalTwoByteStringUtf16CharacterStream stream(
+        Handle<ExternalTwoByteString>::cast(source), 0, source->length());
+    scanner_.Initialize(&stream);
+    result = DoParseProgram(info);
+  } else {
+    GenericStringUtf16CharacterStream stream(source, 0, source->length());
+    scanner_.Initialize(&stream);
+    result = DoParseProgram(info);
+  }
+  if (result != NULL) {
+    DCHECK_EQ(scanner_.peek_location().beg_pos, source->length());
+  }
+  HandleSourceURLComments(isolate, info->script());
+
+  if (FLAG_trace_parse && result != NULL) {
+    double ms = timer.Elapsed().InMillisecondsF();
+    if (info->is_eval()) {
+      PrintF("[parsing eval");
+    } else if (info->script()->name()->IsString()) {
+      String* name = String::cast(info->script()->name());
+      base::SmartArrayPointer<char> name_chars = name->ToCString();
+      PrintF("[parsing script: %s", name_chars.get());
+    } else {
+      PrintF("[parsing script");
+    }
+    PrintF(" - took %0.3f ms]\n", ms);
+  }
+  if (produce_cached_parse_data()) {
+    if (result != NULL) *info->cached_data() = recorder.GetScriptData();
+    log_ = NULL;
+  }
+  return result;
+}
+
+
+FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
+  // Note that this function can be called from the main thread or from a
+  // background thread. We should not access anything Isolate / heap dependent
+  // via ParseInfo, and also not pass it forward.
+  DCHECK(scope_ == NULL);
+  DCHECK(target_stack_ == NULL);
+
+  Mode parsing_mode = FLAG_lazy && allow_lazy() ? PARSE_LAZILY : PARSE_EAGERLY;
+  if (allow_natives() || extension_ != NULL) parsing_mode = PARSE_EAGERLY;
+
+  FunctionLiteral* result = NULL;
+  {
+    // TODO(wingo): Add an outer SCRIPT_SCOPE corresponding to the native
+    // context, which will have the "this" binding for script scopes.
+    Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
+    info->set_script_scope(scope);
+    if (!info->context().is_null() && !info->context()->IsNativeContext()) {
+      scope = Scope::DeserializeScopeChain(info->isolate(), zone(),
+                                           *info->context(), scope);
+      // The Scope is backed up by ScopeInfo (which is in the V8 heap); this
+      // means the Parser cannot operate independent of the V8 heap. Tell the
+      // string table to internalize strings and values right after they're
+      // created. This kind of parsing can only be done in the main thread.
+      DCHECK(parsing_on_main_thread_);
+      ast_value_factory()->Internalize(info->isolate());
+    }
+    original_scope_ = scope;
+    if (info->is_eval()) {
+      if (!scope->is_script_scope() || is_strict(info->language_mode())) {
+        parsing_mode = PARSE_EAGERLY;
+      }
+      scope = NewScope(scope, EVAL_SCOPE);
+    } else if (info->is_module()) {
+      scope = NewScope(scope, MODULE_SCOPE);
+    }
+
+    scope->set_start_position(0);
+
+    // Enter 'scope' with the given parsing mode.
+    ParsingModeScope parsing_mode_scope(this, parsing_mode);
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, scope,
+                                 kNormalFunction, &function_factory);
+
+    // Don't count the mode in the use counters--give the program a chance
+    // to enable script/module-wide strict/strong mode below.
+    scope_->SetLanguageMode(info->language_mode());
+    ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
+    bool ok = true;
+    int beg_pos = scanner()->location().beg_pos;
+    if (info->is_module()) {
+      ParseModuleItemList(body, &ok);
+    } else {
+      ParseStatementList(body, Token::EOS, &ok);
+    }
+
+    // The parser will peek but not consume EOS.  Our scope logically goes all
+    // the way to the EOS, though.
+    scope->set_end_position(scanner()->peek_location().beg_pos);
+
+    if (ok && is_strict(language_mode())) {
+      CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
+    }
+    if (ok && is_sloppy(language_mode()) && allow_harmony_sloppy_function()) {
+      // TODO(littledan): Function bindings on the global object that modify
+      // pre-existing bindings should be made writable, enumerable and
+      // nonconfigurable if possible, whereas this code will leave attributes
+      // unchanged if the property already exists.
+      InsertSloppyBlockFunctionVarBindings(scope, &ok);
+    }
+    if (ok && (is_strict(language_mode()) || allow_harmony_sloppy() ||
+               allow_harmony_destructuring_bind())) {
+      CheckConflictingVarDeclarations(scope_, &ok);
+    }
+
+    if (ok && info->parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
+      if (body->length() != 1 ||
+          !body->at(0)->IsExpressionStatement() ||
+          !body->at(0)->AsExpressionStatement()->
+              expression()->IsFunctionLiteral()) {
+        ReportMessage(MessageTemplate::kSingleFunctionLiteral);
+        ok = false;
+      }
+    }
+
+    if (ok) {
+      ParserTraits::RewriteDestructuringAssignments();
+      result = factory()->NewFunctionLiteral(
+          ast_value_factory()->empty_string(), scope_, body,
+          function_state.materialized_literal_count(),
+          function_state.expected_property_count(), 0,
+          FunctionLiteral::kNoDuplicateParameters,
+          FunctionLiteral::kGlobalOrEval, FunctionLiteral::kShouldLazyCompile,
+          FunctionKind::kNormalFunction, 0);
+    }
+  }
+
+  // Make sure the target stack is empty.
+  DCHECK(target_stack_ == NULL);
+
+  return result;
+}
+
+
+FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) {
+  // It's OK to use the Isolate & counters here, since this function is only
+  // called in the main thread.
+  DCHECK(parsing_on_main_thread_);
+  HistogramTimerScope timer_scope(isolate->counters()->parse_lazy());
+  Handle<String> source(String::cast(info->script()->source()));
+  isolate->counters()->total_parse_size()->Increment(source->length());
+  base::ElapsedTimer timer;
+  if (FLAG_trace_parse) {
+    timer.Start();
+  }
+  Handle<SharedFunctionInfo> shared_info = info->shared_info();
+
+  // Initialize parser state.
+  source = String::Flatten(source);
+  FunctionLiteral* result;
+  if (source->IsExternalTwoByteString()) {
+    ExternalTwoByteStringUtf16CharacterStream stream(
+        Handle<ExternalTwoByteString>::cast(source),
+        shared_info->start_position(),
+        shared_info->end_position());
+    result = ParseLazy(isolate, info, &stream);
+  } else {
+    GenericStringUtf16CharacterStream stream(source,
+                                             shared_info->start_position(),
+                                             shared_info->end_position());
+    result = ParseLazy(isolate, info, &stream);
+  }
+
+  if (FLAG_trace_parse && result != NULL) {
+    double ms = timer.Elapsed().InMillisecondsF();
+    base::SmartArrayPointer<char> name_chars =
+        result->debug_name()->ToCString();
+    PrintF("[parsing function: %s - took %0.3f ms]\n", name_chars.get(), ms);
+  }
+  return result;
+}
+
+
+FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
+                                   Utf16CharacterStream* source) {
+  Handle<SharedFunctionInfo> shared_info = info->shared_info();
+  scanner_.Initialize(source);
+  DCHECK(scope_ == NULL);
+  DCHECK(target_stack_ == NULL);
+
+  Handle<String> name(String::cast(shared_info->name()));
+  DCHECK(ast_value_factory());
+  fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
+  const AstRawString* raw_name = ast_value_factory()->GetString(name);
+  fni_->PushEnclosingName(raw_name);
+
+  ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
+
+  // Place holder for the result.
+  FunctionLiteral* result = NULL;
+
+  {
+    // Parse the function literal.
+    Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
+    info->set_script_scope(scope);
+    if (!info->closure().is_null()) {
+      // Ok to use Isolate here, since lazy function parsing is only done in the
+      // main thread.
+      DCHECK(parsing_on_main_thread_);
+      scope = Scope::DeserializeScopeChain(isolate, zone(),
+                                           info->closure()->context(), scope);
+    }
+    original_scope_ = scope;
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, scope,
+                                 shared_info->kind(), &function_factory);
+    DCHECK(is_sloppy(scope->language_mode()) ||
+           is_strict(info->language_mode()));
+    DCHECK(info->language_mode() == shared_info->language_mode());
+    FunctionLiteral::FunctionType function_type =
+        shared_info->is_expression()
+            ? (shared_info->is_anonymous()
+                   ? FunctionLiteral::kAnonymousExpression
+                   : FunctionLiteral::kNamedExpression)
+            : FunctionLiteral::kDeclaration;
+    bool ok = true;
+
+    if (shared_info->is_arrow()) {
+      // TODO(adamk): We should construct this scope from the ScopeInfo.
+      Scope* scope =
+          NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
+
+      // These two bits only need to be explicitly set because we're
+      // not passing the ScopeInfo to the Scope constructor.
+      // TODO(adamk): Remove these calls once the above NewScope call
+      // passes the ScopeInfo.
+      if (shared_info->scope_info()->CallsEval()) {
+        scope->RecordEvalCall();
+      }
+      SetLanguageMode(scope, shared_info->language_mode());
+
+      scope->set_start_position(shared_info->start_position());
+      ExpressionClassifier formals_classifier;
+      ParserFormalParameters formals(scope);
+      Checkpoint checkpoint(this);
+      {
+        // Parsing patterns as variable reference expression creates
+        // NewUnresolved references in current scope. Entrer arrow function
+        // scope for formal parameter parsing.
+        BlockState block_state(&scope_, scope);
+        if (Check(Token::LPAREN)) {
+          // '(' StrictFormalParameters ')'
+          ParseFormalParameterList(&formals, &formals_classifier, &ok);
+          if (ok) ok = Check(Token::RPAREN);
+        } else {
+          // BindingIdentifier
+          ParseFormalParameter(&formals, &formals_classifier, &ok);
+          if (ok) {
+            DeclareFormalParameter(formals.scope, formals.at(0),
+                                   &formals_classifier);
+          }
+        }
+      }
+
+      if (ok) {
+        checkpoint.Restore(&formals.materialized_literals_count);
+        // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
+        // not be observable, or else the preparser would have failed.
+        Expression* expression =
+            ParseArrowFunctionLiteral(true, formals, formals_classifier, &ok);
+        if (ok) {
+          // Scanning must end at the same position that was recorded
+          // previously. If not, parsing has been interrupted due to a stack
+          // overflow, at which point the partially parsed arrow function
+          // concise body happens to be a valid expression. This is a problem
+          // only for arrow functions with single expression bodies, since there
+          // is no end token such as "}" for normal functions.
+          if (scanner()->location().end_pos == shared_info->end_position()) {
+            // The pre-parser saw an arrow function here, so the full parser
+            // must produce a FunctionLiteral.
+            DCHECK(expression->IsFunctionLiteral());
+            result = expression->AsFunctionLiteral();
+          } else {
+            ok = false;
+          }
+        }
+      }
+    } else if (shared_info->is_default_constructor()) {
+      result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()),
+                                  scope, shared_info->start_position(),
+                                  shared_info->end_position(),
+                                  shared_info->language_mode());
+    } else {
+      result = ParseFunctionLiteral(
+          raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck,
+          shared_info->kind(), RelocInfo::kNoPosition, function_type,
+          FunctionLiteral::kNormalArity, shared_info->language_mode(), &ok);
+    }
+    // Make sure the results agree.
+    DCHECK(ok == (result != NULL));
+  }
+
+  // Make sure the target stack is empty.
+  DCHECK(target_stack_ == NULL);
+
+  if (result != NULL) {
+    Handle<String> inferred_name(shared_info->inferred_name());
+    result->set_inferred_name(inferred_name);
+  }
+  return result;
+}
+
+
+void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
+                                 bool* ok) {
+  // StatementList ::
+  //   (StatementListItem)* <end_token>
+
+  // Allocate a target stack to use for this set of source
+  // elements. This way, all scripts and functions get their own
+  // target stack thus avoiding illegal breaks and continues across
+  // functions.
+  TargetScope scope(&this->target_stack_);
+
+  DCHECK(body != NULL);
+  bool directive_prologue = true;     // Parsing directive prologue.
+
+  while (peek() != end_token) {
+    if (directive_prologue && peek() != Token::STRING) {
+      directive_prologue = false;
+    }
+
+    Scanner::Location token_loc = scanner()->peek_location();
+    Scanner::Location old_this_loc = function_state_->this_location();
+    Scanner::Location old_super_loc = function_state_->super_location();
+    Statement* stat = ParseStatementListItem(CHECK_OK);
+
+    if (is_strong(language_mode()) && scope_->is_function_scope() &&
+        IsClassConstructor(function_state_->kind())) {
+      Scanner::Location this_loc = function_state_->this_location();
+      Scanner::Location super_loc = function_state_->super_location();
+      if (this_loc.beg_pos != old_this_loc.beg_pos &&
+          this_loc.beg_pos != token_loc.beg_pos) {
+        ReportMessageAt(this_loc, MessageTemplate::kStrongConstructorThis);
+        *ok = false;
+        return nullptr;
+      }
+      if (super_loc.beg_pos != old_super_loc.beg_pos &&
+          super_loc.beg_pos != token_loc.beg_pos) {
+        ReportMessageAt(super_loc, MessageTemplate::kStrongConstructorSuper);
+        *ok = false;
+        return nullptr;
+      }
+    }
+
+    if (stat == NULL || stat->IsEmpty()) {
+      directive_prologue = false;   // End of directive prologue.
+      continue;
+    }
+
+    if (directive_prologue) {
+      // A shot at a directive.
+      ExpressionStatement* e_stat;
+      Literal* literal;
+      // Still processing directive prologue?
+      if ((e_stat = stat->AsExpressionStatement()) != NULL &&
+          (literal = e_stat->expression()->AsLiteral()) != NULL &&
+          literal->raw_value()->IsString()) {
+        // Check "use strict" directive (ES5 14.1), "use asm" directive, and
+        // "use strong" directive (experimental).
+        bool use_strict_found =
+            literal->raw_value()->AsString() ==
+                ast_value_factory()->use_strict_string() &&
+            token_loc.end_pos - token_loc.beg_pos ==
+                ast_value_factory()->use_strict_string()->length() + 2;
+        bool use_strong_found =
+            allow_strong_mode() &&
+            literal->raw_value()->AsString() ==
+                ast_value_factory()->use_strong_string() &&
+            token_loc.end_pos - token_loc.beg_pos ==
+                ast_value_factory()->use_strong_string()->length() + 2;
+        if (use_strict_found || use_strong_found) {
+          // Strong mode implies strict mode. If there are several "use strict"
+          // / "use strong" directives, do the strict mode changes only once.
+          if (is_sloppy(scope_->language_mode())) {
+            RaiseLanguageMode(STRICT);
+          }
+
+          if (use_strong_found) {
+            RaiseLanguageMode(STRONG);
+            if (IsClassConstructor(function_state_->kind())) {
+              // "use strong" cannot occur in a class constructor body, to avoid
+              // unintuitive strong class object semantics.
+              ParserTraits::ReportMessageAt(
+                  token_loc, MessageTemplate::kStrongConstructorDirective);
+              *ok = false;
+              return nullptr;
+            }
+          }
+          if (!scope_->HasSimpleParameters()) {
+            // TC39 deemed "use strict" directives to be an error when occurring
+            // in the body of a function with non-simple parameter list, on
+            // 29/7/2015. https://goo.gl/ueA7Ln
+            //
+            // In V8, this also applies to "use strong " directives.
+            const AstRawString* string = literal->raw_value()->AsString();
+            ParserTraits::ReportMessageAt(
+                token_loc, MessageTemplate::kIllegalLanguageModeDirective,
+                string);
+            *ok = false;
+            return nullptr;
+          }
+          // Because declarations in strict eval code don't leak into the scope
+          // of the eval call, it is likely that functions declared in strict
+          // eval code will be used within the eval code, so lazy parsing is
+          // probably not a win.
+          if (scope_->is_eval_scope()) mode_ = PARSE_EAGERLY;
+        } else if (literal->raw_value()->AsString() ==
+                       ast_value_factory()->use_asm_string() &&
+                   token_loc.end_pos - token_loc.beg_pos ==
+                       ast_value_factory()->use_asm_string()->length() + 2) {
+          // Store the usage count; The actual use counter on the isolate is
+          // incremented after parsing is done.
+          ++use_counts_[v8::Isolate::kUseAsm];
+          scope_->SetAsmModule();
+        } else {
+          // Should not change mode, but will increment UseCounter
+          // if appropriate. Ditto usages below.
+          RaiseLanguageMode(SLOPPY);
+        }
+      } else {
+        // End of the directive prologue.
+        directive_prologue = false;
+        RaiseLanguageMode(SLOPPY);
+      }
+    } else {
+      RaiseLanguageMode(SLOPPY);
+    }
+
+    body->Add(stat, zone());
+  }
+
+  return 0;
+}
+
+
+Statement* Parser::ParseStatementListItem(bool* ok) {
+  // (Ecma 262 6th Edition, 13.1):
+  // StatementListItem:
+  //    Statement
+  //    Declaration
+
+  if (peek() != Token::CLASS) {
+    // No more classes follow; reset the start position for the consecutive
+    // class declaration group.
+    scope_->set_class_declaration_group_start(-1);
+  }
+
+  switch (peek()) {
+    case Token::FUNCTION:
+      return ParseFunctionDeclaration(NULL, ok);
+    case Token::CLASS:
+      if (scope_->class_declaration_group_start() < 0) {
+        scope_->set_class_declaration_group_start(
+            scanner()->peek_location().beg_pos);
+      }
+      return ParseClassDeclaration(NULL, ok);
+    case Token::CONST:
+      if (allow_const()) {
+        return ParseVariableStatement(kStatementListItem, NULL, ok);
+      }
+      break;
+    case Token::VAR:
+      return ParseVariableStatement(kStatementListItem, NULL, ok);
+    case Token::LET:
+      if (IsNextLetKeyword()) {
+        return ParseVariableStatement(kStatementListItem, NULL, ok);
+      }
+      break;
+    default:
+      break;
+  }
+  return ParseStatement(NULL, ok);
+}
+
+
+Statement* Parser::ParseModuleItem(bool* ok) {
+  // (Ecma 262 6th Edition, 15.2):
+  // ModuleItem :
+  //    ImportDeclaration
+  //    ExportDeclaration
+  //    StatementListItem
+
+  switch (peek()) {
+    case Token::IMPORT:
+      return ParseImportDeclaration(ok);
+    case Token::EXPORT:
+      return ParseExportDeclaration(ok);
+    default:
+      return ParseStatementListItem(ok);
+  }
+}
+
+
+void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
+  // (Ecma 262 6th Edition, 15.2):
+  // Module :
+  //    ModuleBody?
+  //
+  // ModuleBody :
+  //    ModuleItem*
+
+  DCHECK(scope_->is_module_scope());
+  RaiseLanguageMode(STRICT);
+
+  while (peek() != Token::EOS) {
+    Statement* stat = ParseModuleItem(CHECK_OK);
+    if (stat && !stat->IsEmpty()) {
+      body->Add(stat, zone());
+    }
+  }
+
+  // Check that all exports are bound.
+  ModuleDescriptor* descriptor = scope_->module();
+  for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
+       it.Advance()) {
+    if (scope_->LookupLocal(it.local_name()) == NULL) {
+      // TODO(adamk): Pass both local_name and export_name once ParserTraits
+      // supports multiple arg error messages.
+      // Also try to report this at a better location.
+      ParserTraits::ReportMessage(MessageTemplate::kModuleExportUndefined,
+                                  it.local_name());
+      *ok = false;
+      return NULL;
+    }
+  }
+
+  scope_->module()->Freeze();
+  return NULL;
+}
+
+
+const AstRawString* Parser::ParseModuleSpecifier(bool* ok) {
+  // ModuleSpecifier :
+  //    StringLiteral
+
+  Expect(Token::STRING, CHECK_OK);
+  return GetSymbol(scanner());
+}
+
+
+void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
+                                ZoneList<Scanner::Location>* export_locations,
+                                ZoneList<const AstRawString*>* local_names,
+                                Scanner::Location* reserved_loc, bool* ok) {
+  // ExportClause :
+  //   '{' '}'
+  //   '{' ExportsList '}'
+  //   '{' ExportsList ',' '}'
+  //
+  // ExportsList :
+  //   ExportSpecifier
+  //   ExportsList ',' ExportSpecifier
+  //
+  // ExportSpecifier :
+  //   IdentifierName
+  //   IdentifierName 'as' IdentifierName
+
+  Expect(Token::LBRACE, CHECK_OK);
+
+  Token::Value name_tok;
+  while ((name_tok = peek()) != Token::RBRACE) {
+    // Keep track of the first reserved word encountered in case our
+    // caller needs to report an error.
+    if (!reserved_loc->IsValid() &&
+        !Token::IsIdentifier(name_tok, STRICT, false)) {
+      *reserved_loc = scanner()->location();
+    }
+    const AstRawString* local_name = ParseIdentifierName(CHECK_OK);
+    const AstRawString* export_name = NULL;
+    if (CheckContextualKeyword(CStrVector("as"))) {
+      export_name = ParseIdentifierName(CHECK_OK);
+    }
+    if (export_name == NULL) {
+      export_name = local_name;
+    }
+    export_names->Add(export_name, zone());
+    local_names->Add(local_name, zone());
+    export_locations->Add(scanner()->location(), zone());
+    if (peek() == Token::RBRACE) break;
+    Expect(Token::COMMA, CHECK_OK);
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+
+  return 0;
+}
+
+
+ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
+  // NamedImports :
+  //   '{' '}'
+  //   '{' ImportsList '}'
+  //   '{' ImportsList ',' '}'
+  //
+  // ImportsList :
+  //   ImportSpecifier
+  //   ImportsList ',' ImportSpecifier
+  //
+  // ImportSpecifier :
+  //   BindingIdentifier
+  //   IdentifierName 'as' BindingIdentifier
+
+  Expect(Token::LBRACE, CHECK_OK);
+
+  ZoneList<ImportDeclaration*>* result =
+      new (zone()) ZoneList<ImportDeclaration*>(1, zone());
+  while (peek() != Token::RBRACE) {
+    const AstRawString* import_name = ParseIdentifierName(CHECK_OK);
+    const AstRawString* local_name = import_name;
+    // In the presence of 'as', the left-side of the 'as' can
+    // be any IdentifierName. But without 'as', it must be a valid
+    // BindingIdentifier.
+    if (CheckContextualKeyword(CStrVector("as"))) {
+      local_name = ParseIdentifierName(CHECK_OK);
+    }
+    if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false)) {
+      *ok = false;
+      ReportMessage(MessageTemplate::kUnexpectedReserved);
+      return NULL;
+    } else if (IsEvalOrArguments(local_name)) {
+      *ok = false;
+      ReportMessage(MessageTemplate::kStrictEvalArguments);
+      return NULL;
+    } else if (is_strong(language_mode()) && IsUndefined(local_name)) {
+      *ok = false;
+      ReportMessage(MessageTemplate::kStrongUndefined);
+      return NULL;
+    }
+    VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
+    ImportDeclaration* declaration =
+        factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
+    Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+    result->Add(declaration, zone());
+    if (peek() == Token::RBRACE) break;
+    Expect(Token::COMMA, CHECK_OK);
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+
+  return result;
+}
+
+
+Statement* Parser::ParseImportDeclaration(bool* ok) {
+  // ImportDeclaration :
+  //   'import' ImportClause 'from' ModuleSpecifier ';'
+  //   'import' ModuleSpecifier ';'
+  //
+  // ImportClause :
+  //   NameSpaceImport
+  //   NamedImports
+  //   ImportedDefaultBinding
+  //   ImportedDefaultBinding ',' NameSpaceImport
+  //   ImportedDefaultBinding ',' NamedImports
+  //
+  // NameSpaceImport :
+  //   '*' 'as' ImportedBinding
+
+  int pos = peek_position();
+  Expect(Token::IMPORT, CHECK_OK);
+
+  Token::Value tok = peek();
+
+  // 'import' ModuleSpecifier ';'
+  if (tok == Token::STRING) {
+    const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
+    scope_->module()->AddModuleRequest(module_specifier, zone());
+    ExpectSemicolon(CHECK_OK);
+    return factory()->NewEmptyStatement(pos);
+  }
+
+  // Parse ImportedDefaultBinding if present.
+  ImportDeclaration* import_default_declaration = NULL;
+  if (tok != Token::MUL && tok != Token::LBRACE) {
+    const AstRawString* local_name =
+        ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
+    VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
+    import_default_declaration = factory()->NewImportDeclaration(
+        proxy, ast_value_factory()->default_string(), NULL, scope_, pos);
+    Declare(import_default_declaration, DeclarationDescriptor::NORMAL, true,
+            CHECK_OK);
+  }
+
+  const AstRawString* module_instance_binding = NULL;
+  ZoneList<ImportDeclaration*>* named_declarations = NULL;
+  if (import_default_declaration == NULL || Check(Token::COMMA)) {
+    switch (peek()) {
+      case Token::MUL: {
+        Consume(Token::MUL);
+        ExpectContextualKeyword(CStrVector("as"), CHECK_OK);
+        module_instance_binding =
+            ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
+        // TODO(ES6): Add an appropriate declaration.
+        break;
+      }
+
+      case Token::LBRACE:
+        named_declarations = ParseNamedImports(pos, CHECK_OK);
+        break;
+
+      default:
+        *ok = false;
+        ReportUnexpectedToken(scanner()->current_token());
+        return NULL;
+    }
+  }
+
+  ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
+  const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
+  scope_->module()->AddModuleRequest(module_specifier, zone());
+
+  if (module_instance_binding != NULL) {
+    // TODO(ES6): Set the module specifier for the module namespace binding.
+  }
+
+  if (import_default_declaration != NULL) {
+    import_default_declaration->set_module_specifier(module_specifier);
+  }
+
+  if (named_declarations != NULL) {
+    for (int i = 0; i < named_declarations->length(); ++i) {
+      named_declarations->at(i)->set_module_specifier(module_specifier);
+    }
+  }
+
+  ExpectSemicolon(CHECK_OK);
+  return factory()->NewEmptyStatement(pos);
+}
+
+
+Statement* Parser::ParseExportDefault(bool* ok) {
+  //  Supports the following productions, starting after the 'default' token:
+  //    'export' 'default' FunctionDeclaration
+  //    'export' 'default' ClassDeclaration
+  //    'export' 'default' AssignmentExpression[In] ';'
+
+  Expect(Token::DEFAULT, CHECK_OK);
+  Scanner::Location default_loc = scanner()->location();
+
+  ZoneList<const AstRawString*> names(1, zone());
+  Statement* result = NULL;
+  switch (peek()) {
+    case Token::FUNCTION:
+      // TODO(ES6): Support parsing anonymous function declarations here.
+      result = ParseFunctionDeclaration(&names, CHECK_OK);
+      break;
+
+    case Token::CLASS:
+      // TODO(ES6): Support parsing anonymous class declarations here.
+      result = ParseClassDeclaration(&names, CHECK_OK);
+      break;
+
+    default: {
+      int pos = peek_position();
+      ExpressionClassifier classifier;
+      Expression* expr = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+      expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+
+      ExpectSemicolon(CHECK_OK);
+      result = factory()->NewExpressionStatement(expr, pos);
+      break;
+    }
+  }
+
+  const AstRawString* default_string = ast_value_factory()->default_string();
+
+  DCHECK_LE(names.length(), 1);
+  if (names.length() == 1) {
+    scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
+    if (!*ok) {
+      ParserTraits::ReportMessageAt(
+          default_loc, MessageTemplate::kDuplicateExport, default_string);
+      return NULL;
+    }
+  } else {
+    // TODO(ES6): Assign result to a const binding with the name "*default*"
+    // and add an export entry with "*default*" as the local name.
+  }
+
+  return result;
+}
+
+
+Statement* Parser::ParseExportDeclaration(bool* ok) {
+  // ExportDeclaration:
+  //    'export' '*' 'from' ModuleSpecifier ';'
+  //    'export' ExportClause ('from' ModuleSpecifier)? ';'
+  //    'export' VariableStatement
+  //    'export' Declaration
+  //    'export' 'default' ... (handled in ParseExportDefault)
+
+  int pos = peek_position();
+  Expect(Token::EXPORT, CHECK_OK);
+
+  Statement* result = NULL;
+  ZoneList<const AstRawString*> names(1, zone());
+  switch (peek()) {
+    case Token::DEFAULT:
+      return ParseExportDefault(ok);
+
+    case Token::MUL: {
+      Consume(Token::MUL);
+      ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
+      const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
+      scope_->module()->AddModuleRequest(module_specifier, zone());
+      // TODO(ES6): scope_->module()->AddStarExport(...)
+      ExpectSemicolon(CHECK_OK);
+      return factory()->NewEmptyStatement(pos);
+    }
+
+    case Token::LBRACE: {
+      // There are two cases here:
+      //
+      // 'export' ExportClause ';'
+      // and
+      // 'export' ExportClause FromClause ';'
+      //
+      // In the first case, the exported identifiers in ExportClause must
+      // not be reserved words, while in the latter they may be. We
+      // pass in a location that gets filled with the first reserved word
+      // encountered, and then throw a SyntaxError if we are in the
+      // non-FromClause case.
+      Scanner::Location reserved_loc = Scanner::Location::invalid();
+      ZoneList<const AstRawString*> export_names(1, zone());
+      ZoneList<Scanner::Location> export_locations(1, zone());
+      ZoneList<const AstRawString*> local_names(1, zone());
+      ParseExportClause(&export_names, &export_locations, &local_names,
+                        &reserved_loc, CHECK_OK);
+      const AstRawString* indirect_export_module_specifier = NULL;
+      if (CheckContextualKeyword(CStrVector("from"))) {
+        indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK);
+      } else if (reserved_loc.IsValid()) {
+        // No FromClause, so reserved words are invalid in ExportClause.
+        *ok = false;
+        ReportMessageAt(reserved_loc, MessageTemplate::kUnexpectedReserved);
+        return NULL;
+      }
+      ExpectSemicolon(CHECK_OK);
+      const int length = export_names.length();
+      DCHECK_EQ(length, local_names.length());
+      DCHECK_EQ(length, export_locations.length());
+      if (indirect_export_module_specifier == NULL) {
+        for (int i = 0; i < length; ++i) {
+          scope_->module()->AddLocalExport(export_names[i], local_names[i],
+                                           zone(), ok);
+          if (!*ok) {
+            ParserTraits::ReportMessageAt(export_locations[i],
+                                          MessageTemplate::kDuplicateExport,
+                                          export_names[i]);
+            return NULL;
+          }
+        }
+      } else {
+        scope_->module()->AddModuleRequest(indirect_export_module_specifier,
+                                           zone());
+        for (int i = 0; i < length; ++i) {
+          // TODO(ES6): scope_->module()->AddIndirectExport(...);(
+        }
+      }
+      return factory()->NewEmptyStatement(pos);
+    }
+
+    case Token::FUNCTION:
+      result = ParseFunctionDeclaration(&names, CHECK_OK);
+      break;
+
+    case Token::CLASS:
+      result = ParseClassDeclaration(&names, CHECK_OK);
+      break;
+
+    case Token::VAR:
+    case Token::LET:
+    case Token::CONST:
+      result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
+      break;
+
+    default:
+      *ok = false;
+      ReportUnexpectedToken(scanner()->current_token());
+      return NULL;
+  }
+
+  // Extract declared names into export declarations.
+  ModuleDescriptor* descriptor = scope_->module();
+  for (int i = 0; i < names.length(); ++i) {
+    descriptor->AddLocalExport(names[i], names[i], zone(), ok);
+    if (!*ok) {
+      // TODO(adamk): Possibly report this error at the right place.
+      ParserTraits::ReportMessage(MessageTemplate::kDuplicateExport, names[i]);
+      return NULL;
+    }
+  }
+
+  DCHECK_NOT_NULL(result);
+  return result;
+}
+
+
+Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
+                                  bool* ok) {
+  // Statement ::
+  //   EmptyStatement
+  //   ...
+
+  if (peek() == Token::SEMICOLON) {
+    Next();
+    return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+  }
+  return ParseSubStatement(labels, ok);
+}
+
+
+Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
+                                     bool* ok) {
+  // Statement ::
+  //   Block
+  //   VariableStatement
+  //   EmptyStatement
+  //   ExpressionStatement
+  //   IfStatement
+  //   IterationStatement
+  //   ContinueStatement
+  //   BreakStatement
+  //   ReturnStatement
+  //   WithStatement
+  //   LabelledStatement
+  //   SwitchStatement
+  //   ThrowStatement
+  //   TryStatement
+  //   DebuggerStatement
+
+  // Note: Since labels can only be used by 'break' and 'continue'
+  // statements, which themselves are only valid within blocks,
+  // iterations or 'switch' statements (i.e., BreakableStatements),
+  // labels can be simply ignored in all other cases; except for
+  // trivial labeled break statements 'label: break label' which is
+  // parsed into an empty statement.
+  switch (peek()) {
+    case Token::LBRACE:
+      return ParseBlock(labels, ok);
+
+    case Token::SEMICOLON:
+      if (is_strong(language_mode())) {
+        ReportMessageAt(scanner()->peek_location(),
+                        MessageTemplate::kStrongEmpty);
+        *ok = false;
+        return NULL;
+      }
+      Next();
+      return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+
+    case Token::IF:
+      return ParseIfStatement(labels, ok);
+
+    case Token::DO:
+      return ParseDoWhileStatement(labels, ok);
+
+    case Token::WHILE:
+      return ParseWhileStatement(labels, ok);
+
+    case Token::FOR:
+      return ParseForStatement(labels, ok);
+
+    case Token::CONTINUE:
+    case Token::BREAK:
+    case Token::RETURN:
+    case Token::THROW:
+    case Token::TRY: {
+      // These statements must have their labels preserved in an enclosing
+      // block
+      if (labels == NULL) {
+        return ParseStatementAsUnlabelled(labels, ok);
+      } else {
+        Block* result =
+            factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition);
+        Target target(&this->target_stack_, result);
+        Statement* statement = ParseStatementAsUnlabelled(labels, CHECK_OK);
+        if (result) result->statements()->Add(statement, zone());
+        return result;
+      }
+    }
+
+    case Token::WITH:
+      return ParseWithStatement(labels, ok);
+
+    case Token::SWITCH:
+      return ParseSwitchStatement(labels, ok);
+
+    case Token::FUNCTION: {
+      // FunctionDeclaration is only allowed in the context of SourceElements
+      // (Ecma 262 5th Edition, clause 14):
+      // SourceElement:
+      //    Statement
+      //    FunctionDeclaration
+      // Common language extension is to allow function declaration in place
+      // of any statement. This language extension is disabled in strict mode.
+      //
+      // In Harmony mode, this case also handles the extension:
+      // Statement:
+      //    GeneratorDeclaration
+      if (is_strict(language_mode())) {
+        ReportMessageAt(scanner()->peek_location(),
+                        MessageTemplate::kStrictFunction);
+        *ok = false;
+        return NULL;
+      }
+      return ParseFunctionDeclaration(NULL, ok);
+    }
+
+    case Token::DEBUGGER:
+      return ParseDebuggerStatement(ok);
+
+    case Token::VAR:
+      return ParseVariableStatement(kStatement, NULL, ok);
+
+    case Token::CONST:
+      // In ES6 CONST is not allowed as a Statement, only as a
+      // LexicalDeclaration, however we continue to allow it in sloppy mode for
+      // backwards compatibility.
+      if (is_sloppy(language_mode()) && allow_legacy_const()) {
+        return ParseVariableStatement(kStatement, NULL, ok);
+      }
+
+    // Fall through.
+    default:
+      return ParseExpressionOrLabelledStatement(labels, ok);
+  }
+}
+
+Statement* Parser::ParseStatementAsUnlabelled(
+    ZoneList<const AstRawString*>* labels, bool* ok) {
+  switch (peek()) {
+    case Token::CONTINUE:
+      return ParseContinueStatement(ok);
+
+    case Token::BREAK:
+      return ParseBreakStatement(labels, ok);
+
+    case Token::RETURN:
+      return ParseReturnStatement(ok);
+
+    case Token::THROW:
+      return ParseThrowStatement(ok);
+
+    case Token::TRY:
+      return ParseTryStatement(ok);
+
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+VariableProxy* Parser::NewUnresolved(const AstRawString* name,
+                                     VariableMode mode) {
+  // If we are inside a function, a declaration of a var/const variable is a
+  // truly local variable, and the scope of the variable is always the function
+  // scope.
+  // Let/const variables in harmony mode are always added to the immediately
+  // enclosing scope.
+  Scope* scope =
+      IsLexicalVariableMode(mode) ? scope_ : scope_->DeclarationScope();
+  return scope->NewUnresolved(factory(), name, Variable::NORMAL,
+                              scanner()->location().beg_pos,
+                              scanner()->location().end_pos);
+}
+
+
+Variable* Parser::Declare(Declaration* declaration,
+                          DeclarationDescriptor::Kind declaration_kind,
+                          bool resolve, bool* ok, Scope* scope) {
+  VariableProxy* proxy = declaration->proxy();
+  DCHECK(proxy->raw_name() != NULL);
+  const AstRawString* name = proxy->raw_name();
+  VariableMode mode = declaration->mode();
+  bool is_function_declaration = declaration->IsFunctionDeclaration();
+  if (scope == nullptr) scope = scope_;
+  Scope* declaration_scope =
+      IsLexicalVariableMode(mode) ? scope : scope->DeclarationScope();
+  Variable* var = NULL;
+
+  // If a suitable scope exists, then we can statically declare this
+  // variable and also set its mode. In any case, a Declaration node
+  // will be added to the scope so that the declaration can be added
+  // to the corresponding activation frame at runtime if necessary.
+  // For instance, var declarations inside a sloppy eval scope need
+  // to be added to the calling function context. Similarly, strict
+  // mode eval scope and lexical eval bindings do not leak variable
+  // declarations to the caller's scope so we declare all locals, too.
+  if (declaration_scope->is_function_scope() ||
+      declaration_scope->is_block_scope() ||
+      declaration_scope->is_module_scope() ||
+      declaration_scope->is_script_scope() ||
+      (declaration_scope->is_eval_scope() &&
+       (is_strict(declaration_scope->language_mode()) ||
+        IsLexicalVariableMode(mode)))) {
+    // Declare the variable in the declaration scope.
+    var = declaration_scope->LookupLocal(name);
+    if (var == NULL) {
+      // Declare the name.
+      Variable::Kind kind = Variable::NORMAL;
+      int declaration_group_start = -1;
+      if (is_function_declaration) {
+        kind = Variable::FUNCTION;
+      } else if (declaration->IsVariableDeclaration() &&
+                 declaration->AsVariableDeclaration()->is_class_declaration()) {
+        kind = Variable::CLASS;
+        declaration_group_start =
+            declaration->AsVariableDeclaration()->declaration_group_start();
+      }
+      var = declaration_scope->DeclareLocal(
+          name, mode, declaration->initialization(), kind, kNotAssigned,
+          declaration_group_start);
+    } else if (((IsLexicalVariableMode(mode) ||
+                 IsLexicalVariableMode(var->mode())) &&
+                // Allow duplicate function decls for web compat, see bug 4693.
+                (is_strict(language_mode()) || !is_function_declaration ||
+                 !var->is_function())) ||
+               ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
+                !declaration_scope->is_script_scope())) {
+      // The name was declared in this scope before; check for conflicting
+      // re-declarations. We have a conflict if either of the declarations is
+      // not a var (in script scope, we also have to ignore legacy const for
+      // compatibility). There is similar code in runtime.cc in the Declare
+      // functions. The function CheckConflictingVarDeclarations checks for
+      // var and let bindings from different scopes whereas this is a check for
+      // conflicting declarations within the same scope. This check also covers
+      // the special case
+      //
+      // function () { let x; { var x; } }
+      //
+      // because the var declaration is hoisted to the function scope where 'x'
+      // is already bound.
+      DCHECK(IsDeclaredVariableMode(var->mode()));
+      if (is_strict(language_mode()) ||
+          (allow_harmony_sloppy() && mode != CONST_LEGACY &&
+           var->mode() != CONST_LEGACY)) {
+        // In harmony we treat re-declarations as early errors. See
+        // ES5 16 for a definition of early errors.
+        if (declaration_kind == DeclarationDescriptor::NORMAL) {
+          ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name);
+        } else {
+          ParserTraits::ReportMessage(MessageTemplate::kParamDupe);
+        }
+        *ok = false;
+        return nullptr;
+      }
+      Expression* expression = NewThrowSyntaxError(
+          MessageTemplate::kVarRedeclaration, name, declaration->position());
+      declaration_scope->SetIllegalRedeclaration(expression);
+    } else if (mode == VAR) {
+      var->set_maybe_assigned();
+    }
+  } else if (declaration_scope->is_eval_scope() &&
+             is_sloppy(declaration_scope->language_mode()) &&
+             !IsLexicalVariableMode(mode)) {
+    // In a var binding in a sloppy direct eval, pollute the enclosing scope
+    // with this new binding by doing the following:
+    // The proxy is bound to a lookup variable to force a dynamic declaration
+    // using the DeclareLookupSlot runtime function.
+    Variable::Kind kind = Variable::NORMAL;
+    // TODO(sigurds) figure out if kNotAssigned is OK here
+    var = new (zone()) Variable(declaration_scope, name, mode, kind,
+                                declaration->initialization(), kNotAssigned);
+    var->AllocateTo(VariableLocation::LOOKUP, -1);
+    var->SetFromEval();
+    resolve = true;
+  }
+
+
+  // We add a declaration node for every declaration. The compiler
+  // will only generate code if necessary. In particular, declarations
+  // for inner local variables that do not represent functions won't
+  // result in any generated code.
+  //
+  // Note that we always add an unresolved proxy even if it's not
+  // used, simply because we don't know in this method (w/o extra
+  // parameters) if the proxy is needed or not. The proxy will be
+  // bound during variable resolution time unless it was pre-bound
+  // below.
+  //
+  // WARNING: This will lead to multiple declaration nodes for the
+  // same variable if it is declared several times. This is not a
+  // semantic issue as long as we keep the source order, but it may be
+  // a performance issue since it may lead to repeated
+  // RuntimeHidden_DeclareLookupSlot calls.
+  declaration_scope->AddDeclaration(declaration);
+
+  if (mode == CONST_LEGACY && declaration_scope->is_script_scope()) {
+    // For global const variables we bind the proxy to a variable.
+    DCHECK(resolve);  // should be set by all callers
+    Variable::Kind kind = Variable::NORMAL;
+    var = new (zone()) Variable(declaration_scope, name, mode, kind,
+                                kNeedsInitialization, kNotAssigned);
+  }
+
+  // If requested and we have a local variable, bind the proxy to the variable
+  // at parse-time. This is used for functions (and consts) declared inside
+  // statements: the corresponding function (or const) variable must be in the
+  // function scope and not a statement-local scope, e.g. as provided with a
+  // 'with' statement:
+  //
+  //   with (obj) {
+  //     function f() {}
+  //   }
+  //
+  // which is translated into:
+  //
+  //   with (obj) {
+  //     // in this case this is not: 'var f; f = function () {};'
+  //     var f = function () {};
+  //   }
+  //
+  // Note that if 'f' is accessed from inside the 'with' statement, it
+  // will be allocated in the context (because we must be able to look
+  // it up dynamically) but it will also be accessed statically, i.e.,
+  // with a context slot index and a context chain length for this
+  // initialization code. Thus, inside the 'with' statement, we need
+  // both access to the static and the dynamic context chain; the
+  // runtime needs to provide both.
+  if (resolve && var != NULL) {
+    proxy->BindTo(var);
+  }
+  return var;
+}
+
+
+// Language extension which is only enabled for source files loaded
+// through the API's extension mechanism.  A native function
+// declaration is resolved by looking up the function through a
+// callback provided by the extension.
+Statement* Parser::ParseNativeDeclaration(bool* ok) {
+  int pos = peek_position();
+  Expect(Token::FUNCTION, CHECK_OK);
+  // Allow "eval" or "arguments" for backward compatibility.
+  const AstRawString* name =
+      ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  bool done = (peek() == Token::RPAREN);
+  while (!done) {
+    ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+    done = (peek() == Token::RPAREN);
+    if (!done) {
+      Expect(Token::COMMA, CHECK_OK);
+    }
+  }
+  Expect(Token::RPAREN, CHECK_OK);
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  // Make sure that the function containing the native declaration
+  // isn't lazily compiled. The extension structures are only
+  // accessible while parsing the first time not when reparsing
+  // because of lazy compilation.
+  // TODO(adamk): Should this be ClosureScope()?
+  scope_->DeclarationScope()->ForceEagerCompilation();
+
+  // TODO(1240846): It's weird that native function declarations are
+  // introduced dynamically when we meet their declarations, whereas
+  // other functions are set up when entering the surrounding scope.
+  VariableProxy* proxy = NewUnresolved(name, VAR);
+  Declaration* declaration =
+      factory()->NewVariableDeclaration(proxy, VAR, scope_, pos);
+  Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+  NativeFunctionLiteral* lit = factory()->NewNativeFunctionLiteral(
+      name, extension_, RelocInfo::kNoPosition);
+  return factory()->NewExpressionStatement(
+      factory()->NewAssignment(Token::INIT, proxy, lit, RelocInfo::kNoPosition),
+      pos);
+}
+
+
+Statement* Parser::ParseFunctionDeclaration(
+    ZoneList<const AstRawString*>* names, bool* ok) {
+  // FunctionDeclaration ::
+  //   'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+  // GeneratorDeclaration ::
+  //   'function' '*' Identifier '(' FormalParameterListopt ')'
+  //      '{' FunctionBody '}'
+  Expect(Token::FUNCTION, CHECK_OK);
+  int pos = position();
+  bool is_generator = Check(Token::MUL);
+  bool is_strict_reserved = false;
+  const AstRawString* name = ParseIdentifierOrStrictReservedWord(
+      &is_strict_reserved, CHECK_OK);
+
+  FuncNameInferrer::State fni_state(fni_);
+  if (fni_ != NULL) fni_->PushEnclosingName(name);
+  FunctionLiteral* fun = ParseFunctionLiteral(
+      name, scanner()->location(),
+      is_strict_reserved ? kFunctionNameIsStrictReserved
+                         : kFunctionNameValidityUnknown,
+      is_generator ? FunctionKind::kGeneratorFunction
+                   : FunctionKind::kNormalFunction,
+      pos, FunctionLiteral::kDeclaration, FunctionLiteral::kNormalArity,
+      language_mode(), CHECK_OK);
+
+  // Even if we're not at the top-level of the global or a function
+  // scope, we treat it as such and introduce the function with its
+  // initial value upon entering the corresponding scope.
+  // In ES6, a function behaves as a lexical binding, except in
+  // a script scope, or the initial scope of eval or another function.
+  VariableMode mode =
+      is_strong(language_mode())
+          ? CONST
+          : (is_strict(language_mode()) || allow_harmony_sloppy_function()) &&
+                    !scope_->is_declaration_scope()
+                ? LET
+                : VAR;
+  VariableProxy* proxy = NewUnresolved(name, mode);
+  Declaration* declaration =
+      factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos);
+  Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+  if (names) names->Add(name, zone());
+  EmptyStatement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+  if (is_sloppy(language_mode()) && allow_harmony_sloppy_function() &&
+      !scope_->is_declaration_scope()) {
+    SloppyBlockFunctionStatement* delegate =
+        factory()->NewSloppyBlockFunctionStatement(empty, scope_);
+    scope_->DeclarationScope()->sloppy_block_function_map()->Declare(name,
+                                                                     delegate);
+    return delegate;
+  }
+  return empty;
+}
+
+
+Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
+                                         bool* ok) {
+  // ClassDeclaration ::
+  //   'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
+  //
+  // A ClassDeclaration
+  //
+  //   class C { ... }
+  //
+  // has the same semantics as:
+  //
+  //   let C = class C { ... };
+  //
+  // so rewrite it as such.
+
+  Expect(Token::CLASS, CHECK_OK);
+  if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
+    ReportMessage(MessageTemplate::kSloppyLexical);
+    *ok = false;
+    return NULL;
+  }
+
+  int pos = position();
+  bool is_strict_reserved = false;
+  const AstRawString* name =
+      ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
+  ClassLiteral* value = ParseClassLiteral(name, scanner()->location(),
+                                          is_strict_reserved, pos, CHECK_OK);
+
+  VariableMode mode = is_strong(language_mode()) ? CONST : LET;
+  VariableProxy* proxy = NewUnresolved(name, mode);
+  const bool is_class_declaration = true;
+  Declaration* declaration = factory()->NewVariableDeclaration(
+      proxy, mode, scope_, pos, is_class_declaration,
+      scope_->class_declaration_group_start());
+  Variable* outer_class_variable =
+      Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+  proxy->var()->set_initializer_position(position());
+  // This is needed because a class ("class Name { }") creates two bindings (one
+  // in the outer scope, and one in the class scope). The method is a function
+  // scope inside the inner scope (class scope). The consecutive class
+  // declarations are in the outer scope.
+  if (value->class_variable_proxy() && value->class_variable_proxy()->var() &&
+      outer_class_variable->is_class()) {
+    // In some cases, the outer variable is not detected as a class variable;
+    // this happens e.g., for lazy methods. They are excluded from strong mode
+    // checks for now. TODO(marja, rossberg): re-create variables with the
+    // correct Kind and remove this hack.
+    value->class_variable_proxy()
+        ->var()
+        ->AsClassVariable()
+        ->set_declaration_group_start(
+            outer_class_variable->AsClassVariable()->declaration_group_start());
+  }
+
+  Assignment* assignment =
+      factory()->NewAssignment(Token::INIT, proxy, value, pos);
+  Statement* assignment_statement =
+      factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+  if (names) names->Add(name, zone());
+  return assignment_statement;
+}
+
+
+Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels,
+                          bool finalize_block_scope, bool* ok) {
+  // The harmony mode uses block elements instead of statements.
+  //
+  // Block ::
+  //   '{' StatementList '}'
+
+  // Construct block expecting 16 statements.
+  Block* body =
+      factory()->NewBlock(labels, 16, false, RelocInfo::kNoPosition);
+  Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+
+  // Parse the statements and collect escaping labels.
+  Expect(Token::LBRACE, CHECK_OK);
+  block_scope->set_start_position(scanner()->location().beg_pos);
+  { BlockState block_state(&scope_, block_scope);
+    Target target(&this->target_stack_, body);
+
+    while (peek() != Token::RBRACE) {
+      Statement* stat = ParseStatementListItem(CHECK_OK);
+      if (stat && !stat->IsEmpty()) {
+        body->statements()->Add(stat, zone());
+      }
+    }
+  }
+  Expect(Token::RBRACE, CHECK_OK);
+  block_scope->set_end_position(scanner()->location().end_pos);
+  if (finalize_block_scope) {
+    block_scope = block_scope->FinalizeBlockScope();
+  }
+  body->set_scope(block_scope);
+  return body;
+}
+
+
+Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
+  return ParseBlock(labels, true, ok);
+}
+
+
+Block* Parser::DeclarationParsingResult::BuildInitializationBlock(
+    ZoneList<const AstRawString*>* names, bool* ok) {
+  Block* result = descriptor.parser->factory()->NewBlock(
+      NULL, 1, true, descriptor.declaration_pos);
+  for (auto declaration : declarations) {
+    PatternRewriter::DeclareAndInitializeVariables(
+        result, &descriptor, &declaration, names, CHECK_OK);
+  }
+  return result;
+}
+
+
+Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
+                                      ZoneList<const AstRawString*>* names,
+                                      bool* ok) {
+  // VariableStatement ::
+  //   VariableDeclarations ';'
+
+  // The scope of a var/const declared variable anywhere inside a function
+  // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
+  // transform a source-level var/const declaration into a (Function)
+  // Scope declaration, and rewrite the source-level initialization into an
+  // assignment statement. We use a block to collect multiple assignments.
+  //
+  // We mark the block as initializer block because we don't want the
+  // rewriter to add a '.result' assignment to such a block (to get compliant
+  // behavior for code such as print(eval('var x = 7')), and for cosmetic
+  // reasons when pretty-printing. Also, unless an assignment (initialization)
+  // is inside an initializer block, it is ignored.
+
+  DeclarationParsingResult parsing_result;
+  ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+
+  Block* result = parsing_result.BuildInitializationBlock(names, CHECK_OK);
+  return result;
+}
+
+
+void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
+                                       DeclarationParsingResult* parsing_result,
+                                       bool* ok) {
+  // VariableDeclarations ::
+  //   ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
+  //
+  // The ES6 Draft Rev3 specifies the following grammar for const declarations
+  //
+  // ConstDeclaration ::
+  //   const ConstBinding (',' ConstBinding)* ';'
+  // ConstBinding ::
+  //   Identifier '=' AssignmentExpression
+  //
+  // TODO(ES6):
+  // ConstBinding ::
+  //   BindingPattern '=' AssignmentExpression
+
+  parsing_result->descriptor.parser = this;
+  parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
+  parsing_result->descriptor.declaration_pos = peek_position();
+  parsing_result->descriptor.initialization_pos = peek_position();
+  parsing_result->descriptor.mode = VAR;
+  // True if the binding needs initialization. 'let' and 'const' declared
+  // bindings are created uninitialized by their declaration nodes and
+  // need initialization. 'var' declared bindings are always initialized
+  // immediately by their declaration nodes.
+  parsing_result->descriptor.needs_init = false;
+  if (peek() == Token::VAR) {
+    if (is_strong(language_mode())) {
+      Scanner::Location location = scanner()->peek_location();
+      ReportMessageAt(location, MessageTemplate::kStrongVar);
+      *ok = false;
+      return;
+    }
+    Consume(Token::VAR);
+  } else if (peek() == Token::CONST && allow_const()) {
+    Consume(Token::CONST);
+    if (is_sloppy(language_mode()) && allow_legacy_const()) {
+      parsing_result->descriptor.mode = CONST_LEGACY;
+      ++use_counts_[v8::Isolate::kLegacyConst];
+    } else {
+      DCHECK(is_strict(language_mode()) || allow_harmony_sloppy());
+      DCHECK(var_context != kStatement);
+      parsing_result->descriptor.mode = CONST;
+    }
+    parsing_result->descriptor.needs_init = true;
+  } else if (peek() == Token::LET && allow_let()) {
+    Consume(Token::LET);
+    DCHECK(var_context != kStatement);
+    parsing_result->descriptor.mode = LET;
+    parsing_result->descriptor.needs_init = true;
+  } else {
+    UNREACHABLE();  // by current callers
+  }
+
+  parsing_result->descriptor.scope = scope_;
+  parsing_result->descriptor.hoist_scope = nullptr;
+
+
+  bool first_declaration = true;
+  int bindings_start = peek_position();
+  bool is_for_iteration_variable;
+  do {
+    FuncNameInferrer::State fni_state(fni_);
+
+    // Parse name.
+    if (!first_declaration) Consume(Token::COMMA);
+
+    Expression* pattern;
+    int decl_pos = peek_position();
+    {
+      ExpressionClassifier pattern_classifier;
+      Token::Value next = peek();
+      pattern = ParsePrimaryExpression(&pattern_classifier, ok);
+      if (!*ok) return;
+      ValidateBindingPattern(&pattern_classifier, ok);
+      if (!*ok) return;
+      if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
+        ValidateLetPattern(&pattern_classifier, ok);
+        if (!*ok) return;
+      }
+      if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) {
+        ReportUnexpectedToken(next);
+        *ok = false;
+        return;
+      }
+    }
+
+    bool is_pattern =
+        (pattern->IsObjectLiteral() || pattern->IsArrayLiteral()) &&
+        !pattern->is_parenthesized();
+
+    Scanner::Location variable_loc = scanner()->location();
+    const AstRawString* single_name =
+        pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name()
+                                   : nullptr;
+    if (single_name != nullptr) {
+      if (fni_ != NULL) fni_->PushVariableName(single_name);
+    }
+
+    is_for_iteration_variable =
+        var_context == kForStatement &&
+        (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
+    if (is_for_iteration_variable &&
+        (parsing_result->descriptor.mode == CONST ||
+         parsing_result->descriptor.mode == CONST_LEGACY)) {
+      parsing_result->descriptor.needs_init = false;
+    }
+
+    Expression* value = NULL;
+    // Harmony consts have non-optional initializers.
+    int initializer_position = RelocInfo::kNoPosition;
+    if (Check(Token::ASSIGN)) {
+      ExpressionClassifier classifier;
+      value = ParseAssignmentExpression(var_context != kForStatement,
+                                        &classifier, ok);
+      if (!*ok) return;
+      value = ParserTraits::RewriteNonPattern(value, &classifier, ok);
+      if (!*ok) return;
+      variable_loc.end_pos = scanner()->location().end_pos;
+
+      if (!parsing_result->first_initializer_loc.IsValid()) {
+        parsing_result->first_initializer_loc = variable_loc;
+      }
+
+      // Don't infer if it is "a = function(){...}();"-like expression.
+      if (single_name) {
+        if (fni_ != NULL && value->AsCall() == NULL &&
+            value->AsCallNew() == NULL) {
+          fni_->Infer();
+        } else {
+          fni_->RemoveLastFunction();
+        }
+      }
+
+      if (allow_harmony_function_name() && single_name) {
+        if (value->IsFunctionLiteral()) {
+          auto function_literal = value->AsFunctionLiteral();
+          if (function_literal->is_anonymous()) {
+            function_literal->set_raw_name(single_name);
+          }
+        } else if (value->IsClassLiteral()) {
+          auto class_literal = value->AsClassLiteral();
+          if (class_literal->raw_name() == nullptr) {
+            class_literal->set_raw_name(single_name);
+          }
+        }
+      }
+
+      // End position of the initializer is after the assignment expression.
+      initializer_position = scanner()->location().end_pos;
+    } else {
+      if ((parsing_result->descriptor.mode == CONST || is_pattern) &&
+          !is_for_iteration_variable) {
+        ParserTraits::ReportMessageAt(
+            Scanner::Location(decl_pos, scanner()->location().end_pos),
+            MessageTemplate::kDeclarationMissingInitializer,
+            is_pattern ? "destructuring" : "const");
+        *ok = false;
+        return;
+      }
+      // End position of the initializer is after the variable.
+      initializer_position = position();
+    }
+
+    // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
+    if (value == NULL && parsing_result->descriptor.needs_init) {
+      value = GetLiteralUndefined(position());
+    }
+
+    parsing_result->declarations.Add(DeclarationParsingResult::Declaration(
+        pattern, initializer_position, value));
+    first_declaration = false;
+  } while (peek() == Token::COMMA);
+
+  parsing_result->bindings_loc =
+      Scanner::Location(bindings_start, scanner()->location().end_pos);
+}
+
+
+static bool ContainsLabel(ZoneList<const AstRawString*>* labels,
+                          const AstRawString* label) {
+  DCHECK(label != NULL);
+  if (labels != NULL) {
+    for (int i = labels->length(); i-- > 0; ) {
+      if (labels->at(i) == label) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+Statement* Parser::ParseExpressionOrLabelledStatement(
+    ZoneList<const AstRawString*>* labels, bool* ok) {
+  // ExpressionStatement | LabelledStatement ::
+  //   Expression ';'
+  //   Identifier ':' Statement
+  //
+  // ExpressionStatement[Yield] :
+  //   [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ;
+
+  int pos = peek_position();
+
+  switch (peek()) {
+    case Token::FUNCTION:
+    case Token::LBRACE:
+      UNREACHABLE();  // Always handled by the callers.
+    case Token::CLASS:
+      ReportUnexpectedToken(Next());
+      *ok = false;
+      return nullptr;
+
+    case Token::THIS:
+      if (!FLAG_strong_this) break;
+      // Fall through.
+    case Token::SUPER:
+      if (is_strong(language_mode()) &&
+          IsClassConstructor(function_state_->kind())) {
+        bool is_this = peek() == Token::THIS;
+        Expression* expr;
+        ExpressionClassifier classifier;
+        if (is_this) {
+          expr = ParseStrongInitializationExpression(&classifier, CHECK_OK);
+        } else {
+          expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK);
+        }
+        expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+        switch (peek()) {
+          case Token::SEMICOLON:
+            Consume(Token::SEMICOLON);
+            break;
+          case Token::RBRACE:
+          case Token::EOS:
+            break;
+          default:
+            if (!scanner()->HasAnyLineTerminatorBeforeNext()) {
+              ReportMessageAt(function_state_->this_location(),
+                              is_this
+                                  ? MessageTemplate::kStrongConstructorThis
+                                  : MessageTemplate::kStrongConstructorSuper);
+              *ok = false;
+              return nullptr;
+            }
+        }
+        return factory()->NewExpressionStatement(expr, pos);
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  bool starts_with_idenfifier = peek_any_identifier();
+  Expression* expr = ParseExpression(true, CHECK_OK);
+  if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
+      expr->AsVariableProxy() != NULL &&
+      !expr->AsVariableProxy()->is_this()) {
+    // Expression is a single identifier, and not, e.g., a parenthesized
+    // identifier.
+    VariableProxy* var = expr->AsVariableProxy();
+    const AstRawString* label = var->raw_name();
+    // TODO(1240780): We don't check for redeclaration of labels
+    // during preparsing since keeping track of the set of active
+    // labels requires nontrivial changes to the way scopes are
+    // structured.  However, these are probably changes we want to
+    // make later anyway so we should go back and fix this then.
+    if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
+      ParserTraits::ReportMessage(MessageTemplate::kLabelRedeclaration, label);
+      *ok = false;
+      return NULL;
+    }
+    if (labels == NULL) {
+      labels = new(zone()) ZoneList<const AstRawString*>(4, zone());
+    }
+    labels->Add(label, zone());
+    // Remove the "ghost" variable that turned out to be a label
+    // from the top scope. This way, we don't try to resolve it
+    // during the scope processing.
+    scope_->RemoveUnresolved(var);
+    Expect(Token::COLON, CHECK_OK);
+    return ParseStatement(labels, ok);
+  }
+
+  // If we have an extension, we allow a native function declaration.
+  // A native function declaration starts with "native function" with
+  // no line-terminator between the two words.
+  if (extension_ != NULL && peek() == Token::FUNCTION &&
+      !scanner()->HasAnyLineTerminatorBeforeNext() && expr != NULL &&
+      expr->AsVariableProxy() != NULL &&
+      expr->AsVariableProxy()->raw_name() ==
+          ast_value_factory()->native_string() &&
+      !scanner()->literal_contains_escapes()) {
+    return ParseNativeDeclaration(ok);
+  }
+
+  // Parsed expression statement, followed by semicolon.
+  // Detect attempts at 'let' declarations in sloppy mode.
+  if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
+      expr->AsVariableProxy() != NULL &&
+      expr->AsVariableProxy()->raw_name() ==
+          ast_value_factory()->let_string()) {
+    ReportMessage(MessageTemplate::kSloppyLexical, NULL);
+    *ok = false;
+    return NULL;
+  }
+  ExpectSemicolon(CHECK_OK);
+  return factory()->NewExpressionStatement(expr, pos);
+}
+
+
+IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels,
+                                      bool* ok) {
+  // IfStatement ::
+  //   'if' '(' Expression ')' Statement ('else' Statement)?
+
+  int pos = peek_position();
+  Expect(Token::IF, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* condition = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+  Statement* then_statement = ParseSubStatement(labels, CHECK_OK);
+  Statement* else_statement = NULL;
+  if (peek() == Token::ELSE) {
+    Next();
+    else_statement = ParseSubStatement(labels, CHECK_OK);
+  } else {
+    else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+  }
+  return factory()->NewIfStatement(
+      condition, then_statement, else_statement, pos);
+}
+
+
+Statement* Parser::ParseContinueStatement(bool* ok) {
+  // ContinueStatement ::
+  //   'continue' Identifier? ';'
+
+  int pos = peek_position();
+  Expect(Token::CONTINUE, CHECK_OK);
+  const AstRawString* label = NULL;
+  Token::Value tok = peek();
+  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
+      tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+  }
+  IterationStatement* target = LookupContinueTarget(label, CHECK_OK);
+  if (target == NULL) {
+    // Illegal continue statement.
+    MessageTemplate::Template message = MessageTemplate::kIllegalContinue;
+    if (label != NULL) {
+      message = MessageTemplate::kUnknownLabel;
+    }
+    ParserTraits::ReportMessage(message, label);
+    *ok = false;
+    return NULL;
+  }
+  ExpectSemicolon(CHECK_OK);
+  return factory()->NewContinueStatement(target, pos);
+}
+
+
+Statement* Parser::ParseBreakStatement(ZoneList<const AstRawString*>* labels,
+                                       bool* ok) {
+  // BreakStatement ::
+  //   'break' Identifier? ';'
+
+  int pos = peek_position();
+  Expect(Token::BREAK, CHECK_OK);
+  const AstRawString* label = NULL;
+  Token::Value tok = peek();
+  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
+      tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+  }
+  // Parse labeled break statements that target themselves into
+  // empty statements, e.g. 'l1: l2: l3: break l2;'
+  if (label != NULL && ContainsLabel(labels, label)) {
+    ExpectSemicolon(CHECK_OK);
+    return factory()->NewEmptyStatement(pos);
+  }
+  BreakableStatement* target = NULL;
+  target = LookupBreakTarget(label, CHECK_OK);
+  if (target == NULL) {
+    // Illegal break statement.
+    MessageTemplate::Template message = MessageTemplate::kIllegalBreak;
+    if (label != NULL) {
+      message = MessageTemplate::kUnknownLabel;
+    }
+    ParserTraits::ReportMessage(message, label);
+    *ok = false;
+    return NULL;
+  }
+  ExpectSemicolon(CHECK_OK);
+  return factory()->NewBreakStatement(target, pos);
+}
+
+
+Statement* Parser::ParseReturnStatement(bool* ok) {
+  // ReturnStatement ::
+  //   'return' Expression? ';'
+
+  // Consume the return token. It is necessary to do that before
+  // reporting any errors on it, because of the way errors are
+  // reported (underlining).
+  Expect(Token::RETURN, CHECK_OK);
+  Scanner::Location loc = scanner()->location();
+  function_state_->set_return_location(loc);
+
+  Token::Value tok = peek();
+  Statement* result;
+  Expression* return_value;
+  if (scanner()->HasAnyLineTerminatorBeforeNext() ||
+      tok == Token::SEMICOLON ||
+      tok == Token::RBRACE ||
+      tok == Token::EOS) {
+    if (IsSubclassConstructor(function_state_->kind())) {
+      return_value = ThisExpression(scope_, factory(), loc.beg_pos);
+    } else {
+      return_value = GetLiteralUndefined(position());
+    }
+  } else {
+    if (is_strong(language_mode()) &&
+        IsClassConstructor(function_state_->kind())) {
+      int pos = peek_position();
+      ReportMessageAt(Scanner::Location(pos, pos + 1),
+                      MessageTemplate::kStrongConstructorReturnValue);
+      *ok = false;
+      return NULL;
+    }
+
+    int pos = peek_position();
+    return_value = ParseExpression(true, CHECK_OK);
+
+    if (IsSubclassConstructor(function_state_->kind())) {
+      // For subclass constructors we need to return this in case of undefined
+      // and throw an exception in case of a non object.
+      //
+      //   return expr;
+      //
+      // Is rewritten as:
+      //
+      //   return (temp = expr) === undefined ? this :
+      //       %_IsJSReceiver(temp) ? temp : throw new TypeError(...);
+      Variable* temp = scope_->NewTemporary(
+          ast_value_factory()->empty_string());
+      Assignment* assign = factory()->NewAssignment(
+          Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
+
+      Expression* throw_expression =
+          NewThrowTypeError(MessageTemplate::kDerivedConstructorReturn,
+                            ast_value_factory()->empty_string(), pos);
+
+      // %_IsJSReceiver(temp)
+      ZoneList<Expression*>* is_spec_object_args =
+          new (zone()) ZoneList<Expression*>(1, zone());
+      is_spec_object_args->Add(factory()->NewVariableProxy(temp), zone());
+      Expression* is_spec_object_call = factory()->NewCallRuntime(
+          Runtime::kInlineIsJSReceiver, is_spec_object_args, pos);
+
+      // %_IsJSReceiver(temp) ? temp : throw_expression
+      Expression* is_object_conditional = factory()->NewConditional(
+          is_spec_object_call, factory()->NewVariableProxy(temp),
+          throw_expression, pos);
+
+      // temp === undefined
+      Expression* is_undefined = factory()->NewCompareOperation(
+          Token::EQ_STRICT, assign,
+          factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), pos);
+
+      // is_undefined ? this : is_object_conditional
+      return_value = factory()->NewConditional(
+          is_undefined, ThisExpression(scope_, factory(), pos),
+          is_object_conditional, pos);
+    }
+
+    return_value->MarkTail();
+  }
+  ExpectSemicolon(CHECK_OK);
+
+  if (is_generator()) {
+    Expression* generator = factory()->NewVariableProxy(
+        function_state_->generator_object_variable());
+    Expression* yield = factory()->NewYield(
+        generator, return_value, Yield::kFinal, loc.beg_pos);
+    result = factory()->NewExpressionStatement(yield, loc.beg_pos);
+  } else {
+    result = factory()->NewReturnStatement(return_value, loc.beg_pos);
+  }
+
+  Scope* decl_scope = scope_->DeclarationScope();
+  if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) {
+    ReportMessageAt(loc, MessageTemplate::kIllegalReturn);
+    *ok = false;
+    return NULL;
+  }
+  return result;
+}
+
+
+Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
+                                      bool* ok) {
+  // WithStatement ::
+  //   'with' '(' Expression ')' Statement
+
+  Expect(Token::WITH, CHECK_OK);
+  int pos = position();
+
+  if (is_strict(language_mode())) {
+    ReportMessage(MessageTemplate::kStrictWith);
+    *ok = false;
+    return NULL;
+  }
+
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* expr = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  scope_->DeclarationScope()->RecordWithStatement();
+  Scope* with_scope = NewScope(scope_, WITH_SCOPE);
+  Block* body;
+  { BlockState block_state(&scope_, with_scope);
+    with_scope->set_start_position(scanner()->peek_location().beg_pos);
+
+    // The body of the with statement must be enclosed in an additional
+    // lexical scope in case the body is a FunctionDeclaration.
+    body = factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition);
+    Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+    block_scope->set_start_position(scanner()->location().beg_pos);
+    {
+      BlockState block_state(&scope_, block_scope);
+      Target target(&this->target_stack_, body);
+      Statement* stmt = ParseSubStatement(labels, CHECK_OK);
+      body->statements()->Add(stmt, zone());
+      block_scope->set_end_position(scanner()->location().end_pos);
+      block_scope = block_scope->FinalizeBlockScope();
+      body->set_scope(block_scope);
+    }
+
+    with_scope->set_end_position(scanner()->location().end_pos);
+  }
+  return factory()->NewWithStatement(with_scope, expr, body, pos);
+}
+
+
+CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
+  // CaseClause ::
+  //   'case' Expression ':' StatementList
+  //   'default' ':' StatementList
+
+  Expression* label = NULL;  // NULL expression indicates default case
+  if (peek() == Token::CASE) {
+    Expect(Token::CASE, CHECK_OK);
+    label = ParseExpression(true, CHECK_OK);
+  } else {
+    Expect(Token::DEFAULT, CHECK_OK);
+    if (*default_seen_ptr) {
+      ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch);
+      *ok = false;
+      return NULL;
+    }
+    *default_seen_ptr = true;
+  }
+  Expect(Token::COLON, CHECK_OK);
+  int pos = position();
+  ZoneList<Statement*>* statements =
+      new(zone()) ZoneList<Statement*>(5, zone());
+  Statement* stat = NULL;
+  while (peek() != Token::CASE &&
+         peek() != Token::DEFAULT &&
+         peek() != Token::RBRACE) {
+    stat = ParseStatementListItem(CHECK_OK);
+    statements->Add(stat, zone());
+  }
+  if (is_strong(language_mode()) && stat != NULL && !stat->IsJump() &&
+      peek() != Token::RBRACE) {
+    ReportMessageAt(scanner()->location(),
+                    MessageTemplate::kStrongSwitchFallthrough);
+    *ok = false;
+    return NULL;
+  }
+  return factory()->NewCaseClause(label, statements, pos);
+}
+
+
+Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
+                                        bool* ok) {
+  // SwitchStatement ::
+  //   'switch' '(' Expression ')' '{' CaseClause* '}'
+  // In order to get the CaseClauses to execute in their own lexical scope,
+  // but without requiring downstream code to have special scope handling
+  // code for switch statements, desugar into blocks as follows:
+  // {  // To group the statements--harmless to evaluate Expression in scope
+  //   .tag_variable = Expression;
+  //   {  // To give CaseClauses a scope
+  //     switch (.tag_variable) { CaseClause* }
+  //   }
+  // }
+
+  Block* switch_block =
+      factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
+  int switch_pos = peek_position();
+
+  Expect(Token::SWITCH, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* tag = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  Variable* tag_variable =
+      scope_->NewTemporary(ast_value_factory()->dot_switch_tag_string());
+  Assignment* tag_assign = factory()->NewAssignment(
+      Token::ASSIGN, factory()->NewVariableProxy(tag_variable), tag,
+      tag->position());
+  Statement* tag_statement =
+      factory()->NewExpressionStatement(tag_assign, RelocInfo::kNoPosition);
+  switch_block->statements()->Add(tag_statement, zone());
+
+  // make statement: undefined;
+  // This is needed so the tag isn't returned as the value, in case the switch
+  // statements don't have a value.
+  switch_block->statements()->Add(
+      factory()->NewExpressionStatement(
+          factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+          RelocInfo::kNoPosition),
+      zone());
+
+  Block* cases_block =
+      factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
+  Scope* cases_scope = NewScope(scope_, BLOCK_SCOPE);
+  cases_scope->SetNonlinear();
+
+  SwitchStatement* switch_statement =
+      factory()->NewSwitchStatement(labels, switch_pos);
+
+  cases_scope->set_start_position(scanner()->location().beg_pos);
+  {
+    BlockState cases_block_state(&scope_, cases_scope);
+    Target target(&this->target_stack_, switch_statement);
+
+    Expression* tag_read = factory()->NewVariableProxy(tag_variable);
+
+    bool default_seen = false;
+    ZoneList<CaseClause*>* cases =
+        new (zone()) ZoneList<CaseClause*>(4, zone());
+    Expect(Token::LBRACE, CHECK_OK);
+    while (peek() != Token::RBRACE) {
+      CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
+      cases->Add(clause, zone());
+    }
+    switch_statement->Initialize(tag_read, cases);
+    cases_block->statements()->Add(switch_statement, zone());
+  }
+  Expect(Token::RBRACE, CHECK_OK);
+
+  cases_scope->set_end_position(scanner()->location().end_pos);
+  cases_scope = cases_scope->FinalizeBlockScope();
+  cases_block->set_scope(cases_scope);
+
+  switch_block->statements()->Add(cases_block, zone());
+
+  return switch_block;
+}
+
+
+Statement* Parser::ParseThrowStatement(bool* ok) {
+  // ThrowStatement ::
+  //   'throw' Expression ';'
+
+  Expect(Token::THROW, CHECK_OK);
+  int pos = position();
+  if (scanner()->HasAnyLineTerminatorBeforeNext()) {
+    ReportMessage(MessageTemplate::kNewlineAfterThrow);
+    *ok = false;
+    return NULL;
+  }
+  Expression* exception = ParseExpression(true, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+
+  return factory()->NewExpressionStatement(
+      factory()->NewThrow(exception, pos), pos);
+}
+
+
+TryStatement* Parser::ParseTryStatement(bool* ok) {
+  // TryStatement ::
+  //   'try' Block Catch
+  //   'try' Block Finally
+  //   'try' Block Catch Finally
+  //
+  // Catch ::
+  //   'catch' '(' Identifier ')' Block
+  //
+  // Finally ::
+  //   'finally' Block
+
+  Expect(Token::TRY, CHECK_OK);
+  int pos = position();
+
+  Block* try_block = ParseBlock(NULL, CHECK_OK);
+
+  Token::Value tok = peek();
+  if (tok != Token::CATCH && tok != Token::FINALLY) {
+    ReportMessage(MessageTemplate::kNoCatchOrFinally);
+    *ok = false;
+    return NULL;
+  }
+
+  Scope* catch_scope = NULL;
+  Variable* catch_variable = NULL;
+  Block* catch_block = NULL;
+  if (tok == Token::CATCH) {
+    Consume(Token::CATCH);
+
+    Expect(Token::LPAREN, CHECK_OK);
+    catch_scope = NewScope(scope_, CATCH_SCOPE);
+    catch_scope->set_start_position(scanner()->location().beg_pos);
+
+    ExpressionClassifier pattern_classifier;
+    Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+    ValidateBindingPattern(&pattern_classifier, CHECK_OK);
+
+    const AstRawString* name = ast_value_factory()->dot_catch_string();
+    bool is_simple = pattern->IsVariableProxy();
+    if (is_simple) {
+      auto proxy = pattern->AsVariableProxy();
+      scope_->RemoveUnresolved(proxy);
+      name = proxy->raw_name();
+    }
+
+    catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
+                                               Variable::NORMAL);
+
+    Expect(Token::RPAREN, CHECK_OK);
+
+    {
+      BlockState block_state(&scope_, catch_scope);
+
+      // TODO(adamk): Make a version of ParseBlock that takes a scope and
+      // a block.
+      catch_block =
+          factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
+      Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+
+      block_scope->set_start_position(scanner()->location().beg_pos);
+      {
+        BlockState block_state(&scope_, block_scope);
+        Target target(&this->target_stack_, catch_block);
+
+        if (!is_simple) {
+          DeclarationDescriptor descriptor;
+          descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
+          descriptor.parser = this;
+          descriptor.scope = scope_;
+          descriptor.hoist_scope = nullptr;
+          descriptor.mode = LET;
+          descriptor.needs_init = true;
+          descriptor.declaration_pos = pattern->position();
+          descriptor.initialization_pos = pattern->position();
+
+          DeclarationParsingResult::Declaration decl(
+              pattern, pattern->position(),
+              factory()->NewVariableProxy(catch_variable));
+
+          PatternRewriter::DeclareAndInitializeVariables(
+              catch_block, &descriptor, &decl, nullptr, CHECK_OK);
+        }
+
+        Expect(Token::LBRACE, CHECK_OK);
+        while (peek() != Token::RBRACE) {
+          Statement* stat = ParseStatementListItem(CHECK_OK);
+          if (stat && !stat->IsEmpty()) {
+            catch_block->statements()->Add(stat, zone());
+          }
+        }
+        Consume(Token::RBRACE);
+      }
+      block_scope->set_end_position(scanner()->location().end_pos);
+      block_scope = block_scope->FinalizeBlockScope();
+      catch_block->set_scope(block_scope);
+    }
+
+    catch_scope->set_end_position(scanner()->location().end_pos);
+    tok = peek();
+  }
+
+  Block* finally_block = NULL;
+  DCHECK(tok == Token::FINALLY || catch_block != NULL);
+  if (tok == Token::FINALLY) {
+    Consume(Token::FINALLY);
+    finally_block = ParseBlock(NULL, CHECK_OK);
+  }
+
+  // Simplify the AST nodes by converting:
+  //   'try B0 catch B1 finally B2'
+  // to:
+  //   'try { try B0 catch B1 } finally B2'
+
+  if (catch_block != NULL && finally_block != NULL) {
+    // If we have both, create an inner try/catch.
+    DCHECK(catch_scope != NULL && catch_variable != NULL);
+    TryCatchStatement* statement =
+        factory()->NewTryCatchStatement(try_block, catch_scope, catch_variable,
+                                        catch_block, RelocInfo::kNoPosition);
+    try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
+    try_block->statements()->Add(statement, zone());
+    catch_block = NULL;  // Clear to indicate it's been handled.
+  }
+
+  TryStatement* result = NULL;
+  if (catch_block != NULL) {
+    DCHECK(finally_block == NULL);
+    DCHECK(catch_scope != NULL && catch_variable != NULL);
+    result = factory()->NewTryCatchStatement(try_block, catch_scope,
+                                             catch_variable, catch_block, pos);
+  } else {
+    DCHECK(finally_block != NULL);
+    result = factory()->NewTryFinallyStatement(try_block, finally_block, pos);
+  }
+
+  return result;
+}
+
+
+DoWhileStatement* Parser::ParseDoWhileStatement(
+    ZoneList<const AstRawString*>* labels, bool* ok) {
+  // DoStatement ::
+  //   'do' Statement 'while' '(' Expression ')' ';'
+
+  DoWhileStatement* loop =
+      factory()->NewDoWhileStatement(labels, peek_position());
+  Target target(&this->target_stack_, loop);
+
+  Expect(Token::DO, CHECK_OK);
+  Statement* body = ParseSubStatement(NULL, CHECK_OK);
+  Expect(Token::WHILE, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+
+  Expression* cond = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  // Allow do-statements to be terminated with and without
+  // semi-colons. This allows code such as 'do;while(0)return' to
+  // parse, which would not be the case if we had used the
+  // ExpectSemicolon() functionality here.
+  if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
+
+  if (loop != NULL) loop->Initialize(cond, body);
+  return loop;
+}
+
+
+WhileStatement* Parser::ParseWhileStatement(
+    ZoneList<const AstRawString*>* labels, bool* ok) {
+  // WhileStatement ::
+  //   'while' '(' Expression ')' Statement
+
+  WhileStatement* loop = factory()->NewWhileStatement(labels, peek_position());
+  Target target(&this->target_stack_, loop);
+
+  Expect(Token::WHILE, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  Expression* cond = ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+  Statement* body = ParseSubStatement(NULL, CHECK_OK);
+
+  if (loop != NULL) loop->Initialize(cond, body);
+  return loop;
+}
+
+
+// !%_IsJSReceiver(result = iterator.next()) &&
+//     %ThrowIteratorResultNotAnObject(result)
+Expression* Parser::BuildIteratorNextResult(Expression* iterator,
+                                            Variable* result, int pos) {
+  Expression* next_literal = factory()->NewStringLiteral(
+      ast_value_factory()->next_string(), RelocInfo::kNoPosition);
+  Expression* next_property =
+      factory()->NewProperty(iterator, next_literal, RelocInfo::kNoPosition);
+  ZoneList<Expression*>* next_arguments =
+      new (zone()) ZoneList<Expression*>(0, zone());
+  Expression* next_call =
+      factory()->NewCall(next_property, next_arguments, pos);
+  Expression* result_proxy = factory()->NewVariableProxy(result);
+  Expression* left =
+      factory()->NewAssignment(Token::ASSIGN, result_proxy, next_call, pos);
+
+  // %_IsJSReceiver(...)
+  ZoneList<Expression*>* is_spec_object_args =
+      new (zone()) ZoneList<Expression*>(1, zone());
+  is_spec_object_args->Add(left, zone());
+  Expression* is_spec_object_call = factory()->NewCallRuntime(
+      Runtime::kInlineIsJSReceiver, is_spec_object_args, pos);
+
+  // %ThrowIteratorResultNotAnObject(result)
+  Expression* result_proxy_again = factory()->NewVariableProxy(result);
+  ZoneList<Expression*>* throw_arguments =
+      new (zone()) ZoneList<Expression*>(1, zone());
+  throw_arguments->Add(result_proxy_again, zone());
+  Expression* throw_call = factory()->NewCallRuntime(
+      Runtime::kThrowIteratorResultNotAnObject, throw_arguments, pos);
+
+  return factory()->NewBinaryOperation(
+      Token::AND,
+      factory()->NewUnaryOperation(Token::NOT, is_spec_object_call, pos),
+      throw_call, pos);
+}
+
+
+void Parser::InitializeForEachStatement(ForEachStatement* stmt,
+                                        Expression* each, Expression* subject,
+                                        Statement* body,
+                                        bool is_destructuring) {
+  DCHECK(!is_destructuring || allow_harmony_destructuring_assignment());
+  ForOfStatement* for_of = stmt->AsForOfStatement();
+
+  if (for_of != NULL) {
+    Variable* iterator = scope_->NewTemporary(
+        ast_value_factory()->dot_iterator_string());
+    Variable* result = scope_->NewTemporary(
+        ast_value_factory()->dot_result_string());
+
+    Expression* assign_iterator;
+    Expression* next_result;
+    Expression* result_done;
+    Expression* assign_each;
+
+    // iterator = subject[Symbol.iterator]()
+    // Hackily disambiguate o from o.next and o [Symbol.iterator]().
+    // TODO(verwaest): Come up with a better solution.
+    assign_iterator = factory()->NewAssignment(
+        Token::ASSIGN, factory()->NewVariableProxy(iterator),
+        GetIterator(subject, factory(), subject->position() - 2),
+        subject->position());
+
+    // !%_IsJSReceiver(result = iterator.next()) &&
+    //     %ThrowIteratorResultNotAnObject(result)
+    {
+      // result = iterator.next()
+      Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
+      // Hackily disambiguate o from o.next and o [Symbol.iterator]().
+      // TODO(verwaest): Come up with a better solution.
+      next_result = BuildIteratorNextResult(iterator_proxy, result,
+                                            subject->position() - 1);
+    }
+
+    // result.done
+    {
+      Expression* done_literal = factory()->NewStringLiteral(
+          ast_value_factory()->done_string(), RelocInfo::kNoPosition);
+      Expression* result_proxy = factory()->NewVariableProxy(result);
+      result_done = factory()->NewProperty(
+          result_proxy, done_literal, RelocInfo::kNoPosition);
+    }
+
+    // each = result.value
+    {
+      Expression* value_literal = factory()->NewStringLiteral(
+          ast_value_factory()->value_string(), RelocInfo::kNoPosition);
+      Expression* result_proxy = factory()->NewVariableProxy(result);
+      Expression* result_value = factory()->NewProperty(
+          result_proxy, value_literal, RelocInfo::kNoPosition);
+      assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value,
+                                             RelocInfo::kNoPosition);
+      if (is_destructuring) {
+        assign_each = PatternRewriter::RewriteDestructuringAssignment(
+            this, assign_each->AsAssignment(), scope_);
+      }
+    }
+
+    for_of->Initialize(each, subject, body,
+                       assign_iterator,
+                       next_result,
+                       result_done,
+                       assign_each);
+  } else {
+    if (is_destructuring) {
+      Variable* temp =
+          scope_->NewTemporary(ast_value_factory()->empty_string());
+      VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
+      Expression* assign_each = PatternRewriter::RewriteDestructuringAssignment(
+          this, factory()->NewAssignment(Token::ASSIGN, each, temp_proxy,
+                                         RelocInfo::kNoPosition),
+          scope_);
+      auto block =
+          factory()->NewBlock(nullptr, 2, false, RelocInfo::kNoPosition);
+      block->statements()->Add(factory()->NewExpressionStatement(
+                                   assign_each, RelocInfo::kNoPosition),
+                               zone());
+      block->statements()->Add(body, zone());
+      body = block;
+      each = factory()->NewVariableProxy(temp);
+    }
+    stmt->Initialize(each, subject, body);
+  }
+}
+
+
+Statement* Parser::DesugarLexicalBindingsInForStatement(
+    Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
+    ForStatement* loop, Statement* init, Expression* cond, Statement* next,
+    Statement* body, bool* ok) {
+  // ES6 13.7.4.8 specifies that on each loop iteration the let variables are
+  // copied into a new environment.  Moreover, the "next" statement must be
+  // evaluated not in the environment of the just completed iteration but in
+  // that of the upcoming one.  We achieve this with the following desugaring.
+  // Extra care is needed to preserve the completion value of the original loop.
+  //
+  // We are given a for statement of the form
+  //
+  //  labels: for (let/const x = i; cond; next) body
+  //
+  // and rewrite it as follows.  Here we write {{ ... }} for init-blocks, ie.,
+  // blocks whose ignore_completion_value_ flag is set.
+  //
+  //  {
+  //    let/const x = i;
+  //    temp_x = x;
+  //    first = 1;
+  //    undefined;
+  //    outer: for (;;) {
+  //      let/const x = temp_x;
+  //      {{ if (first == 1) {
+  //           first = 0;
+  //         } else {
+  //           next;
+  //         }
+  //         flag = 1;
+  //         if (!cond) break;
+  //      }}
+  //      labels: for (; flag == 1; flag = 0, temp_x = x) {
+  //        body
+  //      }
+  //      {{ if (flag == 1)  // Body used break.
+  //           break;
+  //      }}
+  //    }
+  //  }
+
+  DCHECK(names->length() > 0);
+  Scope* for_scope = scope_;
+  ZoneList<Variable*> temps(names->length(), zone());
+
+  Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false,
+                                           RelocInfo::kNoPosition);
+
+  // Add statement: let/const x = i.
+  outer_block->statements()->Add(init, zone());
+
+  const AstRawString* temp_name = ast_value_factory()->dot_for_string();
+
+  // For each lexical variable x:
+  //   make statement: temp_x = x.
+  for (int i = 0; i < names->length(); i++) {
+    VariableProxy* proxy = NewUnresolved(names->at(i), LET);
+    Variable* temp = scope_->NewTemporary(temp_name);
+    VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
+    Assignment* assignment = factory()->NewAssignment(
+        Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
+    Statement* assignment_statement = factory()->NewExpressionStatement(
+        assignment, RelocInfo::kNoPosition);
+    outer_block->statements()->Add(assignment_statement, zone());
+    temps.Add(temp, zone());
+  }
+
+  Variable* first = NULL;
+  // Make statement: first = 1.
+  if (next) {
+    first = scope_->NewTemporary(temp_name);
+    VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+    Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+    Assignment* assignment = factory()->NewAssignment(
+        Token::ASSIGN, first_proxy, const1, RelocInfo::kNoPosition);
+    Statement* assignment_statement =
+        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+    outer_block->statements()->Add(assignment_statement, zone());
+  }
+
+  // make statement: undefined;
+  outer_block->statements()->Add(
+      factory()->NewExpressionStatement(
+          factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+          RelocInfo::kNoPosition),
+      zone());
+
+  // Make statement: outer: for (;;)
+  // Note that we don't actually create the label, or set this loop up as an
+  // explicit break target, instead handing it directly to those nodes that
+  // need to know about it. This should be safe because we don't run any code
+  // in this function that looks up break targets.
+  ForStatement* outer_loop =
+      factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
+  outer_block->statements()->Add(outer_loop, zone());
+
+  outer_block->set_scope(for_scope);
+  scope_ = inner_scope;
+
+  Block* inner_block =
+      factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
+  Block* ignore_completion_block = factory()->NewBlock(
+      NULL, names->length() + 3, true, RelocInfo::kNoPosition);
+  ZoneList<Variable*> inner_vars(names->length(), zone());
+  // For each let variable x:
+  //    make statement: let/const x = temp_x.
+  VariableMode mode = is_const ? CONST : LET;
+  for (int i = 0; i < names->length(); i++) {
+    VariableProxy* proxy = NewUnresolved(names->at(i), mode);
+    Declaration* declaration = factory()->NewVariableDeclaration(
+        proxy, mode, scope_, RelocInfo::kNoPosition);
+    Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+    inner_vars.Add(declaration->proxy()->var(), zone());
+    VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
+    Assignment* assignment = factory()->NewAssignment(
+        Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
+    Statement* assignment_statement =
+        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+    DCHECK(init->position() != RelocInfo::kNoPosition);
+    proxy->var()->set_initializer_position(init->position());
+    ignore_completion_block->statements()->Add(assignment_statement, zone());
+  }
+
+  // Make statement: if (first == 1) { first = 0; } else { next; }
+  if (next) {
+    DCHECK(first);
+    Expression* compare = NULL;
+    // Make compare expression: first == 1.
+    {
+      Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+      VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+      compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
+                                               RelocInfo::kNoPosition);
+    }
+    Statement* clear_first = NULL;
+    // Make statement: first = 0.
+    {
+      VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+      Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+      Assignment* assignment = factory()->NewAssignment(
+          Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
+      clear_first =
+          factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+    }
+    Statement* clear_first_or_next = factory()->NewIfStatement(
+        compare, clear_first, next, RelocInfo::kNoPosition);
+    ignore_completion_block->statements()->Add(clear_first_or_next, zone());
+  }
+
+  Variable* flag = scope_->NewTemporary(temp_name);
+  // Make statement: flag = 1.
+  {
+    VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+    Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+    Assignment* assignment = factory()->NewAssignment(
+        Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
+    Statement* assignment_statement =
+        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+    ignore_completion_block->statements()->Add(assignment_statement, zone());
+  }
+
+  // Make statement: if (!cond) break.
+  if (cond) {
+    Statement* stop =
+        factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+    Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+    ignore_completion_block->statements()->Add(
+        factory()->NewIfStatement(cond, noop, stop, cond->position()), zone());
+  }
+
+  inner_block->statements()->Add(ignore_completion_block, zone());
+  // Make cond expression for main loop: flag == 1.
+  Expression* flag_cond = NULL;
+  {
+    Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+    VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+    flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+                                               RelocInfo::kNoPosition);
+  }
+
+  // Create chain of expressions "flag = 0, temp_x = x, ..."
+  Statement* compound_next_statement = NULL;
+  {
+    Expression* compound_next = NULL;
+    // Make expression: flag = 0.
+    {
+      VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+      Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+      compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
+                                               const0, RelocInfo::kNoPosition);
+    }
+
+    // Make the comma-separated list of temp_x = x assignments.
+    int inner_var_proxy_pos = scanner()->location().beg_pos;
+    for (int i = 0; i < names->length(); i++) {
+      VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
+      VariableProxy* proxy =
+          factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
+      Assignment* assignment = factory()->NewAssignment(
+          Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
+      compound_next = factory()->NewBinaryOperation(
+          Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+    }
+
+    compound_next_statement = factory()->NewExpressionStatement(
+        compound_next, RelocInfo::kNoPosition);
+  }
+
+  // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
+  // Note that we re-use the original loop node, which retains its labels
+  // and ensures that any break or continue statements in body point to
+  // the right place.
+  loop->Initialize(NULL, flag_cond, compound_next_statement, body);
+  inner_block->statements()->Add(loop, zone());
+
+  // Make statement: {{if (flag == 1) break;}}
+  {
+    Expression* compare = NULL;
+    // Make compare expresion: flag == 1.
+    {
+      Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+      VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+      compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+                                               RelocInfo::kNoPosition);
+    }
+    Statement* stop =
+        factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+    Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+    Statement* if_flag_break =
+        factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
+    Block* ignore_completion_block =
+        factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+    ignore_completion_block->statements()->Add(if_flag_break, zone());
+    inner_block->statements()->Add(ignore_completion_block, zone());
+  }
+
+  inner_scope->set_end_position(scanner()->location().end_pos);
+  inner_block->set_scope(inner_scope);
+  scope_ = for_scope;
+
+  outer_loop->Initialize(NULL, NULL, NULL, inner_block);
+  return outer_block;
+}
+
+
+Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
+                                     bool* ok) {
+  // ForStatement ::
+  //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
+
+  int stmt_pos = peek_position();
+  bool is_const = false;
+  Statement* init = NULL;
+  ZoneList<const AstRawString*> lexical_bindings(1, zone());
+
+  // Create an in-between scope for let-bound iteration variables.
+  Scope* saved_scope = scope_;
+  Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
+  scope_ = for_scope;
+  Expect(Token::FOR, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  for_scope->set_start_position(scanner()->location().beg_pos);
+  bool is_let_identifier_expression = false;
+  DeclarationParsingResult parsing_result;
+  if (peek() != Token::SEMICOLON) {
+    if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
+        (peek() == Token::LET && IsNextLetKeyword())) {
+      ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
+      is_const = parsing_result.descriptor.mode == CONST;
+
+      int num_decl = parsing_result.declarations.length();
+      bool accept_IN = num_decl >= 1;
+      ForEachStatement::VisitMode mode;
+      int each_beg_pos = scanner()->location().beg_pos;
+      int each_end_pos = scanner()->location().end_pos;
+
+      if (accept_IN && CheckInOrOf(&mode, ok)) {
+        if (!*ok) return nullptr;
+        if (num_decl != 1) {
+          const char* loop_type =
+              mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
+          ParserTraits::ReportMessageAt(
+              parsing_result.bindings_loc,
+              MessageTemplate::kForInOfLoopMultiBindings, loop_type);
+          *ok = false;
+          return nullptr;
+        }
+        DeclarationParsingResult::Declaration& decl =
+            parsing_result.declarations[0];
+        if (parsing_result.first_initializer_loc.IsValid() &&
+            (is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
+             IsLexicalVariableMode(parsing_result.descriptor.mode) ||
+             !decl.pattern->IsVariableProxy())) {
+          if (mode == ForEachStatement::ITERATE) {
+            ReportMessageAt(parsing_result.first_initializer_loc,
+                            MessageTemplate::kForOfLoopInitializer);
+          } else {
+            // TODO(caitp): This should be an error in sloppy mode too.
+            ReportMessageAt(parsing_result.first_initializer_loc,
+                            MessageTemplate::kForInLoopInitializer);
+          }
+          *ok = false;
+          return nullptr;
+        }
+
+        Block* init_block = nullptr;
+
+        // special case for legacy for (var/const x =.... in)
+        if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
+            decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
+          const AstRawString* name =
+              decl.pattern->AsVariableProxy()->raw_name();
+          VariableProxy* single_var = scope_->NewUnresolved(
+              factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos);
+          init_block = factory()->NewBlock(
+              nullptr, 2, true, parsing_result.descriptor.declaration_pos);
+          init_block->statements()->Add(
+              factory()->NewExpressionStatement(
+                  factory()->NewAssignment(Token::ASSIGN, single_var,
+                                           decl.initializer,
+                                           RelocInfo::kNoPosition),
+                  RelocInfo::kNoPosition),
+              zone());
+        }
+
+        // Rewrite a for-in/of statement of the form
+        //
+        //   for (let/const/var x in/of e) b
+        //
+        // into
+        //
+        //   {
+        //     <let x' be a temporary variable>
+        //     for (x' in/of e) {
+        //       let/const/var x;
+        //       x = x';
+        //       b;
+        //     }
+        //     let x;  // for TDZ
+        //   }
+
+        Variable* temp = scope_->NewTemporary(
+            ast_value_factory()->dot_for_string());
+        ForEachStatement* loop =
+            factory()->NewForEachStatement(mode, labels, stmt_pos);
+        Target target(&this->target_stack_, loop);
+
+        Expression* enumerable = ParseExpression(true, CHECK_OK);
+
+        Expect(Token::RPAREN, CHECK_OK);
+
+        Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
+        body_scope->set_start_position(scanner()->location().beg_pos);
+        scope_ = body_scope;
+
+        Statement* body = ParseSubStatement(NULL, CHECK_OK);
+
+        Block* body_block =
+            factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
+
+        auto each_initialization_block =
+            factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+        {
+          auto descriptor = parsing_result.descriptor;
+          descriptor.declaration_pos = RelocInfo::kNoPosition;
+          descriptor.initialization_pos = RelocInfo::kNoPosition;
+          decl.initializer = factory()->NewVariableProxy(temp);
+
+          PatternRewriter::DeclareAndInitializeVariables(
+              each_initialization_block, &descriptor, &decl,
+              IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
+                                                     : nullptr,
+              CHECK_OK);
+        }
+
+        body_block->statements()->Add(each_initialization_block, zone());
+        body_block->statements()->Add(body, zone());
+        VariableProxy* temp_proxy =
+            factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
+        InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
+                                   false);
+        scope_ = for_scope;
+        body_scope->set_end_position(scanner()->location().end_pos);
+        body_scope = body_scope->FinalizeBlockScope();
+        if (body_scope != nullptr) {
+          body_block->set_scope(body_scope);
+        }
+
+        // Create a TDZ for any lexically-bound names.
+        if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
+          DCHECK_NULL(init_block);
+
+          init_block =
+              factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
+
+          for (int i = 0; i < lexical_bindings.length(); ++i) {
+            // TODO(adamk): This needs to be some sort of special
+            // INTERNAL variable that's invisible to the debugger
+            // but visible to everything else.
+            VariableProxy* tdz_proxy = NewUnresolved(lexical_bindings[i], LET);
+            Declaration* tdz_decl = factory()->NewVariableDeclaration(
+                tdz_proxy, LET, scope_, RelocInfo::kNoPosition);
+            Variable* tdz_var = Declare(tdz_decl, DeclarationDescriptor::NORMAL,
+                                        true, CHECK_OK);
+            tdz_var->set_initializer_position(position());
+          }
+        }
+
+        scope_ = saved_scope;
+        for_scope->set_end_position(scanner()->location().end_pos);
+        for_scope = for_scope->FinalizeBlockScope();
+        // Parsed for-in loop w/ variable declarations.
+        if (init_block != nullptr) {
+          init_block->statements()->Add(loop, zone());
+          if (for_scope != nullptr) {
+            init_block->set_scope(for_scope);
+          }
+          return init_block;
+        } else {
+          DCHECK_NULL(for_scope);
+          return loop;
+        }
+      } else {
+        init = parsing_result.BuildInitializationBlock(
+            IsLexicalVariableMode(parsing_result.descriptor.mode)
+                ? &lexical_bindings
+                : nullptr,
+            CHECK_OK);
+      }
+    } else {
+      int lhs_beg_pos = peek_position();
+      ExpressionClassifier classifier;
+      Expression* expression = ParseExpression(false, &classifier, CHECK_OK);
+      int lhs_end_pos = scanner()->location().end_pos;
+      ForEachStatement::VisitMode mode;
+      is_let_identifier_expression =
+          expression->IsVariableProxy() &&
+          expression->AsVariableProxy()->raw_name() ==
+              ast_value_factory()->let_string();
+
+      bool is_for_each = CheckInOrOf(&mode, ok);
+      if (!*ok) return nullptr;
+      bool is_destructuring =
+          is_for_each && allow_harmony_destructuring_assignment() &&
+          (expression->IsArrayLiteral() || expression->IsObjectLiteral());
+
+      if (is_destructuring) {
+        ValidateAssignmentPattern(&classifier, CHECK_OK);
+      } else {
+        expression =
+            ParserTraits::RewriteNonPattern(expression, &classifier, CHECK_OK);
+      }
+
+      if (is_for_each) {
+        if (!is_destructuring) {
+          expression = this->CheckAndRewriteReferenceExpression(
+              expression, lhs_beg_pos, lhs_end_pos,
+              MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK);
+        }
+
+        ForEachStatement* loop =
+            factory()->NewForEachStatement(mode, labels, stmt_pos);
+        Target target(&this->target_stack_, loop);
+
+        Expression* enumerable = ParseExpression(true, CHECK_OK);
+        Expect(Token::RPAREN, CHECK_OK);
+
+        // Make a block around the statement in case a lexical binding
+        // is introduced, e.g. by a FunctionDeclaration.
+        // This block must not use for_scope as its scope because if a
+        // lexical binding is introduced which overlaps with the for-in/of,
+        // expressions in head of the loop should actually have variables
+        // resolved in the outer scope.
+        Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE);
+        scope_ = body_scope;
+        Block* block =
+            factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
+        Statement* body = ParseSubStatement(NULL, CHECK_OK);
+        block->statements()->Add(body, zone());
+        InitializeForEachStatement(loop, expression, enumerable, block,
+                                   is_destructuring);
+        scope_ = saved_scope;
+        body_scope->set_end_position(scanner()->location().end_pos);
+        body_scope = body_scope->FinalizeBlockScope();
+        if (body_scope != nullptr) {
+          block->set_scope(body_scope);
+        }
+        for_scope->set_end_position(scanner()->location().end_pos);
+        for_scope = for_scope->FinalizeBlockScope();
+        DCHECK(for_scope == nullptr);
+        // Parsed for-in loop.
+        return loop;
+
+      } else {
+        init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
+      }
+    }
+  }
+
+  // Standard 'for' loop
+  ForStatement* loop = factory()->NewForStatement(labels, stmt_pos);
+  Target target(&this->target_stack_, loop);
+
+  // Parsed initializer at this point.
+  // Detect attempts at 'let' declarations in sloppy mode.
+  if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
+      is_sloppy(language_mode()) && is_let_identifier_expression) {
+    ReportMessage(MessageTemplate::kSloppyLexical, NULL);
+    *ok = false;
+    return NULL;
+  }
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  // If there are let bindings, then condition and the next statement of the
+  // for loop must be parsed in a new scope.
+  Scope* inner_scope = NULL;
+  if (lexical_bindings.length() > 0) {
+    inner_scope = NewScope(for_scope, BLOCK_SCOPE);
+    inner_scope->set_start_position(scanner()->location().beg_pos);
+    scope_ = inner_scope;
+  }
+
+  Expression* cond = NULL;
+  if (peek() != Token::SEMICOLON) {
+    cond = ParseExpression(true, CHECK_OK);
+  }
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  Statement* next = NULL;
+  if (peek() != Token::RPAREN) {
+    Expression* exp = ParseExpression(true, CHECK_OK);
+    next = factory()->NewExpressionStatement(exp, exp->position());
+  }
+  Expect(Token::RPAREN, CHECK_OK);
+
+  Statement* body = ParseSubStatement(NULL, CHECK_OK);
+
+  Statement* result = NULL;
+  if (lexical_bindings.length() > 0) {
+    scope_ = for_scope;
+    result = DesugarLexicalBindingsInForStatement(
+                 inner_scope, is_const, &lexical_bindings, loop, init, cond,
+                 next, body, CHECK_OK);
+    scope_ = saved_scope;
+    for_scope->set_end_position(scanner()->location().end_pos);
+  } else {
+    scope_ = saved_scope;
+    for_scope->set_end_position(scanner()->location().end_pos);
+    for_scope = for_scope->FinalizeBlockScope();
+    if (for_scope) {
+      // Rewrite a for statement of the form
+      //   for (const x = i; c; n) b
+      //
+      // into
+      //
+      //   {
+      //     const x = i;
+      //     for (; c; n) b
+      //   }
+      //
+      // or, desugar
+      //   for (; c; n) b
+      // into
+      //   {
+      //     for (; c; n) b
+      //   }
+      // just in case b introduces a lexical binding some other way, e.g., if b
+      // is a FunctionDeclaration.
+      Block* block =
+          factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
+      if (init != nullptr) {
+        block->statements()->Add(init, zone());
+      }
+      block->statements()->Add(loop, zone());
+      block->set_scope(for_scope);
+      loop->Initialize(NULL, cond, next, body);
+      result = block;
+    } else {
+      loop->Initialize(init, cond, next, body);
+      result = loop;
+    }
+  }
+  return result;
+}
+
+
+DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
+  // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
+  // contexts this is used as a statement which invokes the debugger as i a
+  // break point is present.
+  // DebuggerStatement ::
+  //   'debugger' ';'
+
+  int pos = peek_position();
+  Expect(Token::DEBUGGER, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+  return factory()->NewDebuggerStatement(pos);
+}
+
+
+bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
+  if (expression->IsLiteral()) return true;
+  MaterializedLiteral* lit = expression->AsMaterializedLiteral();
+  return lit != NULL && lit->is_simple();
+}
+
+
+Handle<FixedArray> CompileTimeValue::GetValue(Isolate* isolate,
+                                              Expression* expression) {
+  Factory* factory = isolate->factory();
+  DCHECK(IsCompileTimeValue(expression));
+  Handle<FixedArray> result = factory->NewFixedArray(2, TENURED);
+  ObjectLiteral* object_literal = expression->AsObjectLiteral();
+  if (object_literal != NULL) {
+    DCHECK(object_literal->is_simple());
+    if (object_literal->fast_elements()) {
+      result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
+    } else {
+      result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
+    }
+    result->set(kElementsSlot, *object_literal->constant_properties());
+  } else {
+    ArrayLiteral* array_literal = expression->AsArrayLiteral();
+    DCHECK(array_literal != NULL && array_literal->is_simple());
+    result->set(kLiteralTypeSlot, Smi::FromInt(ARRAY_LITERAL));
+    result->set(kElementsSlot, *array_literal->constant_elements());
+  }
+  return result;
+}
+
+
+CompileTimeValue::LiteralType CompileTimeValue::GetLiteralType(
+    Handle<FixedArray> value) {
+  Smi* literal_type = Smi::cast(value->get(kLiteralTypeSlot));
+  return static_cast<LiteralType>(literal_type->value());
+}
+
+
+Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
+  return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
+}
+
+
+void ParserTraits::ParseArrowFunctionFormalParameters(
+    ParserFormalParameters* parameters, Expression* expr,
+    const Scanner::Location& params_loc, bool* ok) {
+  if (parameters->Arity() >= Code::kMaxArguments) {
+    ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
+    *ok = false;
+    return;
+  }
+
+  // ArrowFunctionFormals ::
+  //    Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail)
+  //    Tail
+  // NonTailArrowFunctionFormals ::
+  //    Binary(Token::COMMA, NonTailArrowFunctionFormals, VariableProxy)
+  //    VariableProxy
+  // Tail ::
+  //    VariableProxy
+  //    Spread(VariableProxy)
+  //
+  // As we need to visit the parameters in left-to-right order, we recurse on
+  // the left-hand side of comma expressions.
+  //
+  if (expr->IsBinaryOperation()) {
+    BinaryOperation* binop = expr->AsBinaryOperation();
+    // The classifier has already run, so we know that the expression is a valid
+    // arrow function formals production.
+    DCHECK_EQ(binop->op(), Token::COMMA);
+    Expression* left = binop->left();
+    Expression* right = binop->right();
+    ParseArrowFunctionFormalParameters(parameters, left, params_loc, ok);
+    if (!*ok) return;
+    // LHS of comma expression should be unparenthesized.
+    expr = right;
+  }
+
+  // Only the right-most expression may be a rest parameter.
+  DCHECK(!parameters->has_rest);
+
+  bool is_rest = expr->IsSpread();
+  if (is_rest) {
+    expr = expr->AsSpread()->expression();
+    parameters->has_rest = true;
+  }
+  if (parameters->is_simple) {
+    parameters->is_simple = !is_rest && expr->IsVariableProxy();
+  }
+
+  Expression* initializer = nullptr;
+  if (expr->IsVariableProxy()) {
+    // When the formal parameter was originally seen, it was parsed as a
+    // VariableProxy and recorded as unresolved in the scope.  Here we undo that
+    // parse-time side-effect for parameters that are single-names (not
+    // patterns; for patterns that happens uniformly in
+    // PatternRewriter::VisitVariableProxy).
+    parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
+  } else if (expr->IsAssignment()) {
+    Assignment* assignment = expr->AsAssignment();
+    DCHECK(parser_->allow_harmony_default_parameters());
+    DCHECK(!assignment->is_compound());
+    initializer = assignment->value();
+    expr = assignment->target();
+
+    // TODO(adamk): Only call this if necessary.
+    RewriteParameterInitializerScope(parser_->stack_limit(), initializer,
+                                     parser_->scope_, parameters->scope);
+  }
+
+  // TODO(adamk): params_loc.end_pos is not the correct initializer position,
+  // but it should be conservative enough to trigger hole checks for variables
+  // referenced in the initializer (if any).
+  AddFormalParameter(parameters, expr, initializer, params_loc.end_pos,
+                     is_rest);
+}
+
+
+DoExpression* Parser::ParseDoExpression(bool* ok) {
+  // AssignmentExpression ::
+  //     do '{' StatementList '}'
+  int pos = peek_position();
+
+  Expect(Token::DO, CHECK_OK);
+  Variable* result =
+      scope_->NewTemporary(ast_value_factory()->dot_result_string());
+  Block* block = ParseBlock(nullptr, false, CHECK_OK);
+  DoExpression* expr = factory()->NewDoExpression(block, result, pos);
+  if (!Rewriter::Rewrite(this, expr, ast_value_factory())) {
+    *ok = false;
+    return nullptr;
+  }
+  block->set_scope(block->scope()->FinalizeBlockScope());
+  return expr;
+}
+
+
+void ParserTraits::ParseArrowFunctionFormalParameterList(
+    ParserFormalParameters* parameters, Expression* expr,
+    const Scanner::Location& params_loc,
+    Scanner::Location* duplicate_loc, bool* ok) {
+  if (expr->IsEmptyParentheses()) return;
+
+  ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
+  if (!*ok) return;
+
+  ExpressionClassifier classifier;
+  if (!parameters->is_simple) {
+    classifier.RecordNonSimpleParameter();
+  }
+  for (int i = 0; i < parameters->Arity(); ++i) {
+    auto parameter = parameters->at(i);
+    DeclareFormalParameter(parameters->scope, parameter, &classifier);
+    if (!duplicate_loc->IsValid()) {
+      *duplicate_loc = classifier.duplicate_formal_parameter_error().location;
+    }
+  }
+  DCHECK_EQ(parameters->is_simple, parameters->scope->has_simple_parameters());
+}
+
+
+void ParserTraits::ReindexLiterals(const ParserFormalParameters& parameters) {
+  if (parser_->function_state_->materialized_literal_count() > 0) {
+    AstLiteralReindexer reindexer;
+
+    for (const auto p : parameters.params) {
+      if (p.pattern != nullptr) reindexer.Reindex(p.pattern);
+      if (p.initializer != nullptr) reindexer.Reindex(p.initializer);
+    }
+
+    DCHECK(reindexer.count() <=
+           parser_->function_state_->materialized_literal_count());
+  }
+}
+
+
+FunctionLiteral* Parser::ParseFunctionLiteral(
+    const AstRawString* function_name, Scanner::Location function_name_location,
+    FunctionNameValidity function_name_validity, FunctionKind kind,
+    int function_token_pos, FunctionLiteral::FunctionType function_type,
+    FunctionLiteral::ArityRestriction arity_restriction,
+    LanguageMode language_mode, bool* ok) {
+  // Function ::
+  //   '(' FormalParameterList? ')' '{' FunctionBody '}'
+  //
+  // Getter ::
+  //   '(' ')' '{' FunctionBody '}'
+  //
+  // Setter ::
+  //   '(' PropertySetParameterList ')' '{' FunctionBody '}'
+
+  int pos = function_token_pos == RelocInfo::kNoPosition
+      ? peek_position() : function_token_pos;
+
+  bool is_generator = IsGeneratorFunction(kind);
+
+  // Anonymous functions were passed either the empty symbol or a null
+  // handle as the function name.  Remember if we were passed a non-empty
+  // handle to decide whether to invoke function name inference.
+  bool should_infer_name = function_name == NULL;
+
+  // We want a non-null handle as the function name.
+  if (should_infer_name) {
+    function_name = ast_value_factory()->empty_string();
+  }
+
+  // Function declarations are function scoped in normal mode, so they are
+  // hoisted. In harmony block scoping mode they are block scoped, so they
+  // are not hoisted.
+  //
+  // One tricky case are function declarations in a local sloppy-mode eval:
+  // their declaration is hoisted, but they still see the local scope. E.g.,
+  //
+  // function() {
+  //   var x = 0
+  //   try { throw 1 } catch (x) { eval("function g() { return x }") }
+  //   return g()
+  // }
+  //
+  // needs to return 1. To distinguish such cases, we need to detect
+  // (1) whether a function stems from a sloppy eval, and
+  // (2) whether it actually hoists across the eval.
+  // Unfortunately, we do not represent sloppy eval scopes, so we do not have
+  // either information available directly, especially not when lazily compiling
+  // a function like 'g'. We hence rely on the following invariants:
+  // - (1) is the case iff the innermost scope of the deserialized scope chain
+  //   under which we compile is _not_ a declaration scope. This holds because
+  //   in all normal cases, function declarations are fully hoisted to a
+  //   declaration scope and compiled relative to that.
+  // - (2) is the case iff the current declaration scope is still the original
+  //   one relative to the deserialized scope chain. Otherwise we must be
+  //   compiling a function in an inner declaration scope in the eval, e.g. a
+  //   nested function, and hoisting works normally relative to that.
+  Scope* declaration_scope = scope_->DeclarationScope();
+  Scope* original_declaration_scope = original_scope_->DeclarationScope();
+  Scope* scope = function_type == FunctionLiteral::kDeclaration &&
+                         is_sloppy(language_mode) &&
+                         !allow_harmony_sloppy_function() &&
+                         (original_scope_ == original_declaration_scope ||
+                          declaration_scope != original_declaration_scope)
+                     ? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
+                     : NewScope(scope_, FUNCTION_SCOPE, kind);
+  SetLanguageMode(scope, language_mode);
+  ZoneList<Statement*>* body = NULL;
+  int arity = -1;
+  int materialized_literal_count = -1;
+  int expected_property_count = -1;
+  DuplicateFinder duplicate_finder(scanner()->unicode_cache());
+  ExpressionClassifier formals_classifier(&duplicate_finder);
+  FunctionLiteral::EagerCompileHint eager_compile_hint =
+      parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
+                              : FunctionLiteral::kShouldLazyCompile;
+  bool should_be_used_once_hint = false;
+  // Parse function.
+  {
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, scope, kind,
+                                 &function_factory);
+    scope_->SetScopeName(function_name);
+
+    if (is_generator) {
+      // For generators, allocating variables in contexts is currently a win
+      // because it minimizes the work needed to suspend and resume an
+      // activation.
+      scope_->ForceContextAllocation();
+
+      // Calling a generator returns a generator object.  That object is stored
+      // in a temporary variable, a definition that is used by "yield"
+      // expressions. This also marks the FunctionState as a generator.
+      Variable* temp = scope_->NewTemporary(
+          ast_value_factory()->dot_generator_object_string());
+      function_state.set_generator_object_variable(temp);
+    }
+
+    Expect(Token::LPAREN, CHECK_OK);
+    int start_position = scanner()->location().beg_pos;
+    scope_->set_start_position(start_position);
+    ParserFormalParameters formals(scope);
+    ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
+    arity = formals.Arity();
+    Expect(Token::RPAREN, CHECK_OK);
+    int formals_end_position = scanner()->location().end_pos;
+
+    CheckArityRestrictions(arity, arity_restriction,
+                           formals.has_rest, start_position,
+                           formals_end_position, CHECK_OK);
+    Expect(Token::LBRACE, CHECK_OK);
+
+    // Determine if the function can be parsed lazily. Lazy parsing is different
+    // from lazy compilation; we need to parse more eagerly than we compile.
+
+    // We can only parse lazily if we also compile lazily. The heuristics for
+    // lazy compilation are:
+    // - It must not have been prohibited by the caller to Parse (some callers
+    //   need a full AST).
+    // - The outer scope must allow lazy compilation of inner functions.
+    // - The function mustn't be a function expression with an open parenthesis
+    //   before; we consider that a hint that the function will be called
+    //   immediately, and it would be a waste of time to make it lazily
+    //   compiled.
+    // These are all things we can know at this point, without looking at the
+    // function itself.
+
+    // In addition, we need to distinguish between these cases:
+    // (function foo() {
+    //   bar = function() { return 1; }
+    //  })();
+    // and
+    // (function foo() {
+    //   var a = 1;
+    //   bar = function() { return a; }
+    //  })();
+
+    // Now foo will be parsed eagerly and compiled eagerly (optimization: assume
+    // parenthesis before the function means that it will be called
+    // immediately). The inner function *must* be parsed eagerly to resolve the
+    // possible reference to the variable in foo's scope. However, it's possible
+    // that it will be compiled lazily.
+
+    // To make this additional case work, both Parser and PreParser implement a
+    // logic where only top-level functions will be parsed lazily.
+    bool is_lazily_parsed = mode() == PARSE_LAZILY &&
+                            scope_->AllowsLazyParsing() &&
+                            !parenthesized_function_;
+    parenthesized_function_ = false;  // The bit was set for this function only.
+
+    // Eager or lazy parse?
+    // If is_lazily_parsed, we'll parse lazy. If we can set a bookmark, we'll
+    // pass it to SkipLazyFunctionBody, which may use it to abort lazy
+    // parsing if it suspect that wasn't a good idea. If so, or if we didn't
+    // try to lazy parse in the first place, we'll have to parse eagerly.
+    Scanner::BookmarkScope bookmark(scanner());
+    if (is_lazily_parsed) {
+      Scanner::BookmarkScope* maybe_bookmark =
+          bookmark.Set() ? &bookmark : nullptr;
+      SkipLazyFunctionBody(&materialized_literal_count,
+                           &expected_property_count, /*CHECK_OK*/ ok,
+                           maybe_bookmark);
+
+      materialized_literal_count += formals.materialized_literals_count +
+                                    function_state.materialized_literal_count();
+
+      if (bookmark.HasBeenReset()) {
+        // Trigger eager (re-)parsing, just below this block.
+        is_lazily_parsed = false;
+
+        // This is probably an initialization function. Inform the compiler it
+        // should also eager-compile this function, and that we expect it to be
+        // used once.
+        eager_compile_hint = FunctionLiteral::kShouldEagerCompile;
+        should_be_used_once_hint = true;
+      }
+    }
+    if (!is_lazily_parsed) {
+      // Determine whether the function body can be discarded after parsing.
+      // The preconditions are:
+      // - Lazy compilation has to be enabled.
+      // - Neither V8 natives nor native function declarations can be allowed,
+      //   since parsing one would retroactively force the function to be
+      //   eagerly compiled.
+      // - The invoker of this parser can't depend on the AST being eagerly
+      //   built (either because the function is about to be compiled, or
+      //   because the AST is going to be inspected for some reason).
+      // - Because of the above, we can't be attempting to parse a
+      //   FunctionExpression; even without enclosing parentheses it might be
+      //   immediately invoked.
+      // - The function literal shouldn't be hinted to eagerly compile.
+      bool use_temp_zone =
+          FLAG_lazy && !allow_natives() && extension_ == NULL && allow_lazy() &&
+          function_type == FunctionLiteral::kDeclaration &&
+          eager_compile_hint != FunctionLiteral::kShouldEagerCompile;
+      // Open a new BodyScope, which sets our AstNodeFactory to allocate in the
+      // new temporary zone if the preconditions are satisfied, and ensures that
+      // the previous zone is always restored after parsing the body.
+      // For the purpose of scope analysis, some ZoneObjects allocated by the
+      // factory must persist after the function body is thrown away and
+      // temp_zone is deallocated. These objects are instead allocated in a
+      // parser-persistent zone (see parser_zone_ in AstNodeFactory).
+      {
+        Zone temp_zone;
+        AstNodeFactory::BodyScope inner(factory(), &temp_zone, use_temp_zone);
+
+        body = ParseEagerFunctionBody(function_name, pos, formals, kind,
+                                      function_type, CHECK_OK);
+      }
+      materialized_literal_count = function_state.materialized_literal_count();
+      expected_property_count = function_state.expected_property_count();
+      if (use_temp_zone) {
+        // If the preconditions are correct the function body should never be
+        // accessed, but do this anyway for better behaviour if they're wrong.
+        body = NULL;
+      }
+    }
+
+    // Parsing the body may change the language mode in our scope.
+    language_mode = scope->language_mode();
+
+    if (is_strong(language_mode) && IsSubclassConstructor(kind)) {
+      if (!function_state.super_location().IsValid()) {
+        ReportMessageAt(function_name_location,
+                        MessageTemplate::kStrongSuperCallMissing,
+                        kReferenceError);
+        *ok = false;
+        return nullptr;
+      }
+    }
+
+    // Validate name and parameter names. We can do this only after parsing the
+    // function, since the function can declare itself strict.
+    CheckFunctionName(language_mode, function_name, function_name_validity,
+                      function_name_location, CHECK_OK);
+    const bool allow_duplicate_parameters =
+        is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
+    ValidateFormalParameters(&formals_classifier, language_mode,
+                             allow_duplicate_parameters, CHECK_OK);
+
+    if (is_strict(language_mode)) {
+      CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
+                              CHECK_OK);
+    }
+    if (is_sloppy(language_mode) && allow_harmony_sloppy_function()) {
+      InsertSloppyBlockFunctionVarBindings(scope, CHECK_OK);
+    }
+    if (is_strict(language_mode) || allow_harmony_sloppy() ||
+        allow_harmony_destructuring_bind()) {
+      CheckConflictingVarDeclarations(scope, CHECK_OK);
+    }
+
+    if (body) {
+      // If body can be inspected, rewrite queued destructuring assignments
+      ParserTraits::RewriteDestructuringAssignments();
+    }
+  }
+
+  bool has_duplicate_parameters =
+      !formals_classifier.is_valid_formal_parameter_list_without_duplicates();
+  FunctionLiteral::ParameterFlag duplicate_parameters =
+      has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
+                               : FunctionLiteral::kNoDuplicateParameters;
+
+  FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
+      function_name, scope, body, materialized_literal_count,
+      expected_property_count, arity, duplicate_parameters, function_type,
+      eager_compile_hint, kind, pos);
+  function_literal->set_function_token_position(function_token_pos);
+  if (should_be_used_once_hint)
+    function_literal->set_should_be_used_once_hint();
+
+  if (scope->has_rest_parameter()) {
+    function_literal->set_dont_optimize_reason(kRestParameter);
+  }
+
+  if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
+  return function_literal;
+}
+
+
+void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
+                                  int* expected_property_count, bool* ok,
+                                  Scanner::BookmarkScope* bookmark) {
+  DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet());
+  if (produce_cached_parse_data()) CHECK(log_);
+
+  int function_block_pos = position();
+  if (consume_cached_parse_data() && !cached_parse_data_->rejected()) {
+    // If we have cached data, we use it to skip parsing the function body. The
+    // data contains the information we need to construct the lazy function.
+    FunctionEntry entry =
+        cached_parse_data_->GetFunctionEntry(function_block_pos);
+    // Check that cached data is valid. If not, mark it as invalid (the embedder
+    // handles it). Note that end position greater than end of stream is safe,
+    // and hard to check.
+    if (entry.is_valid() && entry.end_pos() > function_block_pos) {
+      scanner()->SeekForward(entry.end_pos() - 1);
+
+      scope_->set_end_position(entry.end_pos());
+      Expect(Token::RBRACE, ok);
+      if (!*ok) {
+        return;
+      }
+      total_preparse_skipped_ += scope_->end_position() - function_block_pos;
+      *materialized_literal_count = entry.literal_count();
+      *expected_property_count = entry.property_count();
+      SetLanguageMode(scope_, entry.language_mode());
+      if (entry.uses_super_property()) scope_->RecordSuperPropertyUsage();
+      if (entry.calls_eval()) scope_->RecordEvalCall();
+      return;
+    }
+    cached_parse_data_->Reject();
+  }
+  // With no cached data, we partially parse the function, without building an
+  // AST. This gathers the data needed to build a lazy function.
+  SingletonLogger logger;
+  PreParser::PreParseResult result =
+      ParseLazyFunctionBodyWithPreParser(&logger, bookmark);
+  if (bookmark && bookmark->HasBeenReset()) {
+    return;  // Return immediately if pre-parser devided to abort parsing.
+  }
+  if (result == PreParser::kPreParseStackOverflow) {
+    // Propagate stack overflow.
+    set_stack_overflow();
+    *ok = false;
+    return;
+  }
+  if (logger.has_error()) {
+    ParserTraits::ReportMessageAt(
+        Scanner::Location(logger.start(), logger.end()), logger.message(),
+        logger.argument_opt(), logger.error_type());
+    *ok = false;
+    return;
+  }
+  scope_->set_end_position(logger.end());
+  Expect(Token::RBRACE, ok);
+  if (!*ok) {
+    return;
+  }
+  total_preparse_skipped_ += scope_->end_position() - function_block_pos;
+  *materialized_literal_count = logger.literals();
+  *expected_property_count = logger.properties();
+  SetLanguageMode(scope_, logger.language_mode());
+  if (logger.uses_super_property()) {
+    scope_->RecordSuperPropertyUsage();
+  }
+  if (logger.calls_eval()) {
+    scope_->RecordEvalCall();
+  }
+  if (produce_cached_parse_data()) {
+    DCHECK(log_);
+    // Position right after terminal '}'.
+    int body_end = scanner()->location().end_pos;
+    log_->LogFunction(function_block_pos, body_end, *materialized_literal_count,
+                      *expected_property_count, scope_->language_mode(),
+                      scope_->uses_super_property(), scope_->calls_eval());
+  }
+}
+
+
+Statement* Parser::BuildAssertIsCoercible(Variable* var) {
+  // if (var === null || var === undefined)
+  //     throw /* type error kNonCoercible) */;
+
+  Expression* condition = factory()->NewBinaryOperation(
+      Token::OR, factory()->NewCompareOperation(
+                     Token::EQ_STRICT, factory()->NewVariableProxy(var),
+                     factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+                     RelocInfo::kNoPosition),
+      factory()->NewCompareOperation(
+          Token::EQ_STRICT, factory()->NewVariableProxy(var),
+          factory()->NewNullLiteral(RelocInfo::kNoPosition),
+          RelocInfo::kNoPosition),
+      RelocInfo::kNoPosition);
+  Expression* throw_type_error = this->NewThrowTypeError(
+      MessageTemplate::kNonCoercible, ast_value_factory()->empty_string(),
+      RelocInfo::kNoPosition);
+  IfStatement* if_statement = factory()->NewIfStatement(
+      condition, factory()->NewExpressionStatement(throw_type_error,
+                                                   RelocInfo::kNoPosition),
+      factory()->NewEmptyStatement(RelocInfo::kNoPosition),
+      RelocInfo::kNoPosition);
+  return if_statement;
+}
+
+
+class InitializerRewriter : public AstExpressionVisitor {
+ public:
+  InitializerRewriter(uintptr_t stack_limit, Expression* root, Parser* parser,
+                      Scope* scope)
+      : AstExpressionVisitor(stack_limit, root),
+        parser_(parser),
+        scope_(scope) {}
+
+ private:
+  void VisitExpression(Expression* expr) {
+    RewritableAssignmentExpression* to_rewrite =
+        expr->AsRewritableAssignmentExpression();
+    if (to_rewrite == nullptr || to_rewrite->is_rewritten()) return;
+
+    Parser::PatternRewriter::RewriteDestructuringAssignment(parser_, to_rewrite,
+                                                            scope_);
+  }
+
+ private:
+  Parser* parser_;
+  Scope* scope_;
+};
+
+
+void Parser::RewriteParameterInitializer(Expression* expr, Scope* scope) {
+  InitializerRewriter rewriter(stack_limit_, expr, this, scope);
+  rewriter.Run();
+}
+
+
+Block* Parser::BuildParameterInitializationBlock(
+    const ParserFormalParameters& parameters, bool* ok) {
+  DCHECK(!parameters.is_simple);
+  DCHECK(scope_->is_function_scope());
+  Block* init_block =
+      factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+  for (int i = 0; i < parameters.params.length(); ++i) {
+    auto parameter = parameters.params[i];
+    if (parameter.is_rest && parameter.pattern->IsVariableProxy()) break;
+    DeclarationDescriptor descriptor;
+    descriptor.declaration_kind = DeclarationDescriptor::PARAMETER;
+    descriptor.parser = this;
+    descriptor.scope = scope_;
+    descriptor.hoist_scope = nullptr;
+    descriptor.mode = LET;
+    descriptor.needs_init = true;
+    descriptor.declaration_pos = parameter.pattern->position();
+    // The position that will be used by the AssignmentExpression
+    // which copies from the temp parameter to the pattern.
+    //
+    // TODO(adamk): Should this be RelocInfo::kNoPosition, since
+    // it's just copying from a temp var to the real param var?
+    descriptor.initialization_pos = parameter.pattern->position();
+    // The initializer position which will end up in,
+    // Variable::initializer_position(), used for hole check elimination.
+    int initializer_position = parameter.pattern->position();
+    Expression* initial_value =
+        factory()->NewVariableProxy(parameters.scope->parameter(i));
+    if (parameter.initializer != nullptr) {
+      // IS_UNDEFINED($param) ? initializer : $param
+
+      // Ensure initializer is rewritten
+      RewriteParameterInitializer(parameter.initializer, scope_);
+
+      auto condition = factory()->NewCompareOperation(
+          Token::EQ_STRICT,
+          factory()->NewVariableProxy(parameters.scope->parameter(i)),
+          factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+          RelocInfo::kNoPosition);
+      initial_value = factory()->NewConditional(
+          condition, parameter.initializer, initial_value,
+          RelocInfo::kNoPosition);
+      descriptor.initialization_pos = parameter.initializer->position();
+      initializer_position = parameter.initializer_end_position;
+    }
+
+    Scope* param_scope = scope_;
+    Block* param_block = init_block;
+    if (!parameter.is_simple() && scope_->calls_sloppy_eval()) {
+      param_scope = NewScope(scope_, BLOCK_SCOPE);
+      param_scope->set_is_declaration_scope();
+      param_scope->set_start_position(parameter.pattern->position());
+      param_scope->set_end_position(RelocInfo::kNoPosition);
+      param_scope->RecordEvalCall();
+      param_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
+      param_block->set_scope(param_scope);
+      descriptor.hoist_scope = scope_;
+    }
+
+    {
+      BlockState block_state(&scope_, param_scope);
+      DeclarationParsingResult::Declaration decl(
+          parameter.pattern, initializer_position, initial_value);
+      PatternRewriter::DeclareAndInitializeVariables(param_block, &descriptor,
+                                                     &decl, nullptr, CHECK_OK);
+    }
+
+    if (!parameter.is_simple() && scope_->calls_sloppy_eval()) {
+      param_scope = param_scope->FinalizeBlockScope();
+      if (param_scope != nullptr) {
+        CheckConflictingVarDeclarations(param_scope, CHECK_OK);
+      }
+      init_block->statements()->Add(param_block, zone());
+    }
+  }
+  return init_block;
+}
+
+
+ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
+    const AstRawString* function_name, int pos,
+    const ParserFormalParameters& parameters, FunctionKind kind,
+    FunctionLiteral::FunctionType function_type, bool* ok) {
+  // Everything inside an eagerly parsed function will be parsed eagerly
+  // (see comment above).
+  ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
+  ZoneList<Statement*>* result = new(zone()) ZoneList<Statement*>(8, zone());
+
+  static const int kFunctionNameAssignmentIndex = 0;
+  if (function_type == FunctionLiteral::kNamedExpression) {
+    DCHECK(function_name != NULL);
+    // If we have a named function expression, we add a local variable
+    // declaration to the body of the function with the name of the
+    // function and let it refer to the function itself (closure).
+    // Not having parsed the function body, the language mode may still change,
+    // so we reserve a spot and create the actual const assignment later.
+    DCHECK_EQ(kFunctionNameAssignmentIndex, result->length());
+    result->Add(NULL, zone());
+  }
+
+  ZoneList<Statement*>* body = result;
+  Scope* inner_scope = scope_;
+  Block* inner_block = nullptr;
+  if (!parameters.is_simple) {
+    inner_scope = NewScope(scope_, BLOCK_SCOPE);
+    inner_scope->set_is_declaration_scope();
+    inner_scope->set_start_position(scanner()->location().beg_pos);
+    inner_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
+    inner_block->set_scope(inner_scope);
+    body = inner_block->statements();
+  }
+
+  {
+    BlockState block_state(&scope_, inner_scope);
+
+    // For generators, allocate and yield an iterator on function entry.
+    if (IsGeneratorFunction(kind)) {
+      ZoneList<Expression*>* arguments =
+          new(zone()) ZoneList<Expression*>(0, zone());
+      CallRuntime* allocation = factory()->NewCallRuntime(
+          Runtime::kCreateJSGeneratorObject, arguments, pos);
+      VariableProxy* init_proxy = factory()->NewVariableProxy(
+          function_state_->generator_object_variable());
+      Assignment* assignment = factory()->NewAssignment(
+          Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
+      VariableProxy* get_proxy = factory()->NewVariableProxy(
+          function_state_->generator_object_variable());
+      Yield* yield = factory()->NewYield(
+          get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
+      body->Add(factory()->NewExpressionStatement(
+          yield, RelocInfo::kNoPosition), zone());
+    }
+
+    ParseStatementList(body, Token::RBRACE, CHECK_OK);
+
+    if (IsGeneratorFunction(kind)) {
+      VariableProxy* get_proxy = factory()->NewVariableProxy(
+          function_state_->generator_object_variable());
+      Expression* undefined =
+          factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
+      Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal,
+                                         RelocInfo::kNoPosition);
+      body->Add(factory()->NewExpressionStatement(
+          yield, RelocInfo::kNoPosition), zone());
+    }
+
+    if (IsSubclassConstructor(kind)) {
+      body->Add(
+          factory()->NewReturnStatement(
+              this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
+              RelocInfo::kNoPosition),
+              zone());
+    }
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+  scope_->set_end_position(scanner()->location().end_pos);
+
+  if (!parameters.is_simple) {
+    DCHECK_NOT_NULL(inner_scope);
+    DCHECK_EQ(body, inner_block->statements());
+    SetLanguageMode(scope_, inner_scope->language_mode());
+    Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK);
+    DCHECK_NOT_NULL(init_block);
+
+    inner_scope->set_end_position(scanner()->location().end_pos);
+    inner_scope = inner_scope->FinalizeBlockScope();
+    if (inner_scope != nullptr) {
+      CheckConflictingVarDeclarations(inner_scope, CHECK_OK);
+      InsertShadowingVarBindingInitializers(inner_block);
+    }
+
+    result->Add(init_block, zone());
+    result->Add(inner_block, zone());
+  }
+
+  if (function_type == FunctionLiteral::kNamedExpression) {
+    // Now that we know the language mode, we can create the const assignment
+    // in the previously reserved spot.
+    // NOTE: We create a proxy and resolve it here so that in the
+    // future we can change the AST to only refer to VariableProxies
+    // instead of Variables and Proxies as is the case now.
+    VariableMode fvar_mode = is_strict(language_mode()) ? CONST : CONST_LEGACY;
+    Variable* fvar = new (zone())
+        Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
+                 kCreatedInitialized, kNotAssigned);
+    VariableProxy* proxy = factory()->NewVariableProxy(fvar);
+    VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
+        proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
+    scope_->DeclareFunctionVar(fvar_declaration);
+
+    VariableProxy* fproxy = factory()->NewVariableProxy(fvar);
+    result->Set(kFunctionNameAssignmentIndex,
+                factory()->NewExpressionStatement(
+                    factory()->NewAssignment(Token::INIT, fproxy,
+                                             factory()->NewThisFunction(pos),
+                                             RelocInfo::kNoPosition),
+                    RelocInfo::kNoPosition));
+  }
+
+  return result;
+}
+
+
+PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
+    SingletonLogger* logger, Scanner::BookmarkScope* bookmark) {
+  // This function may be called on a background thread too; record only the
+  // main thread preparse times.
+  if (pre_parse_timer_ != NULL) {
+    pre_parse_timer_->Start();
+  }
+  DCHECK_EQ(Token::LBRACE, scanner()->current_token());
+
+  if (reusable_preparser_ == NULL) {
+    reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(),
+                                        NULL, stack_limit_);
+    reusable_preparser_->set_allow_lazy(true);
+#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
+    SET_ALLOW(natives);
+    SET_ALLOW(harmony_sloppy);
+    SET_ALLOW(harmony_sloppy_let);
+    SET_ALLOW(harmony_default_parameters);
+    SET_ALLOW(harmony_destructuring_bind);
+    SET_ALLOW(harmony_destructuring_assignment);
+    SET_ALLOW(strong_mode);
+    SET_ALLOW(harmony_do_expressions);
+    SET_ALLOW(harmony_function_name);
+#undef SET_ALLOW
+  }
+  PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
+      language_mode(), function_state_->kind(), scope_->has_simple_parameters(),
+      logger, bookmark);
+  if (pre_parse_timer_ != NULL) {
+    pre_parse_timer_->Stop();
+  }
+  return result;
+}
+
+
+ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
+                                        Scanner::Location class_name_location,
+                                        bool name_is_strict_reserved, int pos,
+                                        bool* ok) {
+  // All parts of a ClassDeclaration and ClassExpression are strict code.
+  if (name_is_strict_reserved) {
+    ReportMessageAt(class_name_location,
+                    MessageTemplate::kUnexpectedStrictReserved);
+    *ok = false;
+    return NULL;
+  }
+  if (IsEvalOrArguments(name)) {
+    ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments);
+    *ok = false;
+    return NULL;
+  }
+  if (is_strong(language_mode()) && IsUndefined(name)) {
+    ReportMessageAt(class_name_location, MessageTemplate::kStrongUndefined);
+    *ok = false;
+    return NULL;
+  }
+
+  Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+  BlockState block_state(&scope_, block_scope);
+  RaiseLanguageMode(STRICT);
+  scope_->SetScopeName(name);
+
+  VariableProxy* proxy = NULL;
+  if (name != NULL) {
+    proxy = NewUnresolved(name, CONST);
+    const bool is_class_declaration = true;
+    Declaration* declaration = factory()->NewVariableDeclaration(
+        proxy, CONST, block_scope, pos, is_class_declaration,
+        scope_->class_declaration_group_start());
+    Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+  }
+
+  Expression* extends = NULL;
+  if (Check(Token::EXTENDS)) {
+    block_scope->set_start_position(scanner()->location().end_pos);
+    ExpressionClassifier classifier;
+    extends = ParseLeftHandSideExpression(&classifier, CHECK_OK);
+    extends = ParserTraits::RewriteNonPattern(extends, &classifier, CHECK_OK);
+  } else {
+    block_scope->set_start_position(scanner()->location().end_pos);
+  }
+
+
+  ClassLiteralChecker checker(this);
+  ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone());
+  FunctionLiteral* constructor = NULL;
+  bool has_seen_constructor = false;
+
+  Expect(Token::LBRACE, CHECK_OK);
+
+  const bool has_extends = extends != nullptr;
+  while (peek() != Token::RBRACE) {
+    if (Check(Token::SEMICOLON)) continue;
+    FuncNameInferrer::State fni_state(fni_);
+    const bool in_class = true;
+    const bool is_static = false;
+    bool is_computed_name = false;  // Classes do not care about computed
+                                    // property names here.
+    ExpressionClassifier classifier;
+    const AstRawString* name = nullptr;
+    ObjectLiteral::Property* property = ParsePropertyDefinition(
+        &checker, in_class, has_extends, is_static, &is_computed_name,
+        &has_seen_constructor, &classifier, &name, CHECK_OK);
+    property = ParserTraits::RewriteNonPatternObjectLiteralProperty(
+        property, &classifier, CHECK_OK);
+
+    if (has_seen_constructor && constructor == NULL) {
+      constructor = GetPropertyValue(property)->AsFunctionLiteral();
+      DCHECK_NOT_NULL(constructor);
+    } else {
+      properties->Add(property, zone());
+    }
+
+    if (fni_ != NULL) fni_->Infer();
+
+    if (allow_harmony_function_name()) {
+      SetFunctionNameFromPropertyName(property, name);
+    }
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+  int end_pos = scanner()->location().end_pos;
+
+  if (constructor == NULL) {
+    constructor = DefaultConstructor(extends != NULL, block_scope, pos, end_pos,
+                                     block_scope->language_mode());
+  }
+
+  // Note that we do not finalize this block scope because strong
+  // mode uses it as a sentinel value indicating an anonymous class.
+  block_scope->set_end_position(end_pos);
+
+  if (name != NULL) {
+    DCHECK_NOT_NULL(proxy);
+    proxy->var()->set_initializer_position(end_pos);
+  }
+
+  return factory()->NewClassLiteral(name, block_scope, proxy, extends,
+                                    constructor, properties, pos, end_pos);
+}
+
+
+Expression* Parser::ParseV8Intrinsic(bool* ok) {
+  // CallRuntime ::
+  //   '%' Identifier Arguments
+
+  int pos = peek_position();
+  Expect(Token::MOD, CHECK_OK);
+  // Allow "eval" or "arguments" for backward compatibility.
+  const AstRawString* name = ParseIdentifier(kAllowRestrictedIdentifiers,
+                                             CHECK_OK);
+  Scanner::Location spread_pos;
+  ExpressionClassifier classifier;
+  ZoneList<Expression*>* args =
+      ParseArguments(&spread_pos, &classifier, CHECK_OK);
+  args = RewriteNonPatternArguments(args, &classifier, CHECK_OK);
+
+  DCHECK(!spread_pos.IsValid());
+
+  if (extension_ != NULL) {
+    // The extension structures are only accessible while parsing the
+    // very first time not when reparsing because of lazy compilation.
+    scope_->DeclarationScope()->ForceEagerCompilation();
+  }
+
+  const Runtime::Function* function = Runtime::FunctionForName(name->string());
+
+  if (function != NULL) {
+    // Check for possible name clash.
+    DCHECK_EQ(Context::kNotFound,
+              Context::IntrinsicIndexForName(name->string()));
+    // Check for built-in IS_VAR macro.
+    if (function->function_id == Runtime::kIS_VAR) {
+      DCHECK_EQ(Runtime::RUNTIME, function->intrinsic_type);
+      // %IS_VAR(x) evaluates to x if x is a variable,
+      // leads to a parse error otherwise.  Could be implemented as an
+      // inline function %_IS_VAR(x) to eliminate this special case.
+      if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) {
+        return args->at(0);
+      } else {
+        ReportMessage(MessageTemplate::kNotIsvar);
+        *ok = false;
+        return NULL;
+      }
+    }
+
+    // Check that the expected number of arguments are being passed.
+    if (function->nargs != -1 && function->nargs != args->length()) {
+      ReportMessage(MessageTemplate::kIllegalAccess);
+      *ok = false;
+      return NULL;
+    }
+
+    return factory()->NewCallRuntime(function, args, pos);
+  }
+
+  int context_index = Context::IntrinsicIndexForName(name->string());
+
+  // Check that the function is defined.
+  if (context_index == Context::kNotFound) {
+    ParserTraits::ReportMessage(MessageTemplate::kNotDefined, name);
+    *ok = false;
+    return NULL;
+  }
+
+  return factory()->NewCallRuntime(context_index, args, pos);
+}
+
+
+Literal* Parser::GetLiteralUndefined(int position) {
+  return factory()->NewUndefinedLiteral(position);
+}
+
+
+void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
+  Declaration* decl = scope->CheckConflictingVarDeclarations();
+  if (decl != NULL) {
+    // In ES6, conflicting variable bindings are early errors.
+    const AstRawString* name = decl->proxy()->raw_name();
+    int position = decl->proxy()->position();
+    Scanner::Location location = position == RelocInfo::kNoPosition
+        ? Scanner::Location::invalid()
+        : Scanner::Location(position, position + 1);
+    ParserTraits::ReportMessageAt(location, MessageTemplate::kVarRedeclaration,
+                                  name);
+    *ok = false;
+  }
+}
+
+
+void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) {
+  // For each var-binding that shadows a parameter, insert an assignment
+  // initializing the variable with the parameter.
+  Scope* inner_scope = inner_block->scope();
+  DCHECK(inner_scope->is_declaration_scope());
+  Scope* function_scope = inner_scope->outer_scope();
+  DCHECK(function_scope->is_function_scope());
+  ZoneList<Declaration*>* decls = inner_scope->declarations();
+  for (int i = 0; i < decls->length(); ++i) {
+    Declaration* decl = decls->at(i);
+    if (decl->mode() != VAR || !decl->IsVariableDeclaration()) continue;
+    const AstRawString* name = decl->proxy()->raw_name();
+    Variable* parameter = function_scope->LookupLocal(name);
+    if (parameter == nullptr) continue;
+    VariableProxy* to = inner_scope->NewUnresolved(factory(), name);
+    VariableProxy* from = factory()->NewVariableProxy(parameter);
+    Expression* assignment = factory()->NewAssignment(
+        Token::ASSIGN, to, from, RelocInfo::kNoPosition);
+    Statement* statement = factory()->NewExpressionStatement(
+        assignment, RelocInfo::kNoPosition);
+    inner_block->statements()->InsertAt(0, statement, zone());
+  }
+}
+
+
+void Parser::InsertSloppyBlockFunctionVarBindings(Scope* scope, bool* ok) {
+  // For each variable which is used as a function declaration in a sloppy
+  // block,
+  DCHECK(scope->is_declaration_scope());
+  SloppyBlockFunctionMap* map = scope->sloppy_block_function_map();
+  for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
+    AstRawString* name = static_cast<AstRawString*>(p->key);
+    // If the variable wouldn't conflict with a lexical declaration,
+    Variable* var = scope->LookupLocal(name);
+    if (var == nullptr || !IsLexicalVariableMode(var->mode())) {
+      // Declare a var-style binding for the function in the outer scope
+      VariableProxy* proxy = scope->NewUnresolved(factory(), name);
+      Declaration* declaration = factory()->NewVariableDeclaration(
+          proxy, VAR, scope, RelocInfo::kNoPosition);
+      Declare(declaration, DeclarationDescriptor::NORMAL, true, ok, scope);
+      DCHECK(ok);  // Based on the preceding check, this should not fail
+      if (!ok) return;
+
+      // Write in assignments to var for each block-scoped function declaration
+      auto delegates = static_cast<SloppyBlockFunctionMap::Vector*>(p->value);
+      for (SloppyBlockFunctionStatement* delegate : *delegates) {
+        // Read from the local lexical scope and write to the function scope
+        VariableProxy* to = scope->NewUnresolved(factory(), name);
+        VariableProxy* from = delegate->scope()->NewUnresolved(factory(), name);
+        Expression* assignment = factory()->NewAssignment(
+            Token::ASSIGN, to, from, RelocInfo::kNoPosition);
+        Statement* statement = factory()->NewExpressionStatement(
+            assignment, RelocInfo::kNoPosition);
+        delegate->set_statement(statement);
+      }
+    }
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Parser support
+
+bool Parser::TargetStackContainsLabel(const AstRawString* label) {
+  for (Target* t = target_stack_; t != NULL; t = t->previous()) {
+    if (ContainsLabel(t->statement()->labels(), label)) return true;
+  }
+  return false;
+}
+
+
+BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label,
+                                              bool* ok) {
+  bool anonymous = label == NULL;
+  for (Target* t = target_stack_; t != NULL; t = t->previous()) {
+    BreakableStatement* stat = t->statement();
+    if ((anonymous && stat->is_target_for_anonymous()) ||
+        (!anonymous && ContainsLabel(stat->labels(), label))) {
+      return stat;
+    }
+  }
+  return NULL;
+}
+
+
+IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
+                                                 bool* ok) {
+  bool anonymous = label == NULL;
+  for (Target* t = target_stack_; t != NULL; t = t->previous()) {
+    IterationStatement* stat = t->statement()->AsIterationStatement();
+    if (stat == NULL) continue;
+
+    DCHECK(stat->is_target_for_anonymous());
+    if (anonymous || ContainsLabel(stat->labels(), label)) {
+      return stat;
+    }
+  }
+  return NULL;
+}
+
+
+void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) {
+  if (scanner_.source_url()->length() > 0) {
+    Handle<String> source_url = scanner_.source_url()->Internalize(isolate);
+    script->set_source_url(*source_url);
+  }
+  if (scanner_.source_mapping_url()->length() > 0) {
+    Handle<String> source_mapping_url =
+        scanner_.source_mapping_url()->Internalize(isolate);
+    script->set_source_mapping_url(*source_mapping_url);
+  }
+}
+
+
+void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) {
+  // Internalize strings.
+  ast_value_factory()->Internalize(isolate);
+
+  // Error processing.
+  if (error) {
+    if (stack_overflow()) {
+      isolate->StackOverflow();
+    } else {
+      DCHECK(pending_error_handler_.has_pending_error());
+      pending_error_handler_.ThrowPendingError(isolate, script);
+    }
+  }
+
+  // Move statistics to Isolate.
+  for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
+       ++feature) {
+    for (int i = 0; i < use_counts_[feature]; ++i) {
+      isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
+    }
+  }
+  isolate->counters()->total_preparse_skipped()->Increment(
+      total_preparse_skipped_);
+}
+
+
+// ----------------------------------------------------------------------------
+// The Parser interface.
+
+
+bool Parser::ParseStatic(ParseInfo* info) {
+  Parser parser(info);
+  if (parser.Parse(info)) {
+    info->set_language_mode(info->literal()->language_mode());
+    return true;
+  }
+  return false;
+}
+
+
+bool Parser::Parse(ParseInfo* info) {
+  DCHECK(info->literal() == NULL);
+  FunctionLiteral* result = NULL;
+  // Ok to use Isolate here; this function is only called in the main thread.
+  DCHECK(parsing_on_main_thread_);
+  Isolate* isolate = info->isolate();
+  pre_parse_timer_ = isolate->counters()->pre_parse();
+  if (FLAG_trace_parse || allow_natives() || extension_ != NULL) {
+    // If intrinsics are allowed, the Parser cannot operate independent of the
+    // V8 heap because of Runtime. Tell the string table to internalize strings
+    // and values right after they're created.
+    ast_value_factory()->Internalize(isolate);
+  }
+
+  if (info->is_lazy()) {
+    DCHECK(!info->is_eval());
+    if (info->shared_info()->is_function()) {
+      result = ParseLazy(isolate, info);
+    } else {
+      result = ParseProgram(isolate, info);
+    }
+  } else {
+    SetCachedData(info);
+    result = ParseProgram(isolate, info);
+  }
+  info->set_literal(result);
+
+  Internalize(isolate, info->script(), result == NULL);
+  DCHECK(ast_value_factory()->IsInternalized());
+  return (result != NULL);
+}
+
+
+void Parser::ParseOnBackground(ParseInfo* info) {
+  parsing_on_main_thread_ = false;
+
+  DCHECK(info->literal() == NULL);
+  FunctionLiteral* result = NULL;
+  fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
+
+  CompleteParserRecorder recorder;
+  if (produce_cached_parse_data()) log_ = &recorder;
+
+  DCHECK(info->source_stream() != NULL);
+  ExternalStreamingStream stream(info->source_stream(),
+                                 info->source_stream_encoding());
+  scanner_.Initialize(&stream);
+  DCHECK(info->context().is_null() || info->context()->IsNativeContext());
+
+  // When streaming, we don't know the length of the source until we have parsed
+  // it. The raw data can be UTF-8, so we wouldn't know the source length until
+  // we have decoded it anyway even if we knew the raw data length (which we
+  // don't). We work around this by storing all the scopes which need their end
+  // position set at the end of the script (the top scope and possible eval
+  // scopes) and set their end position after we know the script length.
+  result = DoParseProgram(info);
+
+  info->set_literal(result);
+
+  // We cannot internalize on a background thread; a foreground task will take
+  // care of calling Parser::Internalize just before compilation.
+
+  if (produce_cached_parse_data()) {
+    if (result != NULL) *info->cached_data() = recorder.GetScriptData();
+    log_ = NULL;
+  }
+}
+
+
+ParserTraits::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) {
+  return new (zone()) ParserTraits::TemplateLiteral(zone(), pos);
+}
+
+
+void Parser::AddTemplateSpan(TemplateLiteralState* state, bool tail) {
+  int pos = scanner()->location().beg_pos;
+  int end = scanner()->location().end_pos - (tail ? 1 : 2);
+  const AstRawString* tv = scanner()->CurrentSymbol(ast_value_factory());
+  const AstRawString* trv = scanner()->CurrentRawSymbol(ast_value_factory());
+  Literal* cooked = factory()->NewStringLiteral(tv, pos);
+  Literal* raw = factory()->NewStringLiteral(trv, pos);
+  (*state)->AddTemplateSpan(cooked, raw, end, zone());
+}
+
+
+void Parser::AddTemplateExpression(TemplateLiteralState* state,
+                                   Expression* expression) {
+  (*state)->AddExpression(expression, zone());
+}
+
+
+Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
+                                         Expression* tag) {
+  TemplateLiteral* lit = *state;
+  int pos = lit->position();
+  const ZoneList<Expression*>* cooked_strings = lit->cooked();
+  const ZoneList<Expression*>* raw_strings = lit->raw();
+  const ZoneList<Expression*>* expressions = lit->expressions();
+  DCHECK_EQ(cooked_strings->length(), raw_strings->length());
+  DCHECK_EQ(cooked_strings->length(), expressions->length() + 1);
+
+  if (!tag) {
+    // Build tree of BinaryOps to simplify code-generation
+    Expression* expr = cooked_strings->at(0);
+    int i = 0;
+    while (i < expressions->length()) {
+      Expression* sub = expressions->at(i++);
+      Expression* cooked_str = cooked_strings->at(i);
+
+      // Let middle be ToString(sub).
+      ZoneList<Expression*>* args =
+          new (zone()) ZoneList<Expression*>(1, zone());
+      args->Add(sub, zone());
+      Expression* middle = factory()->NewCallRuntime(Runtime::kInlineToString,
+                                                     args, sub->position());
+
+      expr = factory()->NewBinaryOperation(
+          Token::ADD, factory()->NewBinaryOperation(
+                          Token::ADD, expr, middle, expr->position()),
+          cooked_str, sub->position());
+    }
+    return expr;
+  } else {
+    uint32_t hash = ComputeTemplateLiteralHash(lit);
+
+    int cooked_idx = function_state_->NextMaterializedLiteralIndex();
+    int raw_idx = function_state_->NextMaterializedLiteralIndex();
+
+    // $getTemplateCallSite
+    ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(4, zone());
+    args->Add(factory()->NewArrayLiteral(
+                  const_cast<ZoneList<Expression*>*>(cooked_strings),
+                  cooked_idx, is_strong(language_mode()), pos),
+              zone());
+    args->Add(
+        factory()->NewArrayLiteral(
+            const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx,
+            is_strong(language_mode()), pos),
+        zone());
+
+    // Ensure hash is suitable as a Smi value
+    Smi* hash_obj = Smi::cast(Internals::IntToSmi(static_cast<int>(hash)));
+    args->Add(factory()->NewSmiLiteral(hash_obj->value(), pos), zone());
+
+    Expression* call_site = factory()->NewCallRuntime(
+        Context::GET_TEMPLATE_CALL_SITE_INDEX, args, start);
+
+    // Call TagFn
+    ZoneList<Expression*>* call_args =
+        new (zone()) ZoneList<Expression*>(expressions->length() + 1, zone());
+    call_args->Add(call_site, zone());
+    call_args->AddAll(*expressions, zone());
+    return factory()->NewCall(tag, call_args, pos);
+  }
+}
+
+
+uint32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) {
+  const ZoneList<Expression*>* raw_strings = lit->raw();
+  int total = raw_strings->length();
+  DCHECK(total);
+
+  uint32_t running_hash = 0;
+
+  for (int index = 0; index < total; ++index) {
+    if (index) {
+      running_hash = StringHasher::ComputeRunningHashOneByte(
+          running_hash, "${}", 3);
+    }
+
+    const AstRawString* raw_string =
+        raw_strings->at(index)->AsLiteral()->raw_value()->AsString();
+    if (raw_string->is_one_byte()) {
+      const char* data = reinterpret_cast<const char*>(raw_string->raw_data());
+      running_hash = StringHasher::ComputeRunningHashOneByte(
+          running_hash, data, raw_string->length());
+    } else {
+      const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data());
+      running_hash = StringHasher::ComputeRunningHash(running_hash, data,
+                                                      raw_string->length());
+    }
+  }
+
+  return running_hash;
+}
+
+
+ZoneList<v8::internal::Expression*>* Parser::PrepareSpreadArguments(
+    ZoneList<v8::internal::Expression*>* list) {
+  ZoneList<v8::internal::Expression*>* args =
+      new (zone()) ZoneList<v8::internal::Expression*>(1, zone());
+  if (list->length() == 1) {
+    // Spread-call with single spread argument produces an InternalArray
+    // containing the values from the array.
+    //
+    // Function is called or constructed with the produced array of arguments
+    //
+    // EG: Apply(Func, Spread(spread0))
+    ZoneList<Expression*>* spread_list =
+        new (zone()) ZoneList<Expression*>(0, zone());
+    spread_list->Add(list->at(0)->AsSpread()->expression(), zone());
+    args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX,
+                                        spread_list, RelocInfo::kNoPosition),
+              zone());
+    return args;
+  } else {
+    // Spread-call with multiple arguments produces array literals for each
+    // sequences of unspread arguments, and converts each spread iterable to
+    // an Internal array. Finally, all of these produced arrays are flattened
+    // into a single InternalArray, containing the arguments for the call.
+    //
+    // EG: Apply(Func, Flatten([unspread0, unspread1], Spread(spread0),
+    //                         Spread(spread1), [unspread2, unspread3]))
+    int i = 0;
+    int n = list->length();
+    while (i < n) {
+      if (!list->at(i)->IsSpread()) {
+        ZoneList<v8::internal::Expression*>* unspread =
+            new (zone()) ZoneList<v8::internal::Expression*>(1, zone());
+
+        // Push array of unspread parameters
+        while (i < n && !list->at(i)->IsSpread()) {
+          unspread->Add(list->at(i++), zone());
+        }
+        int literal_index = function_state_->NextMaterializedLiteralIndex();
+        args->Add(factory()->NewArrayLiteral(unspread, literal_index,
+                                             is_strong(language_mode()),
+                                             RelocInfo::kNoPosition),
+                  zone());
+
+        if (i == n) break;
+      }
+
+      // Push eagerly spread argument
+      ZoneList<v8::internal::Expression*>* spread_list =
+          new (zone()) ZoneList<v8::internal::Expression*>(1, zone());
+      spread_list->Add(list->at(i++)->AsSpread()->expression(), zone());
+      args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX,
+                                          spread_list, RelocInfo::kNoPosition),
+                zone());
+    }
+
+    list = new (zone()) ZoneList<v8::internal::Expression*>(1, zone());
+    list->Add(factory()->NewCallRuntime(Context::SPREAD_ARGUMENTS_INDEX, args,
+                                        RelocInfo::kNoPosition),
+              zone());
+    return list;
+  }
+  UNREACHABLE();
+}
+
+
+Expression* Parser::SpreadCall(Expression* function,
+                               ZoneList<v8::internal::Expression*>* args,
+                               int pos) {
+  if (function->IsSuperCallReference()) {
+    // Super calls
+    // $super_constructor = %_GetSuperConstructor(<this-function>)
+    // %reflect_construct($super_constructor, args, new.target)
+    ZoneList<Expression*>* tmp = new (zone()) ZoneList<Expression*>(1, zone());
+    tmp->Add(function->AsSuperCallReference()->this_function_var(), zone());
+    Expression* super_constructor = factory()->NewCallRuntime(
+        Runtime::kInlineGetSuperConstructor, tmp, pos);
+    args->InsertAt(0, super_constructor, zone());
+    args->Add(function->AsSuperCallReference()->new_target_var(), zone());
+    return factory()->NewCallRuntime(Context::REFLECT_CONSTRUCT_INDEX, args,
+                                     pos);
+  } else {
+    if (function->IsProperty()) {
+      // Method calls
+      if (function->AsProperty()->IsSuperAccess()) {
+        Expression* home =
+            ThisExpression(scope_, factory(), RelocInfo::kNoPosition);
+        args->InsertAt(0, function, zone());
+        args->InsertAt(1, home, zone());
+      } else {
+        Variable* temp =
+            scope_->NewTemporary(ast_value_factory()->empty_string());
+        VariableProxy* obj = factory()->NewVariableProxy(temp);
+        Assignment* assign_obj = factory()->NewAssignment(
+            Token::ASSIGN, obj, function->AsProperty()->obj(),
+            RelocInfo::kNoPosition);
+        function = factory()->NewProperty(
+            assign_obj, function->AsProperty()->key(), RelocInfo::kNoPosition);
+        args->InsertAt(0, function, zone());
+        obj = factory()->NewVariableProxy(temp);
+        args->InsertAt(1, obj, zone());
+      }
+    } else {
+      // Non-method calls
+      args->InsertAt(0, function, zone());
+      args->InsertAt(1, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+                     zone());
+    }
+    return factory()->NewCallRuntime(Context::REFLECT_APPLY_INDEX, args, pos);
+  }
+}
+
+
+Expression* Parser::SpreadCallNew(Expression* function,
+                                  ZoneList<v8::internal::Expression*>* args,
+                                  int pos) {
+  args->InsertAt(0, function, zone());
+
+  return factory()->NewCallRuntime(Context::REFLECT_CONSTRUCT_INDEX, args, pos);
+}
+
+
+void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) {
+  v8::Isolate::UseCounterFeature feature;
+  if (is_sloppy(mode))
+    feature = v8::Isolate::kSloppyMode;
+  else if (is_strong(mode))
+    feature = v8::Isolate::kStrongMode;
+  else if (is_strict(mode))
+    feature = v8::Isolate::kStrictMode;
+  else
+    UNREACHABLE();
+  ++use_counts_[feature];
+  scope->SetLanguageMode(mode);
+}
+
+
+void Parser::RaiseLanguageMode(LanguageMode mode) {
+  SetLanguageMode(scope_,
+                  static_cast<LanguageMode>(scope_->language_mode() | mode));
+}
+
+
+void ParserTraits::RewriteDestructuringAssignments() {
+  parser_->RewriteDestructuringAssignments();
+}
+
+
+Expression* ParserTraits::RewriteNonPattern(
+    Expression* expr, const ExpressionClassifier* classifier, bool* ok) {
+  return parser_->RewriteNonPattern(expr, classifier, ok);
+}
+
+
+ZoneList<Expression*>* ParserTraits::RewriteNonPatternArguments(
+    ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
+    bool* ok) {
+  return parser_->RewriteNonPatternArguments(args, classifier, ok);
+}
+
+
+ObjectLiteralProperty* ParserTraits::RewriteNonPatternObjectLiteralProperty(
+    ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
+    bool* ok) {
+  return parser_->RewriteNonPatternObjectLiteralProperty(property, classifier,
+                                                         ok);
+}
+
+
+Expression* Parser::RewriteNonPattern(Expression* expr,
+                                      const ExpressionClassifier* classifier,
+                                      bool* ok) {
+  // For the time being, this does no rewriting at all.
+  ValidateExpression(classifier, ok);
+  return expr;
+}
+
+
+ZoneList<Expression*>* Parser::RewriteNonPatternArguments(
+    ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
+    bool* ok) {
+  // For the time being, this does no rewriting at all.
+  ValidateExpression(classifier, ok);
+  return args;
+}
+
+
+ObjectLiteralProperty* Parser::RewriteNonPatternObjectLiteralProperty(
+    ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
+    bool* ok) {
+  if (property != nullptr) {
+    Expression* key = RewriteNonPattern(property->key(), classifier, ok);
+    property->set_key(key);
+    Expression* value = RewriteNonPattern(property->value(), classifier, ok);
+    property->set_value(value);
+  }
+  return property;
+}
+
+
+void Parser::RewriteDestructuringAssignments() {
+  FunctionState* func = function_state_;
+  if (!allow_harmony_destructuring_assignment()) return;
+  const List<DestructuringAssignment>& assignments =
+      func->destructuring_assignments_to_rewrite();
+  for (int i = assignments.length() - 1; i >= 0; --i) {
+    // Rewrite list in reverse, so that nested assignment patterns are rewritten
+    // correctly.
+    DestructuringAssignment pair = assignments.at(i);
+    RewritableAssignmentExpression* to_rewrite =
+        pair.assignment->AsRewritableAssignmentExpression();
+    Scope* scope = pair.scope;
+    DCHECK_NOT_NULL(to_rewrite);
+    if (!to_rewrite->is_rewritten()) {
+      PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope);
+    }
+  }
+}
+
+
+void ParserTraits::QueueDestructuringAssignmentForRewriting(Expression* expr) {
+  DCHECK(expr->IsRewritableAssignmentExpression());
+  parser_->function_state_->AddDestructuringAssignment(
+      Parser::DestructuringAssignment(expr, parser_->scope_));
+}
+
+
+void ParserTraits::SetFunctionNameFromPropertyName(
+    ObjectLiteralProperty* property, const AstRawString* name) {
+  Expression* value = property->value();
+  if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
+
+  // TODO(adamk): Support computed names.
+  if (property->is_computed_name()) return;
+  DCHECK_NOT_NULL(name);
+
+  // Ignore "__proto__" as a name when it's being used to set the [[Prototype]]
+  // of an object literal.
+  if (property->kind() == ObjectLiteralProperty::PROTOTYPE) return;
+
+  if (value->IsFunctionLiteral()) {
+    auto function = value->AsFunctionLiteral();
+    if (function->is_anonymous()) {
+      if (property->kind() == ObjectLiteralProperty::GETTER) {
+        function->set_raw_name(parser_->ast_value_factory()->NewConsString(
+            parser_->ast_value_factory()->get_space_string(), name));
+      } else if (property->kind() == ObjectLiteralProperty::SETTER) {
+        function->set_raw_name(parser_->ast_value_factory()->NewConsString(
+            parser_->ast_value_factory()->set_space_string(), name));
+      } else {
+        function->set_raw_name(name);
+        DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
+      }
+    }
+  } else {
+    DCHECK(value->IsClassLiteral());
+    DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
+    auto class_literal = value->AsClassLiteral();
+    if (class_literal->raw_name() == nullptr) {
+      class_literal->set_raw_name(name);
+    }
+  }
+}
+
+
+void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
+                                                    Expression* identifier) {
+  if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
+  if (!identifier->IsVariableProxy()) return;
+
+  auto name = identifier->AsVariableProxy()->raw_name();
+  DCHECK_NOT_NULL(name);
+
+  if (value->IsFunctionLiteral()) {
+    auto function = value->AsFunctionLiteral();
+    if (function->is_anonymous()) {
+      function->set_raw_name(name);
+    }
+  } else {
+    DCHECK(value->IsClassLiteral());
+    auto class_literal = value->AsClassLiteral();
+    if (class_literal->raw_name() == nullptr) {
+      class_literal->set_raw_name(name);
+    }
+  }
+}
+
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/parser.h b/src/parsing/parser.h
new file mode 100644
index 0000000..7d50221
--- /dev/null
+++ b/src/parsing/parser.h
@@ -0,0 +1,1220 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_PARSER_H_
+#define V8_PARSING_PARSER_H_
+
+#include "src/allocation.h"
+#include "src/ast/ast.h"
+#include "src/ast/scopes.h"
+#include "src/compiler.h"  // TODO(titzer): remove this include dependency
+#include "src/parsing/parser-base.h"
+#include "src/parsing/preparse-data.h"
+#include "src/parsing/preparse-data-format.h"
+#include "src/parsing/preparser.h"
+#include "src/pending-compilation-error-handler.h"
+
+namespace v8 {
+
+class ScriptCompiler;
+
+namespace internal {
+
+class Target;
+
+// A container for the inputs, configuration options, and outputs of parsing.
+class ParseInfo {
+ public:
+  explicit ParseInfo(Zone* zone);
+  ParseInfo(Zone* zone, Handle<JSFunction> function);
+  ParseInfo(Zone* zone, Handle<Script> script);
+  // TODO(all) Only used via Debug::FindSharedFunctionInfoInScript, remove?
+  ParseInfo(Zone* zone, Handle<SharedFunctionInfo> shared);
+
+  ~ParseInfo() {
+    if (ast_value_factory_owned()) {
+      delete ast_value_factory_;
+      set_ast_value_factory_owned(false);
+    }
+    ast_value_factory_ = nullptr;
+  }
+
+  Zone* zone() { return zone_; }
+
+// Convenience accessor methods for flags.
+#define FLAG_ACCESSOR(flag, getter, setter)     \
+  bool getter() const { return GetFlag(flag); } \
+  void setter() { SetFlag(flag); }              \
+  void setter(bool val) { SetFlag(flag, val); }
+
+  FLAG_ACCESSOR(kToplevel, is_toplevel, set_toplevel)
+  FLAG_ACCESSOR(kLazy, is_lazy, set_lazy)
+  FLAG_ACCESSOR(kEval, is_eval, set_eval)
+  FLAG_ACCESSOR(kGlobal, is_global, set_global)
+  FLAG_ACCESSOR(kStrictMode, is_strict_mode, set_strict_mode)
+  FLAG_ACCESSOR(kStrongMode, is_strong_mode, set_strong_mode)
+  FLAG_ACCESSOR(kNative, is_native, set_native)
+  FLAG_ACCESSOR(kModule, is_module, set_module)
+  FLAG_ACCESSOR(kAllowLazyParsing, allow_lazy_parsing, set_allow_lazy_parsing)
+  FLAG_ACCESSOR(kAstValueFactoryOwned, ast_value_factory_owned,
+                set_ast_value_factory_owned)
+
+#undef FLAG_ACCESSOR
+
+  void set_parse_restriction(ParseRestriction restriction) {
+    SetFlag(kParseRestriction, restriction != NO_PARSE_RESTRICTION);
+  }
+
+  ParseRestriction parse_restriction() const {
+    return GetFlag(kParseRestriction) ? ONLY_SINGLE_FUNCTION_LITERAL
+                                      : NO_PARSE_RESTRICTION;
+  }
+
+  ScriptCompiler::ExternalSourceStream* source_stream() {
+    return source_stream_;
+  }
+  void set_source_stream(ScriptCompiler::ExternalSourceStream* source_stream) {
+    source_stream_ = source_stream;
+  }
+
+  ScriptCompiler::StreamedSource::Encoding source_stream_encoding() {
+    return source_stream_encoding_;
+  }
+  void set_source_stream_encoding(
+      ScriptCompiler::StreamedSource::Encoding source_stream_encoding) {
+    source_stream_encoding_ = source_stream_encoding;
+  }
+
+  v8::Extension* extension() { return extension_; }
+  void set_extension(v8::Extension* extension) { extension_ = extension; }
+
+  ScriptData** cached_data() { return cached_data_; }
+  void set_cached_data(ScriptData** cached_data) { cached_data_ = cached_data; }
+
+  ScriptCompiler::CompileOptions compile_options() { return compile_options_; }
+  void set_compile_options(ScriptCompiler::CompileOptions compile_options) {
+    compile_options_ = compile_options;
+  }
+
+  Scope* script_scope() { return script_scope_; }
+  void set_script_scope(Scope* script_scope) { script_scope_ = script_scope; }
+
+  AstValueFactory* ast_value_factory() { return ast_value_factory_; }
+  void set_ast_value_factory(AstValueFactory* ast_value_factory) {
+    ast_value_factory_ = ast_value_factory;
+  }
+
+  FunctionLiteral* literal() { return literal_; }
+  void set_literal(FunctionLiteral* literal) { literal_ = literal; }
+
+  Scope* scope() { return scope_; }
+  void set_scope(Scope* scope) { scope_ = scope; }
+
+  UnicodeCache* unicode_cache() { return unicode_cache_; }
+  void set_unicode_cache(UnicodeCache* unicode_cache) {
+    unicode_cache_ = unicode_cache;
+  }
+
+  uintptr_t stack_limit() { return stack_limit_; }
+  void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
+
+  uint32_t hash_seed() { return hash_seed_; }
+  void set_hash_seed(uint32_t hash_seed) { hash_seed_ = hash_seed; }
+
+  //--------------------------------------------------------------------------
+  // TODO(titzer): these should not be part of ParseInfo.
+  //--------------------------------------------------------------------------
+  Isolate* isolate() { return isolate_; }
+  Handle<JSFunction> closure() { return closure_; }
+  Handle<SharedFunctionInfo> shared_info() { return shared_; }
+  Handle<Script> script() { return script_; }
+  Handle<Context> context() { return context_; }
+  void clear_script() { script_ = Handle<Script>::null(); }
+  void set_isolate(Isolate* isolate) { isolate_ = isolate; }
+  void set_context(Handle<Context> context) { context_ = context; }
+  void set_script(Handle<Script> script) { script_ = script; }
+  //--------------------------------------------------------------------------
+
+  LanguageMode language_mode() {
+    return construct_language_mode(is_strict_mode(), is_strong_mode());
+  }
+  void set_language_mode(LanguageMode language_mode) {
+    STATIC_ASSERT(LANGUAGE_END == 3);
+    set_strict_mode(language_mode & STRICT_BIT);
+    set_strong_mode(language_mode & STRONG_BIT);
+  }
+
+  void ReopenHandlesInNewHandleScope() {
+    closure_ = Handle<JSFunction>(*closure_);
+    shared_ = Handle<SharedFunctionInfo>(*shared_);
+    script_ = Handle<Script>(*script_);
+    context_ = Handle<Context>(*context_);
+  }
+
+#ifdef DEBUG
+  bool script_is_native() { return script_->type() == Script::TYPE_NATIVE; }
+#endif  // DEBUG
+
+ private:
+  // Various configuration flags for parsing.
+  enum Flag {
+    // ---------- Input flags ---------------------------
+    kToplevel = 1 << 0,
+    kLazy = 1 << 1,
+    kEval = 1 << 2,
+    kGlobal = 1 << 3,
+    kStrictMode = 1 << 4,
+    kStrongMode = 1 << 5,
+    kNative = 1 << 6,
+    kParseRestriction = 1 << 7,
+    kModule = 1 << 8,
+    kAllowLazyParsing = 1 << 9,
+    // ---------- Output flags --------------------------
+    kAstValueFactoryOwned = 1 << 10
+  };
+
+  //------------- Inputs to parsing and scope analysis -----------------------
+  Zone* zone_;
+  unsigned flags_;
+  ScriptCompiler::ExternalSourceStream* source_stream_;
+  ScriptCompiler::StreamedSource::Encoding source_stream_encoding_;
+  v8::Extension* extension_;
+  ScriptCompiler::CompileOptions compile_options_;
+  Scope* script_scope_;
+  UnicodeCache* unicode_cache_;
+  uintptr_t stack_limit_;
+  uint32_t hash_seed_;
+
+  // TODO(titzer): Move handles and isolate out of ParseInfo.
+  Isolate* isolate_;
+  Handle<JSFunction> closure_;
+  Handle<SharedFunctionInfo> shared_;
+  Handle<Script> script_;
+  Handle<Context> context_;
+
+  //----------- Inputs+Outputs of parsing and scope analysis -----------------
+  ScriptData** cached_data_;  // used if available, populated if requested.
+  AstValueFactory* ast_value_factory_;  // used if available, otherwise new.
+
+  //----------- Outputs of parsing and scope analysis ------------------------
+  FunctionLiteral* literal_;  // produced by full parser.
+  Scope* scope_;              // produced by scope analysis.
+
+  void SetFlag(Flag f) { flags_ |= f; }
+  void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; }
+  bool GetFlag(Flag f) const { return (flags_ & f) != 0; }
+
+  void set_shared_info(Handle<SharedFunctionInfo> shared) { shared_ = shared; }
+  void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
+};
+
+class FunctionEntry BASE_EMBEDDED {
+ public:
+  enum {
+    kStartPositionIndex,
+    kEndPositionIndex,
+    kLiteralCountIndex,
+    kPropertyCountIndex,
+    kLanguageModeIndex,
+    kUsesSuperPropertyIndex,
+    kCallsEvalIndex,
+    kSize
+  };
+
+  explicit FunctionEntry(Vector<unsigned> backing)
+    : backing_(backing) { }
+
+  FunctionEntry() : backing_() { }
+
+  int start_pos() { return backing_[kStartPositionIndex]; }
+  int end_pos() { return backing_[kEndPositionIndex]; }
+  int literal_count() { return backing_[kLiteralCountIndex]; }
+  int property_count() { return backing_[kPropertyCountIndex]; }
+  LanguageMode language_mode() {
+    DCHECK(is_valid_language_mode(backing_[kLanguageModeIndex]));
+    return static_cast<LanguageMode>(backing_[kLanguageModeIndex]);
+  }
+  bool uses_super_property() { return backing_[kUsesSuperPropertyIndex]; }
+  bool calls_eval() { return backing_[kCallsEvalIndex]; }
+
+  bool is_valid() { return !backing_.is_empty(); }
+
+ private:
+  Vector<unsigned> backing_;
+};
+
+
+// Wrapper around ScriptData to provide parser-specific functionality.
+class ParseData {
+ public:
+  static ParseData* FromCachedData(ScriptData* cached_data) {
+    ParseData* pd = new ParseData(cached_data);
+    if (pd->IsSane()) return pd;
+    cached_data->Reject();
+    delete pd;
+    return NULL;
+  }
+
+  void Initialize();
+  FunctionEntry GetFunctionEntry(int start);
+  int FunctionCount();
+
+  bool HasError();
+
+  unsigned* Data() {  // Writable data as unsigned int array.
+    return reinterpret_cast<unsigned*>(const_cast<byte*>(script_data_->data()));
+  }
+
+  void Reject() { script_data_->Reject(); }
+
+  bool rejected() const { return script_data_->rejected(); }
+
+ private:
+  explicit ParseData(ScriptData* script_data) : script_data_(script_data) {}
+
+  bool IsSane();
+  unsigned Magic();
+  unsigned Version();
+  int FunctionsSize();
+  int Length() const {
+    // Script data length is already checked to be a multiple of unsigned size.
+    return script_data_->length() / sizeof(unsigned);
+  }
+
+  ScriptData* script_data_;
+  int function_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(ParseData);
+};
+
+// ----------------------------------------------------------------------------
+// JAVASCRIPT PARSING
+
+class Parser;
+class SingletonLogger;
+
+
+struct ParserFormalParameters : FormalParametersBase {
+  struct Parameter {
+    Parameter(const AstRawString* name, Expression* pattern,
+              Expression* initializer, int initializer_end_position,
+              bool is_rest)
+        : name(name),
+          pattern(pattern),
+          initializer(initializer),
+          initializer_end_position(initializer_end_position),
+          is_rest(is_rest) {}
+    const AstRawString* name;
+    Expression* pattern;
+    Expression* initializer;
+    int initializer_end_position;
+    bool is_rest;
+    bool is_simple() const {
+      return pattern->IsVariableProxy() && initializer == nullptr && !is_rest;
+    }
+  };
+
+  explicit ParserFormalParameters(Scope* scope)
+      : FormalParametersBase(scope), params(4, scope->zone()) {}
+  ZoneList<Parameter> params;
+
+  int Arity() const { return params.length(); }
+  const Parameter& at(int i) const { return params[i]; }
+};
+
+
+class ParserTraits {
+ public:
+  struct Type {
+    // TODO(marja): To be removed. The Traits object should contain all the data
+    // it needs.
+    typedef v8::internal::Parser* Parser;
+
+    typedef Variable GeneratorVariable;
+
+    typedef v8::internal::AstProperties AstProperties;
+
+    // Return types for traversing functions.
+    typedef const AstRawString* Identifier;
+    typedef v8::internal::Expression* Expression;
+    typedef Yield* YieldExpression;
+    typedef v8::internal::FunctionLiteral* FunctionLiteral;
+    typedef v8::internal::ClassLiteral* ClassLiteral;
+    typedef v8::internal::Literal* Literal;
+    typedef ObjectLiteral::Property* ObjectLiteralProperty;
+    typedef ZoneList<v8::internal::Expression*>* ExpressionList;
+    typedef ZoneList<ObjectLiteral::Property*>* PropertyList;
+    typedef ParserFormalParameters::Parameter FormalParameter;
+    typedef ParserFormalParameters FormalParameters;
+    typedef ZoneList<v8::internal::Statement*>* StatementList;
+
+    // For constructing objects returned by the traversing functions.
+    typedef AstNodeFactory Factory;
+  };
+
+  explicit ParserTraits(Parser* parser) : parser_(parser) {}
+
+  // Helper functions for recursive descent.
+  bool IsEval(const AstRawString* identifier) const;
+  bool IsArguments(const AstRawString* identifier) const;
+  bool IsEvalOrArguments(const AstRawString* identifier) const;
+  bool IsUndefined(const AstRawString* identifier) const;
+  V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
+
+  // Returns true if the expression is of type "this.foo".
+  static bool IsThisProperty(Expression* expression);
+
+  static bool IsIdentifier(Expression* expression);
+
+  bool IsPrototype(const AstRawString* identifier) const;
+
+  bool IsConstructor(const AstRawString* identifier) const;
+
+  static const AstRawString* AsIdentifier(Expression* expression) {
+    DCHECK(IsIdentifier(expression));
+    return expression->AsVariableProxy()->raw_name();
+  }
+
+  static bool IsBoilerplateProperty(ObjectLiteral::Property* property) {
+    return ObjectLiteral::IsBoilerplateProperty(property);
+  }
+
+  static bool IsArrayIndex(const AstRawString* string, uint32_t* index) {
+    return string->AsArrayIndex(index);
+  }
+
+  static Expression* GetPropertyValue(ObjectLiteral::Property* property) {
+    return property->value();
+  }
+
+  // Functions for encapsulating the differences between parsing and preparsing;
+  // operations interleaved with the recursive descent.
+  static void PushLiteralName(FuncNameInferrer* fni, const AstRawString* id) {
+    fni->PushLiteralName(id);
+  }
+
+  void PushPropertyName(FuncNameInferrer* fni, Expression* expression);
+
+  static void InferFunctionName(FuncNameInferrer* fni,
+                                FunctionLiteral* func_to_infer) {
+    fni->AddFunction(func_to_infer);
+  }
+
+  static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
+      Scope* scope, ObjectLiteralProperty* property, bool* has_function) {
+    Expression* value = property->value();
+    if (scope->DeclarationScope()->is_script_scope() &&
+        value->AsFunctionLiteral() != NULL) {
+      *has_function = true;
+      value->AsFunctionLiteral()->set_pretenure();
+    }
+  }
+
+  // If we assign a function literal to a property we pretenure the
+  // literal so it can be added as a constant function property.
+  static void CheckAssigningFunctionLiteralToProperty(Expression* left,
+                                                      Expression* right);
+
+  // Determine if the expression is a variable proxy and mark it as being used
+  // in an assignment or with a increment/decrement operator.
+  static Expression* MarkExpressionAsAssigned(Expression* expression);
+
+  // Returns true if we have a binary expression between two numeric
+  // literals. In that case, *x will be changed to an expression which is the
+  // computed value.
+  bool ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y,
+                                              Token::Value op, int pos,
+                                              AstNodeFactory* factory);
+
+  // Rewrites the following types of unary expressions:
+  // not <literal> -> true / false
+  // + <numeric literal> -> <numeric literal>
+  // - <numeric literal> -> <numeric literal with value negated>
+  // ! <literal> -> true / false
+  // The following rewriting rules enable the collection of type feedback
+  // without any special stub and the multiplication is removed later in
+  // Crankshaft's canonicalization pass.
+  // + foo -> foo * 1
+  // - foo -> foo * (-1)
+  // ~ foo -> foo ^(~0)
+  Expression* BuildUnaryExpression(Expression* expression, Token::Value op,
+                                   int pos, AstNodeFactory* factory);
+
+  // Generate AST node that throws a ReferenceError with the given type.
+  Expression* NewThrowReferenceError(MessageTemplate::Template message,
+                                     int pos);
+
+  // Generate AST node that throws a SyntaxError with the given
+  // type. The first argument may be null (in the handle sense) in
+  // which case no arguments are passed to the constructor.
+  Expression* NewThrowSyntaxError(MessageTemplate::Template message,
+                                  const AstRawString* arg, int pos);
+
+  // Generate AST node that throws a TypeError with the given
+  // type. Both arguments must be non-null (in the handle sense).
+  Expression* NewThrowTypeError(MessageTemplate::Template message,
+                                const AstRawString* arg, int pos);
+
+  // Generic AST generator for throwing errors from compiled code.
+  Expression* NewThrowError(Runtime::FunctionId function_id,
+                            MessageTemplate::Template message,
+                            const AstRawString* arg, int pos);
+
+  // Reporting errors.
+  void ReportMessageAt(Scanner::Location source_location,
+                       MessageTemplate::Template message,
+                       const char* arg = NULL,
+                       ParseErrorType error_type = kSyntaxError);
+  void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
+                     ParseErrorType error_type = kSyntaxError);
+  void ReportMessage(MessageTemplate::Template message, const AstRawString* arg,
+                     ParseErrorType error_type = kSyntaxError);
+  void ReportMessageAt(Scanner::Location source_location,
+                       MessageTemplate::Template message,
+                       const AstRawString* arg,
+                       ParseErrorType error_type = kSyntaxError);
+
+  // "null" return type creators.
+  static const AstRawString* EmptyIdentifier() {
+    return NULL;
+  }
+  static Expression* EmptyExpression() {
+    return NULL;
+  }
+  static Literal* EmptyLiteral() {
+    return NULL;
+  }
+  static ObjectLiteralProperty* EmptyObjectLiteralProperty() { return NULL; }
+  static FunctionLiteral* EmptyFunctionLiteral() { return NULL; }
+
+  // Used in error return values.
+  static ZoneList<Expression*>* NullExpressionList() {
+    return NULL;
+  }
+  static const AstRawString* EmptyFormalParameter() { return NULL; }
+
+  // Non-NULL empty string.
+  V8_INLINE const AstRawString* EmptyIdentifierString();
+
+  // Odd-ball literal creators.
+  Literal* GetLiteralTheHole(int position, AstNodeFactory* factory);
+
+  // Producing data during the recursive descent.
+  const AstRawString* GetSymbol(Scanner* scanner);
+  const AstRawString* GetNextSymbol(Scanner* scanner);
+  const AstRawString* GetNumberAsSymbol(Scanner* scanner);
+
+  Expression* ThisExpression(Scope* scope, AstNodeFactory* factory,
+                             int pos = RelocInfo::kNoPosition);
+  Expression* SuperPropertyReference(Scope* scope, AstNodeFactory* factory,
+                                     int pos);
+  Expression* SuperCallReference(Scope* scope, AstNodeFactory* factory,
+                                 int pos);
+  Expression* NewTargetExpression(Scope* scope, AstNodeFactory* factory,
+                                  int pos);
+  Expression* DefaultConstructor(bool call_super, Scope* scope, int pos,
+                                 int end_pos, LanguageMode language_mode);
+  Literal* ExpressionFromLiteral(Token::Value token, int pos, Scanner* scanner,
+                                 AstNodeFactory* factory);
+  Expression* ExpressionFromIdentifier(const AstRawString* name,
+                                       int start_position, int end_position,
+                                       Scope* scope, AstNodeFactory* factory);
+  Expression* ExpressionFromString(int pos, Scanner* scanner,
+                                   AstNodeFactory* factory);
+  Expression* GetIterator(Expression* iterable, AstNodeFactory* factory,
+                          int pos);
+  ZoneList<v8::internal::Expression*>* NewExpressionList(int size, Zone* zone) {
+    return new(zone) ZoneList<v8::internal::Expression*>(size, zone);
+  }
+  ZoneList<ObjectLiteral::Property*>* NewPropertyList(int size, Zone* zone) {
+    return new(zone) ZoneList<ObjectLiteral::Property*>(size, zone);
+  }
+  ZoneList<v8::internal::Statement*>* NewStatementList(int size, Zone* zone) {
+    return new(zone) ZoneList<v8::internal::Statement*>(size, zone);
+  }
+
+  V8_INLINE void AddParameterInitializationBlock(
+      const ParserFormalParameters& parameters,
+      ZoneList<v8::internal::Statement*>* body, bool* ok);
+
+  V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
+                            FunctionKind kind = kNormalFunction);
+
+  V8_INLINE void AddFormalParameter(ParserFormalParameters* parameters,
+                                    Expression* pattern,
+                                    Expression* initializer,
+                                    int initializer_end_position, bool is_rest);
+  V8_INLINE void DeclareFormalParameter(
+      Scope* scope, const ParserFormalParameters::Parameter& parameter,
+      ExpressionClassifier* classifier);
+  void ParseArrowFunctionFormalParameters(ParserFormalParameters* parameters,
+                                          Expression* params,
+                                          const Scanner::Location& params_loc,
+                                          bool* ok);
+  void ParseArrowFunctionFormalParameterList(
+      ParserFormalParameters* parameters, Expression* params,
+      const Scanner::Location& params_loc,
+      Scanner::Location* duplicate_loc, bool* ok);
+
+  V8_INLINE DoExpression* ParseDoExpression(bool* ok);
+
+  void ReindexLiterals(const ParserFormalParameters& parameters);
+
+  // Temporary glue; these functions will move to ParserBase.
+  Expression* ParseV8Intrinsic(bool* ok);
+  FunctionLiteral* ParseFunctionLiteral(
+      const AstRawString* name, Scanner::Location function_name_location,
+      FunctionNameValidity function_name_validity, FunctionKind kind,
+      int function_token_position, FunctionLiteral::FunctionType type,
+      FunctionLiteral::ArityRestriction arity_restriction,
+      LanguageMode language_mode, bool* ok);
+  V8_INLINE void SkipLazyFunctionBody(
+      int* materialized_literal_count, int* expected_property_count, bool* ok,
+      Scanner::BookmarkScope* bookmark = nullptr);
+  V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
+      const AstRawString* name, int pos,
+      const ParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
+
+  ClassLiteral* ParseClassLiteral(const AstRawString* name,
+                                  Scanner::Location class_name_location,
+                                  bool name_is_strict_reserved, int pos,
+                                  bool* ok);
+
+  V8_INLINE void CheckConflictingVarDeclarations(v8::internal::Scope* scope,
+                                                 bool* ok);
+
+  class TemplateLiteral : public ZoneObject {
+   public:
+    TemplateLiteral(Zone* zone, int pos)
+        : cooked_(8, zone), raw_(8, zone), expressions_(8, zone), pos_(pos) {}
+
+    const ZoneList<Expression*>* cooked() const { return &cooked_; }
+    const ZoneList<Expression*>* raw() const { return &raw_; }
+    const ZoneList<Expression*>* expressions() const { return &expressions_; }
+    int position() const { return pos_; }
+
+    void AddTemplateSpan(Literal* cooked, Literal* raw, int end, Zone* zone) {
+      DCHECK_NOT_NULL(cooked);
+      DCHECK_NOT_NULL(raw);
+      cooked_.Add(cooked, zone);
+      raw_.Add(raw, zone);
+    }
+
+    void AddExpression(Expression* expression, Zone* zone) {
+      DCHECK_NOT_NULL(expression);
+      expressions_.Add(expression, zone);
+    }
+
+   private:
+    ZoneList<Expression*> cooked_;
+    ZoneList<Expression*> raw_;
+    ZoneList<Expression*> expressions_;
+    int pos_;
+  };
+
+  typedef TemplateLiteral* TemplateLiteralState;
+
+  V8_INLINE TemplateLiteralState OpenTemplateLiteral(int pos);
+  V8_INLINE void AddTemplateSpan(TemplateLiteralState* state, bool tail);
+  V8_INLINE void AddTemplateExpression(TemplateLiteralState* state,
+                                       Expression* expression);
+  V8_INLINE Expression* CloseTemplateLiteral(TemplateLiteralState* state,
+                                             int start, Expression* tag);
+  V8_INLINE Expression* NoTemplateTag() { return NULL; }
+  V8_INLINE static bool IsTaggedTemplate(const Expression* tag) {
+    return tag != NULL;
+  }
+
+  V8_INLINE ZoneList<v8::internal::Expression*>* PrepareSpreadArguments(
+      ZoneList<v8::internal::Expression*>* list);
+  V8_INLINE void MaterializeUnspreadArgumentsLiterals(int count) {}
+  V8_INLINE Expression* SpreadCall(Expression* function,
+                                   ZoneList<v8::internal::Expression*>* args,
+                                   int pos);
+  V8_INLINE Expression* SpreadCallNew(Expression* function,
+                                      ZoneList<v8::internal::Expression*>* args,
+                                      int pos);
+
+  // Rewrite all DestructuringAssignments in the current FunctionState.
+  V8_INLINE void RewriteDestructuringAssignments();
+
+  V8_INLINE void QueueDestructuringAssignmentForRewriting(
+      Expression* assignment);
+
+  void SetFunctionNameFromPropertyName(ObjectLiteralProperty* property,
+                                       const AstRawString* name);
+
+  void SetFunctionNameFromIdentifierRef(Expression* value,
+                                        Expression* identifier);
+
+  // Rewrite expressions that are not used as patterns
+  V8_INLINE Expression* RewriteNonPattern(
+      Expression* expr, const ExpressionClassifier* classifier, bool* ok);
+  V8_INLINE ZoneList<Expression*>* RewriteNonPatternArguments(
+      ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
+      bool* ok);
+  V8_INLINE ObjectLiteralProperty* RewriteNonPatternObjectLiteralProperty(
+      ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
+      bool* ok);
+
+ private:
+  Parser* parser_;
+};
+
+
+class Parser : public ParserBase<ParserTraits> {
+ public:
+  explicit Parser(ParseInfo* info);
+  ~Parser() {
+    delete reusable_preparser_;
+    reusable_preparser_ = NULL;
+    delete cached_parse_data_;
+    cached_parse_data_ = NULL;
+  }
+
+  // Parses the source code represented by the compilation info and sets its
+  // function literal.  Returns false (and deallocates any allocated AST
+  // nodes) if parsing failed.
+  static bool ParseStatic(ParseInfo* info);
+  bool Parse(ParseInfo* info);
+  void ParseOnBackground(ParseInfo* info);
+
+  // Handle errors detected during parsing, move statistics to Isolate,
+  // internalize strings (move them to the heap).
+  void Internalize(Isolate* isolate, Handle<Script> script, bool error);
+  void HandleSourceURLComments(Isolate* isolate, Handle<Script> script);
+
+ private:
+  friend class ParserTraits;
+
+  // Limit the allowed number of local variables in a function. The hard limit
+  // is that offsets computed by FullCodeGenerator::StackOperand and similar
+  // functions are ints, and they should not overflow. In addition, accessing
+  // local variables creates user-controlled constants in the generated code,
+  // and we don't want too much user-controlled memory inside the code (this was
+  // the reason why this limit was introduced in the first place; see
+  // https://codereview.chromium.org/7003030/ ).
+  static const int kMaxNumFunctionLocals = 4194303;  // 2^22-1
+
+  // Returns NULL if parsing failed.
+  FunctionLiteral* ParseProgram(Isolate* isolate, ParseInfo* info);
+
+  FunctionLiteral* ParseLazy(Isolate* isolate, ParseInfo* info);
+  FunctionLiteral* ParseLazy(Isolate* isolate, ParseInfo* info,
+                             Utf16CharacterStream* source);
+
+  // Called by ParseProgram after setting up the scanner.
+  FunctionLiteral* DoParseProgram(ParseInfo* info);
+
+  void SetCachedData(ParseInfo* info);
+
+  ScriptCompiler::CompileOptions compile_options() const {
+    return compile_options_;
+  }
+  bool consume_cached_parse_data() const {
+    return compile_options_ == ScriptCompiler::kConsumeParserCache &&
+           cached_parse_data_ != NULL;
+  }
+  bool produce_cached_parse_data() const {
+    return compile_options_ == ScriptCompiler::kProduceParserCache;
+  }
+
+  // All ParseXXX functions take as the last argument an *ok parameter
+  // which is set to false if parsing failed; it is unchanged otherwise.
+  // By making the 'exception handling' explicit, we are forced to check
+  // for failure at the call sites.
+  void* ParseStatementList(ZoneList<Statement*>* body, int end_token, bool* ok);
+  Statement* ParseStatementListItem(bool* ok);
+  void* ParseModuleItemList(ZoneList<Statement*>* body, bool* ok);
+  Statement* ParseModuleItem(bool* ok);
+  const AstRawString* ParseModuleSpecifier(bool* ok);
+  Statement* ParseImportDeclaration(bool* ok);
+  Statement* ParseExportDeclaration(bool* ok);
+  Statement* ParseExportDefault(bool* ok);
+  void* ParseExportClause(ZoneList<const AstRawString*>* export_names,
+                          ZoneList<Scanner::Location>* export_locations,
+                          ZoneList<const AstRawString*>* local_names,
+                          Scanner::Location* reserved_loc, bool* ok);
+  ZoneList<ImportDeclaration*>* ParseNamedImports(int pos, bool* ok);
+  Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
+  Statement* ParseSubStatement(ZoneList<const AstRawString*>* labels, bool* ok);
+  Statement* ParseStatementAsUnlabelled(ZoneList<const AstRawString*>* labels,
+                                   bool* ok);
+  Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
+                                      bool* ok);
+  Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
+                                   bool* ok);
+  Statement* ParseNativeDeclaration(bool* ok);
+  Block* ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok);
+  Block* ParseBlock(ZoneList<const AstRawString*>* labels,
+                    bool finalize_block_scope, bool* ok);
+  Block* ParseVariableStatement(VariableDeclarationContext var_context,
+                                ZoneList<const AstRawString*>* names,
+                                bool* ok);
+  DoExpression* ParseDoExpression(bool* ok);
+
+  struct DeclarationDescriptor {
+    enum Kind { NORMAL, PARAMETER };
+    Parser* parser;
+    Scope* scope;
+    Scope* hoist_scope;
+    VariableMode mode;
+    bool needs_init;
+    int declaration_pos;
+    int initialization_pos;
+    Kind declaration_kind;
+  };
+
+  struct DeclarationParsingResult {
+    struct Declaration {
+      Declaration(Expression* pattern, int initializer_position,
+                  Expression* initializer)
+          : pattern(pattern),
+            initializer_position(initializer_position),
+            initializer(initializer) {}
+
+      Expression* pattern;
+      int initializer_position;
+      Expression* initializer;
+    };
+
+    DeclarationParsingResult()
+        : declarations(4),
+          first_initializer_loc(Scanner::Location::invalid()),
+          bindings_loc(Scanner::Location::invalid()) {}
+
+    Block* BuildInitializationBlock(ZoneList<const AstRawString*>* names,
+                                    bool* ok);
+
+    DeclarationDescriptor descriptor;
+    List<Declaration> declarations;
+    Scanner::Location first_initializer_loc;
+    Scanner::Location bindings_loc;
+  };
+
+  class PatternRewriter : private AstVisitor {
+   public:
+    static void DeclareAndInitializeVariables(
+        Block* block, const DeclarationDescriptor* declaration_descriptor,
+        const DeclarationParsingResult::Declaration* declaration,
+        ZoneList<const AstRawString*>* names, bool* ok);
+
+    static void RewriteDestructuringAssignment(
+        Parser* parser, RewritableAssignmentExpression* expr, Scope* Scope);
+
+    static Expression* RewriteDestructuringAssignment(Parser* parser,
+                                                      Assignment* assignment,
+                                                      Scope* scope);
+
+    void set_initializer_position(int pos) { initializer_position_ = pos; }
+
+   private:
+    PatternRewriter() {}
+
+#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node) override;
+    // Visiting functions for AST nodes make this an AstVisitor.
+    AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+    void Visit(AstNode* node) override;
+
+    enum PatternContext {
+      BINDING,
+      INITIALIZER,
+      ASSIGNMENT,
+      ASSIGNMENT_INITIALIZER
+    };
+
+    PatternContext context() const { return context_; }
+    void set_context(PatternContext context) { context_ = context; }
+
+    void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
+      Expression* old_value = current_value_;
+      current_value_ = value;
+      recursion_level_++;
+      pattern->Accept(this);
+      recursion_level_--;
+      current_value_ = old_value;
+    }
+
+    void VisitObjectLiteral(ObjectLiteral* node, Variable** temp_var);
+    void VisitArrayLiteral(ArrayLiteral* node, Variable** temp_var);
+
+    bool IsBindingContext() const { return IsBindingContext(context_); }
+    bool IsInitializerContext() const { return context_ != ASSIGNMENT; }
+    bool IsAssignmentContext() const { return IsAssignmentContext(context_); }
+    bool IsAssignmentContext(PatternContext c) const;
+    bool IsBindingContext(PatternContext c) const;
+    bool IsSubPattern() const { return recursion_level_ > 1; }
+    PatternContext SetAssignmentContextIfNeeded(Expression* node);
+    PatternContext SetInitializerContextIfNeeded(Expression* node);
+
+    Variable* CreateTempVar(Expression* value = nullptr);
+
+    AstNodeFactory* factory() const { return parser_->factory(); }
+    AstValueFactory* ast_value_factory() const {
+      return parser_->ast_value_factory();
+    }
+    Zone* zone() const { return parser_->zone(); }
+    Scope* scope() const { return scope_; }
+
+    Scope* scope_;
+    Parser* parser_;
+    PatternContext context_;
+    Expression* pattern_;
+    int initializer_position_;
+    Block* block_;
+    const DeclarationDescriptor* descriptor_;
+    ZoneList<const AstRawString*>* names_;
+    Expression* current_value_;
+    int recursion_level_;
+    bool* ok_;
+  };
+
+
+  void ParseVariableDeclarations(VariableDeclarationContext var_context,
+                                 DeclarationParsingResult* parsing_result,
+                                 bool* ok);
+  Statement* ParseExpressionOrLabelledStatement(
+      ZoneList<const AstRawString*>* labels, bool* ok);
+  IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels,
+                                bool* ok);
+  Statement* ParseContinueStatement(bool* ok);
+  Statement* ParseBreakStatement(ZoneList<const AstRawString*>* labels,
+                                 bool* ok);
+  Statement* ParseReturnStatement(bool* ok);
+  Statement* ParseWithStatement(ZoneList<const AstRawString*>* labels,
+                                bool* ok);
+  CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
+  Statement* ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
+                                  bool* ok);
+  DoWhileStatement* ParseDoWhileStatement(ZoneList<const AstRawString*>* labels,
+                                          bool* ok);
+  WhileStatement* ParseWhileStatement(ZoneList<const AstRawString*>* labels,
+                                      bool* ok);
+  Statement* ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
+  Statement* ParseThrowStatement(bool* ok);
+  Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
+  TryStatement* ParseTryStatement(bool* ok);
+  DebuggerStatement* ParseDebuggerStatement(bool* ok);
+
+  // !%_IsJSReceiver(result = iterator.next()) &&
+  //     %ThrowIteratorResultNotAnObject(result)
+  Expression* BuildIteratorNextResult(Expression* iterator, Variable* result,
+                                      int pos);
+
+
+  // Initialize the components of a for-in / for-of statement.
+  void InitializeForEachStatement(ForEachStatement* stmt, Expression* each,
+                                  Expression* subject, Statement* body,
+                                  bool is_destructuring);
+  Statement* DesugarLexicalBindingsInForStatement(
+      Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
+      ForStatement* loop, Statement* init, Expression* cond, Statement* next,
+      Statement* body, bool* ok);
+
+  void RewriteDoExpression(Expression* expr, bool* ok);
+
+  FunctionLiteral* ParseFunctionLiteral(
+      const AstRawString* name, Scanner::Location function_name_location,
+      FunctionNameValidity function_name_validity, FunctionKind kind,
+      int function_token_position, FunctionLiteral::FunctionType type,
+      FunctionLiteral::ArityRestriction arity_restriction,
+      LanguageMode language_mode, bool* ok);
+
+
+  ClassLiteral* ParseClassLiteral(const AstRawString* name,
+                                  Scanner::Location class_name_location,
+                                  bool name_is_strict_reserved, int pos,
+                                  bool* ok);
+
+  // Magical syntax support.
+  Expression* ParseV8Intrinsic(bool* ok);
+
+  // Get odd-ball literals.
+  Literal* GetLiteralUndefined(int position);
+
+  // Check if the scope has conflicting var/let declarations from different
+  // scopes. This covers for example
+  //
+  // function f() { { { var x; } let x; } }
+  // function g() { { var x; let x; } }
+  //
+  // The var declarations are hoisted to the function scope, but originate from
+  // a scope where the name has also been let bound or the var declaration is
+  // hoisted over such a scope.
+  void CheckConflictingVarDeclarations(Scope* scope, bool* ok);
+
+  // Insert initializer statements for var-bindings shadowing parameter bindings
+  // from a non-simple parameter list.
+  void InsertShadowingVarBindingInitializers(Block* block);
+
+  // Implement sloppy block-scoped functions, ES2015 Annex B 3.3
+  void InsertSloppyBlockFunctionVarBindings(Scope* scope, bool* ok);
+
+  // Parser support
+  VariableProxy* NewUnresolved(const AstRawString* name, VariableMode mode);
+  Variable* Declare(Declaration* declaration,
+                    DeclarationDescriptor::Kind declaration_kind, bool resolve,
+                    bool* ok, Scope* declaration_scope = nullptr);
+
+  bool TargetStackContainsLabel(const AstRawString* label);
+  BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
+  IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
+
+  Statement* BuildAssertIsCoercible(Variable* var);
+
+  // Factory methods.
+  FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos,
+                                      int end_pos, LanguageMode language_mode);
+
+  // Skip over a lazy function, either using cached data if we have it, or
+  // by parsing the function with PreParser. Consumes the ending }.
+  //
+  // If bookmark is set, the (pre-)parser may decide to abort skipping
+  // in order to force the function to be eagerly parsed, after all.
+  // In this case, it'll reset the scanner using the bookmark.
+  void SkipLazyFunctionBody(int* materialized_literal_count,
+                            int* expected_property_count, bool* ok,
+                            Scanner::BookmarkScope* bookmark = nullptr);
+
+  PreParser::PreParseResult ParseLazyFunctionBodyWithPreParser(
+      SingletonLogger* logger, Scanner::BookmarkScope* bookmark = nullptr);
+
+  Block* BuildParameterInitializationBlock(
+      const ParserFormalParameters& parameters, bool* ok);
+
+  // Consumes the ending }.
+  ZoneList<Statement*>* ParseEagerFunctionBody(
+      const AstRawString* function_name, int pos,
+      const ParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
+
+  void ThrowPendingError(Isolate* isolate, Handle<Script> script);
+
+  TemplateLiteralState OpenTemplateLiteral(int pos);
+  void AddTemplateSpan(TemplateLiteralState* state, bool tail);
+  void AddTemplateExpression(TemplateLiteralState* state,
+                             Expression* expression);
+  Expression* CloseTemplateLiteral(TemplateLiteralState* state, int start,
+                                   Expression* tag);
+  uint32_t ComputeTemplateLiteralHash(const TemplateLiteral* lit);
+
+  ZoneList<v8::internal::Expression*>* PrepareSpreadArguments(
+      ZoneList<v8::internal::Expression*>* list);
+  Expression* SpreadCall(Expression* function,
+                         ZoneList<v8::internal::Expression*>* args, int pos);
+  Expression* SpreadCallNew(Expression* function,
+                            ZoneList<v8::internal::Expression*>* args, int pos);
+
+  void SetLanguageMode(Scope* scope, LanguageMode mode);
+  void RaiseLanguageMode(LanguageMode mode);
+
+  V8_INLINE void RewriteDestructuringAssignments();
+
+  V8_INLINE Expression* RewriteNonPattern(
+      Expression* expr, const ExpressionClassifier* classifier, bool* ok);
+  V8_INLINE ZoneList<Expression*>* RewriteNonPatternArguments(
+      ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
+      bool* ok);
+  V8_INLINE ObjectLiteralProperty* RewriteNonPatternObjectLiteralProperty(
+      ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
+      bool* ok);
+
+  friend class InitializerRewriter;
+  void RewriteParameterInitializer(Expression* expr, Scope* scope);
+
+  Scanner scanner_;
+  PreParser* reusable_preparser_;
+  Scope* original_scope_;  // for ES5 function declarations in sloppy eval
+  Target* target_stack_;  // for break, continue statements
+  ScriptCompiler::CompileOptions compile_options_;
+  ParseData* cached_parse_data_;
+
+  PendingCompilationErrorHandler pending_error_handler_;
+
+  // Other information which will be stored in Parser and moved to Isolate after
+  // parsing.
+  int use_counts_[v8::Isolate::kUseCounterFeatureCount];
+  int total_preparse_skipped_;
+  HistogramTimer* pre_parse_timer_;
+
+  bool parsing_on_main_thread_;
+};
+
+
+bool ParserTraits::IsFutureStrictReserved(
+    const AstRawString* identifier) const {
+  return parser_->scanner()->IdentifierIsFutureStrictReserved(identifier);
+}
+
+
+Scope* ParserTraits::NewScope(Scope* parent_scope, ScopeType scope_type,
+                              FunctionKind kind) {
+  return parser_->NewScope(parent_scope, scope_type, kind);
+}
+
+
+const AstRawString* ParserTraits::EmptyIdentifierString() {
+  return parser_->ast_value_factory()->empty_string();
+}
+
+
+void ParserTraits::SkipLazyFunctionBody(int* materialized_literal_count,
+                                        int* expected_property_count, bool* ok,
+                                        Scanner::BookmarkScope* bookmark) {
+  return parser_->SkipLazyFunctionBody(materialized_literal_count,
+                                       expected_property_count, ok, bookmark);
+}
+
+
+ZoneList<Statement*>* ParserTraits::ParseEagerFunctionBody(
+    const AstRawString* name, int pos, const ParserFormalParameters& parameters,
+    FunctionKind kind, FunctionLiteral::FunctionType function_type, bool* ok) {
+  return parser_->ParseEagerFunctionBody(name, pos, parameters, kind,
+                                         function_type, ok);
+}
+
+
+void ParserTraits::CheckConflictingVarDeclarations(v8::internal::Scope* scope,
+                                                   bool* ok) {
+  parser_->CheckConflictingVarDeclarations(scope, ok);
+}
+
+
+// Support for handling complex values (array and object literals) that
+// can be fully handled at compile time.
+class CompileTimeValue: public AllStatic {
+ public:
+  enum LiteralType {
+    OBJECT_LITERAL_FAST_ELEMENTS,
+    OBJECT_LITERAL_SLOW_ELEMENTS,
+    ARRAY_LITERAL
+  };
+
+  static bool IsCompileTimeValue(Expression* expression);
+
+  // Get the value as a compile time value.
+  static Handle<FixedArray> GetValue(Isolate* isolate, Expression* expression);
+
+  // Get the type of a compile time value returned by GetValue().
+  static LiteralType GetLiteralType(Handle<FixedArray> value);
+
+  // Get the elements array of a compile time value returned by GetValue().
+  static Handle<FixedArray> GetElements(Handle<FixedArray> value);
+
+ private:
+  static const int kLiteralTypeSlot = 0;
+  static const int kElementsSlot = 1;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue);
+};
+
+
+ParserTraits::TemplateLiteralState ParserTraits::OpenTemplateLiteral(int pos) {
+  return parser_->OpenTemplateLiteral(pos);
+}
+
+
+void ParserTraits::AddTemplateSpan(TemplateLiteralState* state, bool tail) {
+  parser_->AddTemplateSpan(state, tail);
+}
+
+
+void ParserTraits::AddTemplateExpression(TemplateLiteralState* state,
+                                         Expression* expression) {
+  parser_->AddTemplateExpression(state, expression);
+}
+
+
+Expression* ParserTraits::CloseTemplateLiteral(TemplateLiteralState* state,
+                                               int start, Expression* tag) {
+  return parser_->CloseTemplateLiteral(state, start, tag);
+}
+
+
+ZoneList<v8::internal::Expression*>* ParserTraits::PrepareSpreadArguments(
+    ZoneList<v8::internal::Expression*>* list) {
+  return parser_->PrepareSpreadArguments(list);
+}
+
+
+Expression* ParserTraits::SpreadCall(Expression* function,
+                                     ZoneList<v8::internal::Expression*>* args,
+                                     int pos) {
+  return parser_->SpreadCall(function, args, pos);
+}
+
+
+Expression* ParserTraits::SpreadCallNew(
+    Expression* function, ZoneList<v8::internal::Expression*>* args, int pos) {
+  return parser_->SpreadCallNew(function, args, pos);
+}
+
+
+void ParserTraits::AddFormalParameter(ParserFormalParameters* parameters,
+                                      Expression* pattern,
+                                      Expression* initializer,
+                                      int initializer_end_position,
+                                      bool is_rest) {
+  bool is_simple = pattern->IsVariableProxy() && initializer == nullptr;
+  const AstRawString* name = is_simple
+                                 ? pattern->AsVariableProxy()->raw_name()
+                                 : parser_->ast_value_factory()->empty_string();
+  parameters->params.Add(
+      ParserFormalParameters::Parameter(name, pattern, initializer,
+                                        initializer_end_position, is_rest),
+      parameters->scope->zone());
+}
+
+
+void ParserTraits::DeclareFormalParameter(
+    Scope* scope, const ParserFormalParameters::Parameter& parameter,
+    ExpressionClassifier* classifier) {
+  bool is_duplicate = false;
+  bool is_simple = classifier->is_simple_parameter_list();
+  auto name = is_simple || parameter.is_rest
+                  ? parameter.name
+                  : parser_->ast_value_factory()->empty_string();
+  auto mode = is_simple || parameter.is_rest ? VAR : TEMPORARY;
+  if (!is_simple) scope->SetHasNonSimpleParameters();
+  bool is_optional = parameter.initializer != nullptr;
+  Variable* var = scope->DeclareParameter(
+      name, mode, is_optional, parameter.is_rest, &is_duplicate);
+  if (is_duplicate) {
+    classifier->RecordDuplicateFormalParameterError(
+        parser_->scanner()->location());
+  }
+  if (is_sloppy(scope->language_mode())) {
+    // TODO(sigurds) Mark every parameter as maybe assigned. This is a
+    // conservative approximation necessary to account for parameters
+    // that are assigned via the arguments array.
+    var->set_maybe_assigned();
+  }
+}
+
+
+void ParserTraits::AddParameterInitializationBlock(
+    const ParserFormalParameters& parameters,
+    ZoneList<v8::internal::Statement*>* body, bool* ok) {
+  if (!parameters.is_simple) {
+    auto* init_block =
+        parser_->BuildParameterInitializationBlock(parameters, ok);
+    if (!*ok) return;
+    if (init_block != nullptr) {
+      body->Add(init_block, parser_->zone());
+    }
+  }
+}
+
+
+DoExpression* ParserTraits::ParseDoExpression(bool* ok) {
+  return parser_->ParseDoExpression(ok);
+}
+
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_PARSER_H_
diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc
new file mode 100644
index 0000000..6e20282
--- /dev/null
+++ b/src/parsing/pattern-rewriter.cc
@@ -0,0 +1,628 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/ast/ast.h"
+#include "src/messages.h"
+#include "src/parsing/parameter-initializer-rewriter.h"
+#include "src/parsing/parser.h"
+
+namespace v8 {
+
+namespace internal {
+
+void Parser::PatternRewriter::DeclareAndInitializeVariables(
+    Block* block, const DeclarationDescriptor* declaration_descriptor,
+    const DeclarationParsingResult::Declaration* declaration,
+    ZoneList<const AstRawString*>* names, bool* ok) {
+  PatternRewriter rewriter;
+
+  rewriter.scope_ = declaration_descriptor->scope;
+  rewriter.parser_ = declaration_descriptor->parser;
+  rewriter.context_ = BINDING;
+  rewriter.pattern_ = declaration->pattern;
+  rewriter.initializer_position_ = declaration->initializer_position;
+  rewriter.block_ = block;
+  rewriter.descriptor_ = declaration_descriptor;
+  rewriter.names_ = names;
+  rewriter.ok_ = ok;
+  rewriter.recursion_level_ = 0;
+
+  rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
+}
+
+
+void Parser::PatternRewriter::RewriteDestructuringAssignment(
+    Parser* parser, RewritableAssignmentExpression* to_rewrite, Scope* scope) {
+  PatternRewriter rewriter;
+
+  DCHECK(!to_rewrite->is_rewritten());
+
+  bool ok = true;
+  rewriter.scope_ = scope;
+  rewriter.parser_ = parser;
+  rewriter.context_ = ASSIGNMENT;
+  rewriter.pattern_ = to_rewrite;
+  rewriter.block_ = nullptr;
+  rewriter.descriptor_ = nullptr;
+  rewriter.names_ = nullptr;
+  rewriter.ok_ = &ok;
+  rewriter.recursion_level_ = 0;
+
+  rewriter.RecurseIntoSubpattern(rewriter.pattern_, nullptr);
+  DCHECK(ok);
+}
+
+
+Expression* Parser::PatternRewriter::RewriteDestructuringAssignment(
+    Parser* parser, Assignment* assignment, Scope* scope) {
+  DCHECK_NOT_NULL(assignment);
+  DCHECK_EQ(Token::ASSIGN, assignment->op());
+  auto to_rewrite =
+      parser->factory()->NewRewritableAssignmentExpression(assignment);
+  RewriteDestructuringAssignment(parser, to_rewrite, scope);
+  return to_rewrite->expression();
+}
+
+
+bool Parser::PatternRewriter::IsAssignmentContext(PatternContext c) const {
+  return c == ASSIGNMENT || c == ASSIGNMENT_INITIALIZER;
+}
+
+
+bool Parser::PatternRewriter::IsBindingContext(PatternContext c) const {
+  return c == BINDING || c == INITIALIZER;
+}
+
+
+Parser::PatternRewriter::PatternContext
+Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) {
+  PatternContext old_context = context();
+  if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN) {
+    set_context(ASSIGNMENT);
+  }
+  return old_context;
+}
+
+
+Parser::PatternRewriter::PatternContext
+Parser::PatternRewriter::SetInitializerContextIfNeeded(Expression* node) {
+  // Set appropriate initializer context for BindingElement and
+  // AssignmentElement nodes
+  PatternContext old_context = context();
+  bool is_destructuring_assignment =
+      node->IsRewritableAssignmentExpression() &&
+      !node->AsRewritableAssignmentExpression()->is_rewritten();
+  bool is_assignment =
+      node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN;
+  if (is_destructuring_assignment || is_assignment) {
+    switch (old_context) {
+      case BINDING:
+        set_context(INITIALIZER);
+        break;
+      case ASSIGNMENT:
+        set_context(ASSIGNMENT_INITIALIZER);
+        break;
+      default:
+        break;
+    }
+  }
+  return old_context;
+}
+
+
+void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
+  Expression* value = current_value_;
+
+  if (IsAssignmentContext()) {
+    // In an assignment context, simply perform the assignment
+    Assignment* assignment = factory()->NewAssignment(
+        Token::ASSIGN, pattern, value, pattern->position());
+    block_->statements()->Add(
+        factory()->NewExpressionStatement(assignment, pattern->position()),
+        zone());
+    return;
+  }
+
+  descriptor_->scope->RemoveUnresolved(pattern);
+
+  // Declare variable.
+  // Note that we *always* must treat the initial value via a separate init
+  // assignment for variables and constants because the value must be assigned
+  // when the variable is encountered in the source. But the variable/constant
+  // is declared (and set to 'undefined') upon entering the function within
+  // which the variable or constant is declared. Only function variables have
+  // an initial value in the declaration (because they are initialized upon
+  // entering the function).
+  //
+  // If we have a legacy const declaration, in an inner scope, the proxy
+  // is always bound to the declared variable (independent of possibly
+  // surrounding 'with' statements).
+  // For let/const declarations in harmony mode, we can also immediately
+  // pre-resolve the proxy because it resides in the same scope as the
+  // declaration.
+  const AstRawString* name = pattern->raw_name();
+  VariableProxy* proxy = parser_->NewUnresolved(name, descriptor_->mode);
+  Declaration* declaration = factory()->NewVariableDeclaration(
+      proxy, descriptor_->mode, descriptor_->scope,
+      descriptor_->declaration_pos);
+  Variable* var =
+      parser_->Declare(declaration, descriptor_->declaration_kind,
+                       descriptor_->mode != VAR, ok_, descriptor_->hoist_scope);
+  if (!*ok_) return;
+  DCHECK_NOT_NULL(var);
+  DCHECK(!proxy->is_resolved() || proxy->var() == var);
+  var->set_initializer_position(initializer_position_);
+
+  DCHECK(initializer_position_ != RelocInfo::kNoPosition);
+
+  Scope* declaration_scope = IsLexicalVariableMode(descriptor_->mode)
+                                 ? descriptor_->scope
+                                 : descriptor_->scope->DeclarationScope();
+  if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
+    parser_->ReportMessage(MessageTemplate::kTooManyVariables);
+    *ok_ = false;
+    return;
+  }
+  if (names_) {
+    names_->Add(name, zone());
+  }
+
+  // Initialize variables if needed. A
+  // declaration of the form:
+  //
+  //    var v = x;
+  //
+  // is syntactic sugar for:
+  //
+  //    var v; v = x;
+  //
+  // In particular, we need to re-lookup 'v' (in scope_, not
+  // declaration_scope) as it may be a different 'v' than the 'v' in the
+  // declaration (e.g., if we are inside a 'with' statement or 'catch'
+  // block).
+  //
+  // However, note that const declarations are different! A const
+  // declaration of the form:
+  //
+  //   const c = x;
+  //
+  // is *not* syntactic sugar for:
+  //
+  //   const c; c = x;
+  //
+  // The "variable" c initialized to x is the same as the declared
+  // one - there is no re-lookup (see the last parameter of the
+  // Declare() call above).
+  Scope* initialization_scope = IsImmutableVariableMode(descriptor_->mode)
+                                    ? declaration_scope
+                                    : descriptor_->scope;
+
+
+  // Global variable declarations must be compiled in a specific
+  // way. When the script containing the global variable declaration
+  // is entered, the global variable must be declared, so that if it
+  // doesn't exist (on the global object itself, see ES5 errata) it
+  // gets created with an initial undefined value. This is handled
+  // by the declarations part of the function representing the
+  // top-level global code; see Runtime::DeclareGlobalVariable. If
+  // it already exists (in the object or in a prototype), it is
+  // *not* touched until the variable declaration statement is
+  // executed.
+  //
+  // Executing the variable declaration statement will always
+  // guarantee to give the global object an own property.
+  // This way, global variable declarations can shadow
+  // properties in the prototype chain, but only after the variable
+  // declaration statement has been executed. This is important in
+  // browsers where the global object (window) has lots of
+  // properties defined in prototype objects.
+  if (initialization_scope->is_script_scope() &&
+      !IsLexicalVariableMode(descriptor_->mode)) {
+    // Compute the arguments for the runtime
+    // call.test-parsing/InitializedDeclarationsInStrictForOfError
+    ZoneList<Expression*>* arguments =
+        new (zone()) ZoneList<Expression*>(3, zone());
+    // We have at least 1 parameter.
+    arguments->Add(
+        factory()->NewStringLiteral(name, descriptor_->declaration_pos),
+        zone());
+    CallRuntime* initialize;
+
+    if (IsImmutableVariableMode(descriptor_->mode)) {
+      arguments->Add(value, zone());
+      value = NULL;  // zap the value to avoid the unnecessary assignment
+
+      // Construct the call to Runtime_InitializeConstGlobal
+      // and add it to the initialization statement block.
+      // Note that the function does different things depending on
+      // the number of arguments (1 or 2).
+      initialize =
+          factory()->NewCallRuntime(Runtime::kInitializeConstGlobal, arguments,
+                                    descriptor_->initialization_pos);
+    } else {
+      // Add language mode.
+      // We may want to pass singleton to avoid Literal allocations.
+      LanguageMode language_mode = initialization_scope->language_mode();
+      arguments->Add(factory()->NewNumberLiteral(language_mode,
+                                                 descriptor_->declaration_pos),
+                     zone());
+
+      // Be careful not to assign a value to the global variable if
+      // we're in a with. The initialization value should not
+      // necessarily be stored in the global object in that case,
+      // which is why we need to generate a separate assignment node.
+      if (value != NULL && !descriptor_->scope->inside_with()) {
+        arguments->Add(value, zone());
+        value = NULL;  // zap the value to avoid the unnecessary assignment
+        // Construct the call to Runtime_InitializeVarGlobal
+        // and add it to the initialization statement block.
+        initialize =
+            factory()->NewCallRuntime(Runtime::kInitializeVarGlobal, arguments,
+                                      descriptor_->declaration_pos);
+      } else {
+        initialize = NULL;
+      }
+    }
+
+    if (initialize != NULL) {
+      block_->statements()->Add(
+          factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
+          zone());
+    }
+  } else if (value != nullptr && (descriptor_->mode == CONST_LEGACY ||
+                                  IsLexicalVariableMode(descriptor_->mode))) {
+    // Constant initializations always assign to the declared constant which
+    // is always at the function scope level. This is only relevant for
+    // dynamically looked-up variables and constants (the
+    // start context for constant lookups is always the function context,
+    // while it is the top context for var declared variables). Sigh...
+    // For 'let' and 'const' declared variables in harmony mode the
+    // initialization also always assigns to the declared variable.
+    DCHECK_NOT_NULL(proxy);
+    DCHECK_NOT_NULL(proxy->var());
+    DCHECK_NOT_NULL(value);
+    // Add break location for destructured sub-pattern.
+    int pos = IsSubPattern() ? pattern->position() : RelocInfo::kNoPosition;
+    Assignment* assignment =
+        factory()->NewAssignment(Token::INIT, proxy, value, pos);
+    block_->statements()->Add(
+        factory()->NewExpressionStatement(assignment, pos), zone());
+    value = NULL;
+  }
+
+  // Add an assignment node to the initialization statement block if we still
+  // have a pending initialization value.
+  if (value != NULL) {
+    DCHECK(descriptor_->mode == VAR);
+    // 'var' initializations are simply assignments (with all the consequences
+    // if they are inside a 'with' statement - they may change a 'with' object
+    // property).
+    VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
+    // Add break location for destructured sub-pattern.
+    int pos = IsSubPattern() ? pattern->position() : RelocInfo::kNoPosition;
+    Assignment* assignment =
+        factory()->NewAssignment(Token::INIT, proxy, value, pos);
+    block_->statements()->Add(
+        factory()->NewExpressionStatement(assignment, pos), zone());
+  }
+}
+
+
+Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
+  auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
+  if (value != nullptr) {
+    auto assignment = factory()->NewAssignment(
+        Token::ASSIGN, factory()->NewVariableProxy(temp), value,
+        RelocInfo::kNoPosition);
+
+    block_->statements()->Add(
+        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
+        zone());
+  }
+  return temp;
+}
+
+
+void Parser::PatternRewriter::VisitRewritableAssignmentExpression(
+    RewritableAssignmentExpression* node) {
+  if (!IsAssignmentContext()) {
+    // Mark the assignment as rewritten to prevent redundant rewriting, and
+    // perform BindingPattern rewriting
+    DCHECK(!node->is_rewritten());
+    node->Rewrite(node->expression());
+    return node->expression()->Accept(this);
+  }
+
+  if (node->is_rewritten()) return;
+  DCHECK(IsAssignmentContext());
+  Assignment* assign = node->expression()->AsAssignment();
+  DCHECK_NOT_NULL(assign);
+  DCHECK_EQ(Token::ASSIGN, assign->op());
+
+  auto initializer = assign->value();
+  auto value = initializer;
+
+  if (IsInitializerContext()) {
+    // let {<pattern> = <init>} = <value>
+    //   becomes
+    // temp = <value>;
+    // <pattern> = temp === undefined ? <init> : temp;
+    auto temp_var = CreateTempVar(current_value_);
+    Expression* is_undefined = factory()->NewCompareOperation(
+        Token::EQ_STRICT, factory()->NewVariableProxy(temp_var),
+        factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+        RelocInfo::kNoPosition);
+    value = factory()->NewConditional(is_undefined, initializer,
+                                      factory()->NewVariableProxy(temp_var),
+                                      RelocInfo::kNoPosition);
+  }
+
+  PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
+  int pos = assign->position();
+  Block* old_block = block_;
+  block_ = factory()->NewBlock(nullptr, 8, false, pos);
+  Variable* temp = nullptr;
+  Expression* pattern = assign->target();
+  Expression* old_value = current_value_;
+  current_value_ = value;
+  if (pattern->IsObjectLiteral()) {
+    VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
+  } else {
+    DCHECK(pattern->IsArrayLiteral());
+    VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
+  }
+  DCHECK_NOT_NULL(temp);
+  current_value_ = old_value;
+  Expression* expr = factory()->NewDoExpression(block_, temp, pos);
+  node->Rewrite(expr);
+  block_ = old_block;
+  if (block_) {
+    block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
+                              zone());
+  }
+  return set_context(old_context);
+}
+
+
+void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
+                                                 Variable** temp_var) {
+  auto temp = *temp_var = CreateTempVar(current_value_);
+
+  block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
+
+  for (ObjectLiteralProperty* property : *pattern->properties()) {
+    PatternContext context = SetInitializerContextIfNeeded(property->value());
+    RecurseIntoSubpattern(
+        property->value(),
+        factory()->NewProperty(factory()->NewVariableProxy(temp),
+                               property->key(), RelocInfo::kNoPosition));
+    set_context(context);
+  }
+}
+
+
+void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
+  Variable* temp_var = nullptr;
+  VisitObjectLiteral(node, &temp_var);
+}
+
+
+void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
+                                                Variable** temp_var) {
+  auto temp = *temp_var = CreateTempVar(current_value_);
+
+  block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
+
+  auto iterator = CreateTempVar(parser_->GetIterator(
+      factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition));
+  auto done = CreateTempVar(
+      factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
+  auto result = CreateTempVar();
+  auto v = CreateTempVar();
+
+  Spread* spread = nullptr;
+  for (Expression* value : *node->values()) {
+    if (value->IsSpread()) {
+      spread = value->AsSpread();
+      break;
+    }
+
+    PatternContext context = SetInitializerContextIfNeeded(value);
+    // if (!done) {
+    //   result = IteratorNext(iterator);
+    //   v = (done = result.done) ? undefined : result.value;
+    // }
+    auto next_block =
+        factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
+    next_block->statements()->Add(factory()->NewExpressionStatement(
+                                      parser_->BuildIteratorNextResult(
+                                          factory()->NewVariableProxy(iterator),
+                                          result, RelocInfo::kNoPosition),
+                                      RelocInfo::kNoPosition),
+                                  zone());
+
+    auto assign_to_done = factory()->NewAssignment(
+        Token::ASSIGN, factory()->NewVariableProxy(done),
+        factory()->NewProperty(
+            factory()->NewVariableProxy(result),
+            factory()->NewStringLiteral(ast_value_factory()->done_string(),
+                                        RelocInfo::kNoPosition),
+            RelocInfo::kNoPosition),
+        RelocInfo::kNoPosition);
+    auto next_value = factory()->NewConditional(
+        assign_to_done, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+        factory()->NewProperty(
+            factory()->NewVariableProxy(result),
+            factory()->NewStringLiteral(ast_value_factory()->value_string(),
+                                        RelocInfo::kNoPosition),
+            RelocInfo::kNoPosition),
+        RelocInfo::kNoPosition);
+    next_block->statements()->Add(
+        factory()->NewExpressionStatement(
+            factory()->NewAssignment(Token::ASSIGN,
+                                     factory()->NewVariableProxy(v), next_value,
+                                     RelocInfo::kNoPosition),
+            RelocInfo::kNoPosition),
+        zone());
+
+    auto if_statement = factory()->NewIfStatement(
+        factory()->NewUnaryOperation(Token::NOT,
+                                     factory()->NewVariableProxy(done),
+                                     RelocInfo::kNoPosition),
+        next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
+        RelocInfo::kNoPosition);
+    block_->statements()->Add(if_statement, zone());
+
+    if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
+      RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
+    }
+    set_context(context);
+  }
+
+  if (spread != nullptr) {
+    // array = [];
+    // if (!done) %concat_iterable_to_array(array, iterator);
+    auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
+    auto array = CreateTempVar(factory()->NewArrayLiteral(
+        empty_exprs,
+        // Reuse pattern's literal index - it is unused since there is no
+        // actual literal allocated.
+        node->literal_index(), is_strong(scope()->language_mode()),
+        RelocInfo::kNoPosition));
+
+    auto arguments = new (zone()) ZoneList<Expression*>(2, zone());
+    arguments->Add(factory()->NewVariableProxy(array), zone());
+    arguments->Add(factory()->NewVariableProxy(iterator), zone());
+    auto spread_into_array_call =
+        factory()->NewCallRuntime(Context::CONCAT_ITERABLE_TO_ARRAY_INDEX,
+                                  arguments, RelocInfo::kNoPosition);
+
+    auto if_statement = factory()->NewIfStatement(
+        factory()->NewUnaryOperation(Token::NOT,
+                                     factory()->NewVariableProxy(done),
+                                     RelocInfo::kNoPosition),
+        factory()->NewExpressionStatement(spread_into_array_call,
+                                          RelocInfo::kNoPosition),
+        factory()->NewEmptyStatement(RelocInfo::kNoPosition),
+        RelocInfo::kNoPosition);
+    block_->statements()->Add(if_statement, zone());
+
+    RecurseIntoSubpattern(spread->expression(),
+                          factory()->NewVariableProxy(array));
+  }
+}
+
+
+void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
+  Variable* temp_var = nullptr;
+  VisitArrayLiteral(node, &temp_var);
+}
+
+
+void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
+  // let {<pattern> = <init>} = <value>
+  //   becomes
+  // temp = <value>;
+  // <pattern> = temp === undefined ? <init> : temp;
+  DCHECK_EQ(Token::ASSIGN, node->op());
+
+  auto initializer = node->value();
+  auto value = initializer;
+  auto temp = CreateTempVar(current_value_);
+
+  if (IsInitializerContext()) {
+    Expression* is_undefined = factory()->NewCompareOperation(
+        Token::EQ_STRICT, factory()->NewVariableProxy(temp),
+        factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+        RelocInfo::kNoPosition);
+    value = factory()->NewConditional(is_undefined, initializer,
+                                      factory()->NewVariableProxy(temp),
+                                      RelocInfo::kNoPosition);
+  }
+
+  if (IsBindingContext() &&
+      descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
+      scope()->is_arrow_scope()) {
+    RewriteParameterInitializerScope(parser_->stack_limit(), initializer,
+                                     scope()->outer_scope(), scope());
+  }
+
+  PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
+  RecurseIntoSubpattern(node->target(), value);
+  set_context(old_context);
+}
+
+
+// =============== AssignmentPattern only ==================
+
+void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
+  DCHECK(IsAssignmentContext());
+  auto value = current_value_;
+
+  Assignment* assignment =
+      factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
+
+  block_->statements()->Add(
+      factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
+      zone());
+}
+
+
+// =============== UNREACHABLE =============================
+
+void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
+
+#define NOT_A_PATTERN(Node)                                        \
+  void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
+    UNREACHABLE();                                                 \
+  }
+
+NOT_A_PATTERN(BinaryOperation)
+NOT_A_PATTERN(Block)
+NOT_A_PATTERN(BreakStatement)
+NOT_A_PATTERN(Call)
+NOT_A_PATTERN(CallNew)
+NOT_A_PATTERN(CallRuntime)
+NOT_A_PATTERN(CaseClause)
+NOT_A_PATTERN(ClassLiteral)
+NOT_A_PATTERN(CompareOperation)
+NOT_A_PATTERN(Conditional)
+NOT_A_PATTERN(ContinueStatement)
+NOT_A_PATTERN(CountOperation)
+NOT_A_PATTERN(DebuggerStatement)
+NOT_A_PATTERN(DoExpression)
+NOT_A_PATTERN(DoWhileStatement)
+NOT_A_PATTERN(EmptyStatement)
+NOT_A_PATTERN(EmptyParentheses)
+NOT_A_PATTERN(ExportDeclaration)
+NOT_A_PATTERN(ExpressionStatement)
+NOT_A_PATTERN(ForInStatement)
+NOT_A_PATTERN(ForOfStatement)
+NOT_A_PATTERN(ForStatement)
+NOT_A_PATTERN(FunctionDeclaration)
+NOT_A_PATTERN(FunctionLiteral)
+NOT_A_PATTERN(IfStatement)
+NOT_A_PATTERN(ImportDeclaration)
+NOT_A_PATTERN(Literal)
+NOT_A_PATTERN(NativeFunctionLiteral)
+NOT_A_PATTERN(RegExpLiteral)
+NOT_A_PATTERN(ReturnStatement)
+NOT_A_PATTERN(SloppyBlockFunctionStatement)
+NOT_A_PATTERN(Spread)
+NOT_A_PATTERN(SuperPropertyReference)
+NOT_A_PATTERN(SuperCallReference)
+NOT_A_PATTERN(SwitchStatement)
+NOT_A_PATTERN(ThisFunction)
+NOT_A_PATTERN(Throw)
+NOT_A_PATTERN(TryCatchStatement)
+NOT_A_PATTERN(TryFinallyStatement)
+NOT_A_PATTERN(UnaryOperation)
+NOT_A_PATTERN(VariableDeclaration)
+NOT_A_PATTERN(WhileStatement)
+NOT_A_PATTERN(WithStatement)
+NOT_A_PATTERN(Yield)
+
+#undef NOT_A_PATTERN
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/preparse-data-format.h b/src/parsing/preparse-data-format.h
new file mode 100644
index 0000000..f7d9f68
--- /dev/null
+++ b/src/parsing/preparse-data-format.h
@@ -0,0 +1,41 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_PREPARSE_DATA_FORMAT_H_
+#define V8_PARSING_PREPARSE_DATA_FORMAT_H_
+
+namespace v8 {
+namespace internal {
+
+// Generic and general data used by preparse data recorders and readers.
+
+struct PreparseDataConstants {
+ public:
+  // Layout and constants of the preparse data exchange format.
+  static const unsigned kMagicNumber = 0xBadDead;
+  static const unsigned kCurrentVersion = 11;
+
+  static const int kMagicOffset = 0;
+  static const int kVersionOffset = 1;
+  static const int kHasErrorOffset = 2;
+  static const int kFunctionsSizeOffset = 3;
+  static const int kSizeOffset = 4;
+  static const int kHeaderSize = 5;
+
+  // If encoding a message, the following positions are fixed.
+  static const int kMessageStartPos = 0;
+  static const int kMessageEndPos = 1;
+  static const int kMessageArgCountPos = 2;
+  static const int kParseErrorTypePos = 3;
+  static const int kMessageTemplatePos = 4;
+  static const int kMessageArgPos = 5;
+
+  static const unsigned char kNumberTerminator = 0x80u;
+};
+
+
+}  // namespace internal
+}  // namespace v8.
+
+#endif  // V8_PARSING_PREPARSE_DATA_FORMAT_H_
diff --git a/src/parsing/preparse-data.cc b/src/parsing/preparse-data.cc
new file mode 100644
index 0000000..d02cd63
--- /dev/null
+++ b/src/parsing/preparse-data.cc
@@ -0,0 +1,80 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/logging.h"
+#include "src/globals.h"
+#include "src/hashmap.h"
+#include "src/parsing/parser.h"
+#include "src/parsing/preparse-data.h"
+#include "src/parsing/preparse-data-format.h"
+
+namespace v8 {
+namespace internal {
+
+
+CompleteParserRecorder::CompleteParserRecorder() {
+  preamble_[PreparseDataConstants::kMagicOffset] =
+      PreparseDataConstants::kMagicNumber;
+  preamble_[PreparseDataConstants::kVersionOffset] =
+      PreparseDataConstants::kCurrentVersion;
+  preamble_[PreparseDataConstants::kHasErrorOffset] = false;
+  preamble_[PreparseDataConstants::kFunctionsSizeOffset] = 0;
+  preamble_[PreparseDataConstants::kSizeOffset] = 0;
+  DCHECK_EQ(5, PreparseDataConstants::kHeaderSize);
+#ifdef DEBUG
+  prev_start_ = -1;
+#endif
+}
+
+
+void CompleteParserRecorder::LogMessage(int start_pos, int end_pos,
+                                        MessageTemplate::Template message,
+                                        const char* arg_opt,
+                                        ParseErrorType error_type) {
+  if (HasError()) return;
+  preamble_[PreparseDataConstants::kHasErrorOffset] = true;
+  function_store_.Reset();
+  STATIC_ASSERT(PreparseDataConstants::kMessageStartPos == 0);
+  function_store_.Add(start_pos);
+  STATIC_ASSERT(PreparseDataConstants::kMessageEndPos == 1);
+  function_store_.Add(end_pos);
+  STATIC_ASSERT(PreparseDataConstants::kMessageArgCountPos == 2);
+  function_store_.Add((arg_opt == NULL) ? 0 : 1);
+  STATIC_ASSERT(PreparseDataConstants::kParseErrorTypePos == 3);
+  function_store_.Add(error_type);
+  STATIC_ASSERT(PreparseDataConstants::kMessageTemplatePos == 4);
+  function_store_.Add(static_cast<unsigned>(message));
+  STATIC_ASSERT(PreparseDataConstants::kMessageArgPos == 5);
+  if (arg_opt != NULL) WriteString(CStrVector(arg_opt));
+}
+
+
+void CompleteParserRecorder::WriteString(Vector<const char> str) {
+  function_store_.Add(str.length());
+  for (int i = 0; i < str.length(); i++) {
+    function_store_.Add(str[i]);
+  }
+}
+
+
+ScriptData* CompleteParserRecorder::GetScriptData() {
+  int function_size = function_store_.size();
+  int total_size = PreparseDataConstants::kHeaderSize + function_size;
+  unsigned* data = NewArray<unsigned>(total_size);
+  preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
+  MemCopy(data, preamble_, sizeof(preamble_));
+  if (function_size > 0) {
+    function_store_.WriteTo(Vector<unsigned>(
+        data + PreparseDataConstants::kHeaderSize, function_size));
+  }
+  DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
+  ScriptData* result = new ScriptData(reinterpret_cast<byte*>(data),
+                                      total_size * sizeof(unsigned));
+  result->AcquireDataOwnership();
+  return result;
+}
+
+
+}  // namespace internal
+}  // namespace v8.
diff --git a/src/parsing/preparse-data.h b/src/parsing/preparse-data.h
new file mode 100644
index 0000000..dbe1022
--- /dev/null
+++ b/src/parsing/preparse-data.h
@@ -0,0 +1,212 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_PREPARSE_DATA_H_
+#define V8_PARSING_PREPARSE_DATA_H_
+
+#include "src/allocation.h"
+#include "src/hashmap.h"
+#include "src/messages.h"
+#include "src/parsing/preparse-data-format.h"
+
+namespace v8 {
+namespace internal {
+
+class ScriptData {
+ public:
+  ScriptData(const byte* data, int length);
+  ~ScriptData() {
+    if (owns_data_) DeleteArray(data_);
+  }
+
+  const byte* data() const { return data_; }
+  int length() const { return length_; }
+  bool rejected() const { return rejected_; }
+
+  void Reject() { rejected_ = true; }
+
+  void AcquireDataOwnership() {
+    DCHECK(!owns_data_);
+    owns_data_ = true;
+  }
+
+  void ReleaseDataOwnership() {
+    DCHECK(owns_data_);
+    owns_data_ = false;
+  }
+
+ private:
+  bool owns_data_ : 1;
+  bool rejected_ : 1;
+  const byte* data_;
+  int length_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptData);
+};
+
+// Abstract interface for preparse data recorder.
+class ParserRecorder {
+ public:
+  ParserRecorder() { }
+  virtual ~ParserRecorder() { }
+
+  // Logs the scope and some details of a function literal in the source.
+  virtual void LogFunction(int start, int end, int literals, int properties,
+                           LanguageMode language_mode, bool uses_super_property,
+                           bool calls_eval) = 0;
+
+  // Logs an error message and marks the log as containing an error.
+  // Further logging will be ignored, and ExtractData will return a vector
+  // representing the error only.
+  virtual void LogMessage(int start, int end, MessageTemplate::Template message,
+                          const char* argument_opt,
+                          ParseErrorType error_type) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ParserRecorder);
+};
+
+
+class SingletonLogger : public ParserRecorder {
+ public:
+  SingletonLogger()
+      : has_error_(false), start_(-1), end_(-1), error_type_(kSyntaxError) {}
+  virtual ~SingletonLogger() {}
+
+  void Reset() { has_error_ = false; }
+
+  virtual void LogFunction(int start, int end, int literals, int properties,
+                           LanguageMode language_mode, bool uses_super_property,
+                           bool calls_eval) {
+    DCHECK(!has_error_);
+    start_ = start;
+    end_ = end;
+    literals_ = literals;
+    properties_ = properties;
+    language_mode_ = language_mode;
+    uses_super_property_ = uses_super_property;
+    calls_eval_ = calls_eval;
+  }
+
+  // Logs an error message and marks the log as containing an error.
+  // Further logging will be ignored, and ExtractData will return a vector
+  // representing the error only.
+  virtual void LogMessage(int start, int end, MessageTemplate::Template message,
+                          const char* argument_opt, ParseErrorType error_type) {
+    if (has_error_) return;
+    has_error_ = true;
+    start_ = start;
+    end_ = end;
+    message_ = message;
+    argument_opt_ = argument_opt;
+    error_type_ = error_type;
+  }
+
+  bool has_error() const { return has_error_; }
+
+  int start() const { return start_; }
+  int end() const { return end_; }
+  int literals() const {
+    DCHECK(!has_error_);
+    return literals_;
+  }
+  int properties() const {
+    DCHECK(!has_error_);
+    return properties_;
+  }
+  LanguageMode language_mode() const {
+    DCHECK(!has_error_);
+    return language_mode_;
+  }
+  bool uses_super_property() const {
+    DCHECK(!has_error_);
+    return uses_super_property_;
+  }
+  bool calls_eval() const {
+    DCHECK(!has_error_);
+    return calls_eval_;
+  }
+  ParseErrorType error_type() const {
+    DCHECK(has_error_);
+    return error_type_;
+  }
+  MessageTemplate::Template message() {
+    DCHECK(has_error_);
+    return message_;
+  }
+  const char* argument_opt() const {
+    DCHECK(has_error_);
+    return argument_opt_;
+  }
+
+ private:
+  bool has_error_;
+  int start_;
+  int end_;
+  // For function entries.
+  int literals_;
+  int properties_;
+  LanguageMode language_mode_;
+  bool uses_super_property_;
+  bool calls_eval_;
+  // For error messages.
+  MessageTemplate::Template message_;
+  const char* argument_opt_;
+  ParseErrorType error_type_;
+};
+
+
+class CompleteParserRecorder : public ParserRecorder {
+ public:
+  struct Key {
+    bool is_one_byte;
+    Vector<const byte> literal_bytes;
+  };
+
+  CompleteParserRecorder();
+  virtual ~CompleteParserRecorder() {}
+
+  virtual void LogFunction(int start, int end, int literals, int properties,
+                           LanguageMode language_mode, bool uses_super_property,
+                           bool calls_eval) {
+    function_store_.Add(start);
+    function_store_.Add(end);
+    function_store_.Add(literals);
+    function_store_.Add(properties);
+    function_store_.Add(language_mode);
+    function_store_.Add(uses_super_property);
+    function_store_.Add(calls_eval);
+  }
+
+  // Logs an error message and marks the log as containing an error.
+  // Further logging will be ignored, and ExtractData will return a vector
+  // representing the error only.
+  virtual void LogMessage(int start, int end, MessageTemplate::Template message,
+                          const char* argument_opt, ParseErrorType error_type);
+  ScriptData* GetScriptData();
+
+  bool HasError() {
+    return static_cast<bool>(preamble_[PreparseDataConstants::kHasErrorOffset]);
+  }
+  Vector<unsigned> ErrorMessageData() {
+    DCHECK(HasError());
+    return function_store_.ToVector();
+  }
+
+ private:
+  void WriteString(Vector<const char> str);
+
+  Collector<unsigned> function_store_;
+  unsigned preamble_[PreparseDataConstants::kHeaderSize];
+
+#ifdef DEBUG
+  int prev_start_;
+#endif
+};
+
+
+}  // namespace internal
+}  // namespace v8.
+
+#endif  // V8_PARSING_PREPARSE_DATA_H_
diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc
new file mode 100644
index 0000000..64511ac
--- /dev/null
+++ b/src/parsing/preparser.cc
@@ -0,0 +1,1292 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cmath>
+
+#include "src/allocation.h"
+#include "src/base/logging.h"
+#include "src/conversions-inl.h"
+#include "src/conversions.h"
+#include "src/globals.h"
+#include "src/hashmap.h"
+#include "src/list.h"
+#include "src/parsing/parser-base.h"
+#include "src/parsing/preparse-data.h"
+#include "src/parsing/preparse-data-format.h"
+#include "src/parsing/preparser.h"
+#include "src/unicode.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+void PreParserTraits::ReportMessageAt(Scanner::Location location,
+                                      MessageTemplate::Template message,
+                                      const char* arg,
+                                      ParseErrorType error_type) {
+  ReportMessageAt(location.beg_pos, location.end_pos, message, arg, error_type);
+}
+
+
+void PreParserTraits::ReportMessageAt(int start_pos, int end_pos,
+                                      MessageTemplate::Template message,
+                                      const char* arg,
+                                      ParseErrorType error_type) {
+  pre_parser_->log_->LogMessage(start_pos, end_pos, message, arg, error_type);
+}
+
+
+PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
+  if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) {
+    return PreParserIdentifier::FutureReserved();
+  } else if (scanner->current_token() ==
+             Token::FUTURE_STRICT_RESERVED_WORD) {
+    return PreParserIdentifier::FutureStrictReserved();
+  } else if (scanner->current_token() == Token::LET) {
+    return PreParserIdentifier::Let();
+  } else if (scanner->current_token() == Token::STATIC) {
+    return PreParserIdentifier::Static();
+  } else if (scanner->current_token() == Token::YIELD) {
+    return PreParserIdentifier::Yield();
+  }
+  if (scanner->UnescapedLiteralMatches("eval", 4)) {
+    return PreParserIdentifier::Eval();
+  }
+  if (scanner->UnescapedLiteralMatches("arguments", 9)) {
+    return PreParserIdentifier::Arguments();
+  }
+  if (scanner->UnescapedLiteralMatches("undefined", 9)) {
+    return PreParserIdentifier::Undefined();
+  }
+  if (scanner->LiteralMatches("prototype", 9)) {
+    return PreParserIdentifier::Prototype();
+  }
+  if (scanner->LiteralMatches("constructor", 11)) {
+    return PreParserIdentifier::Constructor();
+  }
+  return PreParserIdentifier::Default();
+}
+
+
+PreParserIdentifier PreParserTraits::GetNumberAsSymbol(Scanner* scanner) {
+  return PreParserIdentifier::Default();
+}
+
+
+PreParserExpression PreParserTraits::ExpressionFromString(
+    int pos, Scanner* scanner, PreParserFactory* factory) {
+  if (scanner->UnescapedLiteralMatches("use strict", 10)) {
+    return PreParserExpression::UseStrictStringLiteral();
+  } else if (scanner->UnescapedLiteralMatches("use strong", 10)) {
+    return PreParserExpression::UseStrongStringLiteral();
+  }
+  return PreParserExpression::StringLiteral();
+}
+
+
+PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) {
+  return pre_parser_->ParseV8Intrinsic(ok);
+}
+
+
+PreParserExpression PreParserTraits::ParseFunctionLiteral(
+    PreParserIdentifier name, Scanner::Location function_name_location,
+    FunctionNameValidity function_name_validity, FunctionKind kind,
+    int function_token_position, FunctionLiteral::FunctionType type,
+    FunctionLiteral::ArityRestriction arity_restriction,
+    LanguageMode language_mode, bool* ok) {
+  return pre_parser_->ParseFunctionLiteral(
+      name, function_name_location, function_name_validity, kind,
+      function_token_position, type, arity_restriction, language_mode, ok);
+}
+
+
+PreParser::PreParseResult PreParser::PreParseLazyFunction(
+    LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
+    ParserRecorder* log, Scanner::BookmarkScope* bookmark) {
+  log_ = log;
+  // Lazy functions always have trivial outer scopes (no with/catch scopes).
+  Scope* top_scope = NewScope(scope_, SCRIPT_SCOPE);
+  PreParserFactory top_factory(NULL);
+  FunctionState top_state(&function_state_, &scope_, top_scope, kNormalFunction,
+                          &top_factory);
+  scope_->SetLanguageMode(language_mode);
+  Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind);
+  if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters();
+  PreParserFactory function_factory(NULL);
+  FunctionState function_state(&function_state_, &scope_, function_scope, kind,
+                               &function_factory);
+  DCHECK_EQ(Token::LBRACE, scanner()->current_token());
+  bool ok = true;
+  int start_position = peek_position();
+  ParseLazyFunctionLiteralBody(&ok, bookmark);
+  if (bookmark && bookmark->HasBeenReset()) {
+    // Do nothing, as we've just aborted scanning this function.
+  } else if (stack_overflow()) {
+    return kPreParseStackOverflow;
+  } else if (!ok) {
+    ReportUnexpectedToken(scanner()->current_token());
+  } else {
+    DCHECK_EQ(Token::RBRACE, scanner()->peek());
+    if (is_strict(scope_->language_mode())) {
+      int end_pos = scanner()->location().end_pos;
+      CheckStrictOctalLiteral(start_position, end_pos, &ok);
+      if (!ok) return kPreParseSuccess;
+
+      if (is_strong(scope_->language_mode()) && IsSubclassConstructor(kind)) {
+        if (!function_state.super_location().IsValid()) {
+          ReportMessageAt(Scanner::Location(start_position, start_position + 1),
+                          MessageTemplate::kStrongSuperCallMissing,
+                          kReferenceError);
+          return kPreParseSuccess;
+        }
+      }
+    }
+  }
+  return kPreParseSuccess;
+}
+
+
+PreParserExpression PreParserTraits::ParseClassLiteral(
+    PreParserIdentifier name, Scanner::Location class_name_location,
+    bool name_is_strict_reserved, int pos, bool* ok) {
+  return pre_parser_->ParseClassLiteral(name, class_name_location,
+                                        name_is_strict_reserved, pos, ok);
+}
+
+
+// Preparsing checks a JavaScript program and emits preparse-data that helps
+// a later parsing to be faster.
+// See preparser-data.h for the data.
+
+// The PreParser checks that the syntax follows the grammar for JavaScript,
+// and collects some information about the program along the way.
+// The grammar check is only performed in order to understand the program
+// sufficiently to deduce some information about it, that can be used
+// to speed up later parsing. Finding errors is not the goal of pre-parsing,
+// rather it is to speed up properly written and correct programs.
+// That means that contextual checks (like a label being declared where
+// it is used) are generally omitted.
+
+
+PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
+  // ECMA 262 6th Edition
+  // StatementListItem[Yield, Return] :
+  //   Statement[?Yield, ?Return]
+  //   Declaration[?Yield]
+  //
+  // Declaration[Yield] :
+  //   HoistableDeclaration[?Yield]
+  //   ClassDeclaration[?Yield]
+  //   LexicalDeclaration[In, ?Yield]
+  //
+  // HoistableDeclaration[Yield, Default] :
+  //   FunctionDeclaration[?Yield, ?Default]
+  //   GeneratorDeclaration[?Yield, ?Default]
+  //
+  // LexicalDeclaration[In, Yield] :
+  //   LetOrConst BindingList[?In, ?Yield] ;
+
+  switch (peek()) {
+    case Token::FUNCTION:
+      return ParseFunctionDeclaration(ok);
+    case Token::CLASS:
+      return ParseClassDeclaration(ok);
+    case Token::CONST:
+      if (allow_const()) {
+        return ParseVariableStatement(kStatementListItem, ok);
+      }
+      break;
+    case Token::LET:
+      if (IsNextLetKeyword()) {
+        return ParseVariableStatement(kStatementListItem, ok);
+      }
+      break;
+    default:
+      break;
+  }
+  return ParseStatement(ok);
+}
+
+
+void PreParser::ParseStatementList(int end_token, bool* ok,
+                                   Scanner::BookmarkScope* bookmark) {
+  // SourceElements ::
+  //   (Statement)* <end_token>
+
+  // Bookkeeping for trial parse if bookmark is set:
+  DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet());
+  bool maybe_reset = bookmark != nullptr;
+  int count_statements = 0;
+
+  bool directive_prologue = true;
+  while (peek() != end_token) {
+    if (directive_prologue && peek() != Token::STRING) {
+      directive_prologue = false;
+    }
+    bool starts_with_identifier = peek() == Token::IDENTIFIER;
+    Scanner::Location token_loc = scanner()->peek_location();
+    Scanner::Location old_this_loc = function_state_->this_location();
+    Scanner::Location old_super_loc = function_state_->super_location();
+    Statement statement = ParseStatementListItem(ok);
+    if (!*ok) return;
+
+    if (is_strong(language_mode()) && scope_->is_function_scope() &&
+        IsClassConstructor(function_state_->kind())) {
+      Scanner::Location this_loc = function_state_->this_location();
+      Scanner::Location super_loc = function_state_->super_location();
+      if (this_loc.beg_pos != old_this_loc.beg_pos &&
+          this_loc.beg_pos != token_loc.beg_pos) {
+        ReportMessageAt(this_loc, MessageTemplate::kStrongConstructorThis);
+        *ok = false;
+        return;
+      }
+      if (super_loc.beg_pos != old_super_loc.beg_pos &&
+          super_loc.beg_pos != token_loc.beg_pos) {
+        ReportMessageAt(super_loc, MessageTemplate::kStrongConstructorSuper);
+        *ok = false;
+        return;
+      }
+    }
+
+    if (directive_prologue) {
+      bool use_strict_found = statement.IsUseStrictLiteral();
+      bool use_strong_found =
+          statement.IsUseStrongLiteral() && allow_strong_mode();
+
+      if (use_strict_found) {
+        scope_->SetLanguageMode(
+            static_cast<LanguageMode>(scope_->language_mode() | STRICT));
+      } else if (use_strong_found) {
+        scope_->SetLanguageMode(static_cast<LanguageMode>(
+            scope_->language_mode() | STRONG));
+        if (IsClassConstructor(function_state_->kind())) {
+          // "use strong" cannot occur in a class constructor body, to avoid
+          // unintuitive strong class object semantics.
+          PreParserTraits::ReportMessageAt(
+              token_loc, MessageTemplate::kStrongConstructorDirective);
+          *ok = false;
+          return;
+        }
+      } else if (!statement.IsStringLiteral()) {
+        directive_prologue = false;
+      }
+
+      if ((use_strict_found || use_strong_found) &&
+          !scope_->HasSimpleParameters()) {
+        // TC39 deemed "use strict" directives to be an error when occurring
+        // in the body of a function with non-simple parameter list, on
+        // 29/7/2015. https://goo.gl/ueA7Ln
+        //
+        // In V8, this also applies to "use strong " directives.
+        PreParserTraits::ReportMessageAt(
+            token_loc, MessageTemplate::kIllegalLanguageModeDirective,
+            use_strict_found ? "use strict" : "use strong");
+        *ok = false;
+        return;
+      }
+    }
+
+    // If we're allowed to reset to a bookmark, we will do so when we see a long
+    // and trivial function.
+    // Our current definition of 'long and trivial' is:
+    // - over 200 statements
+    // - all starting with an identifier (i.e., no if, for, while, etc.)
+    if (maybe_reset && (!starts_with_identifier ||
+                        ++count_statements > kLazyParseTrialLimit)) {
+      if (count_statements > kLazyParseTrialLimit) {
+        bookmark->Reset();
+        return;
+      }
+      maybe_reset = false;
+    }
+  }
+}
+
+
+#define CHECK_OK  ok);                   \
+  if (!*ok) return Statement::Default();  \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+
+PreParser::Statement PreParser::ParseStatement(bool* ok) {
+  // Statement ::
+  //   EmptyStatement
+  //   ...
+
+  if (peek() == Token::SEMICOLON) {
+    Next();
+    return Statement::Default();
+  }
+  return ParseSubStatement(ok);
+}
+
+
+PreParser::Statement PreParser::ParseSubStatement(bool* ok) {
+  // Statement ::
+  //   Block
+  //   VariableStatement
+  //   EmptyStatement
+  //   ExpressionStatement
+  //   IfStatement
+  //   IterationStatement
+  //   ContinueStatement
+  //   BreakStatement
+  //   ReturnStatement
+  //   WithStatement
+  //   LabelledStatement
+  //   SwitchStatement
+  //   ThrowStatement
+  //   TryStatement
+  //   DebuggerStatement
+
+  // Note: Since labels can only be used by 'break' and 'continue'
+  // statements, which themselves are only valid within blocks,
+  // iterations or 'switch' statements (i.e., BreakableStatements),
+  // labels can be simply ignored in all other cases; except for
+  // trivial labeled break statements 'label: break label' which is
+  // parsed into an empty statement.
+
+  // Keep the source position of the statement
+  switch (peek()) {
+    case Token::LBRACE:
+      return ParseBlock(ok);
+
+    case Token::SEMICOLON:
+      if (is_strong(language_mode())) {
+        PreParserTraits::ReportMessageAt(scanner()->peek_location(),
+                                         MessageTemplate::kStrongEmpty);
+        *ok = false;
+        return Statement::Default();
+      }
+      Next();
+      return Statement::Default();
+
+    case Token::IF:
+      return ParseIfStatement(ok);
+
+    case Token::DO:
+      return ParseDoWhileStatement(ok);
+
+    case Token::WHILE:
+      return ParseWhileStatement(ok);
+
+    case Token::FOR:
+      return ParseForStatement(ok);
+
+    case Token::CONTINUE:
+      return ParseContinueStatement(ok);
+
+    case Token::BREAK:
+      return ParseBreakStatement(ok);
+
+    case Token::RETURN:
+      return ParseReturnStatement(ok);
+
+    case Token::WITH:
+      return ParseWithStatement(ok);
+
+    case Token::SWITCH:
+      return ParseSwitchStatement(ok);
+
+    case Token::THROW:
+      return ParseThrowStatement(ok);
+
+    case Token::TRY:
+      return ParseTryStatement(ok);
+
+    case Token::FUNCTION: {
+      Scanner::Location start_location = scanner()->peek_location();
+      Statement statement = ParseFunctionDeclaration(CHECK_OK);
+      Scanner::Location end_location = scanner()->location();
+      if (is_strict(language_mode())) {
+        PreParserTraits::ReportMessageAt(start_location.beg_pos,
+                                         end_location.end_pos,
+                                         MessageTemplate::kStrictFunction);
+        *ok = false;
+        return Statement::Default();
+      } else {
+        return statement;
+      }
+    }
+
+    case Token::DEBUGGER:
+      return ParseDebuggerStatement(ok);
+
+    case Token::VAR:
+      return ParseVariableStatement(kStatement, ok);
+
+    case Token::CONST:
+      // In ES6 CONST is not allowed as a Statement, only as a
+      // LexicalDeclaration, however we continue to allow it in sloppy mode for
+      // backwards compatibility.
+      if (is_sloppy(language_mode()) && allow_legacy_const()) {
+        return ParseVariableStatement(kStatement, ok);
+      }
+
+    // Fall through.
+    default:
+      return ParseExpressionOrLabelledStatement(ok);
+  }
+}
+
+
+PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
+  // FunctionDeclaration ::
+  //   'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+  // GeneratorDeclaration ::
+  //   'function' '*' Identifier '(' FormalParameterListopt ')'
+  //      '{' FunctionBody '}'
+  Expect(Token::FUNCTION, CHECK_OK);
+  int pos = position();
+  bool is_generator = Check(Token::MUL);
+  bool is_strict_reserved = false;
+  Identifier name = ParseIdentifierOrStrictReservedWord(
+      &is_strict_reserved, CHECK_OK);
+  ParseFunctionLiteral(name, scanner()->location(),
+                       is_strict_reserved ? kFunctionNameIsStrictReserved
+                                          : kFunctionNameValidityUnknown,
+                       is_generator ? FunctionKind::kGeneratorFunction
+                                    : FunctionKind::kNormalFunction,
+                       pos, FunctionLiteral::kDeclaration,
+                       FunctionLiteral::kNormalArity, language_mode(),
+                       CHECK_OK);
+  return Statement::FunctionDeclaration();
+}
+
+
+PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
+  Expect(Token::CLASS, CHECK_OK);
+  if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
+    ReportMessage(MessageTemplate::kSloppyLexical);
+    *ok = false;
+    return Statement::Default();
+  }
+
+  int pos = position();
+  bool is_strict_reserved = false;
+  Identifier name =
+      ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
+  ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos,
+                    CHECK_OK);
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseBlock(bool* ok) {
+  // Block ::
+  //   '{' StatementList '}'
+
+  Expect(Token::LBRACE, CHECK_OK);
+  Statement final = Statement::Default();
+  while (peek() != Token::RBRACE) {
+    final = ParseStatementListItem(CHECK_OK);
+  }
+  Expect(Token::RBRACE, ok);
+  return final;
+}
+
+
+PreParser::Statement PreParser::ParseVariableStatement(
+    VariableDeclarationContext var_context,
+    bool* ok) {
+  // VariableStatement ::
+  //   VariableDeclarations ';'
+
+  Statement result = ParseVariableDeclarations(
+      var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+  return result;
+}
+
+
+// If the variable declaration declares exactly one non-const
+// variable, then *var is set to that variable. In all other cases,
+// *var is untouched; in particular, it is the caller's responsibility
+// to initialize it properly. This mechanism is also used for the parsing
+// of 'for-in' loops.
+PreParser::Statement PreParser::ParseVariableDeclarations(
+    VariableDeclarationContext var_context, int* num_decl, bool* is_lexical,
+    bool* is_binding_pattern, Scanner::Location* first_initializer_loc,
+    Scanner::Location* bindings_loc, bool* ok) {
+  // VariableDeclarations ::
+  //   ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
+  //
+  // The ES6 Draft Rev3 specifies the following grammar for const declarations
+  //
+  // ConstDeclaration ::
+  //   const ConstBinding (',' ConstBinding)* ';'
+  // ConstBinding ::
+  //   Identifier '=' AssignmentExpression
+  //
+  // TODO(ES6):
+  // ConstBinding ::
+  //   BindingPattern '=' AssignmentExpression
+  bool require_initializer = false;
+  bool lexical = false;
+  bool is_pattern = false;
+  if (peek() == Token::VAR) {
+    if (is_strong(language_mode())) {
+      Scanner::Location location = scanner()->peek_location();
+      ReportMessageAt(location, MessageTemplate::kStrongVar);
+      *ok = false;
+      return Statement::Default();
+    }
+    Consume(Token::VAR);
+  } else if (peek() == Token::CONST && allow_const()) {
+    // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
+    //
+    // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
+    //
+    // * It is a Syntax Error if the code that matches this production is not
+    //   contained in extended code.
+    //
+    // However disallowing const in sloppy mode will break compatibility with
+    // existing pages. Therefore we keep allowing const with the old
+    // non-harmony semantics in sloppy mode.
+    Consume(Token::CONST);
+    if (is_strict(language_mode()) ||
+        (allow_harmony_sloppy() && !allow_legacy_const())) {
+      DCHECK(var_context != kStatement);
+      require_initializer = true;
+      lexical = true;
+    }
+  } else if (peek() == Token::LET && allow_let()) {
+    Consume(Token::LET);
+    DCHECK(var_context != kStatement);
+    lexical = true;
+  } else {
+    *ok = false;
+    return Statement::Default();
+  }
+
+  // The scope of a var/const declared variable anywhere inside a function
+  // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope
+  // of a let declared variable is the scope of the immediately enclosing
+  // block.
+  int nvars = 0;  // the number of variables declared
+  int bindings_start = peek_position();
+  do {
+    // Parse binding pattern.
+    if (nvars > 0) Consume(Token::COMMA);
+    int decl_pos = peek_position();
+    PreParserExpression pattern = PreParserExpression::Default();
+    {
+      ExpressionClassifier pattern_classifier;
+      Token::Value next = peek();
+      pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+
+      ValidateBindingPattern(&pattern_classifier, CHECK_OK);
+      if (lexical) {
+        ValidateLetPattern(&pattern_classifier, CHECK_OK);
+      }
+
+      if (!allow_harmony_destructuring_bind() && !pattern.IsIdentifier()) {
+        ReportUnexpectedToken(next);
+        *ok = false;
+        return Statement::Default();
+      }
+    }
+
+    is_pattern = (pattern.IsObjectLiteral() || pattern.IsArrayLiteral()) &&
+                 !pattern.is_parenthesized();
+
+    bool is_for_iteration_variable =
+        var_context == kForStatement &&
+        (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
+
+    Scanner::Location variable_loc = scanner()->location();
+    nvars++;
+    if (Check(Token::ASSIGN)) {
+      ExpressionClassifier classifier;
+      ParseAssignmentExpression(var_context != kForStatement, &classifier,
+                                CHECK_OK);
+      ValidateExpression(&classifier, CHECK_OK);
+
+      variable_loc.end_pos = scanner()->location().end_pos;
+      if (first_initializer_loc && !first_initializer_loc->IsValid()) {
+        *first_initializer_loc = variable_loc;
+      }
+    } else if ((require_initializer || is_pattern) &&
+               !is_for_iteration_variable) {
+      PreParserTraits::ReportMessageAt(
+          Scanner::Location(decl_pos, scanner()->location().end_pos),
+          MessageTemplate::kDeclarationMissingInitializer,
+          is_pattern ? "destructuring" : "const");
+      *ok = false;
+      return Statement::Default();
+    }
+  } while (peek() == Token::COMMA);
+
+  if (bindings_loc) {
+    *bindings_loc =
+        Scanner::Location(bindings_start, scanner()->location().end_pos);
+  }
+
+  if (num_decl != nullptr) *num_decl = nvars;
+  if (is_lexical != nullptr) *is_lexical = lexical;
+  if (is_binding_pattern != nullptr) *is_binding_pattern = is_pattern;
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
+  // ExpressionStatement | LabelledStatement ::
+  //   Expression ';'
+  //   Identifier ':' Statement
+
+  switch (peek()) {
+    case Token::FUNCTION:
+    case Token::LBRACE:
+      UNREACHABLE();  // Always handled by the callers.
+    case Token::CLASS:
+      ReportUnexpectedToken(Next());
+      *ok = false;
+      return Statement::Default();
+
+    case Token::THIS:
+      if (!FLAG_strong_this) break;
+      // Fall through.
+    case Token::SUPER:
+      if (is_strong(language_mode()) &&
+          IsClassConstructor(function_state_->kind())) {
+        bool is_this = peek() == Token::THIS;
+        Expression expr = Expression::Default();
+        ExpressionClassifier classifier;
+        if (is_this) {
+          expr = ParseStrongInitializationExpression(&classifier, CHECK_OK);
+        } else {
+          expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK);
+        }
+        ValidateExpression(&classifier, CHECK_OK);
+        switch (peek()) {
+          case Token::SEMICOLON:
+            Consume(Token::SEMICOLON);
+            break;
+          case Token::RBRACE:
+          case Token::EOS:
+            break;
+          default:
+            if (!scanner()->HasAnyLineTerminatorBeforeNext()) {
+              ReportMessageAt(function_state_->this_location(),
+                              is_this
+                                  ? MessageTemplate::kStrongConstructorThis
+                                  : MessageTemplate::kStrongConstructorSuper);
+              *ok = false;
+              return Statement::Default();
+            }
+        }
+        return Statement::ExpressionStatement(expr);
+      }
+      break;
+
+    // TODO(arv): Handle `let [`
+    // https://code.google.com/p/v8/issues/detail?id=3847
+
+    default:
+      break;
+  }
+
+  bool starts_with_identifier = peek_any_identifier();
+  ExpressionClassifier classifier;
+  Expression expr = ParseExpression(true, &classifier, CHECK_OK);
+  ValidateExpression(&classifier, CHECK_OK);
+
+  // Even if the expression starts with an identifier, it is not necessarily an
+  // identifier. For example, "foo + bar" starts with an identifier but is not
+  // an identifier.
+  if (starts_with_identifier && expr.IsIdentifier() && peek() == Token::COLON) {
+    // Expression is a single identifier, and not, e.g., a parenthesized
+    // identifier.
+    DCHECK(!expr.AsIdentifier().IsFutureReserved());
+    DCHECK(is_sloppy(language_mode()) ||
+           !IsFutureStrictReserved(expr.AsIdentifier()));
+    Consume(Token::COLON);
+    Statement statement = ParseStatement(ok);
+    return statement.IsJumpStatement() ? Statement::Default() : statement;
+    // Preparsing is disabled for extensions (because the extension details
+    // aren't passed to lazily compiled functions), so we don't
+    // accept "native function" in the preparser.
+  }
+  // Parsed expression statement.
+  // Detect attempts at 'let' declarations in sloppy mode.
+  if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
+      is_sloppy(language_mode()) && expr.IsIdentifier() &&
+      expr.AsIdentifier().IsLet()) {
+    ReportMessage(MessageTemplate::kSloppyLexical, NULL);
+    *ok = false;
+    return Statement::Default();
+  }
+  ExpectSemicolon(CHECK_OK);
+  return Statement::ExpressionStatement(expr);
+}
+
+
+PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
+  // IfStatement ::
+  //   'if' '(' Expression ')' Statement ('else' Statement)?
+
+  Expect(Token::IF, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+  Statement stat = ParseSubStatement(CHECK_OK);
+  if (peek() == Token::ELSE) {
+    Next();
+    Statement else_stat = ParseSubStatement(CHECK_OK);
+    stat = (stat.IsJumpStatement() && else_stat.IsJumpStatement()) ?
+        Statement::Jump() : Statement::Default();
+  } else {
+    stat = Statement::Default();
+  }
+  return stat;
+}
+
+
+PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
+  // ContinueStatement ::
+  //   'continue' [no line terminator] Identifier? ';'
+
+  Expect(Token::CONTINUE, CHECK_OK);
+  Token::Value tok = peek();
+  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
+      tok != Token::SEMICOLON &&
+      tok != Token::RBRACE &&
+      tok != Token::EOS) {
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+  }
+  ExpectSemicolon(CHECK_OK);
+  return Statement::Jump();
+}
+
+
+PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
+  // BreakStatement ::
+  //   'break' [no line terminator] Identifier? ';'
+
+  Expect(Token::BREAK, CHECK_OK);
+  Token::Value tok = peek();
+  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
+      tok != Token::SEMICOLON &&
+      tok != Token::RBRACE &&
+      tok != Token::EOS) {
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+  }
+  ExpectSemicolon(CHECK_OK);
+  return Statement::Jump();
+}
+
+
+PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
+  // ReturnStatement ::
+  //   'return' [no line terminator] Expression? ';'
+
+  // Consume the return token. It is necessary to do before
+  // reporting any errors on it, because of the way errors are
+  // reported (underlining).
+  Expect(Token::RETURN, CHECK_OK);
+  function_state_->set_return_location(scanner()->location());
+
+  // An ECMAScript program is considered syntactically incorrect if it
+  // contains a return statement that is not within the body of a
+  // function. See ECMA-262, section 12.9, page 67.
+  // This is not handled during preparsing.
+
+  Token::Value tok = peek();
+  if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
+      tok != Token::SEMICOLON &&
+      tok != Token::RBRACE &&
+      tok != Token::EOS) {
+    if (is_strong(language_mode()) &&
+        IsClassConstructor(function_state_->kind())) {
+      int pos = peek_position();
+      ReportMessageAt(Scanner::Location(pos, pos + 1),
+                      MessageTemplate::kStrongConstructorReturnValue);
+      *ok = false;
+      return Statement::Default();
+    }
+    ParseExpression(true, CHECK_OK);
+  }
+  ExpectSemicolon(CHECK_OK);
+  return Statement::Jump();
+}
+
+
+PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
+  // WithStatement ::
+  //   'with' '(' Expression ')' Statement
+  Expect(Token::WITH, CHECK_OK);
+  if (is_strict(language_mode())) {
+    ReportMessageAt(scanner()->location(), MessageTemplate::kStrictWith);
+    *ok = false;
+    return Statement::Default();
+  }
+  Expect(Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  Scope* with_scope = NewScope(scope_, WITH_SCOPE);
+  BlockState block_state(&scope_, with_scope);
+  ParseSubStatement(CHECK_OK);
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
+  // SwitchStatement ::
+  //   'switch' '(' Expression ')' '{' CaseClause* '}'
+
+  Expect(Token::SWITCH, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+
+  Expect(Token::LBRACE, CHECK_OK);
+  Token::Value token = peek();
+  while (token != Token::RBRACE) {
+    if (token == Token::CASE) {
+      Expect(Token::CASE, CHECK_OK);
+      ParseExpression(true, CHECK_OK);
+    } else {
+      Expect(Token::DEFAULT, CHECK_OK);
+    }
+    Expect(Token::COLON, CHECK_OK);
+    token = peek();
+    Statement statement = Statement::Jump();
+    while (token != Token::CASE &&
+           token != Token::DEFAULT &&
+           token != Token::RBRACE) {
+      statement = ParseStatementListItem(CHECK_OK);
+      token = peek();
+    }
+    if (is_strong(language_mode()) && !statement.IsJumpStatement() &&
+        token != Token::RBRACE) {
+      ReportMessageAt(scanner()->location(),
+                      MessageTemplate::kStrongSwitchFallthrough);
+      *ok = false;
+      return Statement::Default();
+    }
+  }
+  Expect(Token::RBRACE, ok);
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
+  // DoStatement ::
+  //   'do' Statement 'while' '(' Expression ')' ';'
+
+  Expect(Token::DO, CHECK_OK);
+  ParseSubStatement(CHECK_OK);
+  Expect(Token::WHILE, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, ok);
+  if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
+  // WhileStatement ::
+  //   'while' '(' Expression ')' Statement
+
+  Expect(Token::WHILE, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+  ParseSubStatement(ok);
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseForStatement(bool* ok) {
+  // ForStatement ::
+  //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
+
+  Expect(Token::FOR, CHECK_OK);
+  Expect(Token::LPAREN, CHECK_OK);
+  bool is_let_identifier_expression = false;
+  if (peek() != Token::SEMICOLON) {
+    ForEachStatement::VisitMode mode;
+    if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
+        (peek() == Token::LET && IsNextLetKeyword())) {
+      int decl_count;
+      bool is_lexical;
+      bool is_binding_pattern;
+      Scanner::Location first_initializer_loc = Scanner::Location::invalid();
+      Scanner::Location bindings_loc = Scanner::Location::invalid();
+      ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical,
+                                &is_binding_pattern, &first_initializer_loc,
+                                &bindings_loc, CHECK_OK);
+      bool accept_IN = decl_count >= 1;
+      if (accept_IN && CheckInOrOf(&mode, ok)) {
+        if (!*ok) return Statement::Default();
+        if (decl_count != 1) {
+          const char* loop_type =
+              mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
+          PreParserTraits::ReportMessageAt(
+              bindings_loc, MessageTemplate::kForInOfLoopMultiBindings,
+              loop_type);
+          *ok = false;
+          return Statement::Default();
+        }
+        if (first_initializer_loc.IsValid() &&
+            (is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
+             is_lexical || is_binding_pattern)) {
+          if (mode == ForEachStatement::ITERATE) {
+            ReportMessageAt(first_initializer_loc,
+                            MessageTemplate::kForOfLoopInitializer);
+          } else {
+            // TODO(caitp): This should be an error in sloppy mode, too.
+            ReportMessageAt(first_initializer_loc,
+                            MessageTemplate::kForInLoopInitializer);
+          }
+          *ok = false;
+          return Statement::Default();
+        }
+        ParseExpression(true, CHECK_OK);
+        Expect(Token::RPAREN, CHECK_OK);
+        ParseSubStatement(CHECK_OK);
+        return Statement::Default();
+      }
+    } else {
+      int lhs_beg_pos = peek_position();
+      ExpressionClassifier classifier;
+      Expression lhs = ParseExpression(false, &classifier, CHECK_OK);
+      int lhs_end_pos = scanner()->location().end_pos;
+      is_let_identifier_expression =
+          lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
+      bool is_for_each = CheckInOrOf(&mode, ok);
+      if (!*ok) return Statement::Default();
+      bool is_destructuring = is_for_each &&
+                              allow_harmony_destructuring_assignment() &&
+                              (lhs->IsArrayLiteral() || lhs->IsObjectLiteral());
+
+      if (is_destructuring) {
+        ValidateAssignmentPattern(&classifier, CHECK_OK);
+      } else {
+        ValidateExpression(&classifier, CHECK_OK);
+      }
+
+      if (is_for_each) {
+        if (!is_destructuring) {
+          lhs = CheckAndRewriteReferenceExpression(
+              lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
+              kSyntaxError, CHECK_OK);
+        }
+        ParseExpression(true, CHECK_OK);
+        Expect(Token::RPAREN, CHECK_OK);
+        ParseSubStatement(CHECK_OK);
+        return Statement::Default();
+      }
+    }
+  }
+
+  // Parsed initializer at this point.
+  // Detect attempts at 'let' declarations in sloppy mode.
+  if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
+      is_sloppy(language_mode()) && is_let_identifier_expression) {
+    ReportMessage(MessageTemplate::kSloppyLexical, NULL);
+    *ok = false;
+    return Statement::Default();
+  }
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  if (peek() != Token::SEMICOLON) {
+    ParseExpression(true, CHECK_OK);
+  }
+  Expect(Token::SEMICOLON, CHECK_OK);
+
+  if (peek() != Token::RPAREN) {
+    ParseExpression(true, CHECK_OK);
+  }
+  Expect(Token::RPAREN, CHECK_OK);
+
+  ParseSubStatement(ok);
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
+  // ThrowStatement ::
+  //   'throw' [no line terminator] Expression ';'
+
+  Expect(Token::THROW, CHECK_OK);
+  if (scanner()->HasAnyLineTerminatorBeforeNext()) {
+    ReportMessageAt(scanner()->location(), MessageTemplate::kNewlineAfterThrow);
+    *ok = false;
+    return Statement::Default();
+  }
+  ParseExpression(true, CHECK_OK);
+  ExpectSemicolon(ok);
+  return Statement::Jump();
+}
+
+
+PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
+  // TryStatement ::
+  //   'try' Block Catch
+  //   'try' Block Finally
+  //   'try' Block Catch Finally
+  //
+  // Catch ::
+  //   'catch' '(' Identifier ')' Block
+  //
+  // Finally ::
+  //   'finally' Block
+
+  Expect(Token::TRY, CHECK_OK);
+
+  ParseBlock(CHECK_OK);
+
+  Token::Value tok = peek();
+  if (tok != Token::CATCH && tok != Token::FINALLY) {
+    ReportMessageAt(scanner()->location(), MessageTemplate::kNoCatchOrFinally);
+    *ok = false;
+    return Statement::Default();
+  }
+  if (tok == Token::CATCH) {
+    Consume(Token::CATCH);
+    Expect(Token::LPAREN, CHECK_OK);
+    ExpressionClassifier pattern_classifier;
+    ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+    ValidateBindingPattern(&pattern_classifier, CHECK_OK);
+    Expect(Token::RPAREN, CHECK_OK);
+    {
+      // TODO(adamk): Make this CATCH_SCOPE
+      Scope* with_scope = NewScope(scope_, WITH_SCOPE);
+      BlockState block_state(&scope_, with_scope);
+      ParseBlock(CHECK_OK);
+    }
+    tok = peek();
+  }
+  if (tok == Token::FINALLY) {
+    Consume(Token::FINALLY);
+    ParseBlock(CHECK_OK);
+  }
+  return Statement::Default();
+}
+
+
+PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
+  // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
+  // contexts this is used as a statement which invokes the debugger as if a
+  // break point is present.
+  // DebuggerStatement ::
+  //   'debugger' ';'
+
+  Expect(Token::DEBUGGER, CHECK_OK);
+  ExpectSemicolon(ok);
+  return Statement::Default();
+}
+
+
+#undef CHECK_OK
+#define CHECK_OK  ok);                     \
+  if (!*ok) return Expression::Default();  \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+
+PreParser::Expression PreParser::ParseFunctionLiteral(
+    Identifier function_name, Scanner::Location function_name_location,
+    FunctionNameValidity function_name_validity, FunctionKind kind,
+    int function_token_pos, FunctionLiteral::FunctionType function_type,
+    FunctionLiteral::ArityRestriction arity_restriction,
+    LanguageMode language_mode, bool* ok) {
+  // Function ::
+  //   '(' FormalParameterList? ')' '{' FunctionBody '}'
+
+  // Parse function body.
+  bool outer_is_script_scope = scope_->is_script_scope();
+  Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind);
+  function_scope->SetLanguageMode(language_mode);
+  PreParserFactory factory(NULL);
+  FunctionState function_state(&function_state_, &scope_, function_scope, kind,
+                               &factory);
+  DuplicateFinder duplicate_finder(scanner()->unicode_cache());
+  ExpressionClassifier formals_classifier(&duplicate_finder);
+
+  Expect(Token::LPAREN, CHECK_OK);
+  int start_position = scanner()->location().beg_pos;
+  function_scope->set_start_position(start_position);
+  PreParserFormalParameters formals(function_scope);
+  ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
+  Expect(Token::RPAREN, CHECK_OK);
+  int formals_end_position = scanner()->location().end_pos;
+
+  CheckArityRestrictions(formals.arity, arity_restriction,
+                         formals.has_rest, start_position,
+                         formals_end_position, CHECK_OK);
+
+  // See Parser::ParseFunctionLiteral for more information about lazy parsing
+  // and lazy compilation.
+  bool is_lazily_parsed =
+      (outer_is_script_scope && allow_lazy() && !parenthesized_function_);
+  parenthesized_function_ = false;
+
+  Expect(Token::LBRACE, CHECK_OK);
+  if (is_lazily_parsed) {
+    ParseLazyFunctionLiteralBody(CHECK_OK);
+  } else {
+    ParseStatementList(Token::RBRACE, CHECK_OK);
+  }
+  Expect(Token::RBRACE, CHECK_OK);
+
+  // Parsing the body may change the language mode in our scope.
+  language_mode = function_scope->language_mode();
+
+  // Validate name and parameter names. We can do this only after parsing the
+  // function, since the function can declare itself strict.
+  CheckFunctionName(language_mode, function_name, function_name_validity,
+                    function_name_location, CHECK_OK);
+  const bool allow_duplicate_parameters =
+      is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
+  ValidateFormalParameters(&formals_classifier, language_mode,
+                           allow_duplicate_parameters, CHECK_OK);
+
+  if (is_strict(language_mode)) {
+    int end_position = scanner()->location().end_pos;
+    CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
+  }
+
+  if (is_strong(language_mode) && IsSubclassConstructor(kind)) {
+    if (!function_state.super_location().IsValid()) {
+      ReportMessageAt(function_name_location,
+                      MessageTemplate::kStrongSuperCallMissing,
+                      kReferenceError);
+      *ok = false;
+      return Expression::Default();
+    }
+  }
+
+  return Expression::Default();
+}
+
+
+void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
+                                             Scanner::BookmarkScope* bookmark) {
+  int body_start = position();
+  ParseStatementList(Token::RBRACE, ok, bookmark);
+  if (!*ok) return;
+  if (bookmark && bookmark->HasBeenReset()) return;
+
+  // Position right after terminal '}'.
+  DCHECK_EQ(Token::RBRACE, scanner()->peek());
+  int body_end = scanner()->peek_location().end_pos;
+  log_->LogFunction(body_start, body_end,
+                    function_state_->materialized_literal_count(),
+                    function_state_->expected_property_count(), language_mode(),
+                    scope_->uses_super_property(), scope_->calls_eval());
+}
+
+
+PreParserExpression PreParser::ParseClassLiteral(
+    PreParserIdentifier name, Scanner::Location class_name_location,
+    bool name_is_strict_reserved, int pos, bool* ok) {
+  // All parts of a ClassDeclaration and ClassExpression are strict code.
+  if (name_is_strict_reserved) {
+    ReportMessageAt(class_name_location,
+                    MessageTemplate::kUnexpectedStrictReserved);
+    *ok = false;
+    return EmptyExpression();
+  }
+  if (IsEvalOrArguments(name)) {
+    ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments);
+    *ok = false;
+    return EmptyExpression();
+  }
+  LanguageMode class_language_mode = language_mode();
+  if (is_strong(class_language_mode) && IsUndefined(name)) {
+    ReportMessageAt(class_name_location, MessageTemplate::kStrongUndefined);
+    *ok = false;
+    return EmptyExpression();
+  }
+
+  Scope* scope = NewScope(scope_, BLOCK_SCOPE);
+  BlockState block_state(&scope_, scope);
+  scope_->SetLanguageMode(
+      static_cast<LanguageMode>(class_language_mode | STRICT));
+  // TODO(marja): Make PreParser use scope names too.
+  // scope_->SetScopeName(name);
+
+  bool has_extends = Check(Token::EXTENDS);
+  if (has_extends) {
+    ExpressionClassifier classifier;
+    ParseLeftHandSideExpression(&classifier, CHECK_OK);
+    ValidateExpression(&classifier, CHECK_OK);
+  }
+
+  ClassLiteralChecker checker(this);
+  bool has_seen_constructor = false;
+
+  Expect(Token::LBRACE, CHECK_OK);
+  while (peek() != Token::RBRACE) {
+    if (Check(Token::SEMICOLON)) continue;
+    const bool in_class = true;
+    const bool is_static = false;
+    bool is_computed_name = false;  // Classes do not care about computed
+                                    // property names here.
+    Identifier name;
+    ExpressionClassifier classifier;
+    ParsePropertyDefinition(&checker, in_class, has_extends, is_static,
+                            &is_computed_name, &has_seen_constructor,
+                            &classifier, &name, CHECK_OK);
+    ValidateExpression(&classifier, CHECK_OK);
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+
+  return Expression::Default();
+}
+
+
+PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
+  // CallRuntime ::
+  //   '%' Identifier Arguments
+  Expect(Token::MOD, CHECK_OK);
+  if (!allow_natives()) {
+    *ok = false;
+    return Expression::Default();
+  }
+  // Allow "eval" or "arguments" for backward compatibility.
+  ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+  Scanner::Location spread_pos;
+  ExpressionClassifier classifier;
+  ParseArguments(&spread_pos, &classifier, ok);
+  ValidateExpression(&classifier, CHECK_OK);
+
+  DCHECK(!spread_pos.IsValid());
+
+  return Expression::Default();
+}
+
+
+PreParserExpression PreParser::ParseDoExpression(bool* ok) {
+  // AssignmentExpression ::
+  //     do '{' StatementList '}'
+  Expect(Token::DO, CHECK_OK);
+  Expect(Token::LBRACE, CHECK_OK);
+  Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+  {
+    BlockState block_state(&scope_, block_scope);
+    while (peek() != Token::RBRACE) {
+      ParseStatementListItem(CHECK_OK);
+    }
+    Expect(Token::RBRACE, CHECK_OK);
+    return PreParserExpression::Default();
+  }
+}
+
+#undef CHECK_OK
+
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h
new file mode 100644
index 0000000..59100f1
--- /dev/null
+++ b/src/parsing/preparser.h
@@ -0,0 +1,1175 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_PREPARSER_H
+#define V8_PARSING_PREPARSER_H
+
+#include "src/ast/scopes.h"
+#include "src/bailout-reason.h"
+#include "src/hashmap.h"
+#include "src/messages.h"
+#include "src/parsing/expression-classifier.h"
+#include "src/parsing/func-name-inferrer.h"
+#include "src/parsing/parser-base.h"
+#include "src/parsing/scanner.h"
+#include "src/parsing/token.h"
+
+namespace v8 {
+namespace internal {
+
+
+class PreParserIdentifier {
+ public:
+  PreParserIdentifier() : type_(kUnknownIdentifier) {}
+  static PreParserIdentifier Default() {
+    return PreParserIdentifier(kUnknownIdentifier);
+  }
+  static PreParserIdentifier Eval() {
+    return PreParserIdentifier(kEvalIdentifier);
+  }
+  static PreParserIdentifier Arguments() {
+    return PreParserIdentifier(kArgumentsIdentifier);
+  }
+  static PreParserIdentifier Undefined() {
+    return PreParserIdentifier(kUndefinedIdentifier);
+  }
+  static PreParserIdentifier FutureReserved() {
+    return PreParserIdentifier(kFutureReservedIdentifier);
+  }
+  static PreParserIdentifier FutureStrictReserved() {
+    return PreParserIdentifier(kFutureStrictReservedIdentifier);
+  }
+  static PreParserIdentifier Let() {
+    return PreParserIdentifier(kLetIdentifier);
+  }
+  static PreParserIdentifier Static() {
+    return PreParserIdentifier(kStaticIdentifier);
+  }
+  static PreParserIdentifier Yield() {
+    return PreParserIdentifier(kYieldIdentifier);
+  }
+  static PreParserIdentifier Prototype() {
+    return PreParserIdentifier(kPrototypeIdentifier);
+  }
+  static PreParserIdentifier Constructor() {
+    return PreParserIdentifier(kConstructorIdentifier);
+  }
+  bool IsEval() const { return type_ == kEvalIdentifier; }
+  bool IsArguments() const { return type_ == kArgumentsIdentifier; }
+  bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
+  bool IsUndefined() const { return type_ == kUndefinedIdentifier; }
+  bool IsLet() const { return type_ == kLetIdentifier; }
+  bool IsStatic() const { return type_ == kStaticIdentifier; }
+  bool IsYield() const { return type_ == kYieldIdentifier; }
+  bool IsPrototype() const { return type_ == kPrototypeIdentifier; }
+  bool IsConstructor() const { return type_ == kConstructorIdentifier; }
+  bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; }
+  bool IsFutureStrictReserved() const {
+    return type_ == kFutureStrictReservedIdentifier ||
+           type_ == kLetIdentifier || type_ == kStaticIdentifier ||
+           type_ == kYieldIdentifier;
+  }
+
+  // Allow identifier->name()[->length()] to work. The preparser
+  // does not need the actual positions/lengths of the identifiers.
+  const PreParserIdentifier* operator->() const { return this; }
+  const PreParserIdentifier raw_name() const { return *this; }
+
+  int position() const { return 0; }
+  int length() const { return 0; }
+
+ private:
+  enum Type {
+    kUnknownIdentifier,
+    kFutureReservedIdentifier,
+    kFutureStrictReservedIdentifier,
+    kLetIdentifier,
+    kStaticIdentifier,
+    kYieldIdentifier,
+    kEvalIdentifier,
+    kArgumentsIdentifier,
+    kUndefinedIdentifier,
+    kPrototypeIdentifier,
+    kConstructorIdentifier
+  };
+
+  explicit PreParserIdentifier(Type type) : type_(type) {}
+  Type type_;
+
+  friend class PreParserExpression;
+};
+
+
+class PreParserExpression {
+ public:
+  static PreParserExpression Default() {
+    return PreParserExpression(TypeField::encode(kExpression));
+  }
+
+  static PreParserExpression Spread(PreParserExpression expression) {
+    return PreParserExpression(TypeField::encode(kSpreadExpression));
+  }
+
+  static PreParserExpression FromIdentifier(PreParserIdentifier id) {
+    return PreParserExpression(TypeField::encode(kIdentifierExpression) |
+                               IdentifierTypeField::encode(id.type_));
+  }
+
+  static PreParserExpression BinaryOperation(PreParserExpression left,
+                                             Token::Value op,
+                                             PreParserExpression right) {
+    return PreParserExpression(TypeField::encode(kBinaryOperationExpression));
+  }
+
+  static PreParserExpression Assignment() {
+    return PreParserExpression(TypeField::encode(kExpression) |
+                               ExpressionTypeField::encode(kAssignment));
+  }
+
+  static PreParserExpression ObjectLiteral() {
+    return PreParserExpression(TypeField::encode(kObjectLiteralExpression));
+  }
+
+  static PreParserExpression ArrayLiteral() {
+    return PreParserExpression(TypeField::encode(kArrayLiteralExpression));
+  }
+
+  static PreParserExpression StringLiteral() {
+    return PreParserExpression(TypeField::encode(kStringLiteralExpression));
+  }
+
+  static PreParserExpression UseStrictStringLiteral() {
+    return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
+                               IsUseStrictField::encode(true));
+  }
+
+  static PreParserExpression UseStrongStringLiteral() {
+    return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
+                               IsUseStrongField::encode(true));
+  }
+
+  static PreParserExpression This() {
+    return PreParserExpression(TypeField::encode(kExpression) |
+                               ExpressionTypeField::encode(kThisExpression));
+  }
+
+  static PreParserExpression ThisProperty() {
+    return PreParserExpression(
+        TypeField::encode(kExpression) |
+        ExpressionTypeField::encode(kThisPropertyExpression));
+  }
+
+  static PreParserExpression Property() {
+    return PreParserExpression(
+        TypeField::encode(kExpression) |
+        ExpressionTypeField::encode(kPropertyExpression));
+  }
+
+  static PreParserExpression Call() {
+    return PreParserExpression(TypeField::encode(kExpression) |
+                               ExpressionTypeField::encode(kCallExpression));
+  }
+
+  static PreParserExpression SuperCallReference() {
+    return PreParserExpression(
+        TypeField::encode(kExpression) |
+        ExpressionTypeField::encode(kSuperCallReference));
+  }
+
+  static PreParserExpression NoTemplateTag() {
+    return PreParserExpression(
+        TypeField::encode(kExpression) |
+        ExpressionTypeField::encode(kNoTemplateTagExpression));
+  }
+
+  bool IsIdentifier() const {
+    return TypeField::decode(code_) == kIdentifierExpression;
+  }
+
+  PreParserIdentifier AsIdentifier() const {
+    DCHECK(IsIdentifier());
+    return PreParserIdentifier(IdentifierTypeField::decode(code_));
+  }
+
+  bool IsAssignment() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kAssignment;
+  }
+
+  bool IsObjectLiteral() const {
+    return TypeField::decode(code_) == kObjectLiteralExpression;
+  }
+
+  bool IsArrayLiteral() const {
+    return TypeField::decode(code_) == kArrayLiteralExpression;
+  }
+
+  bool IsStringLiteral() const {
+    return TypeField::decode(code_) == kStringLiteralExpression;
+  }
+
+  bool IsUseStrictLiteral() const {
+    return TypeField::decode(code_) == kStringLiteralExpression &&
+           IsUseStrictField::decode(code_);
+  }
+
+  bool IsUseStrongLiteral() const {
+    return TypeField::decode(code_) == kStringLiteralExpression &&
+           IsUseStrongField::decode(code_);
+  }
+
+  bool IsThis() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kThisExpression;
+  }
+
+  bool IsThisProperty() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kThisPropertyExpression;
+  }
+
+  bool IsProperty() const {
+    return TypeField::decode(code_) == kExpression &&
+           (ExpressionTypeField::decode(code_) == kPropertyExpression ||
+            ExpressionTypeField::decode(code_) == kThisPropertyExpression);
+  }
+
+  bool IsCall() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kCallExpression;
+  }
+
+  bool IsSuperCallReference() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kSuperCallReference;
+  }
+
+  bool IsValidReferenceExpression() const {
+    return IsIdentifier() || IsProperty();
+  }
+
+  // At the moment PreParser doesn't track these expression types.
+  bool IsFunctionLiteral() const { return false; }
+  bool IsCallNew() const { return false; }
+
+  bool IsNoTemplateTag() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kNoTemplateTagExpression;
+  }
+
+  bool IsSpreadExpression() const {
+    return TypeField::decode(code_) == kSpreadExpression;
+  }
+
+  PreParserExpression AsFunctionLiteral() { return *this; }
+
+  bool IsBinaryOperation() const {
+    return TypeField::decode(code_) == kBinaryOperationExpression;
+  }
+
+  // Dummy implementation for making expression->somefunc() work in both Parser
+  // and PreParser.
+  PreParserExpression* operator->() { return this; }
+
+  // More dummy implementations of things PreParser doesn't need to track:
+  void set_index(int index) {}  // For YieldExpressions
+  void set_should_eager_compile() {}
+
+  int position() const { return RelocInfo::kNoPosition; }
+  void set_function_token_position(int position) {}
+
+  // Parenthesized expressions in the form `( Expression )`.
+  void set_is_parenthesized() {
+    code_ = ParenthesizedField::update(code_, true);
+  }
+  bool is_parenthesized() const { return ParenthesizedField::decode(code_); }
+
+ private:
+  enum Type {
+    kExpression,
+    kIdentifierExpression,
+    kStringLiteralExpression,
+    kBinaryOperationExpression,
+    kSpreadExpression,
+    kObjectLiteralExpression,
+    kArrayLiteralExpression
+  };
+
+  enum ExpressionType {
+    kThisExpression,
+    kThisPropertyExpression,
+    kPropertyExpression,
+    kCallExpression,
+    kSuperCallReference,
+    kNoTemplateTagExpression,
+    kAssignment
+  };
+
+  explicit PreParserExpression(uint32_t expression_code)
+      : code_(expression_code) {}
+
+  // The first three bits are for the Type.
+  typedef BitField<Type, 0, 3> TypeField;
+
+  // The high order bit applies only to nodes which would inherit from the
+  // Expression ASTNode --- This is by necessity, due to the fact that
+  // Expression nodes may be represented as multiple Types, not exclusively
+  // through kExpression.
+  // TODO(caitp, adamk): clean up PreParserExpression bitfields.
+  typedef BitField<bool, 31, 1> ParenthesizedField;
+
+  // The rest of the bits are interpreted depending on the value
+  // of the Type field, so they can share the storage.
+  typedef BitField<ExpressionType, TypeField::kNext, 3> ExpressionTypeField;
+  typedef BitField<bool, TypeField::kNext, 1> IsUseStrictField;
+  typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseStrongField;
+  typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 10>
+      IdentifierTypeField;
+  typedef BitField<bool, TypeField::kNext, 1> HasCoverInitializedNameField;
+
+  uint32_t code_;
+};
+
+
+// The pre-parser doesn't need to build lists of expressions, identifiers, or
+// the like.
+template <typename T>
+class PreParserList {
+ public:
+  // These functions make list->Add(some_expression) work (and do nothing).
+  PreParserList() : length_(0) {}
+  PreParserList* operator->() { return this; }
+  void Add(T, void*) { ++length_; }
+  int length() const { return length_; }
+ private:
+  int length_;
+};
+
+
+typedef PreParserList<PreParserExpression> PreParserExpressionList;
+
+
+class PreParserStatement {
+ public:
+  static PreParserStatement Default() {
+    return PreParserStatement(kUnknownStatement);
+  }
+
+  static PreParserStatement Jump() {
+    return PreParserStatement(kJumpStatement);
+  }
+
+  static PreParserStatement FunctionDeclaration() {
+    return PreParserStatement(kFunctionDeclaration);
+  }
+
+  // Creates expression statement from expression.
+  // Preserves being an unparenthesized string literal, possibly
+  // "use strict".
+  static PreParserStatement ExpressionStatement(
+      PreParserExpression expression) {
+    if (expression.IsUseStrictLiteral()) {
+      return PreParserStatement(kUseStrictExpressionStatement);
+    }
+    if (expression.IsUseStrongLiteral()) {
+      return PreParserStatement(kUseStrongExpressionStatement);
+    }
+    if (expression.IsStringLiteral()) {
+      return PreParserStatement(kStringLiteralExpressionStatement);
+    }
+    return Default();
+  }
+
+  bool IsStringLiteral() {
+    return code_ == kStringLiteralExpressionStatement;
+  }
+
+  bool IsUseStrictLiteral() {
+    return code_ == kUseStrictExpressionStatement;
+  }
+
+  bool IsUseStrongLiteral() { return code_ == kUseStrongExpressionStatement; }
+
+  bool IsFunctionDeclaration() {
+    return code_ == kFunctionDeclaration;
+  }
+
+  bool IsJumpStatement() {
+    return code_ == kJumpStatement;
+  }
+
+ private:
+  enum Type {
+    kUnknownStatement,
+    kJumpStatement,
+    kStringLiteralExpressionStatement,
+    kUseStrictExpressionStatement,
+    kUseStrongExpressionStatement,
+    kFunctionDeclaration
+  };
+
+  explicit PreParserStatement(Type code) : code_(code) {}
+  Type code_;
+};
+
+
+typedef PreParserList<PreParserStatement> PreParserStatementList;
+
+
+class PreParserFactory {
+ public:
+  explicit PreParserFactory(void* unused_value_factory) {}
+  PreParserExpression NewStringLiteral(PreParserIdentifier identifier,
+                                       int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewNumberLiteral(double number,
+                                       int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewRegExpLiteral(PreParserIdentifier js_pattern,
+                                       int js_flags, int literal_index,
+                                       bool is_strong, int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewArrayLiteral(PreParserExpressionList values,
+                                      int literal_index,
+                                      bool is_strong,
+                                      int pos) {
+    return PreParserExpression::ArrayLiteral();
+  }
+  PreParserExpression NewArrayLiteral(PreParserExpressionList values,
+                                      int first_spread_index, int literal_index,
+                                      bool is_strong, int pos) {
+    return PreParserExpression::ArrayLiteral();
+  }
+  PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
+                                               PreParserExpression value,
+                                               ObjectLiteralProperty::Kind kind,
+                                               bool is_static,
+                                               bool is_computed_name) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
+                                               PreParserExpression value,
+                                               bool is_static,
+                                               bool is_computed_name) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewObjectLiteral(PreParserExpressionList properties,
+                                       int literal_index,
+                                       int boilerplate_properties,
+                                       bool has_function,
+                                       bool is_strong,
+                                       int pos) {
+    return PreParserExpression::ObjectLiteral();
+  }
+  PreParserExpression NewVariableProxy(void* variable) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewProperty(PreParserExpression obj,
+                                  PreParserExpression key,
+                                  int pos) {
+    if (obj.IsThis()) {
+      return PreParserExpression::ThisProperty();
+    }
+    return PreParserExpression::Property();
+  }
+  PreParserExpression NewUnaryOperation(Token::Value op,
+                                        PreParserExpression expression,
+                                        int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewBinaryOperation(Token::Value op,
+                                         PreParserExpression left,
+                                         PreParserExpression right, int pos) {
+    return PreParserExpression::BinaryOperation(left, op, right);
+  }
+  PreParserExpression NewCompareOperation(Token::Value op,
+                                          PreParserExpression left,
+                                          PreParserExpression right, int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewRewritableAssignmentExpression(
+      PreParserExpression expression) {
+    return expression;
+  }
+  PreParserExpression NewAssignment(Token::Value op,
+                                    PreParserExpression left,
+                                    PreParserExpression right,
+                                    int pos) {
+    return PreParserExpression::Assignment();
+  }
+  PreParserExpression NewYield(PreParserExpression generator_object,
+                               PreParserExpression expression,
+                               Yield::Kind yield_kind,
+                               int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewConditional(PreParserExpression condition,
+                                     PreParserExpression then_expression,
+                                     PreParserExpression else_expression,
+                                     int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewCountOperation(Token::Value op,
+                                        bool is_prefix,
+                                        PreParserExpression expression,
+                                        int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewCall(PreParserExpression expression,
+                              PreParserExpressionList arguments,
+                              int pos) {
+    return PreParserExpression::Call();
+  }
+  PreParserExpression NewCallNew(PreParserExpression expression,
+                                 PreParserExpressionList arguments,
+                                 int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewCallRuntime(const AstRawString* name,
+                                     const Runtime::Function* function,
+                                     PreParserExpressionList arguments,
+                                     int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserStatement NewReturnStatement(PreParserExpression expression,
+                                        int pos) {
+    return PreParserStatement::Default();
+  }
+  PreParserExpression NewFunctionLiteral(
+      PreParserIdentifier name, Scope* scope, PreParserStatementList body,
+      int materialized_literal_count, int expected_property_count,
+      int parameter_count,
+      FunctionLiteral::ParameterFlag has_duplicate_parameters,
+      FunctionLiteral::FunctionType function_type,
+      FunctionLiteral::EagerCompileHint eager_compile_hint, FunctionKind kind,
+      int position) {
+    return PreParserExpression::Default();
+  }
+
+  PreParserExpression NewSpread(PreParserExpression expression, int pos) {
+    return PreParserExpression::Spread(expression);
+  }
+
+  PreParserExpression NewEmptyParentheses(int pos) {
+    return PreParserExpression::Default();
+  }
+
+  // Return the object itself as AstVisitor and implement the needed
+  // dummy method right in this class.
+  PreParserFactory* visitor() { return this; }
+  int* ast_properties() {
+    static int dummy = 42;
+    return &dummy;
+  }
+};
+
+
+struct PreParserFormalParameters : FormalParametersBase {
+  explicit PreParserFormalParameters(Scope* scope)
+      : FormalParametersBase(scope) {}
+  int arity = 0;
+
+  int Arity() const { return arity; }
+  PreParserIdentifier at(int i) { return PreParserIdentifier(); }  // Dummy
+};
+
+
+class PreParser;
+
+class PreParserTraits {
+ public:
+  struct Type {
+    // TODO(marja): To be removed. The Traits object should contain all the data
+    // it needs.
+    typedef PreParser* Parser;
+
+    // PreParser doesn't need to store generator variables.
+    typedef void GeneratorVariable;
+
+    typedef int AstProperties;
+
+    // Return types for traversing functions.
+    typedef PreParserIdentifier Identifier;
+    typedef PreParserExpression Expression;
+    typedef PreParserExpression YieldExpression;
+    typedef PreParserExpression FunctionLiteral;
+    typedef PreParserExpression ClassLiteral;
+    typedef PreParserExpression ObjectLiteralProperty;
+    typedef PreParserExpression Literal;
+    typedef PreParserExpressionList ExpressionList;
+    typedef PreParserExpressionList PropertyList;
+    typedef PreParserIdentifier FormalParameter;
+    typedef PreParserFormalParameters FormalParameters;
+    typedef PreParserStatementList StatementList;
+
+    // For constructing objects returned by the traversing functions.
+    typedef PreParserFactory Factory;
+  };
+
+  explicit PreParserTraits(PreParser* pre_parser) : pre_parser_(pre_parser) {}
+
+  // Helper functions for recursive descent.
+  static bool IsEval(PreParserIdentifier identifier) {
+    return identifier.IsEval();
+  }
+
+  static bool IsArguments(PreParserIdentifier identifier) {
+    return identifier.IsArguments();
+  }
+
+  static bool IsEvalOrArguments(PreParserIdentifier identifier) {
+    return identifier.IsEvalOrArguments();
+  }
+
+  static bool IsUndefined(PreParserIdentifier identifier) {
+    return identifier.IsUndefined();
+  }
+
+  static bool IsPrototype(PreParserIdentifier identifier) {
+    return identifier.IsPrototype();
+  }
+
+  static bool IsConstructor(PreParserIdentifier identifier) {
+    return identifier.IsConstructor();
+  }
+
+  // Returns true if the expression is of type "this.foo".
+  static bool IsThisProperty(PreParserExpression expression) {
+    return expression.IsThisProperty();
+  }
+
+  static bool IsIdentifier(PreParserExpression expression) {
+    return expression.IsIdentifier();
+  }
+
+  static PreParserIdentifier AsIdentifier(PreParserExpression expression) {
+    return expression.AsIdentifier();
+  }
+
+  static bool IsFutureStrictReserved(PreParserIdentifier identifier) {
+    return identifier.IsFutureStrictReserved();
+  }
+
+  static bool IsBoilerplateProperty(PreParserExpression property) {
+    // PreParser doesn't count boilerplate properties.
+    return false;
+  }
+
+  static bool IsArrayIndex(PreParserIdentifier string, uint32_t* index) {
+    return false;
+  }
+
+  static PreParserExpression GetPropertyValue(PreParserExpression property) {
+    return PreParserExpression::Default();
+  }
+
+  // Functions for encapsulating the differences between parsing and preparsing;
+  // operations interleaved with the recursive descent.
+  static void PushLiteralName(FuncNameInferrer* fni, PreParserIdentifier id) {
+    // PreParser should not use FuncNameInferrer.
+    UNREACHABLE();
+  }
+
+  static void PushPropertyName(FuncNameInferrer* fni,
+                               PreParserExpression expression) {
+    // PreParser should not use FuncNameInferrer.
+    UNREACHABLE();
+  }
+
+  static void InferFunctionName(FuncNameInferrer* fni,
+                                PreParserExpression expression) {
+    // PreParser should not use FuncNameInferrer.
+    UNREACHABLE();
+  }
+
+  static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
+      Scope* scope, PreParserExpression property, bool* has_function) {}
+
+  static void CheckAssigningFunctionLiteralToProperty(
+      PreParserExpression left, PreParserExpression right) {}
+
+  static PreParserExpression MarkExpressionAsAssigned(
+      PreParserExpression expression) {
+    // TODO(marja): To be able to produce the same errors, the preparser needs
+    // to start tracking which expressions are variables and which are assigned.
+    return expression;
+  }
+
+  bool ShortcutNumericLiteralBinaryExpression(PreParserExpression* x,
+                                              PreParserExpression y,
+                                              Token::Value op,
+                                              int pos,
+                                              PreParserFactory* factory) {
+    return false;
+  }
+
+  PreParserExpression BuildUnaryExpression(PreParserExpression expression,
+                                           Token::Value op, int pos,
+                                           PreParserFactory* factory) {
+    return PreParserExpression::Default();
+  }
+
+  PreParserExpression NewThrowReferenceError(MessageTemplate::Template message,
+                                             int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewThrowSyntaxError(MessageTemplate::Template message,
+                                          Handle<Object> arg, int pos) {
+    return PreParserExpression::Default();
+  }
+  PreParserExpression NewThrowTypeError(MessageTemplate::Template message,
+                                        Handle<Object> arg, int pos) {
+    return PreParserExpression::Default();
+  }
+
+  // Reporting errors.
+  void ReportMessageAt(Scanner::Location location,
+                       MessageTemplate::Template message,
+                       const char* arg = NULL,
+                       ParseErrorType error_type = kSyntaxError);
+  void ReportMessageAt(int start_pos, int end_pos,
+                       MessageTemplate::Template message,
+                       const char* arg = NULL,
+                       ParseErrorType error_type = kSyntaxError);
+
+  // "null" return type creators.
+  static PreParserIdentifier EmptyIdentifier() {
+    return PreParserIdentifier::Default();
+  }
+  static PreParserIdentifier EmptyIdentifierString() {
+    return PreParserIdentifier::Default();
+  }
+  static PreParserExpression EmptyExpression() {
+    return PreParserExpression::Default();
+  }
+  static PreParserExpression EmptyLiteral() {
+    return PreParserExpression::Default();
+  }
+  static PreParserExpression EmptyObjectLiteralProperty() {
+    return PreParserExpression::Default();
+  }
+  static PreParserExpression EmptyFunctionLiteral() {
+    return PreParserExpression::Default();
+  }
+  static PreParserExpressionList NullExpressionList() {
+    return PreParserExpressionList();
+  }
+
+  // Odd-ball literal creators.
+  static PreParserExpression GetLiteralTheHole(int position,
+                                               PreParserFactory* factory) {
+    return PreParserExpression::Default();
+  }
+
+  // Producing data during the recursive descent.
+  PreParserIdentifier GetSymbol(Scanner* scanner);
+  PreParserIdentifier GetNumberAsSymbol(Scanner* scanner);
+
+  static PreParserIdentifier GetNextSymbol(Scanner* scanner) {
+    return PreParserIdentifier::Default();
+  }
+
+  static PreParserExpression ThisExpression(Scope* scope,
+                                            PreParserFactory* factory,
+                                            int pos) {
+    return PreParserExpression::This();
+  }
+
+  static PreParserExpression SuperPropertyReference(Scope* scope,
+                                                    PreParserFactory* factory,
+                                                    int pos) {
+    return PreParserExpression::Default();
+  }
+
+  static PreParserExpression SuperCallReference(Scope* scope,
+                                                PreParserFactory* factory,
+                                                int pos) {
+    return PreParserExpression::SuperCallReference();
+  }
+
+  static PreParserExpression NewTargetExpression(Scope* scope,
+                                                 PreParserFactory* factory,
+                                                 int pos) {
+    return PreParserExpression::Default();
+  }
+
+  static PreParserExpression DefaultConstructor(bool call_super, Scope* scope,
+                                                int pos, int end_pos) {
+    return PreParserExpression::Default();
+  }
+
+  static PreParserExpression ExpressionFromLiteral(
+      Token::Value token, int pos, Scanner* scanner,
+      PreParserFactory* factory) {
+    return PreParserExpression::Default();
+  }
+
+  static PreParserExpression ExpressionFromIdentifier(
+      PreParserIdentifier name, int start_position, int end_position,
+      Scope* scope, PreParserFactory* factory) {
+    return PreParserExpression::FromIdentifier(name);
+  }
+
+  PreParserExpression ExpressionFromString(int pos,
+                                           Scanner* scanner,
+                                           PreParserFactory* factory = NULL);
+
+  PreParserExpression GetIterator(PreParserExpression iterable,
+                                  PreParserFactory* factory, int pos) {
+    return PreParserExpression::Default();
+  }
+
+  static PreParserExpressionList NewExpressionList(int size, Zone* zone) {
+    return PreParserExpressionList();
+  }
+
+  static PreParserStatementList NewStatementList(int size, Zone* zone) {
+    return PreParserStatementList();
+  }
+
+  static PreParserExpressionList NewPropertyList(int size, Zone* zone) {
+    return PreParserExpressionList();
+  }
+
+  static void AddParameterInitializationBlock(
+      const PreParserFormalParameters& parameters,
+      PreParserStatementList list, bool* ok) {}
+
+  V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
+                                      int* expected_property_count, bool* ok) {
+    UNREACHABLE();
+  }
+
+  V8_INLINE PreParserStatementList ParseEagerFunctionBody(
+      PreParserIdentifier function_name, int pos,
+      const PreParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
+
+  V8_INLINE void ParseArrowFunctionFormalParameterList(
+      PreParserFormalParameters* parameters,
+      PreParserExpression expression, const Scanner::Location& params_loc,
+      Scanner::Location* duplicate_loc, bool* ok);
+
+  void ReindexLiterals(const PreParserFormalParameters& paramaters) {}
+
+  struct TemplateLiteralState {};
+
+  TemplateLiteralState OpenTemplateLiteral(int pos) {
+    return TemplateLiteralState();
+  }
+  void AddTemplateSpan(TemplateLiteralState*, bool) {}
+  void AddTemplateExpression(TemplateLiteralState*, PreParserExpression) {}
+  PreParserExpression CloseTemplateLiteral(TemplateLiteralState*, int,
+                                           PreParserExpression tag) {
+    if (IsTaggedTemplate(tag)) {
+      // Emulate generation of array literals for tag callsite
+      // 1st is array of cooked strings, second is array of raw strings
+      MaterializeTemplateCallsiteLiterals();
+    }
+    return EmptyExpression();
+  }
+  inline void MaterializeTemplateCallsiteLiterals();
+  PreParserExpression NoTemplateTag() {
+    return PreParserExpression::NoTemplateTag();
+  }
+  static bool IsTaggedTemplate(const PreParserExpression tag) {
+    return !tag.IsNoTemplateTag();
+  }
+
+  void AddFormalParameter(PreParserFormalParameters* parameters,
+                          PreParserExpression pattern,
+                          PreParserExpression initializer,
+                          int initializer_end_position, bool is_rest) {
+    ++parameters->arity;
+  }
+  void DeclareFormalParameter(Scope* scope, PreParserIdentifier parameter,
+                              ExpressionClassifier* classifier) {
+    if (!classifier->is_simple_parameter_list()) {
+      scope->SetHasNonSimpleParameters();
+    }
+  }
+
+  void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
+
+  // Temporary glue; these functions will move to ParserBase.
+  PreParserExpression ParseV8Intrinsic(bool* ok);
+  V8_INLINE PreParserExpression ParseDoExpression(bool* ok);
+  PreParserExpression ParseFunctionLiteral(
+      PreParserIdentifier name, Scanner::Location function_name_location,
+      FunctionNameValidity function_name_validity, FunctionKind kind,
+      int function_token_position, FunctionLiteral::FunctionType type,
+      FunctionLiteral::ArityRestriction arity_restriction,
+      LanguageMode language_mode, bool* ok);
+
+  PreParserExpression ParseClassLiteral(PreParserIdentifier name,
+                                        Scanner::Location class_name_location,
+                                        bool name_is_strict_reserved, int pos,
+                                        bool* ok);
+
+  PreParserExpressionList PrepareSpreadArguments(PreParserExpressionList list) {
+    return list;
+  }
+
+  inline void MaterializeUnspreadArgumentsLiterals(int count);
+
+  inline PreParserExpression SpreadCall(PreParserExpression function,
+                                        PreParserExpressionList args, int pos);
+
+  inline PreParserExpression SpreadCallNew(PreParserExpression function,
+                                           PreParserExpressionList args,
+                                           int pos);
+
+  inline void RewriteDestructuringAssignments() {}
+
+  inline void QueueDestructuringAssignmentForRewriting(PreParserExpression) {}
+
+  void SetFunctionNameFromPropertyName(PreParserExpression,
+                                       PreParserIdentifier) {}
+  void SetFunctionNameFromIdentifierRef(PreParserExpression,
+                                        PreParserExpression) {}
+
+  inline PreParserExpression RewriteNonPattern(
+      PreParserExpression expr, const ExpressionClassifier* classifier,
+      bool* ok);
+  inline PreParserExpression RewriteNonPatternArguments(
+      PreParserExpression args, const ExpressionClassifier* classifier,
+      bool* ok);
+  inline PreParserExpression RewriteNonPatternObjectLiteralProperty(
+      PreParserExpression property, const ExpressionClassifier* classifier,
+      bool* ok);
+
+ private:
+  PreParser* pre_parser_;
+};
+
+
+// Preparsing checks a JavaScript program and emits preparse-data that helps
+// a later parsing to be faster.
+// See preparse-data-format.h for the data format.
+
+// The PreParser checks that the syntax follows the grammar for JavaScript,
+// and collects some information about the program along the way.
+// The grammar check is only performed in order to understand the program
+// sufficiently to deduce some information about it, that can be used
+// to speed up later parsing. Finding errors is not the goal of pre-parsing,
+// rather it is to speed up properly written and correct programs.
+// That means that contextual checks (like a label being declared where
+// it is used) are generally omitted.
+class PreParser : public ParserBase<PreParserTraits> {
+ public:
+  typedef PreParserIdentifier Identifier;
+  typedef PreParserExpression Expression;
+  typedef PreParserStatement Statement;
+
+  enum PreParseResult {
+    kPreParseStackOverflow,
+    kPreParseSuccess
+  };
+
+  PreParser(Zone* zone, Scanner* scanner, AstValueFactory* ast_value_factory,
+            ParserRecorder* log, uintptr_t stack_limit)
+      : ParserBase<PreParserTraits>(zone, scanner, stack_limit, NULL,
+                                    ast_value_factory, log, this) {}
+
+  // Pre-parse the program from the character stream; returns true on
+  // success (even if parsing failed, the pre-parse data successfully
+  // captured the syntax error), and false if a stack-overflow happened
+  // during parsing.
+  PreParseResult PreParseProgram(int* materialized_literals = 0) {
+    Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
+    PreParserFactory factory(NULL);
+    FunctionState top_scope(&function_state_, &scope_, scope, kNormalFunction,
+                            &factory);
+    bool ok = true;
+    int start_position = scanner()->peek_location().beg_pos;
+    ParseStatementList(Token::EOS, &ok);
+    if (stack_overflow()) return kPreParseStackOverflow;
+    if (!ok) {
+      ReportUnexpectedToken(scanner()->current_token());
+    } else if (is_strict(scope_->language_mode())) {
+      CheckStrictOctalLiteral(start_position, scanner()->location().end_pos,
+                              &ok);
+    }
+    if (materialized_literals) {
+      *materialized_literals = function_state_->materialized_literal_count();
+    }
+    return kPreParseSuccess;
+  }
+
+  // Parses a single function literal, from the opening parentheses before
+  // parameters to the closing brace after the body.
+  // Returns a FunctionEntry describing the body of the function in enough
+  // detail that it can be lazily compiled.
+  // The scanner is expected to have matched the "function" or "function*"
+  // keyword and parameters, and have consumed the initial '{'.
+  // At return, unless an error occurred, the scanner is positioned before the
+  // the final '}'.
+  PreParseResult PreParseLazyFunction(
+      LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
+      ParserRecorder* log, Scanner::BookmarkScope* bookmark = nullptr);
+
+ private:
+  friend class PreParserTraits;
+
+  static const int kLazyParseTrialLimit = 200;
+
+  // These types form an algebra over syntactic categories that is just
+  // rich enough to let us recognize and propagate the constructs that
+  // are either being counted in the preparser data, or is important
+  // to throw the correct syntax error exceptions.
+
+  // All ParseXXX functions take as the last argument an *ok parameter
+  // which is set to false if parsing failed; it is unchanged otherwise.
+  // By making the 'exception handling' explicit, we are forced to check
+  // for failure at the call sites.
+  Statement ParseStatementListItem(bool* ok);
+  void ParseStatementList(int end_token, bool* ok,
+                          Scanner::BookmarkScope* bookmark = nullptr);
+  Statement ParseStatement(bool* ok);
+  Statement ParseSubStatement(bool* ok);
+  Statement ParseFunctionDeclaration(bool* ok);
+  Statement ParseClassDeclaration(bool* ok);
+  Statement ParseBlock(bool* ok);
+  Statement ParseVariableStatement(VariableDeclarationContext var_context,
+                                   bool* ok);
+  Statement ParseVariableDeclarations(VariableDeclarationContext var_context,
+                                      int* num_decl, bool* is_lexical,
+                                      bool* is_binding_pattern,
+                                      Scanner::Location* first_initializer_loc,
+                                      Scanner::Location* bindings_loc,
+                                      bool* ok);
+  Statement ParseExpressionOrLabelledStatement(bool* ok);
+  Statement ParseIfStatement(bool* ok);
+  Statement ParseContinueStatement(bool* ok);
+  Statement ParseBreakStatement(bool* ok);
+  Statement ParseReturnStatement(bool* ok);
+  Statement ParseWithStatement(bool* ok);
+  Statement ParseSwitchStatement(bool* ok);
+  Statement ParseDoWhileStatement(bool* ok);
+  Statement ParseWhileStatement(bool* ok);
+  Statement ParseForStatement(bool* ok);
+  Statement ParseThrowStatement(bool* ok);
+  Statement ParseTryStatement(bool* ok);
+  Statement ParseDebuggerStatement(bool* ok);
+  Expression ParseConditionalExpression(bool accept_IN, bool* ok);
+  Expression ParseObjectLiteral(bool* ok);
+  Expression ParseV8Intrinsic(bool* ok);
+  Expression ParseDoExpression(bool* ok);
+
+  V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
+                                      int* expected_property_count, bool* ok);
+  V8_INLINE PreParserStatementList ParseEagerFunctionBody(
+      PreParserIdentifier function_name, int pos,
+      const PreParserFormalParameters& parameters, FunctionKind kind,
+      FunctionLiteral::FunctionType function_type, bool* ok);
+
+  Expression ParseFunctionLiteral(
+      Identifier name, Scanner::Location function_name_location,
+      FunctionNameValidity function_name_validity, FunctionKind kind,
+      int function_token_pos, FunctionLiteral::FunctionType function_type,
+      FunctionLiteral::ArityRestriction arity_restriction,
+      LanguageMode language_mode, bool* ok);
+  void ParseLazyFunctionLiteralBody(bool* ok,
+                                    Scanner::BookmarkScope* bookmark = nullptr);
+
+  PreParserExpression ParseClassLiteral(PreParserIdentifier name,
+                                        Scanner::Location class_name_location,
+                                        bool name_is_strict_reserved, int pos,
+                                        bool* ok);
+};
+
+
+void PreParserTraits::MaterializeTemplateCallsiteLiterals() {
+  pre_parser_->function_state_->NextMaterializedLiteralIndex();
+  pre_parser_->function_state_->NextMaterializedLiteralIndex();
+}
+
+
+void PreParserTraits::MaterializeUnspreadArgumentsLiterals(int count) {
+  for (int i = 0; i < count; ++i) {
+    pre_parser_->function_state_->NextMaterializedLiteralIndex();
+  }
+}
+
+
+PreParserExpression PreParserTraits::SpreadCall(PreParserExpression function,
+                                                PreParserExpressionList args,
+                                                int pos) {
+  return pre_parser_->factory()->NewCall(function, args, pos);
+}
+
+PreParserExpression PreParserTraits::SpreadCallNew(PreParserExpression function,
+                                                   PreParserExpressionList args,
+                                                   int pos) {
+  return pre_parser_->factory()->NewCallNew(function, args, pos);
+}
+
+
+void PreParserTraits::ParseArrowFunctionFormalParameterList(
+    PreParserFormalParameters* parameters,
+    PreParserExpression params, const Scanner::Location& params_loc,
+    Scanner::Location* duplicate_loc, bool* ok) {
+  // TODO(wingo): Detect duplicated identifiers in paramlists.  Detect parameter
+  // lists that are too long.
+}
+
+
+PreParserExpression PreParserTraits::ParseDoExpression(bool* ok) {
+  return pre_parser_->ParseDoExpression(ok);
+}
+
+
+PreParserExpression PreParserTraits::RewriteNonPattern(
+    PreParserExpression expr, const ExpressionClassifier* classifier,
+    bool* ok) {
+  pre_parser_->ValidateExpression(classifier, ok);
+  return expr;
+}
+
+
+PreParserExpression PreParserTraits::RewriteNonPatternArguments(
+    PreParserExpression args, const ExpressionClassifier* classifier,
+    bool* ok) {
+  pre_parser_->ValidateExpression(classifier, ok);
+  return args;
+}
+
+
+PreParserExpression PreParserTraits::RewriteNonPatternObjectLiteralProperty(
+    PreParserExpression property, const ExpressionClassifier* classifier,
+    bool* ok) {
+  pre_parser_->ValidateExpression(classifier, ok);
+  return property;
+}
+
+
+PreParserStatementList PreParser::ParseEagerFunctionBody(
+    PreParserIdentifier function_name, int pos,
+    const PreParserFormalParameters& parameters, FunctionKind kind,
+    FunctionLiteral::FunctionType function_type, bool* ok) {
+  ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
+
+  ParseStatementList(Token::RBRACE, ok);
+  if (!*ok) return PreParserStatementList();
+
+  Expect(Token::RBRACE, ok);
+  return PreParserStatementList();
+}
+
+
+PreParserStatementList PreParserTraits::ParseEagerFunctionBody(
+    PreParserIdentifier function_name, int pos,
+    const PreParserFormalParameters& parameters, FunctionKind kind,
+    FunctionLiteral::FunctionType function_type, bool* ok) {
+  return pre_parser_->ParseEagerFunctionBody(function_name, pos, parameters,
+                                             kind, function_type, ok);
+}
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_PREPARSER_H
diff --git a/src/parsing/rewriter.cc b/src/parsing/rewriter.cc
new file mode 100644
index 0000000..4da60ac
--- /dev/null
+++ b/src/parsing/rewriter.cc
@@ -0,0 +1,403 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/parsing/rewriter.h"
+
+#include "src/ast/ast.h"
+#include "src/ast/scopes.h"
+#include "src/parsing/parser.h"
+
+namespace v8 {
+namespace internal {
+
+class Processor: public AstVisitor {
+ public:
+  Processor(Isolate* isolate, Scope* scope, Variable* result,
+            AstValueFactory* ast_value_factory)
+      : result_(result),
+        result_assigned_(false),
+        replacement_(nullptr),
+        is_set_(false),
+        zone_(ast_value_factory->zone()),
+        scope_(scope),
+        factory_(ast_value_factory) {
+    InitializeAstVisitor(isolate);
+  }
+
+  Processor(Parser* parser, Scope* scope, Variable* result,
+            AstValueFactory* ast_value_factory)
+      : result_(result),
+        result_assigned_(false),
+        replacement_(nullptr),
+        is_set_(false),
+        scope_(scope),
+        factory_(ast_value_factory) {
+    InitializeAstVisitor(parser->stack_limit());
+  }
+
+  ~Processor() override {}
+
+  void Process(ZoneList<Statement*>* statements);
+  bool result_assigned() const { return result_assigned_; }
+
+  Zone* zone() { return zone_; }
+  Scope* scope() { return scope_; }
+  AstNodeFactory* factory() { return &factory_; }
+
+  // Returns ".result = value"
+  Expression* SetResult(Expression* value) {
+    result_assigned_ = true;
+    VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
+    return factory()->NewAssignment(Token::ASSIGN, result_proxy, value,
+                                    RelocInfo::kNoPosition);
+  }
+
+  // Inserts '.result = undefined' in front of the given statement.
+  Statement* AssignUndefinedBefore(Statement* s);
+
+ private:
+  Variable* result_;
+
+  // We are not tracking result usage via the result_'s use
+  // counts (we leave the accurate computation to the
+  // usage analyzer). Instead we simple remember if
+  // there was ever an assignment to result_.
+  bool result_assigned_;
+
+  // When visiting a node, we "return" a replacement for that node in
+  // [replacement_].  In many cases this will just be the original node.
+  Statement* replacement_;
+
+  // To avoid storing to .result all the time, we eliminate some of
+  // the stores by keeping track of whether or not we're sure .result
+  // will be overwritten anyway. This is a bit more tricky than what I
+  // was hoping for.
+  bool is_set_;
+
+  Zone* zone_;
+  Scope* scope_;
+  AstNodeFactory factory_;
+
+  // Node visitors.
+#define DEF_VISIT(type) void Visit##type(type* node) override;
+  AST_NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+  void VisitIterationStatement(IterationStatement* stmt);
+
+  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+};
+
+
+Statement* Processor::AssignUndefinedBefore(Statement* s) {
+  Expression* result_proxy = factory()->NewVariableProxy(result_);
+  Expression* undef = factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
+  Expression* assignment = factory()->NewAssignment(
+      Token::ASSIGN, result_proxy, undef, RelocInfo::kNoPosition);
+  Block* b = factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
+  b->statements()->Add(
+      factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
+      zone());
+  b->statements()->Add(s, zone());
+  return b;
+}
+
+
+void Processor::Process(ZoneList<Statement*>* statements) {
+  for (int i = statements->length() - 1; i >= 0; --i) {
+    Visit(statements->at(i));
+    statements->Set(i, replacement_);
+  }
+}
+
+
+void Processor::VisitBlock(Block* node) {
+  // An initializer block is the rewritten form of a variable declaration
+  // with initialization expressions. The initializer block contains the
+  // list of assignments corresponding to the initialization expressions.
+  // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
+  // a variable declaration with initialization expression is 'undefined'
+  // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
+  // returns 'undefined'. To obtain the same behavior with v8, we need
+  // to prevent rewriting in that case.
+  if (!node->ignore_completion_value()) Process(node->statements());
+  replacement_ = node;
+}
+
+
+void Processor::VisitExpressionStatement(ExpressionStatement* node) {
+  // Rewrite : <x>; -> .result = <x>;
+  if (!is_set_) {
+    node->set_expression(SetResult(node->expression()));
+    is_set_ = true;
+  }
+  replacement_ = node;
+}
+
+
+void Processor::VisitIfStatement(IfStatement* node) {
+  // Rewrite both branches.
+  bool set_after = is_set_;
+  Visit(node->then_statement());
+  node->set_then_statement(replacement_);
+  bool set_in_then = is_set_;
+  is_set_ = set_after;
+  Visit(node->else_statement());
+  node->set_else_statement(replacement_);
+  is_set_ = is_set_ && set_in_then;
+  replacement_ = node;
+
+  if (FLAG_harmony_completion && !is_set_) {
+    is_set_ = true;
+    replacement_ = AssignUndefinedBefore(node);
+  }
+}
+
+
+void Processor::VisitIterationStatement(IterationStatement* node) {
+  // Rewrite the body.
+  bool set_after = is_set_;
+  is_set_ = false;  // We are in a loop, so we can't rely on [set_after].
+  Visit(node->body());
+  node->set_body(replacement_);
+  is_set_ = is_set_ && set_after;
+  replacement_ = node;
+
+  if (FLAG_harmony_completion && !is_set_) {
+    is_set_ = true;
+    replacement_ = AssignUndefinedBefore(node);
+  }
+}
+
+
+void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
+  VisitIterationStatement(node);
+}
+
+
+void Processor::VisitWhileStatement(WhileStatement* node) {
+  VisitIterationStatement(node);
+}
+
+
+void Processor::VisitForStatement(ForStatement* node) {
+  VisitIterationStatement(node);
+}
+
+
+void Processor::VisitForInStatement(ForInStatement* node) {
+  VisitIterationStatement(node);
+}
+
+
+void Processor::VisitForOfStatement(ForOfStatement* node) {
+  VisitIterationStatement(node);
+}
+
+
+void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
+  // Rewrite both try and catch block.
+  bool set_after = is_set_;
+  Visit(node->try_block());
+  node->set_try_block(static_cast<Block*>(replacement_));
+  bool set_in_try = is_set_;
+  is_set_ = set_after;
+  Visit(node->catch_block());
+  node->set_catch_block(static_cast<Block*>(replacement_));
+  is_set_ = is_set_ && set_in_try;
+  replacement_ = node;
+
+  if (FLAG_harmony_completion && !is_set_) {
+    is_set_ = true;
+    replacement_ = AssignUndefinedBefore(node);
+  }
+}
+
+
+void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
+  // Rewrite both try and finally block (in reverse order).
+  bool set_after = is_set_;
+  is_set_ = true;  // Don't normally need to assign in finally block.
+  Visit(node->finally_block());
+  node->set_finally_block(replacement_->AsBlock());
+  {  // Save .result value at the beginning of the finally block and restore it
+     // at the end again: ".backup = .result; ...; .result = .backup"
+     // This is necessary because the finally block does not normally contribute
+     // to the completion value.
+    Variable* backup = scope()->NewTemporary(
+        factory()->ast_value_factory()->dot_result_string());
+    Expression* backup_proxy = factory()->NewVariableProxy(backup);
+    Expression* result_proxy = factory()->NewVariableProxy(result_);
+    Expression* save = factory()->NewAssignment(
+        Token::ASSIGN, backup_proxy, result_proxy, RelocInfo::kNoPosition);
+    Expression* restore = factory()->NewAssignment(
+        Token::ASSIGN, result_proxy, backup_proxy, RelocInfo::kNoPosition);
+    node->finally_block()->statements()->InsertAt(
+        0, factory()->NewExpressionStatement(save, RelocInfo::kNoPosition),
+        zone());
+    node->finally_block()->statements()->Add(
+        factory()->NewExpressionStatement(restore, RelocInfo::kNoPosition),
+        zone());
+  }
+  is_set_ = set_after;
+  Visit(node->try_block());
+  node->set_try_block(replacement_->AsBlock());
+  replacement_ = node;
+
+  if (FLAG_harmony_completion && !is_set_) {
+    is_set_ = true;
+    replacement_ = AssignUndefinedBefore(node);
+  }
+}
+
+
+void Processor::VisitSwitchStatement(SwitchStatement* node) {
+  // Rewrite statements in all case clauses (in reverse order).
+  ZoneList<CaseClause*>* clauses = node->cases();
+  bool set_after = is_set_;
+  for (int i = clauses->length() - 1; i >= 0; --i) {
+    CaseClause* clause = clauses->at(i);
+    Process(clause->statements());
+  }
+  is_set_ = is_set_ && set_after;
+  replacement_ = node;
+
+  if (FLAG_harmony_completion && !is_set_) {
+    is_set_ = true;
+    replacement_ = AssignUndefinedBefore(node);
+  }
+}
+
+
+void Processor::VisitContinueStatement(ContinueStatement* node) {
+  is_set_ = false;
+  replacement_ = node;
+}
+
+
+void Processor::VisitBreakStatement(BreakStatement* node) {
+  is_set_ = false;
+  replacement_ = node;
+}
+
+
+void Processor::VisitWithStatement(WithStatement* node) {
+  Visit(node->statement());
+  node->set_statement(replacement_);
+  replacement_ = node;
+
+  if (FLAG_harmony_completion && !is_set_) {
+    is_set_ = true;
+    replacement_ = AssignUndefinedBefore(node);
+  }
+}
+
+
+void Processor::VisitSloppyBlockFunctionStatement(
+    SloppyBlockFunctionStatement* node) {
+  Visit(node->statement());
+  node->set_statement(replacement_);
+  replacement_ = node;
+}
+
+
+void Processor::VisitEmptyStatement(EmptyStatement* node) {
+  replacement_ = node;
+}
+
+
+void Processor::VisitReturnStatement(ReturnStatement* node) {
+  is_set_ = true;
+  replacement_ = node;
+}
+
+
+void Processor::VisitDebuggerStatement(DebuggerStatement* node) {
+  replacement_ = node;
+}
+
+
+// Expressions are never visited.
+#define DEF_VISIT(type)                                         \
+  void Processor::Visit##type(type* expr) { UNREACHABLE(); }
+EXPRESSION_NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+
+// Declarations are never visited.
+#define DEF_VISIT(type) \
+  void Processor::Visit##type(type* expr) { UNREACHABLE(); }
+DECLARATION_NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+
+// Assumes code has been parsed.  Mutates the AST, so the AST should not
+// continue to be used in the case of failure.
+bool Rewriter::Rewrite(ParseInfo* info) {
+  FunctionLiteral* function = info->literal();
+  DCHECK(function != NULL);
+  Scope* scope = function->scope();
+  DCHECK(scope != NULL);
+  if (!scope->is_script_scope() && !scope->is_eval_scope()) return true;
+
+  ZoneList<Statement*>* body = function->body();
+  if (!body->is_empty()) {
+    Variable* result =
+        scope->NewTemporary(info->ast_value_factory()->dot_result_string());
+    // The name string must be internalized at this point.
+    DCHECK(!result->name().is_null());
+    Processor processor(info->isolate(), scope, result,
+                        info->ast_value_factory());
+    processor.Process(body);
+    if (processor.HasStackOverflow()) return false;
+
+    if (processor.result_assigned()) {
+      DCHECK(function->end_position() != RelocInfo::kNoPosition);
+      // Set the position of the assignment statement one character past the
+      // source code, such that it definitely is not in the source code range
+      // of an immediate inner scope. For example in
+      //   eval('with ({x:1}) x = 1');
+      // the end position of the function generated for executing the eval code
+      // coincides with the end of the with scope which is the position of '1'.
+      int pos = function->end_position();
+      VariableProxy* result_proxy =
+          processor.factory()->NewVariableProxy(result, pos);
+      Statement* result_statement =
+          processor.factory()->NewReturnStatement(result_proxy, pos);
+      body->Add(result_statement, info->zone());
+    }
+  }
+
+  return true;
+}
+
+
+bool Rewriter::Rewrite(Parser* parser, DoExpression* expr,
+                       AstValueFactory* factory) {
+  Block* block = expr->block();
+  Scope* scope = block->scope();
+  ZoneList<Statement*>* body = block->statements();
+  VariableProxy* result = expr->result();
+  Variable* result_var = result->var();
+
+  if (!body->is_empty()) {
+    Processor processor(parser, scope, result_var, factory);
+    processor.Process(body);
+    if (processor.HasStackOverflow()) return false;
+
+    if (!processor.result_assigned()) {
+      AstNodeFactory* node_factory = processor.factory();
+      Expression* undef =
+          node_factory->NewUndefinedLiteral(RelocInfo::kNoPosition);
+      Statement* completion = node_factory->NewExpressionStatement(
+          processor.SetResult(undef), expr->position());
+      body->Add(completion, factory->zone());
+    }
+  }
+  return true;
+}
+
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/rewriter.h b/src/parsing/rewriter.h
new file mode 100644
index 0000000..477644a
--- /dev/null
+++ b/src/parsing/rewriter.h
@@ -0,0 +1,36 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_REWRITER_H_
+#define V8_PARSING_REWRITER_H_
+
+namespace v8 {
+namespace internal {
+
+class AstValueFactory;
+class DoExpression;
+class ParseInfo;
+class Parser;
+
+class Rewriter {
+ public:
+  // Rewrite top-level code (ECMA 262 "programs") so as to conservatively
+  // include an assignment of the value of the last statement in the code to
+  // a compiler-generated temporary variable wherever needed.
+  //
+  // Assumes code has been parsed and scopes have been analyzed.  Mutates the
+  // AST, so the AST should not continue to be used in the case of failure.
+  static bool Rewrite(ParseInfo* info);
+
+  // Rewrite a list of statements, using the same rules as a top-level program,
+  // to  ensure identical behaviour of completion result.
+  static bool Rewrite(Parser* parser, DoExpression* expr,
+                      AstValueFactory* factory);
+};
+
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_REWRITER_H_
diff --git a/src/parsing/scanner-character-streams.cc b/src/parsing/scanner-character-streams.cc
new file mode 100644
index 0000000..91ed54f
--- /dev/null
+++ b/src/parsing/scanner-character-streams.cc
@@ -0,0 +1,589 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/parsing/scanner-character-streams.h"
+
+#include "include/v8.h"
+#include "src/globals.h"
+#include "src/handles.h"
+#include "src/list-inl.h"  // TODO(mstarzinger): Temporary cycle breaker!
+#include "src/objects.h"
+#include "src/unicode-inl.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+size_t CopyCharsHelper(uint16_t* dest, size_t length, const uint8_t* src,
+                       size_t* src_pos, size_t src_length,
+                       ScriptCompiler::StreamedSource::Encoding encoding) {
+  // It's possible that this will be called with length 0, but don't assume that
+  // the functions this calls handle it gracefully.
+  if (length == 0) return 0;
+
+  if (encoding == ScriptCompiler::StreamedSource::UTF8) {
+    return v8::internal::Utf8ToUtf16CharacterStream::CopyChars(
+        dest, length, src, src_pos, src_length);
+  }
+
+  size_t to_fill = length;
+  if (to_fill > src_length - *src_pos) to_fill = src_length - *src_pos;
+
+  if (encoding == ScriptCompiler::StreamedSource::ONE_BYTE) {
+    v8::internal::CopyChars<uint8_t, uint16_t>(dest, src + *src_pos, to_fill);
+  } else {
+    DCHECK(encoding == ScriptCompiler::StreamedSource::TWO_BYTE);
+    v8::internal::CopyChars<uint16_t, uint16_t>(
+        dest, reinterpret_cast<const uint16_t*>(src + *src_pos), to_fill);
+  }
+  *src_pos += to_fill;
+  return to_fill;
+}
+
+}  // namespace
+
+
+// ----------------------------------------------------------------------------
+// BufferedUtf16CharacterStreams
+
+BufferedUtf16CharacterStream::BufferedUtf16CharacterStream()
+    : Utf16CharacterStream(),
+      pushback_limit_(NULL) {
+  // Initialize buffer as being empty. First read will fill the buffer.
+  buffer_cursor_ = buffer_;
+  buffer_end_ = buffer_;
+}
+
+
+BufferedUtf16CharacterStream::~BufferedUtf16CharacterStream() { }
+
+void BufferedUtf16CharacterStream::PushBack(uc32 character) {
+  if (character == kEndOfInput) {
+    pos_--;
+    return;
+  }
+  if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) {
+    // buffer_ is writable, buffer_cursor_ is const pointer.
+    buffer_[--buffer_cursor_ - buffer_] = static_cast<uc16>(character);
+    pos_--;
+    return;
+  }
+  SlowPushBack(static_cast<uc16>(character));
+}
+
+
+void BufferedUtf16CharacterStream::SlowPushBack(uc16 character) {
+  // In pushback mode, the end of the buffer contains pushback,
+  // and the start of the buffer (from buffer start to pushback_limit_)
+  // contains valid data that comes just after the pushback.
+  // We NULL the pushback_limit_ if pushing all the way back to the
+  // start of the buffer.
+
+  if (pushback_limit_ == NULL) {
+    // Enter pushback mode.
+    pushback_limit_ = buffer_end_;
+    buffer_end_ = buffer_ + kBufferSize;
+    buffer_cursor_ = buffer_end_;
+  }
+  // Ensure that there is room for at least one pushback.
+  DCHECK(buffer_cursor_ > buffer_);
+  DCHECK(pos_ > 0);
+  buffer_[--buffer_cursor_ - buffer_] = character;
+  if (buffer_cursor_ == buffer_) {
+    pushback_limit_ = NULL;
+  } else if (buffer_cursor_ < pushback_limit_) {
+    pushback_limit_ = buffer_cursor_;
+  }
+  pos_--;
+}
+
+
+bool BufferedUtf16CharacterStream::ReadBlock() {
+  buffer_cursor_ = buffer_;
+  if (pushback_limit_ != NULL) {
+    // Leave pushback mode.
+    buffer_end_ = pushback_limit_;
+    pushback_limit_ = NULL;
+    // If there were any valid characters left at the
+    // start of the buffer, use those.
+    if (buffer_cursor_ < buffer_end_) return true;
+    // Otherwise read a new block.
+  }
+  size_t length = FillBuffer(pos_);
+  buffer_end_ = buffer_ + length;
+  return length > 0;
+}
+
+
+size_t BufferedUtf16CharacterStream::SlowSeekForward(size_t delta) {
+  // Leave pushback mode (i.e., ignore that there might be valid data
+  // in the buffer before the pushback_limit_ point).
+  pushback_limit_ = NULL;
+  return BufferSeekForward(delta);
+}
+
+
+// ----------------------------------------------------------------------------
+// GenericStringUtf16CharacterStream
+
+
+GenericStringUtf16CharacterStream::GenericStringUtf16CharacterStream(
+    Handle<String> data, size_t start_position, size_t end_position)
+    : string_(data), length_(end_position), bookmark_(kNoBookmark) {
+  DCHECK(end_position >= start_position);
+  pos_ = start_position;
+}
+
+
+GenericStringUtf16CharacterStream::~GenericStringUtf16CharacterStream() { }
+
+
+bool GenericStringUtf16CharacterStream::SetBookmark() {
+  bookmark_ = pos_;
+  return true;
+}
+
+
+void GenericStringUtf16CharacterStream::ResetToBookmark() {
+  DCHECK(bookmark_ != kNoBookmark);
+  pos_ = bookmark_;
+  buffer_cursor_ = buffer_;
+  buffer_end_ = buffer_ + FillBuffer(pos_);
+}
+
+
+size_t GenericStringUtf16CharacterStream::BufferSeekForward(size_t delta) {
+  size_t old_pos = pos_;
+  pos_ = Min(pos_ + delta, length_);
+  ReadBlock();
+  return pos_ - old_pos;
+}
+
+
+size_t GenericStringUtf16CharacterStream::FillBuffer(size_t from_pos) {
+  if (from_pos >= length_) return 0;
+  size_t length = kBufferSize;
+  if (from_pos + length > length_) {
+    length = length_ - from_pos;
+  }
+  String::WriteToFlat<uc16>(*string_, buffer_, static_cast<int>(from_pos),
+                            static_cast<int>(from_pos + length));
+  return length;
+}
+
+
+// ----------------------------------------------------------------------------
+// Utf8ToUtf16CharacterStream
+Utf8ToUtf16CharacterStream::Utf8ToUtf16CharacterStream(const byte* data,
+                                                       size_t length)
+    : BufferedUtf16CharacterStream(),
+      raw_data_(data),
+      raw_data_length_(length),
+      raw_data_pos_(0),
+      raw_character_position_(0) {
+  ReadBlock();
+}
+
+
+Utf8ToUtf16CharacterStream::~Utf8ToUtf16CharacterStream() { }
+
+
+size_t Utf8ToUtf16CharacterStream::CopyChars(uint16_t* dest, size_t length,
+                                             const byte* src, size_t* src_pos,
+                                             size_t src_length) {
+  static const unibrow::uchar kMaxUtf16Character =
+      unibrow::Utf16::kMaxNonSurrogateCharCode;
+  size_t i = 0;
+  // Because of the UTF-16 lead and trail surrogates, we stop filling the buffer
+  // one character early (in the normal case), because we need to have at least
+  // two free spaces in the buffer to be sure that the next character will fit.
+  while (i < length - 1) {
+    if (*src_pos == src_length) break;
+    unibrow::uchar c = src[*src_pos];
+    if (c <= unibrow::Utf8::kMaxOneByteChar) {
+      *src_pos = *src_pos + 1;
+    } else {
+      c = unibrow::Utf8::CalculateValue(src + *src_pos, src_length - *src_pos,
+                                        src_pos);
+    }
+    if (c > kMaxUtf16Character) {
+      dest[i++] = unibrow::Utf16::LeadSurrogate(c);
+      dest[i++] = unibrow::Utf16::TrailSurrogate(c);
+    } else {
+      dest[i++] = static_cast<uc16>(c);
+    }
+  }
+  return i;
+}
+
+
+size_t Utf8ToUtf16CharacterStream::BufferSeekForward(size_t delta) {
+  size_t old_pos = pos_;
+  size_t target_pos = pos_ + delta;
+  SetRawPosition(target_pos);
+  pos_ = raw_character_position_;
+  ReadBlock();
+  return pos_ - old_pos;
+}
+
+
+size_t Utf8ToUtf16CharacterStream::FillBuffer(size_t char_position) {
+  SetRawPosition(char_position);
+  if (raw_character_position_ != char_position) {
+    // char_position was not a valid position in the stream (hit the end
+    // while spooling to it).
+    return 0u;
+  }
+  size_t i = CopyChars(buffer_, kBufferSize, raw_data_, &raw_data_pos_,
+                       raw_data_length_);
+  raw_character_position_ = char_position + i;
+  return i;
+}
+
+
+static const byte kUtf8MultiByteMask = 0xC0;
+static const byte kUtf8MultiByteCharFollower = 0x80;
+
+
+#ifdef DEBUG
+static const byte kUtf8MultiByteCharStart = 0xC0;
+static bool IsUtf8MultiCharacterStart(byte first_byte) {
+  return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart;
+}
+#endif
+
+
+static bool IsUtf8MultiCharacterFollower(byte later_byte) {
+  return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower;
+}
+
+
+// Move the cursor back to point at the preceding UTF-8 character start
+// in the buffer.
+static inline void Utf8CharacterBack(const byte* buffer, size_t* cursor) {
+  byte character = buffer[--*cursor];
+  if (character > unibrow::Utf8::kMaxOneByteChar) {
+    DCHECK(IsUtf8MultiCharacterFollower(character));
+    // Last byte of a multi-byte character encoding. Step backwards until
+    // pointing to the first byte of the encoding, recognized by having the
+    // top two bits set.
+    while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { }
+    DCHECK(IsUtf8MultiCharacterStart(buffer[*cursor]));
+  }
+}
+
+
+// Move the cursor forward to point at the next following UTF-8 character start
+// in the buffer.
+static inline void Utf8CharacterForward(const byte* buffer, size_t* cursor) {
+  byte character = buffer[(*cursor)++];
+  if (character > unibrow::Utf8::kMaxOneByteChar) {
+    // First character of a multi-byte character encoding.
+    // The number of most-significant one-bits determines the length of the
+    // encoding:
+    //  110..... - (0xCx, 0xDx) one additional byte (minimum).
+    //  1110.... - (0xEx) two additional bytes.
+    //  11110... - (0xFx) three additional bytes (maximum).
+    DCHECK(IsUtf8MultiCharacterStart(character));
+    // Additional bytes is:
+    // 1 if value in range 0xC0 .. 0xDF.
+    // 2 if value in range 0xE0 .. 0xEF.
+    // 3 if value in range 0xF0 .. 0xF7.
+    // Encode that in a single value.
+    size_t additional_bytes =
+        ((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03;
+    *cursor += additional_bytes;
+    DCHECK(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes]));
+  }
+}
+
+
+// This can't set a raw position between two surrogate pairs, since there
+// is no position in the UTF8 stream that corresponds to that.  This assumes
+// that the surrogate pair is correctly coded as a 4 byte UTF-8 sequence.  If
+// it is illegally coded as two 3 byte sequences then there is no problem here.
+void Utf8ToUtf16CharacterStream::SetRawPosition(size_t target_position) {
+  if (raw_character_position_ > target_position) {
+    // Spool backwards in utf8 buffer.
+    do {
+      size_t old_pos = raw_data_pos_;
+      Utf8CharacterBack(raw_data_, &raw_data_pos_);
+      raw_character_position_--;
+      DCHECK(old_pos - raw_data_pos_ <= 4);
+      // Step back over both code units for surrogate pairs.
+      if (old_pos - raw_data_pos_ == 4) raw_character_position_--;
+    } while (raw_character_position_ > target_position);
+    // No surrogate pair splitting.
+    DCHECK(raw_character_position_ == target_position);
+    return;
+  }
+  // Spool forwards in the utf8 buffer.
+  while (raw_character_position_ < target_position) {
+    if (raw_data_pos_ == raw_data_length_) return;
+    size_t old_pos = raw_data_pos_;
+    Utf8CharacterForward(raw_data_, &raw_data_pos_);
+    raw_character_position_++;
+    DCHECK(raw_data_pos_ - old_pos <= 4);
+    if (raw_data_pos_ - old_pos == 4) raw_character_position_++;
+  }
+  // No surrogate pair splitting.
+  DCHECK(raw_character_position_ == target_position);
+}
+
+
+size_t ExternalStreamingStream::FillBuffer(size_t position) {
+  // Ignore "position" which is the position in the decoded data. Instead,
+  // ExternalStreamingStream keeps track of the position in the raw data.
+  size_t data_in_buffer = 0;
+  // Note that the UTF-8 decoder might not be able to fill the buffer
+  // completely; it will typically leave the last character empty (see
+  // Utf8ToUtf16CharacterStream::CopyChars).
+  while (data_in_buffer < kBufferSize - 1) {
+    if (current_data_ == NULL) {
+      // GetSomeData will wait until the embedder has enough data. Here's an
+      // interface between the API which uses size_t (which is the correct type
+      // here) and the internal parts which use size_t.
+      current_data_length_ = source_stream_->GetMoreData(&current_data_);
+      current_data_offset_ = 0;
+      bool data_ends = current_data_length_ == 0;
+      bookmark_data_is_from_current_data_ = false;
+
+      // A caveat: a data chunk might end with bytes from an incomplete UTF-8
+      // character (the rest of the bytes will be in the next chunk).
+      if (encoding_ == ScriptCompiler::StreamedSource::UTF8) {
+        HandleUtf8SplitCharacters(&data_in_buffer);
+        if (!data_ends && current_data_offset_ == current_data_length_) {
+          // The data stream didn't end, but we used all the data in the
+          // chunk. This will only happen when the chunk was really small. We
+          // don't handle the case where a UTF-8 character is split over several
+          // chunks; in that case V8 won't crash, but it will be a parse error.
+          FlushCurrent();
+          continue;  // Request a new chunk.
+        }
+      }
+
+      // Did the data stream end?
+      if (data_ends) {
+        DCHECK(utf8_split_char_buffer_length_ == 0);
+        return data_in_buffer;
+      }
+    }
+
+    // Fill the buffer from current_data_.
+    size_t new_offset = 0;
+    size_t new_chars_in_buffer =
+        CopyCharsHelper(buffer_ + data_in_buffer, kBufferSize - data_in_buffer,
+                        current_data_ + current_data_offset_, &new_offset,
+                        current_data_length_ - current_data_offset_, encoding_);
+    data_in_buffer += new_chars_in_buffer;
+    current_data_offset_ += new_offset;
+    DCHECK(data_in_buffer <= kBufferSize);
+
+    // Did we use all the data in the data chunk?
+    if (current_data_offset_ == current_data_length_) {
+      FlushCurrent();
+    }
+  }
+  return data_in_buffer;
+}
+
+
+bool ExternalStreamingStream::SetBookmark() {
+  // Bookmarking for this stream is a bit more complex than expected, since
+  // the stream state is distributed over several places:
+  // - pos_ (inherited from Utf16CharacterStream)
+  // - buffer_cursor_ and buffer_end_ (also from Utf16CharacterStream)
+  // - buffer_ (from BufferedUtf16CharacterStream)
+  // - current_data_ (+ .._offset_ and .._length) (this class)
+  // - utf8_split_char_buffer_* (a partial utf8 symbol at the block boundary)
+  //
+  // The underlying source_stream_ instance likely could re-construct this
+  // local data for us, but with the given interfaces we have no way of
+  // accomplishing this. Thus, we'll have to save all data locally.
+  //
+  // What gets saved where:
+  // - pos_  =>  bookmark_
+  // - buffer_[buffer_cursor_ .. buffer_end_]  =>  bookmark_buffer_
+  // - current_data_[.._offset_ .. .._length_]  =>  bookmark_data_
+  // - utf8_split_char_buffer_* => bookmark_utf8_split...
+  //
+  // To make sure we don't unnecessarily copy data, we also maintain
+  // whether bookmark_data_ contains a copy of the current current_data_
+  // block. This is done with:
+  // - bookmark_data_is_from_current_data_
+  // - bookmark_data_offset_: offset into bookmark_data_
+  //
+  // Note that bookmark_data_is_from_current_data_ must be maintained
+  // whenever current_data_ is updated.
+
+  bookmark_ = pos_;
+
+  size_t buffer_length = buffer_end_ - buffer_cursor_;
+  bookmark_buffer_.Dispose();
+  bookmark_buffer_ = Vector<uint16_t>::New(static_cast<int>(buffer_length));
+  CopyCharsUnsigned(bookmark_buffer_.start(), buffer_cursor_, buffer_length);
+
+  size_t data_length = current_data_length_ - current_data_offset_;
+  size_t bookmark_data_length = static_cast<size_t>(bookmark_data_.length());
+  if (bookmark_data_is_from_current_data_ &&
+      data_length < bookmark_data_length) {
+    // Fast case: bookmark_data_ was previously copied from the current
+    //            data block, and we have enough data for this bookmark.
+    bookmark_data_offset_ = bookmark_data_length - data_length;
+  } else {
+    // Slow case: We need to copy current_data_.
+    bookmark_data_.Dispose();
+    bookmark_data_ = Vector<uint8_t>::New(static_cast<int>(data_length));
+    CopyBytes(bookmark_data_.start(), current_data_ + current_data_offset_,
+              data_length);
+    bookmark_data_is_from_current_data_ = true;
+    bookmark_data_offset_ = 0;
+  }
+
+  bookmark_utf8_split_char_buffer_length_ = utf8_split_char_buffer_length_;
+  for (size_t i = 0; i < utf8_split_char_buffer_length_; i++) {
+    bookmark_utf8_split_char_buffer_[i] = utf8_split_char_buffer_[i];
+  }
+
+  return source_stream_->SetBookmark();
+}
+
+
+void ExternalStreamingStream::ResetToBookmark() {
+  source_stream_->ResetToBookmark();
+  FlushCurrent();
+
+  pos_ = bookmark_;
+
+  // bookmark_data_* => current_data_*
+  // (current_data_ assumes ownership of its memory.)
+  current_data_offset_ = 0;
+  current_data_length_ = bookmark_data_.length() - bookmark_data_offset_;
+  uint8_t* data = new uint8_t[current_data_length_];
+  CopyCharsUnsigned(data, bookmark_data_.begin() + bookmark_data_offset_,
+                    current_data_length_);
+  delete[] current_data_;
+  current_data_ = data;
+  bookmark_data_is_from_current_data_ = true;
+
+  // bookmark_buffer_ needs to be copied to buffer_.
+  CopyCharsUnsigned(buffer_, bookmark_buffer_.begin(),
+                    bookmark_buffer_.length());
+  buffer_cursor_ = buffer_;
+  buffer_end_ = buffer_ + bookmark_buffer_.length();
+
+  // utf8 split char buffer
+  utf8_split_char_buffer_length_ = bookmark_utf8_split_char_buffer_length_;
+  for (size_t i = 0; i < bookmark_utf8_split_char_buffer_length_; i++) {
+    utf8_split_char_buffer_[i] = bookmark_utf8_split_char_buffer_[i];
+  }
+}
+
+
+void ExternalStreamingStream::FlushCurrent() {
+  delete[] current_data_;
+  current_data_ = NULL;
+  current_data_length_ = 0;
+  current_data_offset_ = 0;
+  bookmark_data_is_from_current_data_ = false;
+}
+
+
+void ExternalStreamingStream::HandleUtf8SplitCharacters(
+    size_t* data_in_buffer) {
+  // Note the following property of UTF-8 which makes this function possible:
+  // Given any byte, we can always read its local environment (in both
+  // directions) to find out the (possibly multi-byte) character it belongs
+  // to. Single byte characters are of the form 0b0XXXXXXX. The first byte of a
+  // multi-byte character is of the form 0b110XXXXX, 0b1110XXXX or
+  // 0b11110XXX. The continuation bytes are of the form 0b10XXXXXX.
+
+  // First check if we have leftover data from the last chunk.
+  unibrow::uchar c;
+  if (utf8_split_char_buffer_length_ > 0) {
+    // Move the bytes which are part of the split character (which started in
+    // the previous chunk) into utf8_split_char_buffer_. Note that the
+    // continuation bytes are of the form 0b10XXXXXX, thus c >> 6 == 2.
+    while (current_data_offset_ < current_data_length_ &&
+           utf8_split_char_buffer_length_ < 4 &&
+           (c = current_data_[current_data_offset_]) >> 6 == 2) {
+      utf8_split_char_buffer_[utf8_split_char_buffer_length_] = c;
+      ++utf8_split_char_buffer_length_;
+      ++current_data_offset_;
+    }
+
+    // Convert the data in utf8_split_char_buffer_.
+    size_t new_offset = 0;
+    size_t new_chars_in_buffer =
+        CopyCharsHelper(buffer_ + *data_in_buffer,
+                        kBufferSize - *data_in_buffer, utf8_split_char_buffer_,
+                        &new_offset, utf8_split_char_buffer_length_, encoding_);
+    *data_in_buffer += new_chars_in_buffer;
+    // Make sure we used all the data.
+    DCHECK(new_offset == utf8_split_char_buffer_length_);
+    DCHECK(*data_in_buffer <= kBufferSize);
+
+    utf8_split_char_buffer_length_ = 0;
+  }
+
+  // Move bytes which are part of an incomplete character from the end of the
+  // current chunk to utf8_split_char_buffer_. They will be converted when the
+  // next data chunk arrives. Note that all valid UTF-8 characters are at most 4
+  // bytes long, but if the data is invalid, we can have character values bigger
+  // than unibrow::Utf8::kMaxOneByteChar for more than 4 consecutive bytes.
+  while (current_data_length_ > current_data_offset_ &&
+         (c = current_data_[current_data_length_ - 1]) >
+             unibrow::Utf8::kMaxOneByteChar &&
+         utf8_split_char_buffer_length_ < 4) {
+    --current_data_length_;
+    ++utf8_split_char_buffer_length_;
+    if (c >= (3 << 6)) {
+      // 3 << 6 = 0b11000000; this is the first byte of the multi-byte
+      // character. No need to copy the previous characters into the conversion
+      // buffer (even if they're multi-byte).
+      break;
+    }
+  }
+  CHECK(utf8_split_char_buffer_length_ <= 4);
+  for (size_t i = 0; i < utf8_split_char_buffer_length_; ++i) {
+    utf8_split_char_buffer_[i] = current_data_[current_data_length_ + i];
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// ExternalTwoByteStringUtf16CharacterStream
+
+ExternalTwoByteStringUtf16CharacterStream::
+    ~ExternalTwoByteStringUtf16CharacterStream() { }
+
+
+ExternalTwoByteStringUtf16CharacterStream::
+    ExternalTwoByteStringUtf16CharacterStream(
+        Handle<ExternalTwoByteString> data, int start_position,
+        int end_position)
+    : Utf16CharacterStream(),
+      source_(data),
+      raw_data_(data->GetTwoByteData(start_position)),
+      bookmark_(kNoBookmark) {
+  buffer_cursor_ = raw_data_,
+  buffer_end_ = raw_data_ + (end_position - start_position);
+  pos_ = start_position;
+}
+
+
+bool ExternalTwoByteStringUtf16CharacterStream::SetBookmark() {
+  bookmark_ = pos_;
+  return true;
+}
+
+
+void ExternalTwoByteStringUtf16CharacterStream::ResetToBookmark() {
+  DCHECK(bookmark_ != kNoBookmark);
+  pos_ = bookmark_;
+  buffer_cursor_ = raw_data_ + bookmark_;
+}
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/scanner-character-streams.h b/src/parsing/scanner-character-streams.h
new file mode 100644
index 0000000..603db93
--- /dev/null
+++ b/src/parsing/scanner-character-streams.h
@@ -0,0 +1,189 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_SCANNER_CHARACTER_STREAMS_H_
+#define V8_PARSING_SCANNER_CHARACTER_STREAMS_H_
+
+#include "src/handles.h"
+#include "src/parsing/scanner.h"
+#include "src/vector.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class ExternalTwoByteString;
+
+// A buffered character stream based on a random access character
+// source (ReadBlock can be called with pos_ pointing to any position,
+// even positions before the current).
+class BufferedUtf16CharacterStream: public Utf16CharacterStream {
+ public:
+  BufferedUtf16CharacterStream();
+  ~BufferedUtf16CharacterStream() override;
+
+  void PushBack(uc32 character) override;
+
+ protected:
+  static const size_t kBufferSize = 512;
+  static const size_t kPushBackStepSize = 16;
+
+  size_t SlowSeekForward(size_t delta) override;
+  bool ReadBlock() override;
+  virtual void SlowPushBack(uc16 character);
+
+  virtual size_t BufferSeekForward(size_t delta) = 0;
+  virtual size_t FillBuffer(size_t position) = 0;
+
+  const uc16* pushback_limit_;
+  uc16 buffer_[kBufferSize];
+};
+
+
+// Generic string stream.
+class GenericStringUtf16CharacterStream: public BufferedUtf16CharacterStream {
+ public:
+  GenericStringUtf16CharacterStream(Handle<String> data, size_t start_position,
+                                    size_t end_position);
+  ~GenericStringUtf16CharacterStream() override;
+
+  bool SetBookmark() override;
+  void ResetToBookmark() override;
+
+ protected:
+  static const size_t kNoBookmark = -1;
+
+  size_t BufferSeekForward(size_t delta) override;
+  size_t FillBuffer(size_t position) override;
+
+  Handle<String> string_;
+  size_t length_;
+  size_t bookmark_;
+};
+
+
+// Utf16 stream based on a literal UTF-8 string.
+class Utf8ToUtf16CharacterStream: public BufferedUtf16CharacterStream {
+ public:
+  Utf8ToUtf16CharacterStream(const byte* data, size_t length);
+  ~Utf8ToUtf16CharacterStream() override;
+
+  static size_t CopyChars(uint16_t* dest, size_t length, const byte* src,
+                          size_t* src_pos, size_t src_length);
+
+ protected:
+  size_t BufferSeekForward(size_t delta) override;
+  size_t FillBuffer(size_t char_position) override;
+  void SetRawPosition(size_t char_position);
+
+  const byte* raw_data_;
+  size_t raw_data_length_;  // Measured in bytes, not characters.
+  size_t raw_data_pos_;
+  // The character position of the character at raw_data[raw_data_pos_].
+  // Not necessarily the same as pos_.
+  size_t raw_character_position_;
+};
+
+
+// ExternalStreamingStream is a wrapper around an ExternalSourceStream (see
+// include/v8.h) subclass implemented by the embedder.
+class ExternalStreamingStream : public BufferedUtf16CharacterStream {
+ public:
+  ExternalStreamingStream(ScriptCompiler::ExternalSourceStream* source_stream,
+                          v8::ScriptCompiler::StreamedSource::Encoding encoding)
+      : source_stream_(source_stream),
+        encoding_(encoding),
+        current_data_(NULL),
+        current_data_offset_(0),
+        current_data_length_(0),
+        utf8_split_char_buffer_length_(0),
+        bookmark_(0),
+        bookmark_data_is_from_current_data_(false),
+        bookmark_data_offset_(0),
+        bookmark_utf8_split_char_buffer_length_(0) {}
+
+  ~ExternalStreamingStream() override {
+    delete[] current_data_;
+    bookmark_buffer_.Dispose();
+    bookmark_data_.Dispose();
+  }
+
+  size_t BufferSeekForward(size_t delta) override {
+    // We never need to seek forward when streaming scripts. We only seek
+    // forward when we want to parse a function whose location we already know,
+    // and when streaming, we don't know the locations of anything we haven't
+    // seen yet.
+    UNREACHABLE();
+    return 0;
+  }
+
+  size_t FillBuffer(size_t position) override;
+
+  bool SetBookmark() override;
+  void ResetToBookmark() override;
+
+ private:
+  void HandleUtf8SplitCharacters(size_t* data_in_buffer);
+  void FlushCurrent();
+
+  ScriptCompiler::ExternalSourceStream* source_stream_;
+  v8::ScriptCompiler::StreamedSource::Encoding encoding_;
+  const uint8_t* current_data_;
+  size_t current_data_offset_;
+  size_t current_data_length_;
+  // For converting UTF-8 characters which are split across two data chunks.
+  uint8_t utf8_split_char_buffer_[4];
+  size_t utf8_split_char_buffer_length_;
+
+  // Bookmark support. See comments in ExternalStreamingStream::SetBookmark
+  // for additional details.
+  size_t bookmark_;
+  Vector<uint16_t> bookmark_buffer_;
+  Vector<uint8_t> bookmark_data_;
+  bool bookmark_data_is_from_current_data_;
+  size_t bookmark_data_offset_;
+  uint8_t bookmark_utf8_split_char_buffer_[4];
+  size_t bookmark_utf8_split_char_buffer_length_;
+};
+
+
+// UTF16 buffer to read characters from an external string.
+class ExternalTwoByteStringUtf16CharacterStream: public Utf16CharacterStream {
+ public:
+  ExternalTwoByteStringUtf16CharacterStream(Handle<ExternalTwoByteString> data,
+                                            int start_position,
+                                            int end_position);
+  ~ExternalTwoByteStringUtf16CharacterStream() override;
+
+  void PushBack(uc32 character) override {
+    DCHECK(buffer_cursor_ > raw_data_);
+    buffer_cursor_--;
+    pos_--;
+  }
+
+  bool SetBookmark() override;
+  void ResetToBookmark() override;
+
+ protected:
+  size_t SlowSeekForward(size_t delta) override {
+    // Fast case always handles seeking.
+    return 0;
+  }
+  bool ReadBlock() override {
+    // Entire string is read at start.
+    return false;
+  }
+  Handle<ExternalTwoByteString> source_;
+  const uc16* raw_data_;  // Pointer to the actual array of characters.
+
+ private:
+  static const size_t kNoBookmark = -1;
+
+  size_t bookmark_;
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_SCANNER_CHARACTER_STREAMS_H_
diff --git a/src/parsing/scanner.cc b/src/parsing/scanner.cc
new file mode 100644
index 0000000..7317593
--- /dev/null
+++ b/src/parsing/scanner.cc
@@ -0,0 +1,1673 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Features shared by parsing and pre-parsing scanners.
+
+#include "src/parsing/scanner.h"
+
+#include <stdint.h>
+
+#include <cmath>
+
+#include "src/ast/ast-value-factory.h"
+#include "src/char-predicates-inl.h"
+#include "src/conversions-inl.h"
+#include "src/list-inl.h"
+#include "src/parsing/parser.h"
+
+namespace v8 {
+namespace internal {
+
+
+Handle<String> LiteralBuffer::Internalize(Isolate* isolate) const {
+  if (is_one_byte()) {
+    return isolate->factory()->InternalizeOneByteString(one_byte_literal());
+  }
+  return isolate->factory()->InternalizeTwoByteString(two_byte_literal());
+}
+
+
+// Default implementation for streams that do not support bookmarks.
+bool Utf16CharacterStream::SetBookmark() { return false; }
+void Utf16CharacterStream::ResetToBookmark() { UNREACHABLE(); }
+
+
+// ----------------------------------------------------------------------------
+// Scanner
+
+Scanner::Scanner(UnicodeCache* unicode_cache)
+    : unicode_cache_(unicode_cache),
+      bookmark_c0_(kNoBookmark),
+      octal_pos_(Location::invalid()) {
+  bookmark_current_.literal_chars = &bookmark_current_literal_;
+  bookmark_current_.raw_literal_chars = &bookmark_current_raw_literal_;
+  bookmark_next_.literal_chars = &bookmark_next_literal_;
+  bookmark_next_.raw_literal_chars = &bookmark_next_raw_literal_;
+}
+
+
+void Scanner::Initialize(Utf16CharacterStream* source) {
+  source_ = source;
+  // Need to capture identifiers in order to recognize "get" and "set"
+  // in object literals.
+  Init();
+  // Skip initial whitespace allowing HTML comment ends just like
+  // after a newline and scan first token.
+  has_line_terminator_before_next_ = true;
+  SkipWhiteSpace();
+  Scan();
+}
+
+
+template <bool capture_raw>
+uc32 Scanner::ScanHexNumber(int expected_length) {
+  DCHECK(expected_length <= 4);  // prevent overflow
+
+  uc32 x = 0;
+  for (int i = 0; i < expected_length; i++) {
+    int d = HexValue(c0_);
+    if (d < 0) {
+      return -1;
+    }
+    x = x * 16 + d;
+    Advance<capture_raw>();
+  }
+
+  return x;
+}
+
+
+template <bool capture_raw>
+uc32 Scanner::ScanUnlimitedLengthHexNumber(int max_value) {
+  uc32 x = 0;
+  int d = HexValue(c0_);
+  if (d < 0) {
+    return -1;
+  }
+  while (d >= 0) {
+    x = x * 16 + d;
+    if (x > max_value) return -1;
+    Advance<capture_raw>();
+    d = HexValue(c0_);
+  }
+  return x;
+}
+
+
+// Ensure that tokens can be stored in a byte.
+STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
+
+// Table of one-character tokens, by character (0x00..0x7f only).
+static const byte one_char_tokens[] = {
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::LPAREN,       // 0x28
+  Token::RPAREN,       // 0x29
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::COMMA,        // 0x2c
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::COLON,        // 0x3a
+  Token::SEMICOLON,    // 0x3b
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::CONDITIONAL,  // 0x3f
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::LBRACK,     // 0x5b
+  Token::ILLEGAL,
+  Token::RBRACK,     // 0x5d
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::ILLEGAL,
+  Token::LBRACE,       // 0x7b
+  Token::ILLEGAL,
+  Token::RBRACE,       // 0x7d
+  Token::BIT_NOT,      // 0x7e
+  Token::ILLEGAL
+};
+
+
+Token::Value Scanner::Next() {
+  if (next_.token == Token::EOS) {
+    next_.location.beg_pos = current_.location.beg_pos;
+    next_.location.end_pos = current_.location.end_pos;
+  }
+  current_ = next_;
+  if (V8_UNLIKELY(next_next_.token != Token::UNINITIALIZED)) {
+    next_ = next_next_;
+    next_next_.token = Token::UNINITIALIZED;
+    return current_.token;
+  }
+  has_line_terminator_before_next_ = false;
+  has_multiline_comment_before_next_ = false;
+  if (static_cast<unsigned>(c0_) <= 0x7f) {
+    Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]);
+    if (token != Token::ILLEGAL) {
+      int pos = source_pos();
+      next_.token = token;
+      next_.location.beg_pos = pos;
+      next_.location.end_pos = pos + 1;
+      Advance();
+      return current_.token;
+    }
+  }
+  Scan();
+  return current_.token;
+}
+
+
+Token::Value Scanner::PeekAhead() {
+  if (next_next_.token != Token::UNINITIALIZED) {
+    return next_next_.token;
+  }
+  TokenDesc prev = current_;
+  Next();
+  Token::Value ret = next_.token;
+  next_next_ = next_;
+  next_ = current_;
+  current_ = prev;
+  return ret;
+}
+
+
+// TODO(yangguo): check whether this is actually necessary.
+static inline bool IsLittleEndianByteOrderMark(uc32 c) {
+  // The Unicode value U+FFFE is guaranteed never to be assigned as a
+  // Unicode character; this implies that in a Unicode context the
+  // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
+  // character expressed in little-endian byte order (since it could
+  // not be a U+FFFE character expressed in big-endian byte
+  // order). Nevertheless, we check for it to be compatible with
+  // Spidermonkey.
+  return c == 0xFFFE;
+}
+
+
+bool Scanner::SkipWhiteSpace() {
+  int start_position = source_pos();
+
+  while (true) {
+    while (true) {
+      // The unicode cache accepts unsigned inputs.
+      if (c0_ < 0) break;
+      // Advance as long as character is a WhiteSpace or LineTerminator.
+      // Remember if the latter is the case.
+      if (unicode_cache_->IsLineTerminator(c0_)) {
+        has_line_terminator_before_next_ = true;
+      } else if (!unicode_cache_->IsWhiteSpace(c0_) &&
+                 !IsLittleEndianByteOrderMark(c0_)) {
+        break;
+      }
+      Advance();
+    }
+
+    // If there is an HTML comment end '-->' at the beginning of a
+    // line (with only whitespace in front of it), we treat the rest
+    // of the line as a comment. This is in line with the way
+    // SpiderMonkey handles it.
+    if (c0_ == '-' && has_line_terminator_before_next_) {
+      Advance();
+      if (c0_ == '-') {
+        Advance();
+        if (c0_ == '>') {
+          // Treat the rest of the line as a comment.
+          SkipSingleLineComment();
+          // Continue skipping white space after the comment.
+          continue;
+        }
+        PushBack('-');  // undo Advance()
+      }
+      PushBack('-');  // undo Advance()
+    }
+    // Return whether or not we skipped any characters.
+    return source_pos() != start_position;
+  }
+}
+
+
+Token::Value Scanner::SkipSingleLineComment() {
+  Advance();
+
+  // The line terminator at the end of the line is not considered
+  // to be part of the single-line comment; it is recognized
+  // separately by the lexical grammar and becomes part of the
+  // stream of input elements for the syntactic grammar (see
+  // ECMA-262, section 7.4).
+  while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
+    Advance();
+  }
+
+  return Token::WHITESPACE;
+}
+
+
+Token::Value Scanner::SkipSourceURLComment() {
+  TryToParseSourceURLComment();
+  while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
+    Advance();
+  }
+
+  return Token::WHITESPACE;
+}
+
+
+void Scanner::TryToParseSourceURLComment() {
+  // Magic comments are of the form: //[#@]\s<name>=\s*<value>\s*.* and this
+  // function will just return if it cannot parse a magic comment.
+  if (c0_ < 0 || !unicode_cache_->IsWhiteSpace(c0_)) return;
+  Advance();
+  LiteralBuffer name;
+  while (c0_ >= 0 && !unicode_cache_->IsWhiteSpaceOrLineTerminator(c0_) &&
+         c0_ != '=') {
+    name.AddChar(c0_);
+    Advance();
+  }
+  if (!name.is_one_byte()) return;
+  Vector<const uint8_t> name_literal = name.one_byte_literal();
+  LiteralBuffer* value;
+  if (name_literal == STATIC_CHAR_VECTOR("sourceURL")) {
+    value = &source_url_;
+  } else if (name_literal == STATIC_CHAR_VECTOR("sourceMappingURL")) {
+    value = &source_mapping_url_;
+  } else {
+    return;
+  }
+  if (c0_ != '=')
+    return;
+  Advance();
+  value->Reset();
+  while (c0_ >= 0 && unicode_cache_->IsWhiteSpace(c0_)) {
+    Advance();
+  }
+  while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
+    // Disallowed characters.
+    if (c0_ == '"' || c0_ == '\'') {
+      value->Reset();
+      return;
+    }
+    if (unicode_cache_->IsWhiteSpace(c0_)) {
+      break;
+    }
+    value->AddChar(c0_);
+    Advance();
+  }
+  // Allow whitespace at the end.
+  while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
+    if (!unicode_cache_->IsWhiteSpace(c0_)) {
+      value->Reset();
+      break;
+    }
+    Advance();
+  }
+}
+
+
+Token::Value Scanner::SkipMultiLineComment() {
+  DCHECK(c0_ == '*');
+  Advance();
+
+  while (c0_ >= 0) {
+    uc32 ch = c0_;
+    Advance();
+    if (c0_ >= 0 && unicode_cache_->IsLineTerminator(ch)) {
+      // Following ECMA-262, section 7.4, a comment containing
+      // a newline will make the comment count as a line-terminator.
+      has_multiline_comment_before_next_ = true;
+    }
+    // If we have reached the end of the multi-line comment, we
+    // consume the '/' and insert a whitespace. This way all
+    // multi-line comments are treated as whitespace.
+    if (ch == '*' && c0_ == '/') {
+      c0_ = ' ';
+      return Token::WHITESPACE;
+    }
+  }
+
+  // Unterminated multi-line comment.
+  return Token::ILLEGAL;
+}
+
+
+Token::Value Scanner::ScanHtmlComment() {
+  // Check for <!-- comments.
+  DCHECK(c0_ == '!');
+  Advance();
+  if (c0_ == '-') {
+    Advance();
+    if (c0_ == '-') return SkipSingleLineComment();
+    PushBack('-');  // undo Advance()
+  }
+  PushBack('!');  // undo Advance()
+  DCHECK(c0_ == '!');
+  return Token::LT;
+}
+
+
+void Scanner::Scan() {
+  next_.literal_chars = NULL;
+  next_.raw_literal_chars = NULL;
+  Token::Value token;
+  do {
+    // Remember the position of the next token
+    next_.location.beg_pos = source_pos();
+
+    switch (c0_) {
+      case ' ':
+      case '\t':
+        Advance();
+        token = Token::WHITESPACE;
+        break;
+
+      case '\n':
+        Advance();
+        has_line_terminator_before_next_ = true;
+        token = Token::WHITESPACE;
+        break;
+
+      case '"': case '\'':
+        token = ScanString();
+        break;
+
+      case '<':
+        // < <= << <<= <!--
+        Advance();
+        if (c0_ == '=') {
+          token = Select(Token::LTE);
+        } else if (c0_ == '<') {
+          token = Select('=', Token::ASSIGN_SHL, Token::SHL);
+        } else if (c0_ == '!') {
+          token = ScanHtmlComment();
+        } else {
+          token = Token::LT;
+        }
+        break;
+
+      case '>':
+        // > >= >> >>= >>> >>>=
+        Advance();
+        if (c0_ == '=') {
+          token = Select(Token::GTE);
+        } else if (c0_ == '>') {
+          // >> >>= >>> >>>=
+          Advance();
+          if (c0_ == '=') {
+            token = Select(Token::ASSIGN_SAR);
+          } else if (c0_ == '>') {
+            token = Select('=', Token::ASSIGN_SHR, Token::SHR);
+          } else {
+            token = Token::SAR;
+          }
+        } else {
+          token = Token::GT;
+        }
+        break;
+
+      case '=':
+        // = == === =>
+        Advance();
+        if (c0_ == '=') {
+          token = Select('=', Token::EQ_STRICT, Token::EQ);
+        } else if (c0_ == '>') {
+          token = Select(Token::ARROW);
+        } else {
+          token = Token::ASSIGN;
+        }
+        break;
+
+      case '!':
+        // ! != !==
+        Advance();
+        if (c0_ == '=') {
+          token = Select('=', Token::NE_STRICT, Token::NE);
+        } else {
+          token = Token::NOT;
+        }
+        break;
+
+      case '+':
+        // + ++ +=
+        Advance();
+        if (c0_ == '+') {
+          token = Select(Token::INC);
+        } else if (c0_ == '=') {
+          token = Select(Token::ASSIGN_ADD);
+        } else {
+          token = Token::ADD;
+        }
+        break;
+
+      case '-':
+        // - -- --> -=
+        Advance();
+        if (c0_ == '-') {
+          Advance();
+          if (c0_ == '>' && has_line_terminator_before_next_) {
+            // For compatibility with SpiderMonkey, we skip lines that
+            // start with an HTML comment end '-->'.
+            token = SkipSingleLineComment();
+          } else {
+            token = Token::DEC;
+          }
+        } else if (c0_ == '=') {
+          token = Select(Token::ASSIGN_SUB);
+        } else {
+          token = Token::SUB;
+        }
+        break;
+
+      case '*':
+        // * *=
+        token = Select('=', Token::ASSIGN_MUL, Token::MUL);
+        break;
+
+      case '%':
+        // % %=
+        token = Select('=', Token::ASSIGN_MOD, Token::MOD);
+        break;
+
+      case '/':
+        // /  // /* /=
+        Advance();
+        if (c0_ == '/') {
+          Advance();
+          if (c0_ == '#' || c0_ == '@') {
+            Advance();
+            token = SkipSourceURLComment();
+          } else {
+            PushBack(c0_);
+            token = SkipSingleLineComment();
+          }
+        } else if (c0_ == '*') {
+          token = SkipMultiLineComment();
+        } else if (c0_ == '=') {
+          token = Select(Token::ASSIGN_DIV);
+        } else {
+          token = Token::DIV;
+        }
+        break;
+
+      case '&':
+        // & && &=
+        Advance();
+        if (c0_ == '&') {
+          token = Select(Token::AND);
+        } else if (c0_ == '=') {
+          token = Select(Token::ASSIGN_BIT_AND);
+        } else {
+          token = Token::BIT_AND;
+        }
+        break;
+
+      case '|':
+        // | || |=
+        Advance();
+        if (c0_ == '|') {
+          token = Select(Token::OR);
+        } else if (c0_ == '=') {
+          token = Select(Token::ASSIGN_BIT_OR);
+        } else {
+          token = Token::BIT_OR;
+        }
+        break;
+
+      case '^':
+        // ^ ^=
+        token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
+        break;
+
+      case '.':
+        // . Number
+        Advance();
+        if (IsDecimalDigit(c0_)) {
+          token = ScanNumber(true);
+        } else {
+          token = Token::PERIOD;
+          if (c0_ == '.') {
+            Advance();
+            if (c0_ == '.') {
+              Advance();
+              token = Token::ELLIPSIS;
+            } else {
+              PushBack('.');
+            }
+          }
+        }
+        break;
+
+      case ':':
+        token = Select(Token::COLON);
+        break;
+
+      case ';':
+        token = Select(Token::SEMICOLON);
+        break;
+
+      case ',':
+        token = Select(Token::COMMA);
+        break;
+
+      case '(':
+        token = Select(Token::LPAREN);
+        break;
+
+      case ')':
+        token = Select(Token::RPAREN);
+        break;
+
+      case '[':
+        token = Select(Token::LBRACK);
+        break;
+
+      case ']':
+        token = Select(Token::RBRACK);
+        break;
+
+      case '{':
+        token = Select(Token::LBRACE);
+        break;
+
+      case '}':
+        token = Select(Token::RBRACE);
+        break;
+
+      case '?':
+        token = Select(Token::CONDITIONAL);
+        break;
+
+      case '~':
+        token = Select(Token::BIT_NOT);
+        break;
+
+      case '`':
+        token = ScanTemplateStart();
+        break;
+
+      default:
+        if (c0_ < 0) {
+          token = Token::EOS;
+        } else if (unicode_cache_->IsIdentifierStart(c0_)) {
+          token = ScanIdentifierOrKeyword();
+        } else if (IsDecimalDigit(c0_)) {
+          token = ScanNumber(false);
+        } else if (SkipWhiteSpace()) {
+          token = Token::WHITESPACE;
+        } else {
+          token = Select(Token::ILLEGAL);
+        }
+        break;
+    }
+
+    // Continue scanning for tokens as long as we're just skipping
+    // whitespace.
+  } while (token == Token::WHITESPACE);
+
+  next_.location.end_pos = source_pos();
+  next_.token = token;
+}
+
+
+void Scanner::SeekForward(int pos) {
+  // After this call, we will have the token at the given position as
+  // the "next" token. The "current" token will be invalid.
+  if (pos == next_.location.beg_pos) return;
+  int current_pos = source_pos();
+  DCHECK_EQ(next_.location.end_pos, current_pos);
+  // Positions inside the lookahead token aren't supported.
+  DCHECK(pos >= current_pos);
+  if (pos != current_pos) {
+    source_->SeekForward(pos - source_->pos());
+    Advance();
+    // This function is only called to seek to the location
+    // of the end of a function (at the "}" token). It doesn't matter
+    // whether there was a line terminator in the part we skip.
+    has_line_terminator_before_next_ = false;
+    has_multiline_comment_before_next_ = false;
+  }
+  Scan();
+}
+
+
+template <bool capture_raw, bool in_template_literal>
+bool Scanner::ScanEscape() {
+  uc32 c = c0_;
+  Advance<capture_raw>();
+
+  // Skip escaped newlines.
+  if (!in_template_literal && c0_ >= 0 && unicode_cache_->IsLineTerminator(c)) {
+    // Allow CR+LF newlines in multiline string literals.
+    if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance<capture_raw>();
+    // Allow LF+CR newlines in multiline string literals.
+    if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance<capture_raw>();
+    return true;
+  }
+
+  switch (c) {
+    case '\'':  // fall through
+    case '"' :  // fall through
+    case '\\': break;
+    case 'b' : c = '\b'; break;
+    case 'f' : c = '\f'; break;
+    case 'n' : c = '\n'; break;
+    case 'r' : c = '\r'; break;
+    case 't' : c = '\t'; break;
+    case 'u' : {
+      c = ScanUnicodeEscape<capture_raw>();
+      if (c < 0) return false;
+      break;
+    }
+    case 'v':
+      c = '\v';
+      break;
+    case 'x': {
+      c = ScanHexNumber<capture_raw>(2);
+      if (c < 0) return false;
+      break;
+    }
+    case '0':  // Fall through.
+    case '1':  // fall through
+    case '2':  // fall through
+    case '3':  // fall through
+    case '4':  // fall through
+    case '5':  // fall through
+    case '6':  // fall through
+    case '7':
+      c = ScanOctalEscape<capture_raw>(c, 2);
+      break;
+  }
+
+  // According to ECMA-262, section 7.8.4, characters not covered by the
+  // above cases should be illegal, but they are commonly handled as
+  // non-escaped characters by JS VMs.
+  AddLiteralChar(c);
+  return true;
+}
+
+
+// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
+// ECMA-262. Other JS VMs support them.
+template <bool capture_raw>
+uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
+  uc32 x = c - '0';
+  int i = 0;
+  for (; i < length; i++) {
+    int d = c0_ - '0';
+    if (d < 0 || d > 7) break;
+    int nx = x * 8 + d;
+    if (nx >= 256) break;
+    x = nx;
+    Advance<capture_raw>();
+  }
+  // Anything except '\0' is an octal escape sequence, illegal in strict mode.
+  // Remember the position of octal escape sequences so that an error
+  // can be reported later (in strict mode).
+  // We don't report the error immediately, because the octal escape can
+  // occur before the "use strict" directive.
+  if (c != '0' || i > 0) {
+    octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
+  }
+  return x;
+}
+
+
+const int kMaxAscii = 127;
+
+
+Token::Value Scanner::ScanString() {
+  uc32 quote = c0_;
+  Advance<false, false>();  // consume quote
+
+  LiteralScope literal(this);
+  while (true) {
+    if (c0_ > kMaxAscii) {
+      HandleLeadSurrogate();
+      break;
+    }
+    if (c0_ < 0 || c0_ == '\n' || c0_ == '\r') return Token::ILLEGAL;
+    if (c0_ == quote) {
+      literal.Complete();
+      Advance<false, false>();
+      return Token::STRING;
+    }
+    uc32 c = c0_;
+    if (c == '\\') break;
+    Advance<false, false>();
+    AddLiteralChar(c);
+  }
+
+  while (c0_ != quote && c0_ >= 0
+         && !unicode_cache_->IsLineTerminator(c0_)) {
+    uc32 c = c0_;
+    Advance();
+    if (c == '\\') {
+      if (c0_ < 0 || !ScanEscape<false, false>()) return Token::ILLEGAL;
+    } else {
+      AddLiteralChar(c);
+    }
+  }
+  if (c0_ != quote) return Token::ILLEGAL;
+  literal.Complete();
+
+  Advance();  // consume quote
+  return Token::STRING;
+}
+
+
+Token::Value Scanner::ScanTemplateSpan() {
+  // When scanning a TemplateSpan, we are looking for the following construct:
+  // TEMPLATE_SPAN ::
+  //     ` LiteralChars* ${
+  //   | } LiteralChars* ${
+  //
+  // TEMPLATE_TAIL ::
+  //     ` LiteralChars* `
+  //   | } LiteralChar* `
+  //
+  // A TEMPLATE_SPAN should always be followed by an Expression, while a
+  // TEMPLATE_TAIL terminates a TemplateLiteral and does not need to be
+  // followed by an Expression.
+
+  Token::Value result = Token::TEMPLATE_SPAN;
+  LiteralScope literal(this);
+  StartRawLiteral();
+  const bool capture_raw = true;
+  const bool in_template_literal = true;
+
+  while (true) {
+    uc32 c = c0_;
+    Advance<capture_raw>();
+    if (c == '`') {
+      result = Token::TEMPLATE_TAIL;
+      ReduceRawLiteralLength(1);
+      break;
+    } else if (c == '$' && c0_ == '{') {
+      Advance<capture_raw>();  // Consume '{'
+      ReduceRawLiteralLength(2);
+      break;
+    } else if (c == '\\') {
+      if (c0_ > 0 && unicode_cache_->IsLineTerminator(c0_)) {
+        // The TV of LineContinuation :: \ LineTerminatorSequence is the empty
+        // code unit sequence.
+        uc32 lastChar = c0_;
+        Advance<capture_raw>();
+        if (lastChar == '\r') {
+          ReduceRawLiteralLength(1);  // Remove \r
+          if (c0_ == '\n') {
+            Advance<capture_raw>();  // Adds \n
+          } else {
+            AddRawLiteralChar('\n');
+          }
+        }
+      } else if (!ScanEscape<capture_raw, in_template_literal>()) {
+        return Token::ILLEGAL;
+      }
+    } else if (c < 0) {
+      // Unterminated template literal
+      PushBack(c);
+      break;
+    } else {
+      // The TRV of LineTerminatorSequence :: <CR> is the CV 0x000A.
+      // The TRV of LineTerminatorSequence :: <CR><LF> is the sequence
+      // consisting of the CV 0x000A.
+      if (c == '\r') {
+        ReduceRawLiteralLength(1);  // Remove \r
+        if (c0_ == '\n') {
+          Advance<capture_raw>();  // Adds \n
+        } else {
+          AddRawLiteralChar('\n');
+        }
+        c = '\n';
+      }
+      AddLiteralChar(c);
+    }
+  }
+  literal.Complete();
+  next_.location.end_pos = source_pos();
+  next_.token = result;
+  return result;
+}
+
+
+Token::Value Scanner::ScanTemplateStart() {
+  DCHECK(c0_ == '`');
+  next_.location.beg_pos = source_pos();
+  Advance();  // Consume `
+  return ScanTemplateSpan();
+}
+
+
+Token::Value Scanner::ScanTemplateContinuation() {
+  DCHECK_EQ(next_.token, Token::RBRACE);
+  next_.location.beg_pos = source_pos() - 1;  // We already consumed }
+  return ScanTemplateSpan();
+}
+
+
+void Scanner::ScanDecimalDigits() {
+  while (IsDecimalDigit(c0_))
+    AddLiteralCharAdvance();
+}
+
+
+Token::Value Scanner::ScanNumber(bool seen_period) {
+  DCHECK(IsDecimalDigit(c0_));  // the first digit of the number or the fraction
+
+  enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
+
+  LiteralScope literal(this);
+  bool at_start = !seen_period;
+  if (seen_period) {
+    // we have already seen a decimal point of the float
+    AddLiteralChar('.');
+    ScanDecimalDigits();  // we know we have at least one digit
+
+  } else {
+    // if the first character is '0' we must check for octals and hex
+    if (c0_ == '0') {
+      int start_pos = source_pos();  // For reporting octal positions.
+      AddLiteralCharAdvance();
+
+      // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or
+      // an octal number.
+      if (c0_ == 'x' || c0_ == 'X') {
+        // hex number
+        kind = HEX;
+        AddLiteralCharAdvance();
+        if (!IsHexDigit(c0_)) {
+          // we must have at least one hex digit after 'x'/'X'
+          return Token::ILLEGAL;
+        }
+        while (IsHexDigit(c0_)) {
+          AddLiteralCharAdvance();
+        }
+      } else if (c0_ == 'o' || c0_ == 'O') {
+        kind = OCTAL;
+        AddLiteralCharAdvance();
+        if (!IsOctalDigit(c0_)) {
+          // we must have at least one octal digit after 'o'/'O'
+          return Token::ILLEGAL;
+        }
+        while (IsOctalDigit(c0_)) {
+          AddLiteralCharAdvance();
+        }
+      } else if (c0_ == 'b' || c0_ == 'B') {
+        kind = BINARY;
+        AddLiteralCharAdvance();
+        if (!IsBinaryDigit(c0_)) {
+          // we must have at least one binary digit after 'b'/'B'
+          return Token::ILLEGAL;
+        }
+        while (IsBinaryDigit(c0_)) {
+          AddLiteralCharAdvance();
+        }
+      } else if ('0' <= c0_ && c0_ <= '7') {
+        // (possible) octal number
+        kind = IMPLICIT_OCTAL;
+        while (true) {
+          if (c0_ == '8' || c0_ == '9') {
+            at_start = false;
+            kind = DECIMAL;
+            break;
+          }
+          if (c0_  < '0' || '7'  < c0_) {
+            // Octal literal finished.
+            octal_pos_ = Location(start_pos, source_pos());
+            break;
+          }
+          AddLiteralCharAdvance();
+        }
+      }
+    }
+
+    // Parse decimal digits and allow trailing fractional part.
+    if (kind == DECIMAL) {
+      if (at_start) {
+        uint64_t value = 0;
+        while (IsDecimalDigit(c0_)) {
+          value = 10 * value + (c0_ - '0');
+
+          uc32 first_char = c0_;
+          Advance<false, false>();
+          AddLiteralChar(first_char);
+        }
+
+        if (next_.literal_chars->one_byte_literal().length() <= 10 &&
+            value <= Smi::kMaxValue && c0_ != '.' && c0_ != 'e' && c0_ != 'E') {
+          next_.smi_value_ = static_cast<int>(value);
+          literal.Complete();
+          HandleLeadSurrogate();
+
+          return Token::SMI;
+        }
+        HandleLeadSurrogate();
+      }
+
+      ScanDecimalDigits();  // optional
+      if (c0_ == '.') {
+        AddLiteralCharAdvance();
+        ScanDecimalDigits();  // optional
+      }
+    }
+  }
+
+  // scan exponent, if any
+  if (c0_ == 'e' || c0_ == 'E') {
+    DCHECK(kind != HEX);  // 'e'/'E' must be scanned as part of the hex number
+    if (kind != DECIMAL) return Token::ILLEGAL;
+    // scan exponent
+    AddLiteralCharAdvance();
+    if (c0_ == '+' || c0_ == '-')
+      AddLiteralCharAdvance();
+    if (!IsDecimalDigit(c0_)) {
+      // we must have at least one decimal digit after 'e'/'E'
+      return Token::ILLEGAL;
+    }
+    ScanDecimalDigits();
+  }
+
+  // The source character immediately following a numeric literal must
+  // not be an identifier start or a decimal digit; see ECMA-262
+  // section 7.8.3, page 17 (note that we read only one decimal digit
+  // if the value is 0).
+  if (IsDecimalDigit(c0_) ||
+      (c0_ >= 0 && unicode_cache_->IsIdentifierStart(c0_)))
+    return Token::ILLEGAL;
+
+  literal.Complete();
+
+  return Token::NUMBER;
+}
+
+
+uc32 Scanner::ScanIdentifierUnicodeEscape() {
+  Advance();
+  if (c0_ != 'u') return -1;
+  Advance();
+  return ScanUnicodeEscape<false>();
+}
+
+
+template <bool capture_raw>
+uc32 Scanner::ScanUnicodeEscape() {
+  // Accept both \uxxxx and \u{xxxxxx}. In the latter case, the number of
+  // hex digits between { } is arbitrary. \ and u have already been read.
+  if (c0_ == '{') {
+    Advance<capture_raw>();
+    uc32 cp = ScanUnlimitedLengthHexNumber<capture_raw>(0x10ffff);
+    if (cp < 0) {
+      return -1;
+    }
+    if (c0_ != '}') {
+      return -1;
+    }
+    Advance<capture_raw>();
+    return cp;
+  }
+  return ScanHexNumber<capture_raw>(4);
+}
+
+
+// ----------------------------------------------------------------------------
+// Keyword Matcher
+
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD)                    \
+  KEYWORD_GROUP('b')                                        \
+  KEYWORD("break", Token::BREAK)                            \
+  KEYWORD_GROUP('c')                                        \
+  KEYWORD("case", Token::CASE)                              \
+  KEYWORD("catch", Token::CATCH)                            \
+  KEYWORD("class", Token::CLASS)                            \
+  KEYWORD("const", Token::CONST)                            \
+  KEYWORD("continue", Token::CONTINUE)                      \
+  KEYWORD_GROUP('d')                                        \
+  KEYWORD("debugger", Token::DEBUGGER)                      \
+  KEYWORD("default", Token::DEFAULT)                        \
+  KEYWORD("delete", Token::DELETE)                          \
+  KEYWORD("do", Token::DO)                                  \
+  KEYWORD_GROUP('e')                                        \
+  KEYWORD("else", Token::ELSE)                              \
+  KEYWORD("enum", Token::FUTURE_RESERVED_WORD)              \
+  KEYWORD("export", Token::EXPORT)                          \
+  KEYWORD("extends", Token::EXTENDS)                        \
+  KEYWORD_GROUP('f')                                        \
+  KEYWORD("false", Token::FALSE_LITERAL)                    \
+  KEYWORD("finally", Token::FINALLY)                        \
+  KEYWORD("for", Token::FOR)                                \
+  KEYWORD("function", Token::FUNCTION)                      \
+  KEYWORD_GROUP('i')                                        \
+  KEYWORD("if", Token::IF)                                  \
+  KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
+  KEYWORD("import", Token::IMPORT)                          \
+  KEYWORD("in", Token::IN)                                  \
+  KEYWORD("instanceof", Token::INSTANCEOF)                  \
+  KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD)  \
+  KEYWORD_GROUP('l')                                        \
+  KEYWORD("let", Token::LET)                                \
+  KEYWORD_GROUP('n')                                        \
+  KEYWORD("new", Token::NEW)                                \
+  KEYWORD("null", Token::NULL_LITERAL)                      \
+  KEYWORD_GROUP('p')                                        \
+  KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD)    \
+  KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD)    \
+  KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD)  \
+  KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD)     \
+  KEYWORD_GROUP('r')                                        \
+  KEYWORD("return", Token::RETURN)                          \
+  KEYWORD_GROUP('s')                                        \
+  KEYWORD("static", Token::STATIC)                          \
+  KEYWORD("super", Token::SUPER)                            \
+  KEYWORD("switch", Token::SWITCH)                          \
+  KEYWORD_GROUP('t')                                        \
+  KEYWORD("this", Token::THIS)                              \
+  KEYWORD("throw", Token::THROW)                            \
+  KEYWORD("true", Token::TRUE_LITERAL)                      \
+  KEYWORD("try", Token::TRY)                                \
+  KEYWORD("typeof", Token::TYPEOF)                          \
+  KEYWORD_GROUP('v')                                        \
+  KEYWORD("var", Token::VAR)                                \
+  KEYWORD("void", Token::VOID)                              \
+  KEYWORD_GROUP('w')                                        \
+  KEYWORD("while", Token::WHILE)                            \
+  KEYWORD("with", Token::WITH)                              \
+  KEYWORD_GROUP('y')                                        \
+  KEYWORD("yield", Token::YIELD)
+
+
+static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
+                                             int input_length, bool escaped) {
+  DCHECK(input_length >= 1);
+  const int kMinLength = 2;
+  const int kMaxLength = 10;
+  if (input_length < kMinLength || input_length > kMaxLength) {
+    return Token::IDENTIFIER;
+  }
+  switch (input[0]) {
+    default:
+#define KEYWORD_GROUP_CASE(ch)                                \
+      break;                                                  \
+    case ch:
+#define KEYWORD(keyword, token)                                     \
+  {                                                                 \
+    /* 'keyword' is a char array, so sizeof(keyword) is */          \
+    /* strlen(keyword) plus 1 for the NUL char. */                  \
+    const int keyword_length = sizeof(keyword) - 1;                 \
+    STATIC_ASSERT(keyword_length >= kMinLength);                    \
+    STATIC_ASSERT(keyword_length <= kMaxLength);                    \
+    if (input_length == keyword_length && input[1] == keyword[1] && \
+        (keyword_length <= 2 || input[2] == keyword[2]) &&          \
+        (keyword_length <= 3 || input[3] == keyword[3]) &&          \
+        (keyword_length <= 4 || input[4] == keyword[4]) &&          \
+        (keyword_length <= 5 || input[5] == keyword[5]) &&          \
+        (keyword_length <= 6 || input[6] == keyword[6]) &&          \
+        (keyword_length <= 7 || input[7] == keyword[7]) &&          \
+        (keyword_length <= 8 || input[8] == keyword[8]) &&          \
+        (keyword_length <= 9 || input[9] == keyword[9])) {          \
+      if (escaped) {                                                \
+        return token == Token::FUTURE_STRICT_RESERVED_WORD          \
+                   ? Token::ESCAPED_STRICT_RESERVED_WORD            \
+                   : Token::ESCAPED_KEYWORD;                        \
+      }                                                             \
+      return token;                                                 \
+    }                                                               \
+  }
+    KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
+  }
+  return Token::IDENTIFIER;
+}
+
+
+bool Scanner::IdentifierIsFutureStrictReserved(
+    const AstRawString* string) const {
+  // Keywords are always 1-byte strings.
+  if (!string->is_one_byte()) return false;
+  if (string->IsOneByteEqualTo("let") || string->IsOneByteEqualTo("static") ||
+      string->IsOneByteEqualTo("yield")) {
+    return true;
+  }
+  return Token::FUTURE_STRICT_RESERVED_WORD ==
+         KeywordOrIdentifierToken(string->raw_data(), string->length(), false);
+}
+
+
+Token::Value Scanner::ScanIdentifierOrKeyword() {
+  DCHECK(unicode_cache_->IsIdentifierStart(c0_));
+  LiteralScope literal(this);
+  if (IsInRange(c0_, 'a', 'z')) {
+    do {
+      uc32 first_char = c0_;
+      Advance<false, false>();
+      AddLiteralChar(first_char);
+    } while (IsInRange(c0_, 'a', 'z'));
+
+    if (IsDecimalDigit(c0_) || IsInRange(c0_, 'A', 'Z') || c0_ == '_' ||
+        c0_ == '$') {
+      // Identifier starting with lowercase.
+      uc32 first_char = c0_;
+      Advance<false, false>();
+      AddLiteralChar(first_char);
+      while (IsAsciiIdentifier(c0_)) {
+        uc32 first_char = c0_;
+        Advance<false, false>();
+        AddLiteralChar(first_char);
+      }
+      if (c0_ <= kMaxAscii && c0_ != '\\') {
+        literal.Complete();
+        return Token::IDENTIFIER;
+      }
+    } else if (c0_ <= kMaxAscii && c0_ != '\\') {
+      // Only a-z+: could be a keyword or identifier.
+      literal.Complete();
+      Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
+      return KeywordOrIdentifierToken(chars.start(), chars.length(), false);
+    }
+
+    HandleLeadSurrogate();
+  } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '_' || c0_ == '$') {
+    do {
+      uc32 first_char = c0_;
+      Advance<false, false>();
+      AddLiteralChar(first_char);
+    } while (IsAsciiIdentifier(c0_));
+
+    if (c0_ <= kMaxAscii && c0_ != '\\') {
+      literal.Complete();
+      return Token::IDENTIFIER;
+    }
+
+    HandleLeadSurrogate();
+  } else if (c0_ == '\\') {
+    // Scan identifier start character.
+    uc32 c = ScanIdentifierUnicodeEscape();
+    // Only allow legal identifier start characters.
+    if (c < 0 ||
+        c == '\\' ||  // No recursive escapes.
+        !unicode_cache_->IsIdentifierStart(c)) {
+      return Token::ILLEGAL;
+    }
+    AddLiteralChar(c);
+    return ScanIdentifierSuffix(&literal, true);
+  } else {
+    uc32 first_char = c0_;
+    Advance();
+    AddLiteralChar(first_char);
+  }
+
+  // Scan the rest of the identifier characters.
+  while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
+    if (c0_ != '\\') {
+      uc32 next_char = c0_;
+      Advance();
+      AddLiteralChar(next_char);
+      continue;
+    }
+    // Fallthrough if no longer able to complete keyword.
+    return ScanIdentifierSuffix(&literal, false);
+  }
+
+  literal.Complete();
+
+  if (next_.literal_chars->is_one_byte()) {
+    Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
+    return KeywordOrIdentifierToken(chars.start(), chars.length(), false);
+  }
+  return Token::IDENTIFIER;
+}
+
+
+Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal,
+                                           bool escaped) {
+  // Scan the rest of the identifier characters.
+  while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
+    if (c0_ == '\\') {
+      uc32 c = ScanIdentifierUnicodeEscape();
+      escaped = true;
+      // Only allow legal identifier part characters.
+      if (c < 0 ||
+          c == '\\' ||
+          !unicode_cache_->IsIdentifierPart(c)) {
+        return Token::ILLEGAL;
+      }
+      AddLiteralChar(c);
+    } else {
+      AddLiteralChar(c0_);
+      Advance();
+    }
+  }
+  literal->Complete();
+
+  if (escaped && next_.literal_chars->is_one_byte()) {
+    Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
+    return KeywordOrIdentifierToken(chars.start(), chars.length(), true);
+  }
+  return Token::IDENTIFIER;
+}
+
+
+bool Scanner::ScanRegExpPattern(bool seen_equal) {
+  // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
+  bool in_character_class = false;
+
+  // Previous token is either '/' or '/=', in the second case, the
+  // pattern starts at =.
+  next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
+  next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
+
+  // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
+  // the scanner should pass uninterpreted bodies to the RegExp
+  // constructor.
+  LiteralScope literal(this);
+  if (seen_equal) {
+    AddLiteralChar('=');
+  }
+
+  while (c0_ != '/' || in_character_class) {
+    if (c0_ < 0 || unicode_cache_->IsLineTerminator(c0_)) return false;
+    if (c0_ == '\\') {  // Escape sequence.
+      AddLiteralCharAdvance();
+      if (c0_ < 0 || unicode_cache_->IsLineTerminator(c0_)) return false;
+      AddLiteralCharAdvance();
+      // If the escape allows more characters, i.e., \x??, \u????, or \c?,
+      // only "safe" characters are allowed (letters, digits, underscore),
+      // otherwise the escape isn't valid and the invalid character has
+      // its normal meaning. I.e., we can just continue scanning without
+      // worrying whether the following characters are part of the escape
+      // or not, since any '/', '\\' or '[' is guaranteed to not be part
+      // of the escape sequence.
+
+      // TODO(896): At some point, parse RegExps more throughly to capture
+      // octal esacpes in strict mode.
+    } else {  // Unescaped character.
+      if (c0_ == '[') in_character_class = true;
+      if (c0_ == ']') in_character_class = false;
+      AddLiteralCharAdvance();
+    }
+  }
+  Advance();  // consume '/'
+
+  literal.Complete();
+
+  return true;
+}
+
+
+Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() {
+  // Scan regular expression flags.
+  LiteralScope literal(this);
+  int flags = 0;
+  while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
+    RegExp::Flags flag = RegExp::kNone;
+    switch (c0_) {
+      case 'g':
+        flag = RegExp::kGlobal;
+        break;
+      case 'i':
+        flag = RegExp::kIgnoreCase;
+        break;
+      case 'm':
+        flag = RegExp::kMultiline;
+        break;
+      case 'u':
+        if (!FLAG_harmony_unicode_regexps) return Nothing<RegExp::Flags>();
+        flag = RegExp::kUnicode;
+        break;
+      case 'y':
+        if (!FLAG_harmony_regexps) return Nothing<RegExp::Flags>();
+        flag = RegExp::kSticky;
+        break;
+      default:
+        return Nothing<RegExp::Flags>();
+    }
+    if (flags & flag) return Nothing<RegExp::Flags>();
+    AddLiteralCharAdvance();
+    flags |= flag;
+  }
+  literal.Complete();
+
+  next_.location.end_pos = source_pos();
+  return Just(RegExp::Flags(flags));
+}
+
+
+const AstRawString* Scanner::CurrentSymbol(AstValueFactory* ast_value_factory) {
+  if (is_literal_one_byte()) {
+    return ast_value_factory->GetOneByteString(literal_one_byte_string());
+  }
+  return ast_value_factory->GetTwoByteString(literal_two_byte_string());
+}
+
+
+const AstRawString* Scanner::NextSymbol(AstValueFactory* ast_value_factory) {
+  if (is_next_literal_one_byte()) {
+    return ast_value_factory->GetOneByteString(next_literal_one_byte_string());
+  }
+  return ast_value_factory->GetTwoByteString(next_literal_two_byte_string());
+}
+
+
+const AstRawString* Scanner::CurrentRawSymbol(
+    AstValueFactory* ast_value_factory) {
+  if (is_raw_literal_one_byte()) {
+    return ast_value_factory->GetOneByteString(raw_literal_one_byte_string());
+  }
+  return ast_value_factory->GetTwoByteString(raw_literal_two_byte_string());
+}
+
+
+double Scanner::DoubleValue() {
+  DCHECK(is_literal_one_byte());
+  return StringToDouble(
+      unicode_cache_,
+      literal_one_byte_string(),
+      ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
+}
+
+
+bool Scanner::ContainsDot() {
+  DCHECK(is_literal_one_byte());
+  Vector<const uint8_t> str = literal_one_byte_string();
+  return std::find(str.begin(), str.end(), '.') != str.end();
+}
+
+
+int Scanner::FindSymbol(DuplicateFinder* finder, int value) {
+  if (is_literal_one_byte()) {
+    return finder->AddOneByteSymbol(literal_one_byte_string(), value);
+  }
+  return finder->AddTwoByteSymbol(literal_two_byte_string(), value);
+}
+
+
+bool Scanner::SetBookmark() {
+  if (c0_ != kNoBookmark && bookmark_c0_ == kNoBookmark &&
+      next_next_.token == Token::UNINITIALIZED && source_->SetBookmark()) {
+    bookmark_c0_ = c0_;
+    CopyTokenDesc(&bookmark_current_, &current_);
+    CopyTokenDesc(&bookmark_next_, &next_);
+    return true;
+  }
+  return false;
+}
+
+
+void Scanner::ResetToBookmark() {
+  DCHECK(BookmarkHasBeenSet());  // Caller hasn't called SetBookmark.
+
+  source_->ResetToBookmark();
+  c0_ = bookmark_c0_;
+  StartLiteral();
+  StartRawLiteral();
+  CopyTokenDesc(&next_, &bookmark_current_);
+  current_ = next_;
+  StartLiteral();
+  StartRawLiteral();
+  CopyTokenDesc(&next_, &bookmark_next_);
+
+  bookmark_c0_ = kBookmarkWasApplied;
+}
+
+
+bool Scanner::BookmarkHasBeenSet() { return bookmark_c0_ >= 0; }
+
+
+bool Scanner::BookmarkHasBeenReset() {
+  return bookmark_c0_ == kBookmarkWasApplied;
+}
+
+
+void Scanner::DropBookmark() { bookmark_c0_ = kNoBookmark; }
+
+
+void Scanner::CopyTokenDesc(TokenDesc* to, TokenDesc* from) {
+  DCHECK_NOT_NULL(to);
+  DCHECK_NOT_NULL(from);
+  to->token = from->token;
+  to->location = from->location;
+  to->literal_chars->CopyFrom(from->literal_chars);
+  to->raw_literal_chars->CopyFrom(from->raw_literal_chars);
+}
+
+
+int DuplicateFinder::AddOneByteSymbol(Vector<const uint8_t> key, int value) {
+  return AddSymbol(key, true, value);
+}
+
+
+int DuplicateFinder::AddTwoByteSymbol(Vector<const uint16_t> key, int value) {
+  return AddSymbol(Vector<const uint8_t>::cast(key), false, value);
+}
+
+
+int DuplicateFinder::AddSymbol(Vector<const uint8_t> key,
+                               bool is_one_byte,
+                               int value) {
+  uint32_t hash = Hash(key, is_one_byte);
+  byte* encoding = BackupKey(key, is_one_byte);
+  HashMap::Entry* entry = map_.LookupOrInsert(encoding, hash);
+  int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+  entry->value =
+    reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
+  return old_value;
+}
+
+
+int DuplicateFinder::AddNumber(Vector<const uint8_t> key, int value) {
+  DCHECK(key.length() > 0);
+  // Quick check for already being in canonical form.
+  if (IsNumberCanonical(key)) {
+    return AddOneByteSymbol(key, value);
+  }
+
+  int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY;
+  double double_value = StringToDouble(
+      unicode_constants_, key, flags, 0.0);
+  int length;
+  const char* string;
+  if (!std::isfinite(double_value)) {
+    string = "Infinity";
+    length = 8;  // strlen("Infinity");
+  } else {
+    string = DoubleToCString(double_value,
+                             Vector<char>(number_buffer_, kBufferSize));
+    length = StrLength(string);
+  }
+  return AddSymbol(Vector<const byte>(reinterpret_cast<const byte*>(string),
+                                      length), true, value);
+}
+
+
+bool DuplicateFinder::IsNumberCanonical(Vector<const uint8_t> number) {
+  // Test for a safe approximation of number literals that are already
+  // in canonical form: max 15 digits, no leading zeroes, except an
+  // integer part that is a single zero, and no trailing zeros below
+  // the decimal point.
+  int pos = 0;
+  int length = number.length();
+  if (number.length() > 15) return false;
+  if (number[pos] == '0') {
+    pos++;
+  } else {
+    while (pos < length &&
+           static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++;
+  }
+  if (length == pos) return true;
+  if (number[pos] != '.') return false;
+  pos++;
+  bool invalid_last_digit = true;
+  while (pos < length) {
+    uint8_t digit = number[pos] - '0';
+    if (digit > '9' - '0') return false;
+    invalid_last_digit = (digit == 0);
+    pos++;
+  }
+  return !invalid_last_digit;
+}
+
+
+uint32_t DuplicateFinder::Hash(Vector<const uint8_t> key, bool is_one_byte) {
+  // Primitive hash function, almost identical to the one used
+  // for strings (except that it's seeded by the length and representation).
+  int length = key.length();
+  uint32_t hash = (length << 1) | (is_one_byte ? 1 : 0);
+  for (int i = 0; i < length; i++) {
+    uint32_t c = key[i];
+    hash = (hash + c) * 1025;
+    hash ^= (hash >> 6);
+  }
+  return hash;
+}
+
+
+bool DuplicateFinder::Match(void* first, void* second) {
+  // Decode lengths.
+  // Length + representation is encoded as base 128, most significant heptet
+  // first, with a 8th bit being non-zero while there are more heptets.
+  // The value encodes the number of bytes following, and whether the original
+  // was Latin1.
+  byte* s1 = reinterpret_cast<byte*>(first);
+  byte* s2 = reinterpret_cast<byte*>(second);
+  uint32_t length_one_byte_field = 0;
+  byte c1;
+  do {
+    c1 = *s1;
+    if (c1 != *s2) return false;
+    length_one_byte_field = (length_one_byte_field << 7) | (c1 & 0x7f);
+    s1++;
+    s2++;
+  } while ((c1 & 0x80) != 0);
+  int length = static_cast<int>(length_one_byte_field >> 1);
+  return memcmp(s1, s2, length) == 0;
+}
+
+
+byte* DuplicateFinder::BackupKey(Vector<const uint8_t> bytes,
+                                 bool is_one_byte) {
+  uint32_t one_byte_length = (bytes.length() << 1) | (is_one_byte ? 1 : 0);
+  backing_store_.StartSequence();
+  // Emit one_byte_length as base-128 encoded number, with the 7th bit set
+  // on the byte of every heptet except the last, least significant, one.
+  if (one_byte_length >= (1 << 7)) {
+    if (one_byte_length >= (1 << 14)) {
+      if (one_byte_length >= (1 << 21)) {
+        if (one_byte_length >= (1 << 28)) {
+          backing_store_.Add(
+              static_cast<uint8_t>((one_byte_length >> 28) | 0x80));
+        }
+        backing_store_.Add(
+            static_cast<uint8_t>((one_byte_length >> 21) | 0x80u));
+      }
+      backing_store_.Add(
+          static_cast<uint8_t>((one_byte_length >> 14) | 0x80u));
+    }
+    backing_store_.Add(static_cast<uint8_t>((one_byte_length >> 7) | 0x80u));
+  }
+  backing_store_.Add(static_cast<uint8_t>(one_byte_length & 0x7f));
+
+  backing_store_.AddBlock(bytes);
+  return backing_store_.EndSequence().start();
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/scanner.h b/src/parsing/scanner.h
new file mode 100644
index 0000000..1d0aba0
--- /dev/null
+++ b/src/parsing/scanner.h
@@ -0,0 +1,760 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Features shared by parsing and pre-parsing scanners.
+
+#ifndef V8_PARSING_SCANNER_H_
+#define V8_PARSING_SCANNER_H_
+
+#include "src/allocation.h"
+#include "src/base/logging.h"
+#include "src/char-predicates.h"
+#include "src/globals.h"
+#include "src/hashmap.h"
+#include "src/list.h"
+#include "src/parsing/token.h"
+#include "src/unicode.h"
+#include "src/unicode-decoder.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+
+class AstRawString;
+class AstValueFactory;
+class ParserRecorder;
+class UnicodeCache;
+
+
+// ---------------------------------------------------------------------
+// Buffered stream of UTF-16 code units, using an internal UTF-16 buffer.
+// A code unit is a 16 bit value representing either a 16 bit code point
+// or one part of a surrogate pair that make a single 21 bit code point.
+
+class Utf16CharacterStream {
+ public:
+  Utf16CharacterStream() : pos_(0) { }
+  virtual ~Utf16CharacterStream() { }
+
+  // Returns and advances past the next UTF-16 code unit in the input
+  // stream. If there are no more code units, it returns a negative
+  // value.
+  inline uc32 Advance() {
+    if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
+      pos_++;
+      return static_cast<uc32>(*(buffer_cursor_++));
+    }
+    // Note: currently the following increment is necessary to avoid a
+    // parser problem! The scanner treats the final kEndOfInput as
+    // a code unit with a position, and does math relative to that
+    // position.
+    pos_++;
+
+    return kEndOfInput;
+  }
+
+  // Return the current position in the code unit stream.
+  // Starts at zero.
+  inline size_t pos() const { return pos_; }
+
+  // Skips forward past the next code_unit_count UTF-16 code units
+  // in the input, or until the end of input if that comes sooner.
+  // Returns the number of code units actually skipped. If less
+  // than code_unit_count,
+  inline size_t SeekForward(size_t code_unit_count) {
+    size_t buffered_chars = buffer_end_ - buffer_cursor_;
+    if (code_unit_count <= buffered_chars) {
+      buffer_cursor_ += code_unit_count;
+      pos_ += code_unit_count;
+      return code_unit_count;
+    }
+    return SlowSeekForward(code_unit_count);
+  }
+
+  // Pushes back the most recently read UTF-16 code unit (or negative
+  // value if at end of input), i.e., the value returned by the most recent
+  // call to Advance.
+  // Must not be used right after calling SeekForward.
+  virtual void PushBack(int32_t code_unit) = 0;
+
+  virtual bool SetBookmark();
+  virtual void ResetToBookmark();
+
+ protected:
+  static const uc32 kEndOfInput = -1;
+
+  // Ensures that the buffer_cursor_ points to the code_unit at
+  // position pos_ of the input, if possible. If the position
+  // is at or after the end of the input, return false. If there
+  // are more code_units available, return true.
+  virtual bool ReadBlock() = 0;
+  virtual size_t SlowSeekForward(size_t code_unit_count) = 0;
+
+  const uint16_t* buffer_cursor_;
+  const uint16_t* buffer_end_;
+  size_t pos_;
+};
+
+
+// ---------------------------------------------------------------------
+// DuplicateFinder discovers duplicate symbols.
+
+class DuplicateFinder {
+ public:
+  explicit DuplicateFinder(UnicodeCache* constants)
+      : unicode_constants_(constants),
+        backing_store_(16),
+        map_(&Match) { }
+
+  int AddOneByteSymbol(Vector<const uint8_t> key, int value);
+  int AddTwoByteSymbol(Vector<const uint16_t> key, int value);
+  // Add a a number literal by converting it (if necessary)
+  // to the string that ToString(ToNumber(literal)) would generate.
+  // and then adding that string with AddOneByteSymbol.
+  // This string is the actual value used as key in an object literal,
+  // and the one that must be different from the other keys.
+  int AddNumber(Vector<const uint8_t> key, int value);
+
+ private:
+  int AddSymbol(Vector<const uint8_t> key, bool is_one_byte, int value);
+  // Backs up the key and its length in the backing store.
+  // The backup is stored with a base 127 encoding of the
+  // length (plus a bit saying whether the string is one byte),
+  // followed by the bytes of the key.
+  uint8_t* BackupKey(Vector<const uint8_t> key, bool is_one_byte);
+
+  // Compare two encoded keys (both pointing into the backing store)
+  // for having the same base-127 encoded lengths and representation.
+  // and then having the same 'length' bytes following.
+  static bool Match(void* first, void* second);
+  // Creates a hash from a sequence of bytes.
+  static uint32_t Hash(Vector<const uint8_t> key, bool is_one_byte);
+  // Checks whether a string containing a JS number is its canonical
+  // form.
+  static bool IsNumberCanonical(Vector<const uint8_t> key);
+
+  // Size of buffer. Sufficient for using it to call DoubleToCString in
+  // from conversions.h.
+  static const int kBufferSize = 100;
+
+  UnicodeCache* unicode_constants_;
+  // Backing store used to store strings used as hashmap keys.
+  SequenceCollector<unsigned char> backing_store_;
+  HashMap map_;
+  // Buffer used for string->number->canonical string conversions.
+  char number_buffer_[kBufferSize];
+};
+
+
+// ----------------------------------------------------------------------------
+// LiteralBuffer -  Collector of chars of literals.
+
+class LiteralBuffer {
+ public:
+  LiteralBuffer() : is_one_byte_(true), position_(0), backing_store_() { }
+
+  ~LiteralBuffer() { backing_store_.Dispose(); }
+
+  INLINE(void AddChar(uint32_t code_unit)) {
+    if (position_ >= backing_store_.length()) ExpandBuffer();
+    if (is_one_byte_) {
+      if (code_unit <= unibrow::Latin1::kMaxChar) {
+        backing_store_[position_] = static_cast<byte>(code_unit);
+        position_ += kOneByteSize;
+        return;
+      }
+      ConvertToTwoByte();
+    }
+    if (code_unit <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
+      *reinterpret_cast<uint16_t*>(&backing_store_[position_]) = code_unit;
+      position_ += kUC16Size;
+    } else {
+      *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
+          unibrow::Utf16::LeadSurrogate(code_unit);
+      position_ += kUC16Size;
+      if (position_ >= backing_store_.length()) ExpandBuffer();
+      *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
+          unibrow::Utf16::TrailSurrogate(code_unit);
+      position_ += kUC16Size;
+    }
+  }
+
+  bool is_one_byte() const { return is_one_byte_; }
+
+  bool is_contextual_keyword(Vector<const char> keyword) const {
+    return is_one_byte() && keyword.length() == position_ &&
+        (memcmp(keyword.start(), backing_store_.start(), position_) == 0);
+  }
+
+  Vector<const uint16_t> two_byte_literal() const {
+    DCHECK(!is_one_byte_);
+    DCHECK((position_ & 0x1) == 0);
+    return Vector<const uint16_t>(
+        reinterpret_cast<const uint16_t*>(backing_store_.start()),
+        position_ >> 1);
+  }
+
+  Vector<const uint8_t> one_byte_literal() const {
+    DCHECK(is_one_byte_);
+    return Vector<const uint8_t>(
+        reinterpret_cast<const uint8_t*>(backing_store_.start()),
+        position_);
+  }
+
+  int length() const {
+    return is_one_byte_ ? position_ : (position_ >> 1);
+  }
+
+  void ReduceLength(int delta) {
+    position_ -= delta * (is_one_byte_ ? kOneByteSize : kUC16Size);
+  }
+
+  void Reset() {
+    position_ = 0;
+    is_one_byte_ = true;
+  }
+
+  Handle<String> Internalize(Isolate* isolate) const;
+
+  void CopyFrom(const LiteralBuffer* other) {
+    if (other == nullptr) {
+      Reset();
+    } else {
+      is_one_byte_ = other->is_one_byte_;
+      position_ = other->position_;
+      backing_store_.Dispose();
+      backing_store_ = other->backing_store_.Clone();
+    }
+  }
+
+ private:
+  static const int kInitialCapacity = 16;
+  static const int kGrowthFactory = 4;
+  static const int kMinConversionSlack = 256;
+  static const int kMaxGrowth = 1 * MB;
+  inline int NewCapacity(int min_capacity) {
+    int capacity = Max(min_capacity, backing_store_.length());
+    int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
+    return new_capacity;
+  }
+
+  void ExpandBuffer() {
+    Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
+    MemCopy(new_store.start(), backing_store_.start(), position_);
+    backing_store_.Dispose();
+    backing_store_ = new_store;
+  }
+
+  void ConvertToTwoByte() {
+    DCHECK(is_one_byte_);
+    Vector<byte> new_store;
+    int new_content_size = position_ * kUC16Size;
+    if (new_content_size >= backing_store_.length()) {
+      // Ensure room for all currently read code units as UC16 as well
+      // as the code unit about to be stored.
+      new_store = Vector<byte>::New(NewCapacity(new_content_size));
+    } else {
+      new_store = backing_store_;
+    }
+    uint8_t* src = backing_store_.start();
+    uint16_t* dst = reinterpret_cast<uint16_t*>(new_store.start());
+    for (int i = position_ - 1; i >= 0; i--) {
+      dst[i] = src[i];
+    }
+    if (new_store.start() != backing_store_.start()) {
+      backing_store_.Dispose();
+      backing_store_ = new_store;
+    }
+    position_ = new_content_size;
+    is_one_byte_ = false;
+  }
+
+  bool is_one_byte_;
+  int position_;
+  Vector<byte> backing_store_;
+
+  DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
+};
+
+
+// ----------------------------------------------------------------------------
+// JavaScript Scanner.
+
+class Scanner {
+ public:
+  // Scoped helper for literal recording. Automatically drops the literal
+  // if aborting the scanning before it's complete.
+  class LiteralScope {
+   public:
+    explicit LiteralScope(Scanner* self) : scanner_(self), complete_(false) {
+      scanner_->StartLiteral();
+    }
+     ~LiteralScope() {
+       if (!complete_) scanner_->DropLiteral();
+     }
+    void Complete() {
+      complete_ = true;
+    }
+
+   private:
+    Scanner* scanner_;
+    bool complete_;
+  };
+
+  // Scoped helper for a re-settable bookmark.
+  class BookmarkScope {
+   public:
+    explicit BookmarkScope(Scanner* scanner) : scanner_(scanner) {
+      DCHECK_NOT_NULL(scanner_);
+    }
+    ~BookmarkScope() { scanner_->DropBookmark(); }
+
+    bool Set() { return scanner_->SetBookmark(); }
+    void Reset() { scanner_->ResetToBookmark(); }
+    bool HasBeenSet() { return scanner_->BookmarkHasBeenSet(); }
+    bool HasBeenReset() { return scanner_->BookmarkHasBeenReset(); }
+
+   private:
+    Scanner* scanner_;
+
+    DISALLOW_COPY_AND_ASSIGN(BookmarkScope);
+  };
+
+  // Representation of an interval of source positions.
+  struct Location {
+    Location(int b, int e) : beg_pos(b), end_pos(e) { }
+    Location() : beg_pos(0), end_pos(0) { }
+
+    bool IsValid() const {
+      return beg_pos >= 0 && end_pos >= beg_pos;
+    }
+
+    static Location invalid() { return Location(-1, -1); }
+
+    int beg_pos;
+    int end_pos;
+  };
+
+  // -1 is outside of the range of any real source code.
+  static const int kNoOctalLocation = -1;
+
+  explicit Scanner(UnicodeCache* scanner_contants);
+
+  void Initialize(Utf16CharacterStream* source);
+
+  // Returns the next token and advances input.
+  Token::Value Next();
+  // Returns the token following peek()
+  Token::Value PeekAhead();
+  // Returns the current token again.
+  Token::Value current_token() { return current_.token; }
+  // Returns the location information for the current token
+  // (the token last returned by Next()).
+  Location location() const { return current_.location; }
+
+  // Similar functions for the upcoming token.
+
+  // One token look-ahead (past the token returned by Next()).
+  Token::Value peek() const { return next_.token; }
+
+  Location peek_location() const { return next_.location; }
+
+  bool literal_contains_escapes() const {
+    return LiteralContainsEscapes(current_);
+  }
+  bool next_literal_contains_escapes() const {
+    return LiteralContainsEscapes(next_);
+  }
+  bool is_literal_contextual_keyword(Vector<const char> keyword) {
+    DCHECK_NOT_NULL(current_.literal_chars);
+    return current_.literal_chars->is_contextual_keyword(keyword);
+  }
+  bool is_next_contextual_keyword(Vector<const char> keyword) {
+    DCHECK_NOT_NULL(next_.literal_chars);
+    return next_.literal_chars->is_contextual_keyword(keyword);
+  }
+
+  const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory);
+  const AstRawString* NextSymbol(AstValueFactory* ast_value_factory);
+  const AstRawString* CurrentRawSymbol(AstValueFactory* ast_value_factory);
+
+  double DoubleValue();
+  bool ContainsDot();
+  bool LiteralMatches(const char* data, int length, bool allow_escapes = true) {
+    if (is_literal_one_byte() &&
+        literal_length() == length &&
+        (allow_escapes || !literal_contains_escapes())) {
+      const char* token =
+          reinterpret_cast<const char*>(literal_one_byte_string().start());
+      return !strncmp(token, data, length);
+    }
+    return false;
+  }
+  inline bool UnescapedLiteralMatches(const char* data, int length) {
+    return LiteralMatches(data, length, false);
+  }
+
+  void IsGetOrSet(bool* is_get, bool* is_set) {
+    if (is_literal_one_byte() &&
+        literal_length() == 3 &&
+        !literal_contains_escapes()) {
+      const char* token =
+          reinterpret_cast<const char*>(literal_one_byte_string().start());
+      *is_get = strncmp(token, "get", 3) == 0;
+      *is_set = !*is_get && strncmp(token, "set", 3) == 0;
+    }
+  }
+
+  int FindSymbol(DuplicateFinder* finder, int value);
+
+  UnicodeCache* unicode_cache() { return unicode_cache_; }
+
+  // Returns the location of the last seen octal literal.
+  Location octal_position() const { return octal_pos_; }
+  void clear_octal_position() { octal_pos_ = Location::invalid(); }
+
+  // Returns the value of the last smi that was scanned.
+  int smi_value() const { return current_.smi_value_; }
+
+  // Seek forward to the given position.  This operation does not
+  // work in general, for instance when there are pushed back
+  // characters, but works for seeking forward until simple delimiter
+  // tokens, which is what it is used for.
+  void SeekForward(int pos);
+
+  // Returns true if there was a line terminator before the peek'ed token,
+  // possibly inside a multi-line comment.
+  bool HasAnyLineTerminatorBeforeNext() const {
+    return has_line_terminator_before_next_ ||
+           has_multiline_comment_before_next_;
+  }
+
+  // Scans the input as a regular expression pattern, previous
+  // character(s) must be /(=). Returns true if a pattern is scanned.
+  bool ScanRegExpPattern(bool seen_equal);
+  // Scans the input as regular expression flags. Returns the flags on success.
+  Maybe<RegExp::Flags> ScanRegExpFlags();
+
+  // Scans the input as a template literal
+  Token::Value ScanTemplateStart();
+  Token::Value ScanTemplateContinuation();
+
+  const LiteralBuffer* source_url() const { return &source_url_; }
+  const LiteralBuffer* source_mapping_url() const {
+    return &source_mapping_url_;
+  }
+
+  bool IdentifierIsFutureStrictReserved(const AstRawString* string) const;
+
+ private:
+  // The current and look-ahead token.
+  struct TokenDesc {
+    Token::Value token;
+    Location location;
+    LiteralBuffer* literal_chars;
+    LiteralBuffer* raw_literal_chars;
+    int smi_value_;
+  };
+
+  static const int kCharacterLookaheadBufferSize = 1;
+
+  // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
+  template <bool capture_raw>
+  uc32 ScanOctalEscape(uc32 c, int length);
+
+  // Call this after setting source_ to the input.
+  void Init() {
+    // Set c0_ (one character ahead)
+    STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
+    Advance();
+    // Initialize current_ to not refer to a literal.
+    current_.literal_chars = NULL;
+    current_.raw_literal_chars = NULL;
+    next_next_.token = Token::UNINITIALIZED;
+  }
+
+  // Support BookmarkScope functionality.
+  bool SetBookmark();
+  void ResetToBookmark();
+  bool BookmarkHasBeenSet();
+  bool BookmarkHasBeenReset();
+  void DropBookmark();
+  static void CopyTokenDesc(TokenDesc* to, TokenDesc* from);
+
+  // Literal buffer support
+  inline void StartLiteral() {
+    LiteralBuffer* free_buffer =
+        (current_.literal_chars == &literal_buffer0_)
+            ? &literal_buffer1_
+            : (current_.literal_chars == &literal_buffer1_) ? &literal_buffer2_
+                                                            : &literal_buffer0_;
+    free_buffer->Reset();
+    next_.literal_chars = free_buffer;
+  }
+
+  inline void StartRawLiteral() {
+    LiteralBuffer* free_buffer =
+        (current_.raw_literal_chars == &raw_literal_buffer0_)
+            ? &raw_literal_buffer1_
+            : (current_.raw_literal_chars == &raw_literal_buffer1_)
+                  ? &raw_literal_buffer2_
+                  : &raw_literal_buffer0_;
+    free_buffer->Reset();
+    next_.raw_literal_chars = free_buffer;
+  }
+
+  INLINE(void AddLiteralChar(uc32 c)) {
+    DCHECK_NOT_NULL(next_.literal_chars);
+    next_.literal_chars->AddChar(c);
+  }
+
+  INLINE(void AddRawLiteralChar(uc32 c)) {
+    DCHECK_NOT_NULL(next_.raw_literal_chars);
+    next_.raw_literal_chars->AddChar(c);
+  }
+
+  INLINE(void ReduceRawLiteralLength(int delta)) {
+    DCHECK_NOT_NULL(next_.raw_literal_chars);
+    next_.raw_literal_chars->ReduceLength(delta);
+  }
+
+  // Stops scanning of a literal and drop the collected characters,
+  // e.g., due to an encountered error.
+  inline void DropLiteral() {
+    next_.literal_chars = NULL;
+    next_.raw_literal_chars = NULL;
+  }
+
+  inline void AddLiteralCharAdvance() {
+    AddLiteralChar(c0_);
+    Advance();
+  }
+
+  // Low-level scanning support.
+  template <bool capture_raw = false, bool check_surrogate = true>
+  void Advance() {
+    if (capture_raw) {
+      AddRawLiteralChar(c0_);
+    }
+    c0_ = source_->Advance();
+    if (check_surrogate) HandleLeadSurrogate();
+  }
+
+  void HandleLeadSurrogate() {
+    if (unibrow::Utf16::IsLeadSurrogate(c0_)) {
+      uc32 c1 = source_->Advance();
+      if (!unibrow::Utf16::IsTrailSurrogate(c1)) {
+        source_->PushBack(c1);
+      } else {
+        c0_ = unibrow::Utf16::CombineSurrogatePair(c0_, c1);
+      }
+    }
+  }
+
+  void PushBack(uc32 ch) {
+    if (ch > static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
+      source_->PushBack(unibrow::Utf16::TrailSurrogate(c0_));
+      source_->PushBack(unibrow::Utf16::LeadSurrogate(c0_));
+    } else {
+      source_->PushBack(c0_);
+    }
+    c0_ = ch;
+  }
+
+  inline Token::Value Select(Token::Value tok) {
+    Advance();
+    return tok;
+  }
+
+  inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
+    Advance();
+    if (c0_ == next) {
+      Advance();
+      return then;
+    } else {
+      return else_;
+    }
+  }
+
+  // Returns the literal string, if any, for the current token (the
+  // token last returned by Next()). The string is 0-terminated.
+  // Literal strings are collected for identifiers, strings, numbers as well
+  // as for template literals. For template literals we also collect the raw
+  // form.
+  // These functions only give the correct result if the literal was scanned
+  // when a LiteralScope object is alive.
+  Vector<const uint8_t> literal_one_byte_string() {
+    DCHECK_NOT_NULL(current_.literal_chars);
+    return current_.literal_chars->one_byte_literal();
+  }
+  Vector<const uint16_t> literal_two_byte_string() {
+    DCHECK_NOT_NULL(current_.literal_chars);
+    return current_.literal_chars->two_byte_literal();
+  }
+  bool is_literal_one_byte() {
+    DCHECK_NOT_NULL(current_.literal_chars);
+    return current_.literal_chars->is_one_byte();
+  }
+  int literal_length() const {
+    DCHECK_NOT_NULL(current_.literal_chars);
+    return current_.literal_chars->length();
+  }
+  // Returns the literal string for the next token (the token that
+  // would be returned if Next() were called).
+  Vector<const uint8_t> next_literal_one_byte_string() {
+    DCHECK_NOT_NULL(next_.literal_chars);
+    return next_.literal_chars->one_byte_literal();
+  }
+  Vector<const uint16_t> next_literal_two_byte_string() {
+    DCHECK_NOT_NULL(next_.literal_chars);
+    return next_.literal_chars->two_byte_literal();
+  }
+  bool is_next_literal_one_byte() {
+    DCHECK_NOT_NULL(next_.literal_chars);
+    return next_.literal_chars->is_one_byte();
+  }
+  Vector<const uint8_t> raw_literal_one_byte_string() {
+    DCHECK_NOT_NULL(current_.raw_literal_chars);
+    return current_.raw_literal_chars->one_byte_literal();
+  }
+  Vector<const uint16_t> raw_literal_two_byte_string() {
+    DCHECK_NOT_NULL(current_.raw_literal_chars);
+    return current_.raw_literal_chars->two_byte_literal();
+  }
+  bool is_raw_literal_one_byte() {
+    DCHECK_NOT_NULL(current_.raw_literal_chars);
+    return current_.raw_literal_chars->is_one_byte();
+  }
+
+  template <bool capture_raw>
+  uc32 ScanHexNumber(int expected_length);
+  // Scan a number of any length but not bigger than max_value. For example, the
+  // number can be 000000001, so it's very long in characters but its value is
+  // small.
+  template <bool capture_raw>
+  uc32 ScanUnlimitedLengthHexNumber(int max_value);
+
+  // Scans a single JavaScript token.
+  void Scan();
+
+  bool SkipWhiteSpace();
+  Token::Value SkipSingleLineComment();
+  Token::Value SkipSourceURLComment();
+  void TryToParseSourceURLComment();
+  Token::Value SkipMultiLineComment();
+  // Scans a possible HTML comment -- begins with '<!'.
+  Token::Value ScanHtmlComment();
+
+  void ScanDecimalDigits();
+  Token::Value ScanNumber(bool seen_period);
+  Token::Value ScanIdentifierOrKeyword();
+  Token::Value ScanIdentifierSuffix(LiteralScope* literal, bool escaped);
+
+  Token::Value ScanString();
+
+  // Scans an escape-sequence which is part of a string and adds the
+  // decoded character to the current literal. Returns true if a pattern
+  // is scanned.
+  template <bool capture_raw, bool in_template_literal>
+  bool ScanEscape();
+
+  // Decodes a Unicode escape-sequence which is part of an identifier.
+  // If the escape sequence cannot be decoded the result is kBadChar.
+  uc32 ScanIdentifierUnicodeEscape();
+  // Helper for the above functions.
+  template <bool capture_raw>
+  uc32 ScanUnicodeEscape();
+
+  Token::Value ScanTemplateSpan();
+
+  // Return the current source position.
+  int source_pos() {
+    return static_cast<int>(source_->pos()) - kCharacterLookaheadBufferSize;
+  }
+
+  static bool LiteralContainsEscapes(const TokenDesc& token) {
+    Location location = token.location;
+    int source_length = (location.end_pos - location.beg_pos);
+    if (token.token == Token::STRING) {
+      // Subtract delimiters.
+      source_length -= 2;
+    }
+    return token.literal_chars->length() != source_length;
+  }
+
+  UnicodeCache* unicode_cache_;
+
+  // Buffers collecting literal strings, numbers, etc.
+  LiteralBuffer literal_buffer0_;
+  LiteralBuffer literal_buffer1_;
+  LiteralBuffer literal_buffer2_;
+
+  // Values parsed from magic comments.
+  LiteralBuffer source_url_;
+  LiteralBuffer source_mapping_url_;
+
+  // Buffer to store raw string values
+  LiteralBuffer raw_literal_buffer0_;
+  LiteralBuffer raw_literal_buffer1_;
+  LiteralBuffer raw_literal_buffer2_;
+
+  TokenDesc current_;    // desc for current token (as returned by Next())
+  TokenDesc next_;       // desc for next token (one token look-ahead)
+  TokenDesc next_next_;  // desc for the token after next (after PeakAhead())
+
+  // Variables for Scanner::BookmarkScope and the *Bookmark implementation.
+  // These variables contain the scanner state when a bookmark is set.
+  //
+  // We will use bookmark_c0_ as a 'control' variable, where:
+  // - bookmark_c0_ >= 0: A bookmark has been set and this contains c0_.
+  // - bookmark_c0_ == -1: No bookmark has been set.
+  // - bookmark_c0_ == -2: The bookmark has been applied (ResetToBookmark).
+  //
+  // Which state is being bookmarked? The parser state is distributed over
+  // several variables, roughly like this:
+  //   ...    1234        +       5678 ..... [character stream]
+  //       [current_] [next_] c0_ |      [scanner state]
+  // So when the scanner is logically at the beginning of an expression
+  // like "1234 + 4567", then:
+  // - current_ contains "1234"
+  // - next_ contains "+"
+  // - c0_ contains ' ' (the space between "+" and "5678",
+  // - the source_ character stream points to the beginning of "5678".
+  // To be able to restore this state, we will keep copies of current_, next_,
+  // and c0_; we'll ask the stream to bookmark itself, and we'll copy the
+  // contents of current_'s and next_'s literal buffers to bookmark_*_literal_.
+  static const uc32 kNoBookmark = -1;
+  static const uc32 kBookmarkWasApplied = -2;
+  uc32 bookmark_c0_;
+  TokenDesc bookmark_current_;
+  TokenDesc bookmark_next_;
+  LiteralBuffer bookmark_current_literal_;
+  LiteralBuffer bookmark_current_raw_literal_;
+  LiteralBuffer bookmark_next_literal_;
+  LiteralBuffer bookmark_next_raw_literal_;
+
+  // Input stream. Must be initialized to an Utf16CharacterStream.
+  Utf16CharacterStream* source_;
+
+
+  // Start position of the octal literal last scanned.
+  Location octal_pos_;
+
+  // One Unicode character look-ahead; c0_ < 0 at the end of the input.
+  uc32 c0_;
+
+  // Whether there is a line terminator whitespace character after
+  // the current token, and  before the next. Does not count newlines
+  // inside multiline comments.
+  bool has_line_terminator_before_next_;
+  // Whether there is a multi-line comment that contains a
+  // line-terminator after the current token, and before the next.
+  bool has_multiline_comment_before_next_;
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_SCANNER_H_
diff --git a/src/parsing/token.cc b/src/parsing/token.cc
new file mode 100644
index 0000000..7edfefa
--- /dev/null
+++ b/src/parsing/token.cc
@@ -0,0 +1,42 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+#include "src/parsing/token.h"
+
+namespace v8 {
+namespace internal {
+
+#define T(name, string, precedence) #name,
+const char* const Token::name_[NUM_TOKENS] = {
+  TOKEN_LIST(T, T)
+};
+#undef T
+
+
+#define T(name, string, precedence) string,
+const char* const Token::string_[NUM_TOKENS] = {
+  TOKEN_LIST(T, T)
+};
+#undef T
+
+
+#define T(name, string, precedence) precedence,
+const int8_t Token::precedence_[NUM_TOKENS] = {
+  TOKEN_LIST(T, T)
+};
+#undef T
+
+
+#define KT(a, b, c) 'T',
+#define KK(a, b, c) 'K',
+const char Token::token_type[] = {
+  TOKEN_LIST(KT, KK)
+};
+#undef KT
+#undef KK
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/parsing/token.h b/src/parsing/token.h
new file mode 100644
index 0000000..fee1f7e
--- /dev/null
+++ b/src/parsing/token.h
@@ -0,0 +1,324 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PARSING_TOKEN_H_
+#define V8_PARSING_TOKEN_H_
+
+#include "src/base/logging.h"
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+// TOKEN_LIST takes a list of 3 macros M, all of which satisfy the
+// same signature M(name, string, precedence), where name is the
+// symbolic token name, string is the corresponding syntactic symbol
+// (or NULL, for literals), and precedence is the precedence (or 0).
+// The parameters are invoked for token categories as follows:
+//
+//   T: Non-keyword tokens
+//   K: Keyword tokens
+
+// IGNORE_TOKEN is a convenience macro that can be supplied as
+// an argument (at any position) for a TOKEN_LIST call. It does
+// nothing with tokens belonging to the respective category.
+
+#define IGNORE_TOKEN(name, string, precedence)
+
+#define TOKEN_LIST(T, K)                                             \
+  /* End of source indicator. */                                     \
+  T(EOS, "EOS", 0)                                                   \
+                                                                     \
+  /* Punctuators (ECMA-262, section 7.7, page 15). */                \
+  T(LPAREN, "(", 0)                                                  \
+  T(RPAREN, ")", 0)                                                  \
+  T(LBRACK, "[", 0)                                                  \
+  T(RBRACK, "]", 0)                                                  \
+  T(LBRACE, "{", 0)                                                  \
+  T(RBRACE, "}", 0)                                                  \
+  T(COLON, ":", 0)                                                   \
+  T(SEMICOLON, ";", 0)                                               \
+  T(PERIOD, ".", 0)                                                  \
+  T(ELLIPSIS, "...", 0)                                              \
+  T(CONDITIONAL, "?", 3)                                             \
+  T(INC, "++", 0)                                                    \
+  T(DEC, "--", 0)                                                    \
+  T(ARROW, "=>", 0)                                                  \
+                                                                     \
+  /* Assignment operators. */                                        \
+  /* IsAssignmentOp() and Assignment::is_compound() relies on */     \
+  /* this block of enum values being contiguous and sorted in the */ \
+  /* same order! */                                                  \
+  T(INIT, "=init", 2) /* AST-use only. */                            \
+  T(ASSIGN, "=", 2)                                                  \
+  T(ASSIGN_BIT_OR, "|=", 2)                                          \
+  T(ASSIGN_BIT_XOR, "^=", 2)                                         \
+  T(ASSIGN_BIT_AND, "&=", 2)                                         \
+  T(ASSIGN_SHL, "<<=", 2)                                            \
+  T(ASSIGN_SAR, ">>=", 2)                                            \
+  T(ASSIGN_SHR, ">>>=", 2)                                           \
+  T(ASSIGN_ADD, "+=", 2)                                             \
+  T(ASSIGN_SUB, "-=", 2)                                             \
+  T(ASSIGN_MUL, "*=", 2)                                             \
+  T(ASSIGN_DIV, "/=", 2)                                             \
+  T(ASSIGN_MOD, "%=", 2)                                             \
+                                                                     \
+  /* Binary operators sorted by precedence. */                       \
+  /* IsBinaryOp() relies on this block of enum values */             \
+  /* being contiguous and sorted in the same order! */               \
+  T(COMMA, ",", 1)                                                   \
+  T(OR, "||", 4)                                                     \
+  T(AND, "&&", 5)                                                    \
+  T(BIT_OR, "|", 6)                                                  \
+  T(BIT_XOR, "^", 7)                                                 \
+  T(BIT_AND, "&", 8)                                                 \
+  T(SHL, "<<", 11)                                                   \
+  T(SAR, ">>", 11)                                                   \
+  T(SHR, ">>>", 11)                                                  \
+  T(ROR, "rotate right", 11) /* only used by Crankshaft */           \
+  T(ADD, "+", 12)                                                    \
+  T(SUB, "-", 12)                                                    \
+  T(MUL, "*", 13)                                                    \
+  T(DIV, "/", 13)                                                    \
+  T(MOD, "%", 13)                                                    \
+                                                                     \
+  /* Compare operators sorted by precedence. */                      \
+  /* IsCompareOp() relies on this block of enum values */            \
+  /* being contiguous and sorted in the same order! */               \
+  T(EQ, "==", 9)                                                     \
+  T(NE, "!=", 9)                                                     \
+  T(EQ_STRICT, "===", 9)                                             \
+  T(NE_STRICT, "!==", 9)                                             \
+  T(LT, "<", 10)                                                     \
+  T(GT, ">", 10)                                                     \
+  T(LTE, "<=", 10)                                                   \
+  T(GTE, ">=", 10)                                                   \
+  K(INSTANCEOF, "instanceof", 10)                                    \
+  K(IN, "in", 10)                                                    \
+                                                                     \
+  /* Unary operators. */                                             \
+  /* IsUnaryOp() relies on this block of enum values */              \
+  /* being contiguous and sorted in the same order! */               \
+  T(NOT, "!", 0)                                                     \
+  T(BIT_NOT, "~", 0)                                                 \
+  K(DELETE, "delete", 0)                                             \
+  K(TYPEOF, "typeof", 0)                                             \
+  K(VOID, "void", 0)                                                 \
+                                                                     \
+  /* Keywords (ECMA-262, section 7.5.2, page 13). */                 \
+  K(BREAK, "break", 0)                                               \
+  K(CASE, "case", 0)                                                 \
+  K(CATCH, "catch", 0)                                               \
+  K(CONTINUE, "continue", 0)                                         \
+  K(DEBUGGER, "debugger", 0)                                         \
+  K(DEFAULT, "default", 0)                                           \
+  /* DELETE */                                                       \
+  K(DO, "do", 0)                                                     \
+  K(ELSE, "else", 0)                                                 \
+  K(FINALLY, "finally", 0)                                           \
+  K(FOR, "for", 0)                                                   \
+  K(FUNCTION, "function", 0)                                         \
+  K(IF, "if", 0)                                                     \
+  /* IN */                                                           \
+  /* INSTANCEOF */                                                   \
+  K(NEW, "new", 0)                                                   \
+  K(RETURN, "return", 0)                                             \
+  K(SWITCH, "switch", 0)                                             \
+  K(THIS, "this", 0)                                                 \
+  K(THROW, "throw", 0)                                               \
+  K(TRY, "try", 0)                                                   \
+  /* TYPEOF */                                                       \
+  K(VAR, "var", 0)                                                   \
+  /* VOID */                                                         \
+  K(WHILE, "while", 0)                                               \
+  K(WITH, "with", 0)                                                 \
+                                                                     \
+  /* Literals (ECMA-262, section 7.8, page 16). */                   \
+  K(NULL_LITERAL, "null", 0)                                         \
+  K(TRUE_LITERAL, "true", 0)                                         \
+  K(FALSE_LITERAL, "false", 0)                                       \
+  T(NUMBER, NULL, 0)                                                 \
+  T(SMI, NULL, 0)                                                    \
+  T(STRING, NULL, 0)                                                 \
+                                                                     \
+  /* Identifiers (not keywords or future reserved words). */         \
+  T(IDENTIFIER, NULL, 0)                                             \
+                                                                     \
+  /* Future reserved words (ECMA-262, section 7.6.1.2). */           \
+  T(FUTURE_RESERVED_WORD, NULL, 0)                                   \
+  T(FUTURE_STRICT_RESERVED_WORD, NULL, 0)                            \
+  K(CLASS, "class", 0)                                               \
+  K(CONST, "const", 0)                                               \
+  K(EXPORT, "export", 0)                                             \
+  K(EXTENDS, "extends", 0)                                           \
+  K(IMPORT, "import", 0)                                             \
+  K(LET, "let", 0)                                                   \
+  K(STATIC, "static", 0)                                             \
+  K(YIELD, "yield", 0)                                               \
+  K(SUPER, "super", 0)                                               \
+                                                                     \
+  /* Illegal token - not able to scan. */                            \
+  T(ILLEGAL, "ILLEGAL", 0)                                           \
+  T(ESCAPED_KEYWORD, NULL, 0)                                        \
+  T(ESCAPED_STRICT_RESERVED_WORD, NULL, 0)                           \
+                                                                     \
+  /* Scanner-internal use only. */                                   \
+  T(WHITESPACE, NULL, 0)                                             \
+  T(UNINITIALIZED, NULL, 0)                                          \
+                                                                     \
+  /* ES6 Template Literals */                                        \
+  T(TEMPLATE_SPAN, NULL, 0)                                          \
+  T(TEMPLATE_TAIL, NULL, 0)
+
+
+class Token {
+ public:
+  // All token values.
+#define T(name, string, precedence) name,
+  enum Value {
+    TOKEN_LIST(T, T)
+    NUM_TOKENS
+  };
+#undef T
+
+  // Returns a string corresponding to the C++ token name
+  // (e.g. "LT" for the token LT).
+  static const char* Name(Value tok) {
+    DCHECK(tok < NUM_TOKENS);  // tok is unsigned
+    return name_[tok];
+  }
+
+  // Predicates
+  static bool IsKeyword(Value tok) {
+    return token_type[tok] == 'K';
+  }
+
+  static bool IsIdentifier(Value tok, LanguageMode language_mode,
+                           bool is_generator) {
+    switch (tok) {
+      case IDENTIFIER:
+        return true;
+      case ESCAPED_STRICT_RESERVED_WORD:
+      case FUTURE_STRICT_RESERVED_WORD:
+      case LET:
+      case STATIC:
+        return is_sloppy(language_mode);
+      case YIELD:
+        return !is_generator && is_sloppy(language_mode);
+      default:
+        return false;
+    }
+    UNREACHABLE();
+    return false;
+  }
+
+  static bool IsAssignmentOp(Value tok) {
+    return INIT <= tok && tok <= ASSIGN_MOD;
+  }
+
+  static bool IsBinaryOp(Value op) {
+    return COMMA <= op && op <= MOD;
+  }
+
+  static bool IsTruncatingBinaryOp(Value op) {
+    return BIT_OR <= op && op <= ROR;
+  }
+
+  static bool IsCompareOp(Value op) {
+    return EQ <= op && op <= IN;
+  }
+
+  static bool IsOrderedRelationalCompareOp(Value op) {
+    return op == LT || op == LTE || op == GT || op == GTE;
+  }
+
+  static bool IsEqualityOp(Value op) {
+    return op == EQ || op == EQ_STRICT;
+  }
+
+  static bool IsInequalityOp(Value op) {
+    return op == NE || op == NE_STRICT;
+  }
+
+  static bool IsArithmeticCompareOp(Value op) {
+    return IsOrderedRelationalCompareOp(op) ||
+        IsEqualityOp(op) || IsInequalityOp(op);
+  }
+
+  static Value NegateCompareOp(Value op) {
+    DCHECK(IsArithmeticCompareOp(op));
+    switch (op) {
+      case EQ: return NE;
+      case NE: return EQ;
+      case EQ_STRICT: return NE_STRICT;
+      case NE_STRICT: return EQ_STRICT;
+      case LT: return GTE;
+      case GT: return LTE;
+      case LTE: return GT;
+      case GTE: return LT;
+      default:
+        UNREACHABLE();
+        return op;
+    }
+  }
+
+  static Value ReverseCompareOp(Value op) {
+    DCHECK(IsArithmeticCompareOp(op));
+    switch (op) {
+      case EQ: return EQ;
+      case NE: return NE;
+      case EQ_STRICT: return EQ_STRICT;
+      case NE_STRICT: return NE_STRICT;
+      case LT: return GT;
+      case GT: return LT;
+      case LTE: return GTE;
+      case GTE: return LTE;
+      default:
+        UNREACHABLE();
+        return op;
+    }
+  }
+
+  static bool IsBitOp(Value op) {
+    return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
+  }
+
+  static bool IsUnaryOp(Value op) {
+    return (NOT <= op && op <= VOID) || op == ADD || op == SUB;
+  }
+
+  static bool IsCountOp(Value op) {
+    return op == INC || op == DEC;
+  }
+
+  static bool IsShiftOp(Value op) {
+    return (SHL <= op) && (op <= SHR);
+  }
+
+  // Returns a string corresponding to the JS token string
+  // (.e., "<" for the token LT) or NULL if the token doesn't
+  // have a (unique) string (e.g. an IDENTIFIER).
+  static const char* String(Value tok) {
+    DCHECK(tok < NUM_TOKENS);  // tok is unsigned.
+    return string_[tok];
+  }
+
+  // Returns the precedence > 0 for binary and compare
+  // operators; returns 0 otherwise.
+  static int Precedence(Value tok) {
+    DCHECK(tok < NUM_TOKENS);  // tok is unsigned.
+    return precedence_[tok];
+  }
+
+ private:
+  static const char* const name_[NUM_TOKENS];
+  static const char* const string_[NUM_TOKENS];
+  static const int8_t precedence_[NUM_TOKENS];
+  static const char token_type[NUM_TOKENS];
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_PARSING_TOKEN_H_