aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/parsing
diff options
context:
space:
mode:
authorAli Ijaz Sheikh <ofrobots@google.com>2016-03-01 08:58:05 -0800
committerAli Sheikh <ofrobots@lemonhope.roam.corp.google.com>2016-03-03 20:35:20 -0800
commit069e02ab47656b3efd1b6829c65856b2e1c2d1db (patch)
treeeb643e0a2e88fd64bb9fc927423458d2ae96c2db /deps/v8/src/parsing
parent8938355398c79f583a468284b768652d12ba9bc9 (diff)
downloadandroid-node-v8-069e02ab47656b3efd1b6829c65856b2e1c2d1db.tar.gz
android-node-v8-069e02ab47656b3efd1b6829c65856b2e1c2d1db.tar.bz2
android-node-v8-069e02ab47656b3efd1b6829c65856b2e1c2d1db.zip
deps: upgrade to V8 4.9.385.18
Pick up the current branch head for V8 4.9 https://github.com/v8/v8/commit/1ecba0f PR-URL: https://github.com/nodejs/node/pull/4722 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Michaƫl Zasso <mic.besace@gmail.com>
Diffstat (limited to 'deps/v8/src/parsing')
-rw-r--r--deps/v8/src/parsing/OWNERS6
-rw-r--r--deps/v8/src/parsing/expression-classifier.h356
-rw-r--r--deps/v8/src/parsing/func-name-inferrer.cc85
-rw-r--r--deps/v8/src/parsing/func-name-inferrer.h127
-rw-r--r--deps/v8/src/parsing/json-parser.h842
-rw-r--r--deps/v8/src/parsing/parameter-initializer-rewriter.cc88
-rw-r--r--deps/v8/src/parsing/parameter-initializer-rewriter.h22
-rw-r--r--deps/v8/src/parsing/parser-base.h3380
-rw-r--r--deps/v8/src/parsing/parser.cc5548
-rw-r--r--deps/v8/src/parsing/parser.h1220
-rw-r--r--deps/v8/src/parsing/pattern-rewriter.cc628
-rw-r--r--deps/v8/src/parsing/preparse-data-format.h41
-rw-r--r--deps/v8/src/parsing/preparse-data.cc80
-rw-r--r--deps/v8/src/parsing/preparse-data.h212
-rw-r--r--deps/v8/src/parsing/preparser.cc1292
-rw-r--r--deps/v8/src/parsing/preparser.h1175
-rw-r--r--deps/v8/src/parsing/rewriter.cc403
-rw-r--r--deps/v8/src/parsing/rewriter.h36
-rw-r--r--deps/v8/src/parsing/scanner-character-streams.cc589
-rw-r--r--deps/v8/src/parsing/scanner-character-streams.h189
-rw-r--r--deps/v8/src/parsing/scanner.cc1673
-rw-r--r--deps/v8/src/parsing/scanner.h760
-rw-r--r--deps/v8/src/parsing/token.cc42
-rw-r--r--deps/v8/src/parsing/token.h324
24 files changed, 19118 insertions, 0 deletions
diff --git a/deps/v8/src/parsing/OWNERS b/deps/v8/src/parsing/OWNERS
new file mode 100644
index 0000000000..fbab2056f8
--- /dev/null
+++ b/deps/v8/src/parsing/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+adamk@chromium.org
+littledan@chromium.org
+marja@chromium.org
+rossberg@chromium.org
diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h
new file mode 100644
index 0000000000..96ccf871f4
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/func-name-inferrer.cc b/deps/v8/src/parsing/func-name-inferrer.cc
new file mode 100644
index 0000000000..12013afd28
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/func-name-inferrer.h b/deps/v8/src/parsing/func-name-inferrer.h
new file mode 100644
index 0000000000..ba38ffeb24
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/json-parser.h b/deps/v8/src/parsing/json-parser.h
new file mode 100644
index 0000000000..e23c73383e
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/parameter-initializer-rewriter.cc b/deps/v8/src/parsing/parameter-initializer-rewriter.cc
new file mode 100644
index 0000000000..003bbebae0
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/parameter-initializer-rewriter.h b/deps/v8/src/parsing/parameter-initializer-rewriter.h
new file mode 100644
index 0000000000..255534c99e
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h
new file mode 100644
index 0000000000..2955b0b9d9
--- /dev/null
+++ b/deps/v8/src/parsing/parser-base.h
@@ -0,0 +1,3380 @@
+// 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();
+ BindingPatternUnexpectedToken(classifier);
+ 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_->AllowsLazyCompilation());
+ 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/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc
new file mode 100644
index 0000000000..b1b8c1316b
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h
new file mode 100644
index 0000000000..7d50221334
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/pattern-rewriter.cc b/deps/v8/src/parsing/pattern-rewriter.cc
new file mode 100644
index 0000000000..6e20282785
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/preparse-data-format.h b/deps/v8/src/parsing/preparse-data-format.h
new file mode 100644
index 0000000000..f7d9f68cce
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/preparse-data.cc b/deps/v8/src/parsing/preparse-data.cc
new file mode 100644
index 0000000000..d02cd63d66
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/preparse-data.h b/deps/v8/src/parsing/preparse-data.h
new file mode 100644
index 0000000000..dbe1022d1e
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc
new file mode 100644
index 0000000000..64511acc39
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h
new file mode 100644
index 0000000000..59100f1ae9
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/rewriter.cc b/deps/v8/src/parsing/rewriter.cc
new file mode 100644
index 0000000000..4da60aca18
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/rewriter.h b/deps/v8/src/parsing/rewriter.h
new file mode 100644
index 0000000000..477644a756
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/scanner-character-streams.cc b/deps/v8/src/parsing/scanner-character-streams.cc
new file mode 100644
index 0000000000..91ed54f7be
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/scanner-character-streams.h b/deps/v8/src/parsing/scanner-character-streams.h
new file mode 100644
index 0000000000..603db93d02
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc
new file mode 100644
index 0000000000..19fab9355e
--- /dev/null
+++ b/deps/v8/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_ == '#') {
+ 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/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h
new file mode 100644
index 0000000000..1d0aba0611
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/token.cc b/deps/v8/src/parsing/token.cc
new file mode 100644
index 0000000000..7edfefa821
--- /dev/null
+++ b/deps/v8/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/deps/v8/src/parsing/token.h b/deps/v8/src/parsing/token.h
new file mode 100644
index 0000000000..fee1f7e85a
--- /dev/null
+++ b/deps/v8/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_