summaryrefslogtreecommitdiff
path: root/deps/v8/src/parsing
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2019-03-12 09:01:49 +0100
committerMichaël Zasso <targos@protonmail.com>2019-03-14 18:49:21 +0100
commit7b48713334469818661fe276cf571de9c7899f2d (patch)
tree4dbda49ac88db76ce09dc330a0cb587e68e139ba /deps/v8/src/parsing
parent8549ac09b256666cf5275224ec58fab9939ff32e (diff)
downloadnode-new-7b48713334469818661fe276cf571de9c7899f2d.tar.gz
deps: update V8 to 7.3.492.25
PR-URL: https://github.com/nodejs/node/pull/25852 Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/parsing')
-rw-r--r--deps/v8/src/parsing/duplicate-finder.h36
-rw-r--r--deps/v8/src/parsing/expression-classifier.h568
-rw-r--r--deps/v8/src/parsing/expression-scope-reparenter.cc6
-rw-r--r--deps/v8/src/parsing/expression-scope.h710
-rw-r--r--deps/v8/src/parsing/func-name-inferrer.cc33
-rw-r--r--deps/v8/src/parsing/func-name-inferrer.h65
-rw-r--r--deps/v8/src/parsing/keywords-gen.h177
-rw-r--r--deps/v8/src/parsing/keywords.txt64
-rw-r--r--deps/v8/src/parsing/parse-info.cc35
-rw-r--r--deps/v8/src/parsing/parse-info.h90
-rw-r--r--deps/v8/src/parsing/parser-base.h4704
-rw-r--r--deps/v8/src/parsing/parser.cc2395
-rw-r--r--deps/v8/src/parsing/parser.h457
-rw-r--r--deps/v8/src/parsing/parsing.cc3
-rw-r--r--deps/v8/src/parsing/pattern-rewriter.cc700
-rw-r--r--deps/v8/src/parsing/preparse-data-impl.h234
-rw-r--r--deps/v8/src/parsing/preparse-data.cc716
-rw-r--r--deps/v8/src/parsing/preparse-data.h275
-rw-r--r--deps/v8/src/parsing/preparsed-scope-data-impl.h259
-rw-r--r--deps/v8/src/parsing/preparsed-scope-data.cc737
-rw-r--r--deps/v8/src/parsing/preparsed-scope-data.h214
-rw-r--r--deps/v8/src/parsing/preparser.cc411
-rw-r--r--deps/v8/src/parsing/preparser.h853
-rw-r--r--deps/v8/src/parsing/rewriter.cc79
-rw-r--r--deps/v8/src/parsing/rewriter.h10
-rw-r--r--deps/v8/src/parsing/scanner-character-streams.cc56
-rw-r--r--deps/v8/src/parsing/scanner-inl.h772
-rw-r--r--deps/v8/src/parsing/scanner.cc227
-rw-r--r--deps/v8/src/parsing/scanner.h245
-rw-r--r--deps/v8/src/parsing/token.cc29
-rw-r--r--deps/v8/src/parsing/token.h192
31 files changed, 6805 insertions, 8547 deletions
diff --git a/deps/v8/src/parsing/duplicate-finder.h b/deps/v8/src/parsing/duplicate-finder.h
deleted file mode 100644
index 65bcc4e00d..0000000000
--- a/deps/v8/src/parsing/duplicate-finder.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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_DUPLICATE_FINDER_H_
-#define V8_PARSING_DUPLICATE_FINDER_H_
-
-#include <set>
-
-namespace v8 {
-namespace internal {
-
-class Scanner;
-
-// DuplicateFinder : Helper class to discover duplicate symbols.
-//
-// Allocate a DuplicateFinder for each set of symbols you want to check
-// for duplicates and then pass this instance into
-// Scanner::IsDuplicateSymbol(..).
-//
-// This class only holds the data; all actual logic is in
-// Scanner::IsDuplicateSymbol.
-class DuplicateFinder {
- public:
- DuplicateFinder() = default;
-
- private:
- friend class Scanner;
-
- std::set<const void*> known_symbols_;
-};
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_PARSING_DUPLICATE_FINDER_H_
diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h
deleted file mode 100644
index 2eed75b939..0000000000
--- a/deps/v8/src/parsing/expression-classifier.h
+++ /dev/null
@@ -1,568 +0,0 @@
-// 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 <type_traits>
-
-#include "src/messages.h"
-#include "src/parsing/scanner.h"
-
-namespace v8 {
-namespace internal {
-
-class DuplicateFinder;
-
-#define ERROR_CODES(T) \
- T(ExpressionProduction, 0) \
- T(FormalParameterInitializerProduction, 1) \
- T(BindingPatternProduction, 2) \
- T(AssignmentPatternProduction, 3) \
- T(DistinctFormalParametersProduction, 4) \
- T(StrictModeFormalParametersProduction, 5) \
- T(ArrowFormalParametersProduction, 6) \
- T(LetPatternProduction, 7) \
- T(AsyncArrowFormalParametersProduction, 8)
-
-// Expression classifiers serve two purposes:
-//
-// 1) They keep track of error messages that are pending (and other
-// related information), waiting for the parser to decide whether
-// the parsed expression is a pattern or not.
-// 2) They keep track of expressions that may need to be rewritten, if
-// the parser decides that they are not patterns. (A different
-// mechanism implements the rewriting of patterns.)
-//
-// Expression classifiers are used by the parser in a stack fashion.
-// Each new classifier is pushed on top of the stack. This happens
-// automatically by the class's constructor. While on top of the
-// stack, the classifier records pending error messages and tracks the
-// pending non-patterns of the expression that is being parsed.
-//
-// At the end of its life, a classifier is either "accumulated" to the
-// one that is below it on the stack, or is "discarded". The former
-// is achieved by calling the method Accumulate. The latter is
-// achieved automatically by the destructor, but it can happen earlier
-// by calling the method Discard. Both actions result in removing the
-// classifier from the parser's stack.
-
-// Expression classifier is split into four parts. The base implementing the
-// general expression classifier logic. Two parts that implement the error
-// tracking interface, where one is the actual implementation and the other is
-// an empty class providing only the interface without logic. The expression
-// classifier class then combines the other parts and provides the full
-// expression classifier interface by inheriting conditionally, controlled by
-// Types::ExpressionClassifierReportErrors, either from the ErrorTracker or the
-// EmptyErrorTracker.
-//
-// Base
-// / \
-// / \
-// / \
-// / \
-// ErrorTracker EmptyErrorTracker
-// \ /
-// \ /
-// \ /
-// \ /
-// ExpressionClassifier
-
-template <typename Types>
-class ExpressionClassifier;
-
-template <typename Types, typename ErrorTracker>
-class ExpressionClassifierBase {
- public:
- enum ErrorKind : unsigned {
-#define DEFINE_ERROR_KIND(NAME, CODE) k##NAME = CODE,
- ERROR_CODES(DEFINE_ERROR_KIND)
-#undef DEFINE_ERROR_KIND
- kUnusedError = 15 // Larger than error codes; should fit in 4 bits
- };
-
- struct Error {
- V8_INLINE Error()
- : location(Scanner::Location::invalid()),
- message(MessageTemplate::kNone),
- kind(kUnusedError),
- arg(nullptr) {}
- V8_INLINE explicit Error(Scanner::Location loc,
- MessageTemplate::Template msg, ErrorKind k,
- const char* a = nullptr)
- : location(loc), message(msg), kind(k), arg(a) {}
-
- Scanner::Location location;
- MessageTemplate::Template message : 28;
- unsigned kind : 4;
- const char* arg;
- };
-
- // clang-format off
- enum TargetProduction : unsigned {
-#define DEFINE_PRODUCTION(NAME, CODE) NAME = 1 << CODE,
- ERROR_CODES(DEFINE_PRODUCTION)
-#undef DEFINE_PRODUCTION
-
-#define DEFINE_ALL_PRODUCTIONS(NAME, CODE) NAME |
- AllProductions = ERROR_CODES(DEFINE_ALL_PRODUCTIONS) /* | */ 0
-#undef DEFINE_ALL_PRODUCTIONS
- };
- // clang-format on
-
- explicit ExpressionClassifierBase(typename Types::Base* base,
- DuplicateFinder* duplicate_finder = nullptr)
- : base_(base),
- duplicate_finder_(duplicate_finder),
- invalid_productions_(0),
- is_non_simple_parameter_list_(0) {}
-
- virtual ~ExpressionClassifierBase() = default;
-
- V8_INLINE bool is_valid(unsigned productions) const {
- return (invalid_productions_ & productions) == 0;
- }
-
- V8_INLINE DuplicateFinder* duplicate_finder() const {
- return duplicate_finder_;
- }
-
- V8_INLINE bool is_valid_expression() const {
- return is_valid(ExpressionProduction);
- }
-
- V8_INLINE bool is_valid_formal_parameter_initializer() const {
- return is_valid(FormalParameterInitializerProduction);
- }
-
- V8_INLINE bool is_valid_binding_pattern() const {
- return is_valid(BindingPatternProduction);
- }
-
- V8_INLINE bool is_valid_assignment_pattern() const {
- return is_valid(AssignmentPatternProduction);
- }
-
- V8_INLINE bool is_valid_arrow_formal_parameters() const {
- return is_valid(ArrowFormalParametersProduction);
- }
-
- V8_INLINE 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().
- V8_INLINE bool is_valid_strict_mode_formal_parameters() const {
- return is_valid(StrictModeFormalParametersProduction);
- }
-
- V8_INLINE bool is_valid_let_pattern() const {
- return is_valid(LetPatternProduction);
- }
-
- bool is_valid_async_arrow_formal_parameters() const {
- return is_valid(AsyncArrowFormalParametersProduction);
- }
-
- V8_INLINE bool is_simple_parameter_list() const {
- return !is_non_simple_parameter_list_;
- }
-
- V8_INLINE void RecordNonSimpleParameter() {
- is_non_simple_parameter_list_ = 1;
- }
-
- V8_INLINE void Accumulate(ExpressionClassifier<Types>* const inner,
- unsigned productions) {
-#ifdef DEBUG
- static_cast<ErrorTracker*>(this)->CheckErrorPositions(inner);
-#endif
- // 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) {
- unsigned errors = non_arrow_inner_invalid_productions & productions &
- ~this->invalid_productions_;
- // The result will continue to be a valid arrow formal parameters if the
- // inner expression is a valid binding pattern.
- bool copy_BP_to_AFP = false;
- if (productions & ArrowFormalParametersProduction &&
- this->is_valid_arrow_formal_parameters()) {
- // Also whether we've seen any non-simple parameters
- // if expecting an arrow function parameter.
- this->is_non_simple_parameter_list_ |=
- inner->is_non_simple_parameter_list_;
- if (!inner->is_valid_binding_pattern()) {
- copy_BP_to_AFP = true;
- this->invalid_productions_ |= ArrowFormalParametersProduction;
- }
- }
- if (errors != 0 || copy_BP_to_AFP) {
- this->invalid_productions_ |= errors;
- static_cast<ErrorTracker*>(this)->AccumulateErrorImpl(
- inner, productions, errors, copy_BP_to_AFP);
- }
- }
- static_cast<ErrorTracker*>(this)->RewindErrors(inner);
- }
-
- protected:
- typename Types::Base* base_;
- DuplicateFinder* duplicate_finder_;
- unsigned invalid_productions_ : kUnusedError;
- STATIC_ASSERT(kUnusedError <= 15);
- unsigned is_non_simple_parameter_list_ : 1;
-};
-
-template <typename Types>
-class ExpressionClassifierErrorTracker
- : public ExpressionClassifierBase<Types,
- ExpressionClassifierErrorTracker<Types>> {
- public:
- using BaseClassType =
- ExpressionClassifierBase<Types, ExpressionClassifierErrorTracker<Types>>;
- using typename BaseClassType::Error;
- using typename BaseClassType::ErrorKind;
- using TP = typename BaseClassType::TargetProduction;
-
- ExpressionClassifierErrorTracker(typename Types::Base* base,
- DuplicateFinder* duplicate_finder)
- : BaseClassType(base, duplicate_finder),
- reported_errors_(base->impl()->GetReportedErrorList()) {
- reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
- }
-
- ~ExpressionClassifierErrorTracker() override { Discard(); }
-
- V8_INLINE void Discard() {
- if (reported_errors_end_ == reported_errors_->length()) {
- reported_errors_->Rewind(reported_errors_begin_);
- reported_errors_end_ = reported_errors_begin_;
- }
- DCHECK_EQ(reported_errors_begin_, reported_errors_end_);
- }
-
- protected:
- V8_INLINE const Error& reported_error(ErrorKind kind) const {
- if (this->invalid_productions_ & (1 << kind)) {
- for (int i = reported_errors_begin_; i < reported_errors_end_; i++) {
- if (reported_errors_->at(i).kind == kind)
- return reported_errors_->at(i);
- }
- UNREACHABLE();
- }
- // We should only be looking for an error when we know that one has
- // been reported. But we're not... So this is to make sure we have
- // the same behaviour.
- UNREACHABLE();
-
- // Make MSVC happy by returning an error from this inaccessible path.
- static Error none;
- return none;
- }
-
- // Adds e to the end of the list of reported errors for this classifier.
- // It is expected that this classifier is the last one in the stack.
- V8_INLINE void Add(const Error& e) {
- DCHECK_EQ(reported_errors_end_, reported_errors_->length());
- reported_errors_->Add(e, this->base_->impl()->zone());
- reported_errors_end_++;
- }
-
- // Copies the error at position i of the list of reported errors, so that
- // it becomes the last error reported for this classifier. Position i
- // could be either after the existing errors of this classifier (i.e.,
- // in an inner classifier) or it could be an existing error (in case a
- // copy is needed).
- V8_INLINE void Copy(int i) {
- DCHECK_LT(i, reported_errors_->length());
- if (reported_errors_end_ != i)
- reported_errors_->at(reported_errors_end_) = reported_errors_->at(i);
- reported_errors_end_++;
- }
-
- private:
-#ifdef DEBUG
- V8_INLINE void CheckErrorPositions(ExpressionClassifier<Types>* const inner) {
- DCHECK_EQ(inner->reported_errors_, this->reported_errors_);
- DCHECK_EQ(inner->reported_errors_begin_, this->reported_errors_end_);
- DCHECK_EQ(inner->reported_errors_end_, this->reported_errors_->length());
- }
-#endif
-
- V8_INLINE void RewindErrors(ExpressionClassifier<Types>* const inner) {
- this->reported_errors_->Rewind(this->reported_errors_end_);
- inner->reported_errors_begin_ = inner->reported_errors_end_ =
- this->reported_errors_end_;
- }
-
- void AccumulateErrorImpl(ExpressionClassifier<Types>* const inner,
- unsigned productions, unsigned errors,
- bool copy_BP_to_AFP) {
- // Traverse the list of errors reported by the inner classifier
- // to copy what's necessary.
- int binding_pattern_index = inner->reported_errors_end_;
- for (int i = inner->reported_errors_begin_; i < inner->reported_errors_end_;
- i++) {
- int k = this->reported_errors_->at(i).kind;
- if (errors & (1 << k)) this->Copy(i);
- // Check if it's a BP error that has to be copied to an AFP error.
- if (k == ErrorKind::kBindingPatternProduction && copy_BP_to_AFP) {
- if (this->reported_errors_end_ <= i) {
- // If the BP error itself has not already been copied,
- // copy it now and change it to an AFP error.
- this->Copy(i);
- this->reported_errors_->at(this->reported_errors_end_ - 1).kind =
- ErrorKind::kArrowFormalParametersProduction;
- } else {
- // Otherwise, if the BP error was already copied, keep its
- // position and wait until the end of the traversal.
- DCHECK_EQ(this->reported_errors_end_, i + 1);
- binding_pattern_index = i;
- }
- }
- }
- // Do we still have to copy the BP error to an AFP error?
- if (binding_pattern_index < inner->reported_errors_end_) {
- // If there's still unused space in the list of the inner
- // classifier, copy it there, otherwise add it to the end
- // of the list.
- if (this->reported_errors_end_ < inner->reported_errors_end_)
- this->Copy(binding_pattern_index);
- else
- Add(this->reported_errors_->at(binding_pattern_index));
- this->reported_errors_->at(this->reported_errors_end_ - 1).kind =
- ErrorKind::kArrowFormalParametersProduction;
- }
- }
-
- private:
- ZoneList<Error>* reported_errors_;
- // The uint16_t for reported_errors_begin_ and reported_errors_end_ will
- // not be enough in the case of a long series of expressions using nested
- // classifiers, e.g., a long sequence of assignments, as in:
- // literals with spreads, as in:
- // var N=65536; eval("var x;" + "x=".repeat(N) + "42");
- // This should not be a problem, as such things currently fail with a
- // stack overflow while parsing.
- uint16_t reported_errors_begin_;
- uint16_t reported_errors_end_;
-
- friend BaseClassType;
-};
-
-template <typename Types>
-class ExpressionClassifierEmptyErrorTracker
- : public ExpressionClassifierBase<
- Types, ExpressionClassifierEmptyErrorTracker<Types>> {
- public:
- using BaseClassType =
- ExpressionClassifierBase<Types,
- ExpressionClassifierEmptyErrorTracker<Types>>;
- using typename BaseClassType::Error;
- using typename BaseClassType::ErrorKind;
- using TP = typename BaseClassType::TargetProduction;
-
- ExpressionClassifierEmptyErrorTracker(typename Types::Base* base,
- DuplicateFinder* duplicate_finder)
- : BaseClassType(base, duplicate_finder) {}
-
- V8_INLINE void Discard() {}
-
- protected:
- V8_INLINE const Error& reported_error(ErrorKind kind) const {
- static Error none;
- return none;
- }
-
- V8_INLINE void Add(const Error& e) {}
-
- private:
-#ifdef DEBUG
- V8_INLINE void CheckErrorPositions(ExpressionClassifier<Types>* const inner) {
- }
-#endif
- V8_INLINE void RewindErrors(ExpressionClassifier<Types>* const inner) {}
- V8_INLINE void AccumulateErrorImpl(ExpressionClassifier<Types>* const inner,
- unsigned productions, unsigned errors,
- bool copy_BP_to_AFP) {}
-
- friend BaseClassType;
-};
-
-template <typename Types>
-class ExpressionClassifier
- : public std::conditional<
- Types::ExpressionClassifierReportErrors,
- ExpressionClassifierErrorTracker<Types>,
- ExpressionClassifierEmptyErrorTracker<Types>>::type {
- static constexpr bool ReportErrors = Types::ExpressionClassifierReportErrors;
-
- public:
- using BaseClassType = typename std::conditional<
- Types::ExpressionClassifierReportErrors,
- typename ExpressionClassifierErrorTracker<Types>::BaseClassType,
- typename ExpressionClassifierEmptyErrorTracker<Types>::BaseClassType>::
- type;
- using typename BaseClassType::Error;
- using typename BaseClassType::ErrorKind;
- using TP = typename BaseClassType::TargetProduction;
-
- explicit ExpressionClassifier(typename Types::Base* base,
- DuplicateFinder* duplicate_finder = nullptr)
- : std::conditional<Types::ExpressionClassifierReportErrors,
- ExpressionClassifierErrorTracker<Types>,
- ExpressionClassifierEmptyErrorTracker<Types>>::
- type(base, duplicate_finder),
- previous_(base->classifier_) {
- base->classifier_ = this;
- }
-
- V8_INLINE ~ExpressionClassifier() override {
- if (this->base_->classifier_ == this) this->base_->classifier_ = previous_;
- }
-
- V8_INLINE const Error& expression_error() const {
- return this->reported_error(ErrorKind::kExpressionProduction);
- }
-
- V8_INLINE const Error& formal_parameter_initializer_error() const {
- return this->reported_error(
- ErrorKind::kFormalParameterInitializerProduction);
- }
-
- V8_INLINE const Error& binding_pattern_error() const {
- return this->reported_error(ErrorKind::kBindingPatternProduction);
- }
-
- V8_INLINE const Error& assignment_pattern_error() const {
- return this->reported_error(ErrorKind::kAssignmentPatternProduction);
- }
-
- V8_INLINE const Error& arrow_formal_parameters_error() const {
- return this->reported_error(ErrorKind::kArrowFormalParametersProduction);
- }
-
- V8_INLINE const Error& duplicate_formal_parameter_error() const {
- return this->reported_error(ErrorKind::kDistinctFormalParametersProduction);
- }
-
- V8_INLINE const Error& strict_mode_formal_parameter_error() const {
- return this->reported_error(
- ErrorKind::kStrictModeFormalParametersProduction);
- }
-
- V8_INLINE const Error& let_pattern_error() const {
- return this->reported_error(ErrorKind::kLetPatternProduction);
- }
-
- V8_INLINE const Error& async_arrow_formal_parameters_error() const {
- return this->reported_error(
- ErrorKind::kAsyncArrowFormalParametersProduction);
- }
-
- V8_INLINE bool does_error_reporting() { return ReportErrors; }
-
- void RecordExpressionError(const Scanner::Location& loc,
- MessageTemplate::Template message,
- const char* arg = nullptr) {
- if (!this->is_valid_expression()) return;
- this->invalid_productions_ |= TP::ExpressionProduction;
- this->Add(Error(loc, message, ErrorKind::kExpressionProduction, arg));
- }
-
- void RecordFormalParameterInitializerError(const Scanner::Location& loc,
- MessageTemplate::Template message,
- const char* arg = nullptr) {
- if (!this->is_valid_formal_parameter_initializer()) return;
- this->invalid_productions_ |= TP::FormalParameterInitializerProduction;
- this->Add(Error(loc, message,
- ErrorKind::kFormalParameterInitializerProduction, arg));
- }
-
- void RecordBindingPatternError(const Scanner::Location& loc,
- MessageTemplate::Template message,
- const char* arg = nullptr) {
- if (!this->is_valid_binding_pattern()) return;
- this->invalid_productions_ |= TP::BindingPatternProduction;
- this->Add(Error(loc, message, ErrorKind::kBindingPatternProduction, arg));
- }
-
- void RecordAssignmentPatternError(const Scanner::Location& loc,
- MessageTemplate::Template message,
- const char* arg = nullptr) {
- if (!this->is_valid_assignment_pattern()) return;
- this->invalid_productions_ |= TP::AssignmentPatternProduction;
- this->Add(
- Error(loc, message, ErrorKind::kAssignmentPatternProduction, 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 (!this->is_valid_arrow_formal_parameters()) return;
- this->invalid_productions_ |= TP::ArrowFormalParametersProduction;
- this->Add(
- Error(loc, message, ErrorKind::kArrowFormalParametersProduction, arg));
- }
-
- void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc,
- MessageTemplate::Template message,
- const char* arg = nullptr) {
- if (!this->is_valid_async_arrow_formal_parameters()) return;
- this->invalid_productions_ |= TP::AsyncArrowFormalParametersProduction;
- this->Add(Error(loc, message,
- ErrorKind::kAsyncArrowFormalParametersProduction, arg));
- }
-
- void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
- if (!this->is_valid_formal_parameter_list_without_duplicates()) return;
- this->invalid_productions_ |= TP::DistinctFormalParametersProduction;
- this->Add(Error(loc, MessageTemplate::kParamDupe,
- ErrorKind::kDistinctFormalParametersProduction));
- }
-
- // 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 (!this->is_valid_strict_mode_formal_parameters()) return;
- this->invalid_productions_ |= TP::StrictModeFormalParametersProduction;
- this->Add(Error(loc, message,
- ErrorKind::kStrictModeFormalParametersProduction, arg));
- }
-
- void RecordLetPatternError(const Scanner::Location& loc,
- MessageTemplate::Template message,
- const char* arg = nullptr) {
- if (!this->is_valid_let_pattern()) return;
- this->invalid_productions_ |= TP::LetPatternProduction;
- this->Add(Error(loc, message, ErrorKind::kLetPatternProduction, arg));
- }
-
- ExpressionClassifier* previous() const { return previous_; }
-
- private:
- ExpressionClassifier* previous_;
-
- DISALLOW_COPY_AND_ASSIGN(ExpressionClassifier);
-};
-
-#undef ERROR_CODES
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_PARSING_EXPRESSION_CLASSIFIER_H_
diff --git a/deps/v8/src/parsing/expression-scope-reparenter.cc b/deps/v8/src/parsing/expression-scope-reparenter.cc
index 30e96d1688..95e4935c53 100644
--- a/deps/v8/src/parsing/expression-scope-reparenter.cc
+++ b/deps/v8/src/parsing/expression-scope-reparenter.cc
@@ -27,7 +27,6 @@ class Reparenter final : public AstTraversalVisitor<Reparenter> {
void VisitFunctionLiteral(FunctionLiteral* expr);
void VisitClassLiteral(ClassLiteral* expr);
void VisitVariableProxy(VariableProxy* expr);
- void VisitRewritableExpression(RewritableExpression* expr);
void VisitBlock(Block* stmt);
void VisitTryCatchStatement(TryCatchStatement* stmt);
@@ -79,11 +78,6 @@ void Reparenter::VisitVariableProxy(VariableProxy* proxy) {
}
}
-void Reparenter::VisitRewritableExpression(RewritableExpression* expr) {
- Visit(expr->expression());
- expr->set_scope(scope_);
-}
-
void Reparenter::VisitBlock(Block* stmt) {
if (stmt->scope())
stmt->scope()->ReplaceOuterScope(scope_);
diff --git a/deps/v8/src/parsing/expression-scope.h b/deps/v8/src/parsing/expression-scope.h
new file mode 100644
index 0000000000..878cb3cf25
--- /dev/null
+++ b/deps/v8/src/parsing/expression-scope.h
@@ -0,0 +1,710 @@
+// Copyright 2018 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_SCOPE_H_
+#define V8_PARSING_EXPRESSION_SCOPE_H_
+
+#include "src/ast/scopes.h"
+#include "src/message-template.h"
+#include "src/parsing/scanner.h"
+#include "src/zone/zone.h" // For ScopedPtrList.
+
+namespace v8 {
+namespace internal {
+
+template <typename Types>
+class ExpressionParsingScope;
+template <typename Types>
+class AccumulationScope;
+template <typename Types>
+class ArrowHeadParsingScope;
+template <typename Types>
+class ParameterDeclarationParsingScope;
+template <typename Types>
+class VariableDeclarationParsingScope;
+class VariableProxy;
+
+// ExpressionScope is used in a stack fashion, and is used to specialize
+// expression parsing for the task at hand. It allows the parser to reuse the
+// same code to parse destructuring declarations, assignment patterns,
+// expressions, and (async) arrow function heads.
+//
+// One of the specific subclasses needs to be instantiated to tell the parser
+// the meaning of the expression it will parse next. The parser then calls
+// Record* on the expression_scope() to indicate errors. The expression_scope
+// will either discard those errors, immediately report those errors, or
+// classify the errors for later validation.
+// TODO(verwaest): Record is a slightly odd name since it will directly throw
+// for unambiguous scopes.
+template <typename Types>
+class ExpressionScope {
+ public:
+ typedef typename Types::Impl ParserT;
+ typedef typename Types::Expression ExpressionT;
+
+ VariableProxy* NewVariable(const AstRawString* name,
+ int pos = kNoSourcePosition) {
+ VariableProxy* result = parser_->NewRawVariable(name, pos);
+ if (CanBeExpression()) {
+ AsExpressionParsingScope()->TrackVariable(result);
+ } else if (type_ == kParameterDeclaration) {
+ AsParameterDeclarationParsingScope()->Declare(result);
+ } else {
+ return AsVariableDeclarationParsingScope()->Declare(result);
+ }
+ return result;
+ }
+
+ void MarkIdentifierAsAssigned() {
+ if (!CanBeExpression()) return;
+ AsExpressionParsingScope()->MarkIdentifierAsAssigned();
+ }
+
+ void ValidateAsPattern(ExpressionT expression, int begin, int end) {
+ if (!CanBeExpression()) return;
+ AsExpressionParsingScope()->ValidatePattern(expression, begin, end);
+ AsExpressionParsingScope()->ClearExpressionError();
+ }
+
+ // Record async arrow parameters errors in all ambiguous async arrow scopes in
+ // the chain up to the first unambiguous scope.
+ void RecordAsyncArrowParametersError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ // Only ambiguous scopes (ExpressionParsingScope, *ArrowHeadParsingScope)
+ // need to propagate errors to a possible kAsyncArrowHeadParsingScope, so
+ // immediately return if the current scope is not ambiguous.
+ if (!CanBeExpression()) return;
+ AsExpressionParsingScope()->RecordAsyncArrowParametersError(loc, message);
+ }
+
+ // Record initializer errors in all scopes that can turn into parameter scopes
+ // (ArrowHeadParsingScopes) up to the first known unambiguous parameter scope.
+ void RecordParameterInitializerError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ ExpressionScope* scope = this;
+ while (!scope->IsCertainlyParameterDeclaration()) {
+ if (!has_possible_parameter_in_scope_chain_) return;
+ if (scope->CanBeParameterDeclaration()) {
+ scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message);
+ }
+ scope = scope->parent();
+ if (scope == nullptr) return;
+ }
+ Report(loc, message);
+ }
+
+ void RecordPatternError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ // TODO(verwaest): Non-assigning expression?
+ if (IsCertainlyPattern()) {
+ Report(loc, message);
+ } else {
+ AsExpressionParsingScope()->RecordPatternError(loc, message);
+ }
+ }
+
+ void RecordStrictModeParameterError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ DCHECK_IMPLIES(!has_error(), loc.IsValid());
+ if (!CanBeParameterDeclaration()) return;
+ if (IsCertainlyParameterDeclaration()) {
+ if (is_strict(parser_->language_mode())) {
+ Report(loc, message);
+ } else {
+ parser_->parameters_->set_strict_parameter_error(loc, message);
+ }
+ } else {
+ parser_->next_arrow_function_info_.strict_parameter_error_location = loc;
+ parser_->next_arrow_function_info_.strict_parameter_error_message =
+ message;
+ }
+ }
+
+ void RecordDeclarationError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ if (!CanBeDeclaration()) return;
+ if (IsCertainlyDeclaration()) {
+ Report(loc, message);
+ } else {
+ AsArrowHeadParsingScope()->RecordDeclarationError(loc, message);
+ }
+ }
+
+ void RecordExpressionError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ if (!CanBeExpression()) return;
+ // TODO(verwaest): Non-assigning expression?
+ // if (IsCertainlyExpression()) Report(loc, message);
+ AsExpressionParsingScope()->RecordExpressionError(loc, message);
+ }
+
+ void RecordLexicalDeclarationError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ if (IsLexicalDeclaration()) Report(loc, message);
+ }
+
+ void RecordNonSimpleParameter() {
+ if (!IsArrowHeadParsingScope()) return;
+ AsArrowHeadParsingScope()->RecordNonSimpleParameter();
+ }
+
+ protected:
+ enum ScopeType : uint8_t {
+ // Expression or assignment target.
+ kExpression,
+
+ // Declaration or expression or assignment target.
+ kMaybeArrowParameterDeclaration,
+ kMaybeAsyncArrowParameterDeclaration,
+
+ // Declarations.
+ kParameterDeclaration,
+ kVarDeclaration,
+ kLexicalDeclaration,
+ };
+
+ ParserT* parser() const { return parser_; }
+ ExpressionScope* parent() const { return parent_; }
+
+ void Report(const Scanner::Location& loc, MessageTemplate message) const {
+ parser_->ReportMessageAt(loc, message);
+ }
+
+ ExpressionScope(ParserT* parser, ScopeType type)
+ : parser_(parser),
+ parent_(parser->expression_scope_),
+ type_(type),
+ has_possible_parameter_in_scope_chain_(
+ CanBeParameterDeclaration() ||
+ (parent_ && parent_->has_possible_parameter_in_scope_chain_)) {
+ parser->expression_scope_ = this;
+ }
+
+ ~ExpressionScope() {
+ DCHECK(parser_->expression_scope_ == this ||
+ parser_->expression_scope_ == parent_);
+ parser_->expression_scope_ = parent_;
+ }
+
+ ExpressionParsingScope<Types>* AsExpressionParsingScope() {
+ DCHECK(CanBeExpression());
+ return static_cast<ExpressionParsingScope<Types>*>(this);
+ }
+
+#ifdef DEBUG
+ bool has_error() const { return parser_->has_error(); }
+#endif
+
+ bool CanBeExpression() const {
+ return IsInRange(type_, kExpression, kMaybeAsyncArrowParameterDeclaration);
+ }
+ bool CanBeDeclaration() const {
+ return IsInRange(type_, kMaybeArrowParameterDeclaration,
+ kLexicalDeclaration);
+ }
+ bool IsCertainlyDeclaration() const {
+ return IsInRange(type_, kParameterDeclaration, kLexicalDeclaration);
+ }
+ bool IsVariableDeclaration() const {
+ return IsInRange(type_, kVarDeclaration, kLexicalDeclaration);
+ }
+ bool IsLexicalDeclaration() const { return type_ == kLexicalDeclaration; }
+ bool IsAsyncArrowHeadParsingScope() const {
+ return type_ == kMaybeAsyncArrowParameterDeclaration;
+ }
+
+ private:
+ friend class AccumulationScope<Types>;
+ friend class ExpressionParsingScope<Types>;
+
+ ArrowHeadParsingScope<Types>* AsArrowHeadParsingScope() {
+ DCHECK(IsArrowHeadParsingScope());
+ return static_cast<ArrowHeadParsingScope<Types>*>(this);
+ }
+
+ ParameterDeclarationParsingScope<Types>*
+ AsParameterDeclarationParsingScope() {
+ DCHECK(IsCertainlyParameterDeclaration());
+ return static_cast<ParameterDeclarationParsingScope<Types>*>(this);
+ }
+
+ VariableDeclarationParsingScope<Types>* AsVariableDeclarationParsingScope() {
+ DCHECK(IsVariableDeclaration());
+ return static_cast<VariableDeclarationParsingScope<Types>*>(this);
+ }
+
+ bool IsArrowHeadParsingScope() const {
+ return IsInRange(type_, kMaybeArrowParameterDeclaration,
+ kMaybeAsyncArrowParameterDeclaration);
+ }
+ bool IsCertainlyPattern() const { return IsCertainlyDeclaration(); }
+ bool CanBeParameterDeclaration() const {
+ return IsInRange(type_, kMaybeArrowParameterDeclaration,
+ kParameterDeclaration);
+ }
+ bool IsCertainlyParameterDeclaration() const {
+ return type_ == kParameterDeclaration;
+ }
+
+ ParserT* parser_;
+ ExpressionScope<Types>* parent_;
+ ScopeType type_;
+ bool has_possible_parameter_in_scope_chain_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExpressionScope);
+};
+
+// Used to unambiguously parse var, let, const declarations.
+template <typename Types>
+class VariableDeclarationParsingScope : public ExpressionScope<Types> {
+ public:
+ typedef typename Types::Impl ParserT;
+ typedef class ExpressionScope<Types> ExpressionScopeT;
+ typedef typename ExpressionScopeT::ScopeType ScopeType;
+
+ VariableDeclarationParsingScope(ParserT* parser, VariableMode mode,
+ ZonePtrList<const AstRawString>* names)
+ : ExpressionScopeT(parser, IsLexicalVariableMode(mode)
+ ? ExpressionScopeT::kLexicalDeclaration
+ : ExpressionScopeT::kVarDeclaration),
+ mode_(mode),
+ names_(names) {}
+
+ VariableProxy* Declare(VariableProxy* proxy) {
+ VariableKind kind = NORMAL_VARIABLE;
+ bool was_added;
+ this->parser()->DeclareVariable(
+ proxy, kind, mode_, Variable::DefaultInitializationFlag(mode_),
+ this->parser()->scope(), &was_added, proxy->position());
+ if (was_added &&
+ this->parser()->scope()->num_var() > kMaxNumFunctionLocals) {
+ this->parser()->ReportMessage(MessageTemplate::kTooManyVariables);
+ }
+ if (names_) names_->Add(proxy->raw_name(), this->parser()->zone());
+ if (this->IsLexicalDeclaration()) {
+ if (this->parser()->IsLet(proxy->raw_name())) {
+ this->parser()->ReportMessageAt(proxy->location(),
+ MessageTemplate::kLetInLexicalBinding);
+ }
+ } else {
+ if (this->parser()->loop_nesting_depth() > 0) {
+ // Due to hoisting, the value of a 'var'-declared variable may actually
+ // change even if the code contains only the "initial" assignment,
+ // namely when that assignment occurs inside a loop. For example:
+ //
+ // let i = 10;
+ // do { var x = i } while (i--):
+ //
+ // Note that non-lexical variables include temporaries, which may also
+ // get assigned inside a loop due to the various rewritings that the
+ // parser performs.
+ //
+ // Pessimistically mark all vars in loops as assigned. This
+ // overapproximates the actual assigned vars due to unassigned var
+ // without initializer, but that's unlikely anyway.
+ //
+ // This also handles marking of loop variables in for-in and for-of
+ // loops, as determined by loop-nesting-depth.
+ proxy->set_is_assigned();
+ }
+
+ // Make sure we'll properly resolve the variable since we might be in a
+ // with or catch scope. In those cases the assignment isn't guaranteed to
+ // write to the variable declared above.
+ if (!this->parser()->scope()->is_declaration_scope()) {
+ proxy =
+ this->parser()->NewUnresolved(proxy->raw_name(), proxy->position());
+ }
+ }
+ return proxy;
+ }
+
+ private:
+ // Limit the allowed number of local variables in a function. The hard limit
+ // in Ignition is 2^31-1 due to the size of register operands. We limit it to
+ // a more reasonable lower up-limit.
+ static const int kMaxNumFunctionLocals = (1 << 23) - 1;
+
+ VariableMode mode_;
+ ZonePtrList<const AstRawString>* names_;
+
+ DISALLOW_COPY_AND_ASSIGN(VariableDeclarationParsingScope);
+};
+
+template <typename Types>
+class ParameterDeclarationParsingScope : public ExpressionScope<Types> {
+ public:
+ typedef typename Types::Impl ParserT;
+ typedef class ExpressionScope<Types> ExpressionScopeT;
+ typedef typename ExpressionScopeT::ScopeType ScopeType;
+
+ explicit ParameterDeclarationParsingScope(ParserT* parser)
+ : ExpressionScopeT(parser, ExpressionScopeT::kParameterDeclaration) {}
+
+ void Declare(VariableProxy* proxy) {
+ VariableKind kind = PARAMETER_VARIABLE;
+ VariableMode mode = VariableMode::kVar;
+ bool was_added;
+ this->parser()->DeclareVariable(
+ proxy, kind, mode, Variable::DefaultInitializationFlag(mode),
+ this->parser()->scope(), &was_added, proxy->position());
+ if (!has_duplicate() && !was_added) {
+ duplicate_loc_ = proxy->location();
+ }
+ }
+
+ bool has_duplicate() const { return duplicate_loc_.IsValid(); }
+
+ const Scanner::Location& duplicate_location() const { return duplicate_loc_; }
+
+ private:
+ Scanner::Location duplicate_loc_ = Scanner::Location::invalid();
+ DISALLOW_COPY_AND_ASSIGN(ParameterDeclarationParsingScope);
+};
+
+// Parsing expressions is always ambiguous between at least left-hand-side and
+// right-hand-side of assignments. This class is used to keep track of errors
+// relevant for either side until it is clear what was being parsed.
+// The class also keeps track of all variable proxies that are created while the
+// scope was active. If the scope is an expression, the variable proxies will be
+// added to the unresolved list. Otherwise they are declarations and aren't
+// added. The list is also used to mark the variables as assigned in case we are
+// parsing an assignment expression.
+template <typename Types>
+class ExpressionParsingScope : public ExpressionScope<Types> {
+ public:
+ typedef typename Types::Impl ParserT;
+ typedef typename Types::Expression ExpressionT;
+ typedef class ExpressionScope<Types> ExpressionScopeT;
+ typedef typename ExpressionScopeT::ScopeType ScopeType;
+
+ ExpressionParsingScope(ParserT* parser,
+ ScopeType type = ExpressionScopeT::kExpression)
+ : ExpressionScopeT(parser, type),
+ variable_list_(parser->variable_buffer()),
+ has_async_arrow_in_scope_chain_(
+ type == ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration ||
+ (this->parent() && this->parent()->CanBeExpression() &&
+ this->parent()
+ ->AsExpressionParsingScope()
+ ->has_async_arrow_in_scope_chain_)) {
+ DCHECK(this->CanBeExpression());
+ clear(kExpressionIndex);
+ clear(kPatternIndex);
+ }
+
+ void RecordAsyncArrowParametersError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ for (ExpressionScopeT* scope = this; scope != nullptr;
+ scope = scope->parent()) {
+ if (!has_async_arrow_in_scope_chain_) break;
+ if (scope->type_ ==
+ ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration) {
+ scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message);
+ }
+ }
+ }
+
+ ~ExpressionParsingScope() { DCHECK(this->has_error() || verified_); }
+
+ ExpressionT ValidateAndRewriteReference(ExpressionT expression, int beg_pos,
+ int end_pos) {
+ if (V8_LIKELY(this->parser()->IsAssignableIdentifier(expression))) {
+ MarkIdentifierAsAssigned();
+ this->mark_verified();
+ return expression;
+ } else if (V8_LIKELY(expression->IsProperty())) {
+ ValidateExpression();
+ return expression;
+ }
+ this->mark_verified();
+ return this->parser()->RewriteInvalidReferenceExpression(
+ expression, beg_pos, end_pos, MessageTemplate::kInvalidLhsInFor,
+ kSyntaxError);
+ }
+
+ void RecordExpressionError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ Record(kExpressionIndex, loc, message);
+ }
+
+ void RecordPatternError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ Record(kPatternIndex, loc, message);
+ }
+
+ void ValidateExpression() { Validate(kExpressionIndex); }
+
+ void ValidatePattern(ExpressionT expression, int begin, int end) {
+ Validate(kPatternIndex);
+ if (expression->is_parenthesized()) {
+ ExpressionScopeT::Report(Scanner::Location(begin, end),
+ MessageTemplate::kInvalidDestructuringTarget);
+ }
+ for (int i = 0; i < variable_list_.length(); i++) {
+ variable_list_.at(i)->set_is_assigned();
+ }
+ }
+
+ void ClearExpressionError() {
+ DCHECK(verified_);
+#ifdef DEBUG
+ verified_ = false;
+#endif
+ clear(kExpressionIndex);
+ }
+
+ void TrackVariable(VariableProxy* variable) {
+ if (!this->CanBeDeclaration()) {
+ this->parser()->scope()->AddUnresolved(variable);
+ }
+ variable_list_.Add(variable);
+ }
+
+ void MarkIdentifierAsAssigned() {
+ // It's possible we're parsing a syntax error. In that case it's not
+ // guaranteed that there's a variable in the list.
+ if (variable_list_.length() == 0) return;
+ variable_list_.at(variable_list_.length() - 1)->set_is_assigned();
+ }
+
+ protected:
+ bool is_verified() const {
+#ifdef DEBUG
+ return verified_;
+#else
+ return false;
+#endif
+ }
+
+ void ValidatePattern() { Validate(kPatternIndex); }
+
+ ScopedPtrList<VariableProxy>* variable_list() { return &variable_list_; }
+
+ private:
+ friend class AccumulationScope<Types>;
+
+ enum ErrorNumber : uint8_t {
+ kExpressionIndex = 0,
+ kPatternIndex = 1,
+ kNumberOfErrors = 2,
+ };
+ void clear(int index) {
+ messages_[index] = MessageTemplate::kNone;
+ locations_[index] = Scanner::Location::invalid();
+ }
+ bool is_valid(int index) const { return !locations_[index].IsValid(); }
+ void Record(int index, const Scanner::Location& loc,
+ MessageTemplate message) {
+ DCHECK_IMPLIES(!this->has_error(), loc.IsValid());
+ if (!is_valid(index)) return;
+ messages_[index] = message;
+ locations_[index] = loc;
+ }
+ void Validate(int index) {
+ DCHECK(!this->is_verified());
+ if (!is_valid(index)) Report(index);
+ this->mark_verified();
+ }
+ void Report(int index) const {
+ ExpressionScopeT::Report(locations_[index], messages_[index]);
+ }
+
+ // Debug verification to make sure every scope is validated exactly once.
+ void mark_verified() {
+#ifdef DEBUG
+ verified_ = true;
+#endif
+ }
+ void clear_verified() {
+#ifdef DEBUG
+ verified_ = false;
+#endif
+ }
+#ifdef DEBUG
+ bool verified_ = false;
+#endif
+
+ ScopedPtrList<VariableProxy> variable_list_;
+ MessageTemplate messages_[kNumberOfErrors];
+ Scanner::Location locations_[kNumberOfErrors];
+ bool has_async_arrow_in_scope_chain_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExpressionParsingScope);
+};
+
+// This class is used to parse multiple ambiguous expressions and declarations
+// in the same scope. E.g., in async(X,Y,Z) or [X,Y,Z], X and Y and Z will all
+// be parsed in the respective outer ArrowHeadParsingScope and
+// ExpressionParsingScope. It provides a clean error state in the underlying
+// scope to parse the individual expressions, while keeping track of the
+// expression and pattern errors since the start. The AccumulationScope is only
+// used to keep track of the errors so far, and the underlying ExpressionScope
+// keeps being used as the expression_scope(). If the expression_scope() isn't
+// ambiguous, this class does not do anything.
+template <typename Types>
+class AccumulationScope {
+ public:
+ typedef typename Types::Impl ParserT;
+
+ static const int kNumberOfErrors =
+ ExpressionParsingScope<Types>::kNumberOfErrors;
+ explicit AccumulationScope(ExpressionScope<Types>* scope) : scope_(nullptr) {
+ if (!scope->CanBeExpression()) return;
+ scope_ = scope->AsExpressionParsingScope();
+ for (int i = 0; i < kNumberOfErrors; i++) {
+ // If the underlying scope is already invalid at the start, stop
+ // accumulating. That means an error was found outside of an
+ // accumulating path.
+ if (!scope_->is_valid(i)) {
+ scope_ = nullptr;
+ break;
+ }
+ copy(i);
+ }
+ }
+
+ // Merge errors from the underlying ExpressionParsingScope into this scope.
+ // Only keeps the first error across all accumulate calls, and removes the
+ // error from the underlying scope.
+ void Accumulate() {
+ if (scope_ == nullptr) return;
+ DCHECK(!scope_->is_verified());
+ for (int i = 0; i < kNumberOfErrors; i++) {
+ if (!locations_[i].IsValid()) copy(i);
+ scope_->clear(i);
+ }
+ }
+
+ // This is called instead of Accumulate in case the parsed member is already
+ // known to be an expression. In that case we don't need to accumulate the
+ // expression but rather validate it immediately. We also ignore the pattern
+ // error since the parsed member is known to not be a pattern. This is
+ // necessary for "{x:1}.y" parsed as part of an assignment pattern. {x:1} will
+ // record a pattern error, but "{x:1}.y" is actually a valid as part of an
+ // assignment pattern since it's a property access.
+ void ValidateExpression() {
+ if (scope_ == nullptr) return;
+ DCHECK(!scope_->is_verified());
+ scope_->ValidateExpression();
+ DCHECK(scope_->is_verified());
+ scope_->clear(ExpressionParsingScope<Types>::kPatternIndex);
+#ifdef DEBUG
+ scope_->clear_verified();
+#endif
+ }
+
+ ~AccumulationScope() {
+ if (scope_ == nullptr) return;
+ Accumulate();
+ for (int i = 0; i < kNumberOfErrors; i++) copy_back(i);
+ }
+
+ private:
+ void copy(int entry) {
+ messages_[entry] = scope_->messages_[entry];
+ locations_[entry] = scope_->locations_[entry];
+ }
+
+ void copy_back(int entry) {
+ if (!locations_[entry].IsValid()) return;
+ scope_->messages_[entry] = messages_[entry];
+ scope_->locations_[entry] = locations_[entry];
+ }
+
+ ExpressionParsingScope<Types>* scope_;
+ MessageTemplate messages_[2];
+ Scanner::Location locations_[2];
+
+ DISALLOW_COPY_AND_ASSIGN(AccumulationScope);
+};
+
+// The head of an arrow function is ambiguous between expression, assignment
+// pattern and declaration. This keeps track of the additional declaration
+// error and allows the scope to be validated as a declaration rather than an
+// expression or a pattern.
+template <typename Types>
+class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
+ public:
+ typedef typename Types::Impl ParserT;
+ typedef typename ExpressionScope<Types>::ScopeType ScopeType;
+
+ ArrowHeadParsingScope(ParserT* parser, FunctionKind kind)
+ : ExpressionParsingScope<Types>(
+ parser,
+ kind == FunctionKind::kArrowFunction
+ ? ExpressionScope<Types>::kMaybeArrowParameterDeclaration
+ : ExpressionScope<
+ Types>::kMaybeAsyncArrowParameterDeclaration) {
+ DCHECK(kind == FunctionKind::kAsyncArrowFunction ||
+ kind == FunctionKind::kArrowFunction);
+ DCHECK(this->CanBeDeclaration());
+ DCHECK(!this->IsCertainlyDeclaration());
+ }
+
+ void ValidateExpression() {
+ // Turns out this is not an arrow head. Clear any possible tracked strict
+ // parameter errors, and reinterpret tracked variables as unresolved
+ // references.
+ this->parser()->next_arrow_function_info_.ClearStrictParameterError();
+ ExpressionParsingScope<Types>::ValidateExpression();
+ for (int i = 0; i < this->variable_list()->length(); i++) {
+ this->parser()->scope()->AddUnresolved(this->variable_list()->at(i));
+ }
+ }
+
+ DeclarationScope* ValidateAndCreateScope() {
+ DCHECK(!this->is_verified());
+ if (declaration_error_location.IsValid()) {
+ ExpressionScope<Types>::Report(declaration_error_location,
+ declaration_error_message);
+ }
+ this->ValidatePattern();
+
+ DeclarationScope* result = this->parser()->NewFunctionScope(kind());
+ if (!has_simple_parameter_list_) result->SetHasNonSimpleParameters();
+ VariableKind kind = PARAMETER_VARIABLE;
+ VariableMode mode =
+ has_simple_parameter_list_ ? VariableMode::kVar : VariableMode::kLet;
+ for (int i = 0; i < this->variable_list()->length(); i++) {
+ VariableProxy* proxy = this->variable_list()->at(i);
+ bool was_added;
+ this->parser()->DeclareVariable(proxy, kind, mode,
+ Variable::DefaultInitializationFlag(mode),
+ result, &was_added, proxy->position());
+ if (!was_added) {
+ ExpressionScope<Types>::Report(proxy->location(),
+ MessageTemplate::kParamDupe);
+ }
+ }
+ return result;
+ }
+
+ void RecordDeclarationError(const Scanner::Location& loc,
+ MessageTemplate message) {
+ DCHECK_IMPLIES(!this->has_error(), loc.IsValid());
+ declaration_error_location = loc;
+ declaration_error_message = message;
+ }
+
+ void RecordNonSimpleParameter() { has_simple_parameter_list_ = false; }
+
+ private:
+ FunctionKind kind() const {
+ return this->IsAsyncArrowHeadParsingScope()
+ ? FunctionKind::kAsyncArrowFunction
+ : FunctionKind::kArrowFunction;
+ }
+
+ Scanner::Location declaration_error_location = Scanner::Location::invalid();
+ MessageTemplate declaration_error_message = MessageTemplate::kNone;
+ bool has_simple_parameter_list_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(ArrowHeadParsingScope);
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_PARSING_EXPRESSION_SCOPE_H_
diff --git a/deps/v8/src/parsing/func-name-inferrer.cc b/deps/v8/src/parsing/func-name-inferrer.cc
index 7d476f1e64..c21fb35ae9 100644
--- a/deps/v8/src/parsing/func-name-inferrer.cc
+++ b/deps/v8/src/parsing/func-name-inferrer.cc
@@ -11,13 +11,8 @@
namespace v8 {
namespace internal {
-FuncNameInferrer::FuncNameInferrer(AstValueFactory* ast_value_factory,
- Zone* zone)
- : ast_value_factory_(ast_value_factory),
- entries_stack_(zone),
- names_stack_(zone),
- funcs_to_infer_(zone),
- zone_(zone) {}
+FuncNameInferrer::FuncNameInferrer(AstValueFactory* ast_value_factory)
+ : ast_value_factory_(ast_value_factory) {}
void FuncNameInferrer::PushEnclosingName(const AstRawString* name) {
// Enclosing name is a name of a constructor function. To check
@@ -45,35 +40,31 @@ void FuncNameInferrer::PushVariableName(const AstRawString* name) {
void FuncNameInferrer::RemoveAsyncKeywordFromEnd() {
if (IsOpen()) {
CHECK_GT(names_stack_.size(), 0);
- CHECK(names_stack_.back().name->IsOneByteEqualTo("async"));
+ CHECK(names_stack_.back().name()->IsOneByteEqualTo("async"));
names_stack_.pop_back();
}
}
-void FuncNameInferrer::Leave() {
- DCHECK(IsOpen());
- size_t last_entry = entries_stack_.back();
- entries_stack_.pop_back();
- names_stack_.Rewind(last_entry);
- if (entries_stack_.is_empty()) funcs_to_infer_.Rewind();
-}
-
const AstConsString* FuncNameInferrer::MakeNameFromStack() {
+ if (names_stack_.size() == 0) {
+ return ast_value_factory_->empty_cons_string();
+ }
AstConsString* result = ast_value_factory_->NewConsString();
auto it = names_stack_.begin();
while (it != names_stack_.end()) {
// Advance the iterator to be able to peek the next value.
auto current = it++;
// Skip consecutive variable declarations.
- if (it != names_stack_.end() && current->type == kVariableName &&
- it->type == kVariableName) {
+ if (it != names_stack_.end() && current->type() == kVariableName &&
+ it->type() == kVariableName) {
continue;
}
// Add name. Separate names with ".".
+ Zone* zone = ast_value_factory_->zone();
if (!result->IsEmpty()) {
- result->AddString(zone(), ast_value_factory_->dot_string());
+ result->AddString(zone, ast_value_factory_->dot_string());
}
- result->AddString(zone(), current->name);
+ result->AddString(zone, current->name());
}
return result;
}
@@ -83,7 +74,7 @@ void FuncNameInferrer::InferFunctionsNames() {
for (FunctionLiteral* func : funcs_to_infer_) {
func->set_raw_inferred_name(func_name);
}
- funcs_to_infer_.Rewind(0);
+ funcs_to_infer_.resize(0);
}
diff --git a/deps/v8/src/parsing/func-name-inferrer.h b/deps/v8/src/parsing/func-name-inferrer.h
index d46d7f2c2b..bdc58221e1 100644
--- a/deps/v8/src/parsing/func-name-inferrer.h
+++ b/deps/v8/src/parsing/func-name-inferrer.h
@@ -5,8 +5,10 @@
#ifndef V8_PARSING_FUNC_NAME_INFERRER_H_
#define V8_PARSING_FUNC_NAME_INFERRER_H_
-#include "src/zone/zone-chunk-list.h"
-#include "src/zone/zone.h"
+#include <vector>
+
+#include "src/base/macros.h"
+#include "src/pointer-with-payload.h"
namespace v8 {
namespace internal {
@@ -18,6 +20,11 @@ class FunctionLiteral;
enum class InferName { kYes, kNo };
+template <>
+struct PointerWithPayloadTraits<AstRawString> {
+ static constexpr int value = 2;
+};
+
// 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
@@ -28,25 +35,33 @@ enum class InferName { kYes, kNo };
// 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 {
+class FuncNameInferrer {
public:
- FuncNameInferrer(AstValueFactory* ast_value_factory, Zone* zone);
+ explicit FuncNameInferrer(AstValueFactory* ast_value_factory);
// To enter function name inference state, put a FuncNameInferrer::State
// on the stack.
class State {
public:
- explicit State(FuncNameInferrer* fni) : fni_(fni) { fni_->Enter(); }
- ~State() { fni_->Leave(); }
+ explicit State(FuncNameInferrer* fni)
+ : fni_(fni), top_(fni->names_stack_.size()) {
+ ++fni_->scope_depth_;
+ }
+ ~State() {
+ DCHECK(fni_->IsOpen());
+ fni_->names_stack_.resize(top_);
+ --fni_->scope_depth_;
+ }
private:
FuncNameInferrer* fni_;
+ size_t top_;
DISALLOW_COPY_AND_ASSIGN(State);
};
// Returns whether we have entered name collection state.
- bool IsOpen() const { return !entries_stack_.is_empty(); }
+ bool IsOpen() const { return scope_depth_ > 0; }
// Pushes an enclosing the name of enclosing function onto names stack.
void PushEnclosingName(const AstRawString* name);
@@ -64,9 +79,7 @@ class FuncNameInferrer : public ZoneObject {
}
void RemoveLastFunction() {
- if (IsOpen() && !funcs_to_infer_.is_empty()) {
- funcs_to_infer_.pop_back();
- }
+ if (IsOpen() && !funcs_to_infer_.empty()) funcs_to_infer_.pop_back();
}
void RemoveAsyncKeywordFromEnd();
@@ -74,29 +87,28 @@ class FuncNameInferrer : public ZoneObject {
// Infers a function name and leaves names collection state.
void Infer() {
DCHECK(IsOpen());
- if (!funcs_to_infer_.is_empty()) {
- InferFunctionsNames();
- }
+ if (!funcs_to_infer_.empty()) InferFunctionsNames();
}
private:
- enum NameType {
+ enum NameType : uint8_t {
kEnclosingConstructorName,
kLiteralName,
kVariableName
};
struct Name {
- Name(const AstRawString* name, NameType type) : name(name), type(type) {}
- const AstRawString* name;
- NameType type;
+ // Needed for names_stack_.resize()
+ Name() { UNREACHABLE(); }
+ Name(const AstRawString* name, NameType type)
+ : name_and_type_(name, type) {}
+
+ PointerWithPayload<const AstRawString, NameType, 2> name_and_type_;
+ inline const AstRawString* name() const {
+ return name_and_type_.GetPointer();
+ }
+ inline NameType type() const { return name_and_type_.GetPayload(); }
};
- void Enter() { entries_stack_.push_back(names_stack_.size()); }
-
- void Leave();
-
- Zone* zone() const { return zone_; }
-
// Constructs a full name in dotted notation from gathered names.
const AstConsString* MakeNameFromStack();
@@ -104,10 +116,9 @@ class FuncNameInferrer : public ZoneObject {
void InferFunctionsNames();
AstValueFactory* ast_value_factory_;
- ZoneChunkList<size_t> entries_stack_;
- ZoneChunkList<Name> names_stack_;
- ZoneChunkList<FunctionLiteral*> funcs_to_infer_;
- Zone* zone_;
+ std::vector<Name> names_stack_;
+ std::vector<FunctionLiteral*> funcs_to_infer_;
+ size_t scope_depth_ = 0;
DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
};
diff --git a/deps/v8/src/parsing/keywords-gen.h b/deps/v8/src/parsing/keywords-gen.h
new file mode 100644
index 0000000000..67c47a2dda
--- /dev/null
+++ b/deps/v8/src/parsing/keywords-gen.h
@@ -0,0 +1,177 @@
+// Copyright 2018 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.
+
+// This file is automatically generated by gen-keywords-gen-h.py and should not
+// be modified manually.
+
+#ifndef V8_PARSING_KEYWORDS_GEN_H_
+#define V8_PARSING_KEYWORDS_GEN_H_
+
+#include "src/parsing/token.h"
+
+namespace v8 {
+namespace internal {
+
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -m100 src/parsing/keywords.txt */
+/* Computed positions: -k'1-2' */
+
+#if !( \
+ (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) && ('%' == 37) && \
+ ('&' == 38) && ('\'' == 39) && ('(' == 40) && (')' == 41) && \
+ ('*' == 42) && ('+' == 43) && (',' == 44) && ('-' == 45) && ('.' == 46) && \
+ ('/' == 47) && ('0' == 48) && ('1' == 49) && ('2' == 50) && ('3' == 51) && \
+ ('4' == 52) && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) && \
+ ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) && ('=' == 61) && \
+ ('>' == 62) && ('?' == 63) && ('A' == 65) && ('B' == 66) && ('C' == 67) && \
+ ('D' == 68) && ('E' == 69) && ('F' == 70) && ('G' == 71) && ('H' == 72) && \
+ ('I' == 73) && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) && \
+ ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) && ('R' == 82) && \
+ ('S' == 83) && ('T' == 84) && ('U' == 85) && ('V' == 86) && ('W' == 87) && \
+ ('X' == 88) && ('Y' == 89) && ('Z' == 90) && ('[' == 91) && \
+ ('\\' == 92) && (']' == 93) && ('^' == 94) && ('_' == 95) && \
+ ('a' == 97) && ('b' == 98) && ('c' == 99) && ('d' == 100) && \
+ ('e' == 101) && ('f' == 102) && ('g' == 103) && ('h' == 104) && \
+ ('i' == 105) && ('j' == 106) && ('k' == 107) && ('l' == 108) && \
+ ('m' == 109) && ('n' == 110) && ('o' == 111) && ('p' == 112) && \
+ ('q' == 113) && ('r' == 114) && ('s' == 115) && ('t' == 116) && \
+ ('u' == 117) && ('v' == 118) && ('w' == 119) && ('x' == 120) && \
+ ('y' == 121) && ('z' == 122) && ('{' == 123) && ('|' == 124) && \
+ ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set."
+// If you see this error, please report a bug to <bug-gperf@gnu.org>.
+#endif
+
+struct PerfectKeywordHashTableEntry {
+ const char* name;
+ Token::Value value;
+};
+enum {
+ TOTAL_KEYWORDS = 47,
+ MIN_WORD_LENGTH = 2,
+ MAX_WORD_LENGTH = 10,
+ MIN_HASH_VALUE = 2,
+ MAX_HASH_VALUE = 51
+};
+
+/* maximum key range = 50, duplicates = 0 */
+
+class PerfectKeywordHash {
+ private:
+ static inline unsigned int Hash(const char* str, int len);
+
+ public:
+ static inline Token::Value GetToken(const char* str, int len);
+};
+
+inline unsigned int PerfectKeywordHash::Hash(const char* str, int len) {
+ DCHECK_LT(str[1], 128);
+ DCHECK_LT(str[0], 128);
+ static const unsigned char asso_values[128] = {
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 8, 2, 6, 0, 0, 9, 52, 21, 0, 52, 52, 36, 40, 0, 3,
+ 6, 52, 17, 13, 16, 16, 38, 25, 6, 26, 52, 52, 52, 52, 52, 52};
+ return len + asso_values[static_cast<unsigned char>(str[1])] +
+ asso_values[static_cast<unsigned char>(str[0])];
+}
+
+static const unsigned char kPerfectKeywordLengthTable[64] = {
+ 0, 0, 2, 3, 4, 2, 6, 7, 8, 9, 10, 2, 6, 7, 5, 3, 7, 8, 4, 5, 4, 7,
+ 5, 6, 5, 0, 5, 0, 6, 4, 7, 5, 9, 8, 5, 6, 3, 4, 5, 3, 4, 4, 5, 0,
+ 6, 4, 6, 5, 6, 3, 10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static const struct PerfectKeywordHashTableEntry kPerfectKeywordHashTable[64] =
+ {{"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"in", Token::IN},
+ {"new", Token::NEW},
+ {"enum", Token::ENUM},
+ {"do", Token::DO},
+ {"delete", Token::DELETE},
+ {"default", Token::DEFAULT},
+ {"debugger", Token::DEBUGGER},
+ {"interface", Token::FUTURE_STRICT_RESERVED_WORD},
+ {"instanceof", Token::INSTANCEOF},
+ {"if", Token::IF},
+ {"export", Token::EXPORT},
+ {"extends", Token::EXTENDS},
+ {"const", Token::CONST},
+ {"for", Token::FOR},
+ {"finally", Token::FINALLY},
+ {"continue", Token::CONTINUE},
+ {"case", Token::CASE},
+ {"catch", Token::CATCH},
+ {"null", Token::NULL_LITERAL},
+ {"package", Token::FUTURE_STRICT_RESERVED_WORD},
+ {"false", Token::FALSE_LITERAL},
+ {"return", Token::RETURN},
+ {"break", Token::BREAK},
+ {"", Token::IDENTIFIER},
+ {"async", Token::ASYNC},
+ {"", Token::IDENTIFIER},
+ {"public", Token::FUTURE_STRICT_RESERVED_WORD},
+ {"with", Token::WITH},
+ {"private", Token::FUTURE_STRICT_RESERVED_WORD},
+ {"yield", Token::YIELD},
+ {"protected", Token::FUTURE_STRICT_RESERVED_WORD},
+ {"function", Token::FUNCTION},
+ {"super", Token::SUPER},
+ {"static", Token::STATIC},
+ {"try", Token::TRY},
+ {"true", Token::TRUE_LITERAL},
+ {"await", Token::AWAIT},
+ {"let", Token::LET},
+ {"else", Token::ELSE},
+ {"this", Token::THIS},
+ {"throw", Token::THROW},
+ {"", Token::IDENTIFIER},
+ {"switch", Token::SWITCH},
+ {"void", Token::VOID},
+ {"import", Token::IMPORT},
+ {"class", Token::CLASS},
+ {"typeof", Token::TYPEOF},
+ {"var", Token::VAR},
+ {"implements", Token::FUTURE_STRICT_RESERVED_WORD},
+ {"while", Token::WHILE},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER},
+ {"", Token::IDENTIFIER}};
+
+inline Token::Value PerfectKeywordHash::GetToken(const char* str, int len) {
+ if (IsInRange(len, MIN_WORD_LENGTH, MAX_WORD_LENGTH)) {
+ unsigned int key = Hash(str, len) & 0x3f;
+
+ DCHECK_LT(key, arraysize(kPerfectKeywordLengthTable));
+ DCHECK_LT(key, arraysize(kPerfectKeywordHashTable));
+ if (len == kPerfectKeywordLengthTable[key]) {
+ const char* s = kPerfectKeywordHashTable[key].name;
+
+ while (*s != 0) {
+ if (*s++ != *str++) return Token::IDENTIFIER;
+ }
+ return kPerfectKeywordHashTable[key].value;
+ }
+ }
+ return Token::IDENTIFIER;
+}
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_PARSING_KEYWORDS_GEN_H_
diff --git a/deps/v8/src/parsing/keywords.txt b/deps/v8/src/parsing/keywords.txt
new file mode 100644
index 0000000000..a3b3e4614d
--- /dev/null
+++ b/deps/v8/src/parsing/keywords.txt
@@ -0,0 +1,64 @@
+%struct-type
+%language=C++
+%global-table
+%define initializer-suffix ,Token::IDENTIFIER
+%define hash-function-name Hash
+%define lookup-function-name GetToken
+%define class-name PerfectKeywordHash
+%define word-array-name kPerfectKeywordHashTable
+%define length-table-name kPerfectKeywordLengthTable
+%7bit
+%compare-lengths
+%enum
+%readonly-tables
+%compare-strncmp
+
+struct PerfectKeywordHashTableEntry { const char* name; Token::Value value; };
+%%
+async, Token::ASYNC
+await, Token::AWAIT
+break, Token::BREAK
+case, Token::CASE
+catch, Token::CATCH
+class, Token::CLASS
+const, Token::CONST
+continue, Token::CONTINUE
+debugger, Token::DEBUGGER
+default, Token::DEFAULT
+delete, Token::DELETE
+do, Token::DO
+else, Token::ELSE
+enum, Token::ENUM
+export, Token::EXPORT
+extends, Token::EXTENDS
+false, Token::FALSE_LITERAL
+finally, Token::FINALLY
+for, Token::FOR
+function, Token::FUNCTION
+if, Token::IF
+implements, Token::FUTURE_STRICT_RESERVED_WORD
+import, Token::IMPORT
+in, Token::IN
+instanceof, Token::INSTANCEOF
+interface, Token::FUTURE_STRICT_RESERVED_WORD
+let, Token::LET
+new, Token::NEW
+null, Token::NULL_LITERAL
+package, Token::FUTURE_STRICT_RESERVED_WORD
+private, Token::FUTURE_STRICT_RESERVED_WORD
+protected, Token::FUTURE_STRICT_RESERVED_WORD
+public, Token::FUTURE_STRICT_RESERVED_WORD
+return, Token::RETURN
+static, Token::STATIC
+super, Token::SUPER
+switch, Token::SWITCH
+this, Token::THIS
+throw, Token::THROW
+true, Token::TRUE_LITERAL
+try, Token::TRY
+typeof, Token::TYPEOF
+var, Token::VAR
+void, Token::VOID
+while, Token::WHILE
+with, Token::WITH
+yield, Token::YIELD
diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc
index 129b00a2c2..3050e01b48 100644
--- a/deps/v8/src/parsing/parse-info.cc
+++ b/deps/v8/src/parsing/parse-info.cc
@@ -8,7 +8,10 @@
#include "src/ast/ast-value-factory.h"
#include "src/ast/ast.h"
#include "src/base/template-utils.h"
+#include "src/compiler-dispatcher/compiler-dispatcher.h"
+#include "src/counters.h"
#include "src/heap/heap-inl.h"
+#include "src/log.h"
#include "src/objects-inl.h"
#include "src/objects/scope-info.h"
#include "src/zone/zone.h"
@@ -21,7 +24,6 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
flags_(0),
extension_(nullptr),
script_scope_(nullptr),
- unicode_cache_(nullptr),
stack_limit_(0),
hash_seed_(0),
function_kind_(FunctionKind::kNormalFunction),
@@ -43,12 +45,24 @@ ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator)
: ParseInfo(zone_allocator) {
set_hash_seed(isolate->heap()->HashSeed());
set_stack_limit(isolate->stack_guard()->real_climit());
- set_unicode_cache(isolate->unicode_cache());
set_runtime_call_stats(isolate->counters()->runtime_call_stats());
set_logger(isolate->logger());
set_ast_string_constants(isolate->ast_string_constants());
if (isolate->is_block_code_coverage()) set_block_coverage_enabled();
if (isolate->is_collecting_type_profile()) set_collect_type_profile();
+ if (isolate->compiler_dispatcher()->IsEnabled()) {
+ parallel_tasks_.reset(new ParallelTasks(isolate->compiler_dispatcher()));
+ }
+ set_might_always_opt(FLAG_always_opt || FLAG_prepare_always_opt);
+ set_allow_lazy_compile(FLAG_lazy);
+ set_allow_natives_syntax(FLAG_allow_natives_syntax);
+ set_allow_harmony_public_fields(FLAG_harmony_public_fields);
+ set_allow_harmony_static_fields(FLAG_harmony_static_fields);
+ set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import);
+ set_allow_harmony_import_meta(FLAG_harmony_import_meta);
+ set_allow_harmony_numeric_separator(FLAG_harmony_numeric_separator);
+ set_allow_harmony_private_fields(FLAG_harmony_private_fields);
+ set_allow_harmony_private_methods(FLAG_harmony_private_methods);
}
ParseInfo::ParseInfo(Isolate* isolate)
@@ -63,9 +77,10 @@ void ParseInfo::SetFunctionInfo(T function) {
set_language_mode(function->language_mode());
set_function_kind(function->kind());
set_declaration(function->is_declaration());
- set_requires_instance_fields_initializer(
- function->requires_instance_fields_initializer());
+ set_requires_instance_members_initializer(
+ function->requires_instance_members_initializer());
set_toplevel(function->is_toplevel());
+ set_is_oneshot_iife(function->is_oneshot_iife());
set_wrapped_as_function(function->is_wrapped());
}
@@ -76,7 +91,7 @@ ParseInfo::ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared)
// wrapped script at all.
DCHECK_IMPLIES(is_toplevel(), !Script::cast(shared->script())->is_wrapped());
- set_allow_lazy_parsing(FLAG_lazy_inner_functions);
+ set_allow_lazy_parsing(true);
set_asm_wasm_broken(shared->is_asm_wasm_broken());
set_start_position(shared->StartPosition());
@@ -225,5 +240,15 @@ void ParseInfo::set_script(Handle<Script> script) {
}
}
+void ParseInfo::ParallelTasks::Enqueue(ParseInfo* outer_parse_info,
+ const AstRawString* function_name,
+ FunctionLiteral* literal) {
+ base::Optional<CompilerDispatcher::JobId> job_id =
+ dispatcher_->Enqueue(outer_parse_info, function_name, literal);
+ if (job_id) {
+ enqueued_jobs_.emplace_front(std::make_pair(literal, *job_id));
+ }
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h
index ba3e3d2898..7ab236c82d 100644
--- a/deps/v8/src/parsing/parse-info.h
+++ b/deps/v8/src/parsing/parse-info.h
@@ -13,7 +13,7 @@
#include "src/globals.h"
#include "src/handles.h"
#include "src/objects/script.h"
-#include "src/parsing/preparsed-scope-data.h"
+#include "src/parsing/preparse-data.h"
#include "src/pending-compilation-error-handler.h"
namespace v8 {
@@ -26,12 +26,12 @@ class AccountingAllocator;
class AstRawString;
class AstStringConstants;
class AstValueFactory;
+class CompilerDispatcher;
class DeclarationScope;
class FunctionLiteral;
class RuntimeCallStats;
class Logger;
class SourceRangeMap;
-class UnicodeCache;
class Utf16CharacterStream;
class Zone;
@@ -81,6 +81,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
FLAG_ACCESSOR(kCollectTypeProfile, collect_type_profile,
set_collect_type_profile)
FLAG_ACCESSOR(kIsAsmWasmBroken, is_asm_wasm_broken, set_asm_wasm_broken)
+ FLAG_ACCESSOR(kContainsAsmModule, contains_asm_module,
+ set_contains_asm_module)
FLAG_ACCESSOR(kBlockCoverageEnabled, block_coverage_enabled,
set_block_coverage_enabled)
FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread,
@@ -89,9 +91,30 @@ class V8_EXPORT_PRIVATE ParseInfo {
set_wrapped_as_function)
FLAG_ACCESSOR(kAllowEvalCache, allow_eval_cache, set_allow_eval_cache)
FLAG_ACCESSOR(kIsDeclaration, is_declaration, set_declaration)
- FLAG_ACCESSOR(kRequiresInstanceFieldsInitializer,
- requires_instance_fields_initializer,
- set_requires_instance_fields_initializer);
+ FLAG_ACCESSOR(kRequiresInstanceMembersInitializer,
+ requires_instance_members_initializer,
+ set_requires_instance_members_initializer);
+ FLAG_ACCESSOR(kMightAlwaysOpt, might_always_opt, set_might_always_opt)
+ FLAG_ACCESSOR(kAllowNativeSyntax, allow_natives_syntax,
+ set_allow_natives_syntax)
+ FLAG_ACCESSOR(kAllowLazyCompile, allow_lazy_compile, set_allow_lazy_compile)
+ FLAG_ACCESSOR(kAllowNativeSyntax, allow_native_syntax,
+ set_allow_native_syntax);
+ FLAG_ACCESSOR(kAllowHarmonyPublicFields, allow_harmony_public_fields,
+ set_allow_harmony_public_fields);
+ FLAG_ACCESSOR(kAllowHarmonyStaticFields, allow_harmony_static_fields,
+ set_allow_harmony_static_fields);
+ FLAG_ACCESSOR(kAllowHarmonyDynamicImport, allow_harmony_dynamic_import,
+ set_allow_harmony_dynamic_import);
+ FLAG_ACCESSOR(kAllowHarmonyImportMeta, allow_harmony_import_meta,
+ set_allow_harmony_import_meta);
+ FLAG_ACCESSOR(kAllowHarmonyNumericSeparator, allow_harmony_numeric_separator,
+ set_allow_harmony_numeric_separator);
+ FLAG_ACCESSOR(kAllowHarmonyPrivateFields, allow_harmony_private_fields,
+ set_allow_harmony_private_fields);
+ FLAG_ACCESSOR(kAllowHarmonyPrivateMethods, allow_harmony_private_methods,
+ set_allow_harmony_private_methods);
+ FLAG_ACCESSOR(kIsOneshotIIFE, is_oneshot_iife, set_is_oneshot_iife);
#undef FLAG_ACCESSOR
void set_parse_restriction(ParseRestriction restriction) {
@@ -113,12 +136,11 @@ class V8_EXPORT_PRIVATE ParseInfo {
v8::Extension* extension() const { return extension_; }
void set_extension(v8::Extension* extension) { extension_ = extension; }
- void set_consumed_preparsed_scope_data(
- std::unique_ptr<ConsumedPreParsedScopeData> data) {
- consumed_preparsed_scope_data_.swap(data);
+ void set_consumed_preparse_data(std::unique_ptr<ConsumedPreparseData> data) {
+ consumed_preparse_data_.swap(data);
}
- ConsumedPreParsedScopeData* consumed_preparsed_scope_data() {
- return consumed_preparsed_scope_data_.get();
+ ConsumedPreparseData* consumed_preparse_data() {
+ return consumed_preparse_data_.get();
}
DeclarationScope* script_scope() const { return script_scope_; }
@@ -141,11 +163,6 @@ class V8_EXPORT_PRIVATE ParseInfo {
DeclarationScope* scope() const;
- UnicodeCache* unicode_cache() const { return unicode_cache_; }
- void set_unicode_cache(UnicodeCache* unicode_cache) {
- unicode_cache_ = unicode_cache;
- }
-
uintptr_t stack_limit() const { return stack_limit_; }
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
@@ -205,6 +222,31 @@ class V8_EXPORT_PRIVATE ParseInfo {
return &pending_error_handler_;
}
+ class ParallelTasks {
+ public:
+ explicit ParallelTasks(CompilerDispatcher* compiler_dispatcher)
+ : dispatcher_(compiler_dispatcher) {
+ DCHECK(dispatcher_);
+ }
+
+ void Enqueue(ParseInfo* outer_parse_info, const AstRawString* function_name,
+ FunctionLiteral* literal);
+
+ typedef std::forward_list<std::pair<FunctionLiteral*, uintptr_t>>::iterator
+ EnqueuedJobsIterator;
+
+ EnqueuedJobsIterator begin() { return enqueued_jobs_.begin(); }
+ EnqueuedJobsIterator end() { return enqueued_jobs_.end(); }
+
+ CompilerDispatcher* dispatcher() { return dispatcher_; }
+
+ private:
+ CompilerDispatcher* dispatcher_;
+ std::forward_list<std::pair<FunctionLiteral*, uintptr_t>> enqueued_jobs_;
+ };
+
+ ParallelTasks* parallel_tasks() { return parallel_tasks_.get(); }
+
//--------------------------------------------------------------------------
// TODO(titzer): these should not be part of ParseInfo.
//--------------------------------------------------------------------------
@@ -257,7 +299,19 @@ class V8_EXPORT_PRIVATE ParseInfo {
kWrappedAsFunction = 1 << 14, // Implicitly wrapped as function.
kAllowEvalCache = 1 << 15,
kIsDeclaration = 1 << 16,
- kRequiresInstanceFieldsInitializer = 1 << 17,
+ kRequiresInstanceMembersInitializer = 1 << 17,
+ kContainsAsmModule = 1 << 18,
+ kMightAlwaysOpt = 1 << 19,
+ kAllowLazyCompile = 1 << 20,
+ kAllowNativeSyntax = 1 << 21,
+ kAllowHarmonyPublicFields = 1 << 22,
+ kAllowHarmonyStaticFields = 1 << 23,
+ kAllowHarmonyDynamicImport = 1 << 24,
+ kAllowHarmonyImportMeta = 1 << 25,
+ kAllowHarmonyNumericSeparator = 1 << 26,
+ kAllowHarmonyPrivateFields = 1 << 27,
+ kAllowHarmonyPrivateMethods = 1 << 28,
+ kIsOneshotIIFE = 1 << 29
};
//------------- Inputs to parsing and scope analysis -----------------------
@@ -265,7 +319,6 @@ class V8_EXPORT_PRIVATE ParseInfo {
unsigned flags_;
v8::Extension* extension_;
DeclarationScope* script_scope_;
- UnicodeCache* unicode_cache_;
uintptr_t stack_limit_;
uint64_t hash_seed_;
FunctionKind function_kind_;
@@ -282,13 +335,14 @@ class V8_EXPORT_PRIVATE ParseInfo {
//----------- Inputs+Outputs of parsing and scope analysis -----------------
std::unique_ptr<Utf16CharacterStream> character_stream_;
- std::unique_ptr<ConsumedPreParsedScopeData> consumed_preparsed_scope_data_;
+ std::unique_ptr<ConsumedPreparseData> consumed_preparse_data_;
std::unique_ptr<AstValueFactory> ast_value_factory_;
const class AstStringConstants* ast_string_constants_;
const AstRawString* function_name_;
RuntimeCallStats* runtime_call_stats_;
Logger* logger_;
SourceRangeMap* source_range_map_; // Used when block coverage is enabled.
+ std::unique_ptr<ParallelTasks> parallel_tasks_;
//----------- Output of parsing and scope analysis ------------------------
FunctionLiteral* literal_;
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h
index bfb056e0c8..33c165cd92 100644
--- a/deps/v8/src/parsing/parser-base.h
+++ b/deps/v8/src/parsing/parser-base.h
@@ -18,11 +18,12 @@
#include "src/counters.h"
#include "src/globals.h"
#include "src/log.h"
-#include "src/messages.h"
-#include "src/parsing/expression-classifier.h"
+#include "src/message-template.h"
+#include "src/parsing/expression-scope.h"
#include "src/parsing/func-name-inferrer.h"
#include "src/parsing/scanner.h"
#include "src/parsing/token.h"
+#include "src/pointer-with-payload.h"
#include "src/zone/zone-chunk-list.h"
namespace v8 {
@@ -39,6 +40,8 @@ enum AllowLabelledFunctionStatement {
kDisallowLabelledFunctionStatement,
};
+enum ParsingArrowHeadFlag { kCertainlyNotArrowHead, kMaybeArrowHead };
+
enum class ParseFunctionFlag : uint8_t {
kIsNormal = 0,
kIsGenerator = 1 << 0,
@@ -74,77 +77,39 @@ struct FormalParametersBase {
// Stack-allocated scope to collect source ranges from the parser.
class SourceRangeScope final {
public:
- enum PositionKind {
- POSITION_BEG,
- POSITION_END,
- PEEK_POSITION_BEG,
- PEEK_POSITION_END,
- };
-
- SourceRangeScope(Scanner* scanner, SourceRange* range,
- PositionKind pre_kind = PEEK_POSITION_BEG,
- PositionKind post_kind = POSITION_END)
- : scanner_(scanner), range_(range), post_kind_(post_kind) {
- range_->start = GetPosition(pre_kind);
+ SourceRangeScope(const Scanner* scanner, SourceRange* range)
+ : scanner_(scanner), range_(range) {
+ range_->start = scanner->peek_location().beg_pos;
DCHECK_NE(range_->start, kNoSourcePosition);
+ DCHECK_EQ(range_->end, kNoSourcePosition);
}
- ~SourceRangeScope() { Finalize(); }
-
- const SourceRange& Finalize() {
- if (is_finalized_) return *range_;
- is_finalized_ = true;
- range_->end = GetPosition(post_kind_);
+ ~SourceRangeScope() {
+ DCHECK_EQ(kNoSourcePosition, range_->end);
+ range_->end = scanner_->location().end_pos;
DCHECK_NE(range_->end, kNoSourcePosition);
- return *range_;
}
private:
- int32_t GetPosition(PositionKind kind) {
- switch (kind) {
- case POSITION_BEG:
- return scanner_->location().beg_pos;
- case POSITION_END:
- return scanner_->location().end_pos;
- case PEEK_POSITION_BEG:
- return scanner_->peek_location().beg_pos;
- case PEEK_POSITION_END:
- return scanner_->peek_location().end_pos;
- default:
- UNREACHABLE();
- }
- }
-
- Scanner* scanner_;
+ const Scanner* scanner_;
SourceRange* range_;
- PositionKind post_kind_;
- bool is_finalized_ = false;
DISALLOW_IMPLICIT_CONSTRUCTORS(SourceRangeScope);
};
// ----------------------------------------------------------------------------
-// The CHECK_OK macro is a convenient macro to enforce error
-// handling for functions that may fail (by returning !*ok).
+// The RETURN_IF_PARSE_ERROR macro is a convenient macro to enforce error
+// handling for functions that may fail (by returning if there was an parser
+// error).
//
-// 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_CUSTOM(x, ...) ok); \
- if (!*ok) return impl()->x(__VA_ARGS__); \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
-
-// Used in functions where the return type is ExpressionT.
-#define CHECK_OK CHECK_OK_CUSTOM(NullExpression)
+// Usage:
+// foo = ParseFoo(); // may fail
+// RETURN_IF_PARSE_ERROR
+//
+// SAFE_USE(foo);
-#define CHECK_OK_VOID ok); \
- if (!*ok) return; \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
+#define RETURN_IF_PARSE_ERROR \
+ if (has_error()) return impl()->NullStatement();
// Common base class template shared between parser and pre-parser.
// The Impl parameter is the actual class of the parser/pre-parser,
@@ -217,8 +182,10 @@ enum class ParsePropertyKind : uint8_t {
kAccessorSetter,
kValue,
kShorthand,
+ kAssign,
kMethod,
kClassField,
+ kShorthandOrClassField,
kSpread,
kNotSet
};
@@ -228,25 +195,43 @@ class ParserBase {
public:
// Shorten type names defined by ParserTypes<Impl>.
typedef ParserTypes<Impl> Types;
- typedef typename Types::Identifier IdentifierT;
- typedef typename Types::Expression ExpressionT;
- typedef typename Types::FunctionLiteral FunctionLiteralT;
- typedef typename Types::ObjectLiteralProperty ObjectLiteralPropertyT;
+ typedef typename v8::internal::ExpressionScope<Types> ExpressionScope;
+ typedef typename v8::internal::ExpressionParsingScope<Types>
+ ExpressionParsingScope;
+ typedef typename v8::internal::AccumulationScope<Types> AccumulationScope;
+ typedef typename v8::internal::ArrowHeadParsingScope<Types>
+ ArrowHeadParsingScope;
+ typedef typename v8::internal::VariableDeclarationParsingScope<Types>
+ VariableDeclarationParsingScope;
+ typedef typename v8::internal::ParameterDeclarationParsingScope<Types>
+ ParameterDeclarationParsingScope;
+
+ // Return types for traversing functions.
+ typedef typename Types::Block BlockT;
+ typedef typename Types::BreakableStatement BreakableStatementT;
typedef typename Types::ClassLiteralProperty ClassLiteralPropertyT;
- typedef typename Types::Suspend SuspendExpressionT;
- typedef typename Types::RewritableExpression RewritableExpressionT;
+ typedef typename Types::ClassPropertyList ClassPropertyListT;
+ typedef typename Types::Expression ExpressionT;
typedef typename Types::ExpressionList ExpressionListT;
typedef typename Types::FormalParameters FormalParametersT;
+ typedef typename Types::ForStatement ForStatementT;
+ typedef typename Types::FunctionLiteral FunctionLiteralT;
+ typedef typename Types::Identifier IdentifierT;
+ typedef typename Types::IterationStatement IterationStatementT;
+ typedef typename Types::ObjectLiteralProperty ObjectLiteralPropertyT;
+ typedef typename Types::ObjectPropertyList ObjectPropertyListT;
typedef typename Types::Statement StatementT;
typedef typename Types::StatementList StatementListT;
- typedef typename Types::Block BlockT;
- typedef typename Types::ForStatement ForStatementT;
- typedef typename v8::internal::ExpressionClassifier<Types>
- ExpressionClassifier;
+ typedef typename Types::Suspend SuspendExpressionT;
+ // For constructing objects returned by the traversing functions.
+ typedef typename Types::Factory FactoryT;
+ // Other implementation-specific tasks.
typedef typename Types::FuncNameInferrer FuncNameInferrer;
typedef typename Types::FuncNameInferrer::State FuncNameInferrerState;
typedef typename Types::SourceRange SourceRange;
typedef typename Types::SourceRangeScope SourceRangeScope;
+ typedef typename Types::Target TargetT;
+ typedef typename Types::TargetScope TargetScopeT;
// All implementation-specific methods must be called through this.
Impl* impl() { return static_cast<Impl*>(this); }
@@ -261,7 +246,7 @@ class ParserBase {
original_scope_(nullptr),
function_state_(nullptr),
extension_(extension),
- fni_(ast_value_factory, zone),
+ fni_(ast_value_factory),
ast_value_factory_(ast_value_factory),
ast_node_factory_(ast_value_factory, zone),
runtime_call_stats_(runtime_call_stats),
@@ -271,34 +256,38 @@ class ParserBase {
stack_limit_(stack_limit),
pending_error_handler_(pending_error_handler),
zone_(zone),
- classifier_(nullptr),
+ expression_scope_(nullptr),
scanner_(scanner),
- default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile),
function_literal_id_(0),
script_id_(script_id),
+ default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile),
allow_natives_(false),
- allow_harmony_do_expressions_(false),
allow_harmony_public_fields_(false),
allow_harmony_static_fields_(false),
allow_harmony_dynamic_import_(false),
allow_harmony_import_meta_(false),
allow_harmony_private_fields_(false),
- allow_eval_cache_(true) {}
+ allow_harmony_private_methods_(false),
+ allow_eval_cache_(true) {
+ pointer_buffer_.reserve(32);
+ variable_buffer_.reserve(32);
+ }
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
void set_allow_##name(bool allow) { allow_##name##_ = allow; }
ALLOW_ACCESSORS(natives);
- ALLOW_ACCESSORS(harmony_do_expressions);
ALLOW_ACCESSORS(harmony_public_fields);
ALLOW_ACCESSORS(harmony_static_fields);
ALLOW_ACCESSORS(harmony_dynamic_import);
ALLOW_ACCESSORS(harmony_import_meta);
+ ALLOW_ACCESSORS(harmony_private_methods);
ALLOW_ACCESSORS(eval_cache);
#undef ALLOW_ACCESSORS
+ V8_INLINE bool has_error() const { return scanner()->has_parser_error(); }
bool allow_harmony_numeric_separator() const {
return scanner()->allow_harmony_numeric_separator();
}
@@ -326,6 +315,10 @@ class ParserBase {
return default_eager_compile_hint_;
}
+ int loop_nesting_depth() const {
+ return function_state_->loop_nesting_depth();
+ }
+
int GetNextFunctionLiteralId() { return ++function_literal_id_; }
int GetLastFunctionLiteralId() const { return function_literal_id_; }
@@ -340,14 +333,9 @@ class ParserBase {
Zone* zone() const { return zone_; }
protected:
- friend class v8::internal::ExpressionClassifier<ParserTypes<Impl>>;
-
- enum AllowRestrictedIdentifiers {
- kAllowRestrictedIdentifiers,
- kDontAllowRestrictedIdentifiers
- };
-
- enum LazyParsingResult { kLazyParsingComplete, kLazyParsingAborted };
+ friend class v8::internal::ExpressionScope<ParserTypes<Impl>>;
+ friend class v8::internal::ExpressionParsingScope<ParserTypes<Impl>>;
+ friend class v8::internal::ArrowHeadParsingScope<ParserTypes<Impl>>;
enum VariableDeclarationContext {
kStatementListItem,
@@ -356,7 +344,6 @@ class ParserBase {
};
class ClassLiteralChecker;
- class ObjectLiteralChecker;
// ---------------------------------------------------------------------------
// BlockState and FunctionState implement the parser's scope stack.
@@ -403,33 +390,6 @@ class ParserBase {
FunctionKind kind() const { return scope()->function_kind(); }
- void RewindDestructuringAssignments(int pos) {
- destructuring_assignments_to_rewrite_.Rewind(pos);
- }
-
- void AdoptDestructuringAssignmentsFromParentState(int pos) {
- const auto& outer_assignments =
- outer_function_state_->destructuring_assignments_to_rewrite_;
- DCHECK_GE(outer_assignments.size(), pos);
- auto it = outer_assignments.begin();
- it.Advance(pos);
- for (; it != outer_assignments.end(); ++it) {
- auto expr = *it;
- expr->set_scope(scope_);
- destructuring_assignments_to_rewrite_.push_back(expr);
- }
- outer_function_state_->RewindDestructuringAssignments(pos);
- }
-
- const ZoneChunkList<RewritableExpressionT>&
- destructuring_assignments_to_rewrite() const {
- return destructuring_assignments_to_rewrite_;
- }
-
- ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() {
- return &reported_errors_;
- }
-
bool next_function_is_likely_called() const {
return next_function_is_likely_called_;
}
@@ -450,41 +410,50 @@ class ParserBase {
class FunctionOrEvalRecordingScope {
public:
explicit FunctionOrEvalRecordingScope(FunctionState* state)
- : state_(state) {
- prev_value_ = state->contains_function_or_eval_;
+ : state_and_prev_value_(state, state->contains_function_or_eval_) {
state->contains_function_or_eval_ = false;
}
~FunctionOrEvalRecordingScope() {
- bool found = state_->contains_function_or_eval_;
+ bool found = state_and_prev_value_->contains_function_or_eval_;
if (!found) {
- state_->contains_function_or_eval_ = prev_value_;
+ state_and_prev_value_->contains_function_or_eval_ =
+ state_and_prev_value_.GetPayload();
}
}
private:
- FunctionState* state_;
- bool prev_value_;
+ PointerWithPayload<FunctionState, bool, 1> state_and_prev_value_;
};
- private:
- void AddDestructuringAssignment(RewritableExpressionT expr) {
- destructuring_assignments_to_rewrite_.push_back(expr);
- }
+ class LoopScope {
+ public:
+ explicit LoopScope(FunctionState* function_state)
+ : function_state_(function_state) {
+ function_state_->loop_nesting_depth_++;
+ }
+ ~LoopScope() { function_state_->loop_nesting_depth_--; }
+
+ private:
+ FunctionState* function_state_;
+ };
+
+ int loop_nesting_depth() const { return loop_nesting_depth_; }
+
+ private:
// Properties count estimation.
int expected_property_count_;
// How many suspends are needed for this function.
int suspend_count_;
+ // How deeply nested we currently are in this function.
+ int loop_nesting_depth_ = 0;
+
FunctionState** function_state_stack_;
FunctionState* outer_function_state_;
DeclarationScope* scope_;
- ZoneChunkList<RewritableExpressionT> destructuring_assignments_to_rewrite_;
-
- ZoneList<typename ExpressionClassifier::Error> reported_errors_;
-
// A reason, if any, why this function should not be optimized.
BailoutReason dont_optimize_reason_;
@@ -503,12 +472,10 @@ class ParserBase {
};
struct DeclarationDescriptor {
- enum Kind { NORMAL, PARAMETER, FOR_EACH };
- Scope* scope;
VariableMode mode;
+ VariableKind kind;
int declaration_pos;
int initialization_pos;
- Kind declaration_kind;
};
struct DeclarationParsingResult {
@@ -538,18 +505,12 @@ class ParserBase {
struct CatchInfo {
public:
explicit CatchInfo(ParserBase* parser)
- : name(parser->impl()->NullIdentifier()),
- pattern(parser->impl()->NullExpression()),
- scope(nullptr),
- init_block(parser->impl()->NullStatement()),
- inner_block(parser->impl()->NullStatement()),
- bound_names(1, parser->zone()) {}
- IdentifierT name;
+ : pattern(parser->impl()->NullExpression()),
+ variable(nullptr),
+ scope(nullptr) {}
ExpressionT pattern;
+ Variable* variable;
Scope* scope;
- BlockT init_block;
- BlockT inner_block;
- ZonePtrList<const AstRawString> bound_names;
};
struct ForInfo {
@@ -578,29 +539,102 @@ class ParserBase {
has_name_static_property(false),
has_static_computed_names(false),
has_static_class_fields(false),
- has_instance_class_fields(false),
+ has_instance_members(false),
is_anonymous(false),
static_fields_scope(nullptr),
- instance_fields_scope(nullptr),
+ instance_members_scope(nullptr),
computed_field_count(0) {}
Variable* variable;
ExpressionT extends;
- typename Types::ClassPropertyList properties;
- typename Types::ClassPropertyList static_fields;
- typename Types::ClassPropertyList instance_fields;
+ ClassPropertyListT properties;
+ ClassPropertyListT static_fields;
+ ClassPropertyListT instance_fields;
FunctionLiteralT constructor;
bool has_seen_constructor;
bool has_name_static_property;
bool has_static_computed_names;
bool has_static_class_fields;
- bool has_instance_class_fields;
+ bool has_instance_members;
bool is_anonymous;
DeclarationScope* static_fields_scope;
- DeclarationScope* instance_fields_scope;
+ DeclarationScope* instance_members_scope;
int computed_field_count;
};
+ enum class PropertyPosition { kObjectLiteral, kClassLiteral };
+ struct ParsePropertyInfo {
+ public:
+ explicit ParsePropertyInfo(ParserBase* parser,
+ AccumulationScope* accumulation_scope = nullptr)
+ : accumulation_scope(accumulation_scope),
+ name(parser->impl()->NullIdentifier()),
+ position(PropertyPosition::kClassLiteral),
+ function_flags(ParseFunctionFlag::kIsNormal),
+ kind(ParsePropertyKind::kNotSet),
+ is_computed_name(false),
+ is_private(false),
+ is_static(false),
+ is_rest(false) {}
+
+ bool ParsePropertyKindFromToken(Token::Value token) {
+ // This returns true, setting the property kind, iff the given token is
+ // one which must occur after a property name, indicating that the
+ // previous token was in fact a name and not a modifier (like the "get" in
+ // "get x").
+ switch (token) {
+ case Token::COLON:
+ kind = ParsePropertyKind::kValue;
+ return true;
+ case Token::COMMA:
+ kind = ParsePropertyKind::kShorthand;
+ return true;
+ case Token::RBRACE:
+ kind = ParsePropertyKind::kShorthandOrClassField;
+ return true;
+ case Token::ASSIGN:
+ kind = ParsePropertyKind::kAssign;
+ return true;
+ case Token::LPAREN:
+ kind = ParsePropertyKind::kMethod;
+ return true;
+ case Token::MUL:
+ case Token::SEMICOLON:
+ kind = ParsePropertyKind::kClassField;
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ AccumulationScope* accumulation_scope;
+ IdentifierT name;
+ PropertyPosition position;
+ ParseFunctionFlags function_flags;
+ ParsePropertyKind kind;
+ bool is_computed_name;
+ bool is_private;
+ bool is_static;
+ bool is_rest;
+ };
+
+ ClassLiteralProperty::Kind ClassPropertyKindFor(ParsePropertyKind kind) {
+ switch (kind) {
+ case ParsePropertyKind::kAccessorGetter:
+ return ClassLiteralProperty::GETTER;
+ case ParsePropertyKind::kAccessorSetter:
+ return ClassLiteralProperty::SETTER;
+ case ParsePropertyKind::kMethod:
+ return ClassLiteralProperty::METHOD;
+ case ParsePropertyKind::kClassField:
+ return ClassLiteralProperty::FIELD;
+ default:
+ // Only returns for deterministic kinds
+ UNREACHABLE();
+ }
+ }
+
const AstRawString* ClassFieldVariableName(AstValueFactory* ast_value_factory,
int index) {
std::string name = ".class-field-" + std::to_string(index);
@@ -667,6 +701,22 @@ class ParserBase {
return scope()->GetClosureScope();
}
+ VariableProxy* NewRawVariable(const AstRawString* name, int pos) {
+ return factory()->ast_node_factory()->NewVariableProxy(
+ name, NORMAL_VARIABLE, pos);
+ }
+
+ VariableProxy* NewUnresolved(const AstRawString* name) {
+ return scope()->NewUnresolved(factory()->ast_node_factory(), name,
+ scanner()->location().beg_pos);
+ }
+
+ VariableProxy* NewUnresolved(const AstRawString* name, int begin_pos,
+ VariableKind kind = NORMAL_VARIABLE) {
+ return scope()->NewUnresolved(factory()->ast_node_factory(), name,
+ begin_pos, kind);
+ }
+
Scanner* scanner() const { return scanner_; }
AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
int position() const { return scanner_->location().beg_pos; }
@@ -676,14 +726,18 @@ class ParserBase {
bool stack_overflow() const {
return pending_error_handler()->stack_overflow();
}
- void set_stack_overflow() { pending_error_handler()->set_stack_overflow(); }
+ void set_stack_overflow() {
+ scanner_->set_parser_error();
+ pending_error_handler()->set_stack_overflow();
+ }
+ void CheckStackOverflow() {
+ // Any further calls to Next or peek will return the illegal token.
+ if (GetCurrentStackPosition() < stack_limit_) set_stack_overflow();
+ }
int script_id() { return script_id_; }
void set_script_id(int id) { script_id_ = id; }
- V8_INLINE Token::Value peek() {
- if (stack_overflow()) return Token::ILLEGAL;
- return scanner()->peek();
- }
+ V8_INLINE Token::Value peek() { return scanner()->peek(); }
// Returns the position past the following semicolon (if it exists), and the
// position past the end of the current token otherwise.
@@ -691,33 +745,19 @@ class ParserBase {
return (peek() == Token::SEMICOLON) ? peek_end_position() : end_position();
}
- V8_INLINE Token::Value PeekAhead() {
- if (stack_overflow()) return Token::ILLEGAL;
- return scanner()->PeekAhead();
- }
+ V8_INLINE Token::Value PeekAhead() { return scanner()->PeekAhead(); }
- V8_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.
- set_stack_overflow();
- }
- }
- return scanner()->Next();
- }
+ V8_INLINE Token::Value Next() { return scanner()->Next(); }
- void Consume(Token::Value token) {
- Token::Value next = Next();
+ V8_INLINE void Consume(Token::Value token) {
+ Token::Value next = scanner()->Next();
USE(next);
USE(token);
- DCHECK_EQ(next, token);
+ DCHECK_IMPLIES(!has_error(), next == token);
}
- bool Check(Token::Value token) {
- Token::Value next = peek();
+ V8_INLINE bool Check(Token::Value token) {
+ Token::Value next = scanner()->peek();
if (next == token) {
Consume(next);
return true;
@@ -725,28 +765,26 @@ class ParserBase {
return false;
}
- void Expect(Token::Value token, bool* ok) {
+ void Expect(Token::Value token) {
Token::Value next = Next();
- if (next != token) {
+ if (V8_UNLIKELY(next != token)) {
ReportUnexpectedToken(next);
- *ok = false;
}
}
- void ExpectSemicolon(bool* ok) {
+ void ExpectSemicolon() {
// 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) {
+ if (V8_LIKELY(tok == Token::SEMICOLON)) {
Next();
return;
}
- if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::RBRACE ||
- tok == Token::EOS) {
+ if (V8_LIKELY(scanner()->HasLineTerminatorBeforeNext() ||
+ Token::IsAutoSemicolon(tok))) {
return;
}
- *ok = false;
if (scanner()->current_token() == Token::AWAIT && !is_async_function()) {
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitNotInAsyncFunction, kSyntaxError);
@@ -756,38 +794,28 @@ class ParserBase {
ReportUnexpectedToken(Next());
}
- // Dummy functions, just useful as arguments to CHECK_OK_CUSTOM.
- static void Void() {}
- template <typename T>
- static T Return(T result) {
- return result;
- }
-
bool peek_any_identifier() { return Token::IsAnyIdentifier(peek()); }
- bool CheckContextualKeyword(Token::Value token) {
- if (PeekContextualKeyword(token)) {
+ bool PeekContextualKeyword(const AstRawString* name) {
+ return peek() == Token::IDENTIFIER &&
+ scanner()->NextSymbol(ast_value_factory()) == name;
+ }
+
+ bool CheckContextualKeyword(const AstRawString* name) {
+ if (PeekContextualKeyword(name)) {
Consume(Token::IDENTIFIER);
return true;
}
return false;
}
- bool PeekContextualKeyword(Token::Value token) {
- DCHECK(Token::IsContextualKeyword(token));
- return peek() == Token::IDENTIFIER &&
- scanner()->next_contextual_token() == token;
- }
-
- void ExpectMetaProperty(Token::Value property_name, const char* full_name,
- int pos, bool* ok);
+ void ExpectMetaProperty(const AstRawString* property_name,
+ const char* full_name, int pos);
- void ExpectContextualKeyword(Token::Value token, bool* ok) {
- DCHECK(Token::IsContextualKeyword(token));
- Expect(Token::IDENTIFIER, CHECK_OK_CUSTOM(Void));
- if (scanner()->current_contextual_token() != token) {
+ void ExpectContextualKeyword(const AstRawString* name) {
+ Expect(Token::IDENTIFIER);
+ if (V8_UNLIKELY(scanner()->CurrentSymbol(ast_value_factory()) != name)) {
ReportUnexpectedToken(scanner()->current_token());
- *ok = false;
}
}
@@ -795,7 +823,7 @@ class ParserBase {
if (Check(Token::IN)) {
*visit_mode = ForEachStatement::ENUMERATE;
return true;
- } else if (CheckContextualKeyword(Token::OF)) {
+ } else if (CheckContextualKeyword(ast_value_factory()->of_string())) {
*visit_mode = ForEachStatement::ITERATE;
return true;
}
@@ -803,23 +831,23 @@ class ParserBase {
}
bool PeekInOrOf() {
- return peek() == Token::IN || PeekContextualKeyword(Token::OF);
+ return peek() == Token::IN ||
+ PeekContextualKeyword(ast_value_factory()->of_string());
}
// Checks whether an octal literal was last seen between beg_pos and end_pos.
// Only called for strict mode strings.
- void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+ void CheckStrictOctalLiteral(int beg_pos, int end_pos) {
Scanner::Location octal = scanner()->octal_position();
if (octal.IsValid() && beg_pos <= octal.beg_pos &&
octal.end_pos <= end_pos) {
- MessageTemplate::Template message = scanner()->octal_message();
+ MessageTemplate message = scanner()->octal_message();
DCHECK_NE(message, MessageTemplate::kNone);
impl()->ReportMessageAt(octal, message);
scanner()->clear_octal_position();
if (message == MessageTemplate::kStrictDecimalWithLeadingZero) {
impl()->CountUsage(v8::Isolate::kDecimalWithLeadingZeroInStrictMode);
}
- *ok = false;
}
}
@@ -827,29 +855,29 @@ class ParserBase {
// appears in the current template literal token. In the presence of such,
// either returns false or reports an error, depending on should_throw.
// Otherwise returns true.
- inline bool CheckTemplateEscapes(bool should_throw, bool* ok) {
- DCHECK(scanner()->current_token() == Token::TEMPLATE_SPAN ||
- scanner()->current_token() == Token::TEMPLATE_TAIL);
- if (!scanner()->has_invalid_template_escape()) {
- return true;
- }
+ inline bool CheckTemplateEscapes(bool should_throw) {
+ DCHECK(Token::IsTemplate(scanner()->current_token()));
+ if (!scanner()->has_invalid_template_escape()) return true;
// Handle error case(s)
if (should_throw) {
impl()->ReportMessageAt(scanner()->invalid_template_escape_location(),
scanner()->invalid_template_escape_message());
- *ok = false;
}
- return false;
+ scanner()->clear_invalid_template_escape_message();
+ return should_throw;
}
- void CheckDestructuringElement(ExpressionT element, int beg_pos, int end_pos);
+ ExpressionT ParsePossibleDestructuringSubPattern(AccumulationScope* scope);
+ void ClassifyParameter(IdentifierT parameter, int beg_pos, int end_pos);
+ void ClassifyArrowParameter(AccumulationScope* accumulation_scope,
+ int position, ExpressionT parameter);
// 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) {
+ const Scanner::Location& function_name_loc) {
if (impl()->IsNull(function_name)) return;
if (function_name_validity == kSkipFunctionNameCheck) return;
// The function name needs to be checked in strict mode.
@@ -858,24 +886,15 @@ class ParserBase {
if (impl()->IsEvalOrArguments(function_name)) {
impl()->ReportMessageAt(function_name_loc,
MessageTemplate::kStrictEvalArguments);
- *ok = false;
return;
}
if (function_name_validity == kFunctionNameIsStrictReserved) {
impl()->ReportMessageAt(function_name_loc,
MessageTemplate::kUnexpectedStrictReserved);
- *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 Types::Factory* factory() { return &ast_node_factory_; }
DeclarationScope* GetReceiverScope() const {
@@ -907,405 +926,280 @@ class ParserBase {
}
// Report syntax errors.
- void ReportMessage(MessageTemplate::Template message) {
+ V8_NOINLINE void ReportMessage(MessageTemplate message) {
Scanner::Location source_location = scanner()->location();
impl()->ReportMessageAt(source_location, message,
static_cast<const char*>(nullptr), kSyntaxError);
}
template <typename T>
- void ReportMessage(MessageTemplate::Template message, T arg,
- ParseErrorType error_type = kSyntaxError) {
+ V8_NOINLINE void ReportMessage(MessageTemplate message, T arg,
+ ParseErrorType error_type = kSyntaxError) {
Scanner::Location source_location = scanner()->location();
impl()->ReportMessageAt(source_location, message, arg, error_type);
}
- void ReportMessageAt(Scanner::Location location,
- MessageTemplate::Template message,
- ParseErrorType error_type) {
+ V8_NOINLINE void ReportMessageAt(Scanner::Location location,
+ MessageTemplate message,
+ ParseErrorType error_type) {
impl()->ReportMessageAt(location, message,
static_cast<const char*>(nullptr), error_type);
}
- void GetUnexpectedTokenMessage(
- Token::Value token, MessageTemplate::Template* message,
- Scanner::Location* location, const char** arg,
- MessageTemplate::Template default_ = MessageTemplate::kUnexpectedToken);
+ V8_NOINLINE void ReportUnexpectedToken(Token::Value token);
- void ReportUnexpectedToken(Token::Value token);
- void ReportUnexpectedTokenAt(
- Scanner::Location location, Token::Value token,
- MessageTemplate::Template message = MessageTemplate::kUnexpectedToken);
-
- void ReportClassifierError(
- const typename ExpressionClassifier::Error& error) {
- if (classifier()->does_error_reporting()) {
- impl()->ReportMessageAt(error.location, error.message, error.arg);
- } else {
- impl()->ReportUnidentifiableError();
- }
+ void ValidateFormalParameters(LanguageMode language_mode,
+ const FormalParametersT& parameters,
+ bool allow_duplicates) {
+ if (!allow_duplicates) parameters.ValidateDuplicate(impl());
+ if (is_strict(language_mode)) parameters.ValidateStrictMode(impl());
}
- void ValidateExpression(bool* ok) {
- if (!classifier()->is_valid_expression()) {
- ReportClassifierError(classifier()->expression_error());
- *ok = false;
- }
+ V8_INLINE IdentifierT ParseAndClassifyIdentifier(Token::Value token);
+ // Parses an identifier or a strict mode future reserved word. Allows passing
+ // in function_kind for the case of parsing the identifier in a function
+ // expression, where the relevant "function_kind" bit is of the function being
+ // parsed, not the containing function.
+ V8_INLINE IdentifierT ParseIdentifier(FunctionKind function_kind);
+ V8_INLINE IdentifierT ParseIdentifier() {
+ return ParseIdentifier(function_state_->kind());
}
+ // Same as above but additionally disallows 'eval' and 'arguments' in strict
+ // mode.
+ IdentifierT ParseNonRestrictedIdentifier();
- void ValidateFormalParameterInitializer(bool* ok) {
- if (!classifier()->is_valid_formal_parameter_initializer()) {
- ReportClassifierError(classifier()->formal_parameter_initializer_error());
- *ok = false;
- }
- }
+ V8_INLINE IdentifierT ParsePropertyName();
- void ValidateBindingPattern(bool* ok) {
- if (!classifier()->is_valid_binding_pattern()) {
- ReportClassifierError(classifier()->binding_pattern_error());
- *ok = false;
- }
- }
+ ExpressionT ParsePropertyOrPrivatePropertyName();
- void ValidateAssignmentPattern(bool* ok) {
- if (!classifier()->is_valid_assignment_pattern()) {
- ReportClassifierError(classifier()->assignment_pattern_error());
- *ok = false;
- }
- }
+ ExpressionT ParseRegExpLiteral();
- void ValidateFormalParameters(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;
- }
- }
-
- bool IsValidArrowFormalParametersStart(Token::Value token) {
- return Token::IsAnyIdentifier(token) || token == Token::LPAREN;
- }
-
- void ValidateArrowFormalParameters(ExpressionT expr,
- bool parenthesized_formals, bool is_async,
- bool* ok) {
- if (classifier()->is_valid_binding_pattern()) {
- // A simple arrow formal parameter: IDENTIFIER => BODY.
- if (!impl()->IsIdentifier(expr)) {
- impl()->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 typename ExpressionClassifier::Error& error =
- parenthesized_formals ? classifier()->arrow_formal_parameters_error()
- : classifier()->binding_pattern_error();
- ReportClassifierError(error);
- *ok = false;
- }
- if (is_async && !classifier()->is_valid_async_arrow_formal_parameters()) {
- const typename ExpressionClassifier::Error& error =
- classifier()->async_arrow_formal_parameters_error();
- ReportClassifierError(error);
- *ok = false;
- }
- }
-
- void ValidateLetPattern(bool* ok) {
- if (!classifier()->is_valid_let_pattern()) {
- ReportClassifierError(classifier()->let_pattern_error());
- *ok = false;
- }
- }
-
- void BindingPatternUnexpectedToken() {
- MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
- const char* arg;
- Scanner::Location location = scanner()->peek_location();
- GetUnexpectedTokenMessage(peek(), &message, &location, &arg);
- classifier()->RecordBindingPatternError(location, message, arg);
- }
-
- void ArrowFormalParametersUnexpectedToken() {
- MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
- const char* arg;
- Scanner::Location location = scanner()->peek_location();
- GetUnexpectedTokenMessage(peek(), &message, &location, &arg);
- classifier()->RecordArrowFormalParametersError(location, message, arg);
- }
-
- // Recursive descent functions.
- // 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. The family of CHECK_OK* macros can
- // be useful for this.
-
- // 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(bool* ok);
- // Parses an identifier or a strict mode future reserved word, and indicate
- // whether it is strict mode future reserved. Allows passing in function_kind
- // for the case of parsing the identifier in a function expression, where the
- // relevant "function_kind" bit is of the function being parsed, not the
- // containing function.
- IdentifierT ParseIdentifierOrStrictReservedWord(FunctionKind function_kind,
- bool* is_strict_reserved,
- bool* is_await, bool* ok);
- IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
- bool* is_await, bool* ok) {
- return ParseIdentifierOrStrictReservedWord(
- function_state_->kind(), is_strict_reserved, is_await, ok);
- }
-
- V8_INLINE IdentifierT ParseIdentifierName(bool* ok);
-
- ExpressionT ParseIdentifierNameOrPrivateName(bool* ok);
-
- ExpressionT ParseRegExpLiteral(bool* ok);
-
- ExpressionT ParseBindingPattern(bool* ok);
- ExpressionT ParsePrimaryExpression(bool* is_async, bool* ok);
-
- // Use when parsing an expression that is known to not be a pattern or part
- // of a pattern.
- V8_INLINE ExpressionT ParseExpression(bool* ok);
-
- // This method does not wrap the parsing of the expression inside a
- // new expression classifier; it uses the top-level classifier instead.
- // It should be used whenever we're parsing something with the "cover"
- // grammar that recognizes both patterns and non-patterns (which roughly
- // corresponds to what's inside the parentheses generated by the symbol
+ ExpressionT ParseBindingPattern();
+ ExpressionT ParsePrimaryExpression();
+
+ // Use when parsing an expression that is known to not be a pattern or part of
+ // a pattern.
+ V8_INLINE ExpressionT ParseExpression();
+ V8_INLINE ExpressionT ParseAssignmentExpression();
+
+ // These methods do not wrap the parsing of the expression inside a new
+ // expression_scope; they use the outer expression_scope instead. They should
+ // be used whenever we're parsing something with the "cover" grammar that
+ // recognizes both patterns and non-patterns (which roughly corresponds to
+ // what's inside the parentheses generated by the symbol
// "CoverParenthesizedExpressionAndArrowParameterList" in the ES 2017
// specification).
- ExpressionT ParseExpressionCoverGrammar(bool accept_IN, bool* ok);
+ ExpressionT ParseExpressionCoverGrammar();
+ ExpressionT ParseAssignmentExpressionCoverGrammar();
+
+ ExpressionT ParseArrowParametersWithRest(ExpressionListT* list,
+ AccumulationScope* scope);
- ExpressionT ParseArrayLiteral(bool* ok);
+ ExpressionT ParseArrayLiteral();
inline static bool IsAccessor(ParsePropertyKind kind) {
return IsInRange(kind, ParsePropertyKind::kAccessorGetter,
ParsePropertyKind::kAccessorSetter);
}
- ExpressionT ParsePropertyName(IdentifierT* name, ParsePropertyKind* kind,
- ParseFunctionFlags* flags,
- bool* is_computed_name, bool* ok);
- ExpressionT ParseObjectLiteral(bool* ok);
+ ExpressionT ParseProperty(ParsePropertyInfo* prop_info);
+ ExpressionT ParseObjectLiteral();
ClassLiteralPropertyT ParseClassPropertyDefinition(
- ClassLiteralChecker* checker, ClassInfo* class_info,
- IdentifierT* property_name, bool has_extends, bool* is_computed_name,
- ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok);
- ExpressionT ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos,
- bool is_static, bool* ok);
+ ClassInfo* class_info, ParsePropertyInfo* prop_info, bool has_extends);
+ void CheckClassFieldName(IdentifierT name, bool is_static);
+ void CheckClassMethodName(IdentifierT name, ParsePropertyKind type,
+ ParseFunctionFlags flags, bool is_static,
+ bool* has_seen_constructor);
+ ExpressionT ParseMemberInitializer(ClassInfo* class_info, int beg_pos,
+ bool is_static);
ObjectLiteralPropertyT ParseObjectPropertyDefinition(
- ObjectLiteralChecker* checker, bool* is_computed_name,
- bool* is_rest_property, bool* ok);
- ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
- bool maybe_arrow,
- bool* is_simple_parameter_list, bool* ok);
- ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
- bool* ok) {
- bool is_simple = true;
- return ParseArguments(first_spread_pos, false, &is_simple, ok);
- }
-
- ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
- ExpressionT ParseYieldExpression(bool accept_IN, bool* ok);
- V8_INLINE ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok);
- ExpressionT ParseConditionalContinuation(ExpressionT expression,
- bool accept_IN, int pos, bool* ok);
- ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
- ExpressionT ParseUnaryOpExpression(bool* ok);
- ExpressionT ParseAwaitExpression(bool* ok);
- ExpressionT ParsePrefixExpression(bool* ok);
- V8_INLINE ExpressionT ParseUnaryExpression(bool* ok);
- V8_INLINE ExpressionT ParsePostfixExpression(bool* ok);
- V8_INLINE ExpressionT ParseLeftHandSideExpression(bool* ok);
- ExpressionT ParseMemberWithPresentNewPrefixesExpression(bool* is_async,
- bool* ok);
- V8_INLINE ExpressionT ParseMemberWithNewPrefixesExpression(bool* is_async,
- bool* ok);
- V8_INLINE ExpressionT ParseMemberExpression(bool* is_async, bool* ok);
- V8_INLINE ExpressionT ParseMemberExpressionContinuation(
- ExpressionT expression, bool* is_async, bool* ok);
-
- // `rewritable_length`: length of the destructuring_assignments_to_rewrite()
- // queue in the parent function state, prior to parsing of formal parameters.
- // If the arrow function is lazy, any items added during formal parameter
- // parsing are removed from the queue.
- ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
- const FormalParametersT& parameters,
- int rewritable_length, bool* ok);
- void ParseAsyncFunctionBody(Scope* scope, StatementListT body, bool* ok);
- ExpressionT ParseAsyncFunctionLiteral(bool* ok);
+ ParsePropertyInfo* prop_info, bool* has_seen_proto);
+ void ParseArguments(
+ ExpressionListT* args, bool* has_spread,
+ ParsingArrowHeadFlag maybe_arrow = kCertainlyNotArrowHead);
+
+ ExpressionT ParseYieldExpression();
+ V8_INLINE ExpressionT ParseConditionalExpression();
+ ExpressionT ParseConditionalContinuation(ExpressionT expression, int pos);
+ ExpressionT ParseBinaryContinuation(ExpressionT x, int prec, int prec1);
+ V8_INLINE ExpressionT ParseBinaryExpression(int prec);
+ ExpressionT ParseUnaryOrPrefixExpression();
+ ExpressionT ParseAwaitExpression();
+ V8_INLINE ExpressionT ParseUnaryExpression();
+ V8_INLINE ExpressionT ParsePostfixExpression();
+ V8_INLINE ExpressionT ParseLeftHandSideExpression();
+ ExpressionT ParseLeftHandSideContinuation(ExpressionT expression);
+ ExpressionT ParseMemberWithPresentNewPrefixesExpression();
+ V8_INLINE ExpressionT ParseMemberWithNewPrefixesExpression();
+ ExpressionT ParseFunctionExpression();
+ V8_INLINE ExpressionT ParseMemberExpression();
+ V8_INLINE ExpressionT
+ ParseMemberExpressionContinuation(ExpressionT expression) {
+ if (!Token::IsMember(peek())) return expression;
+ return DoParseMemberExpressionContinuation(expression);
+ }
+ ExpressionT DoParseMemberExpressionContinuation(ExpressionT expression);
+
+ ExpressionT ParseArrowFunctionLiteral(const FormalParametersT& parameters);
+ void ParseAsyncFunctionBody(Scope* scope, StatementListT* body);
+ ExpressionT ParseAsyncFunctionLiteral();
ExpressionT ParseClassLiteral(IdentifierT name,
Scanner::Location class_name_location,
bool name_is_strict_reserved,
- int class_token_pos, bool* ok);
- ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool tagged,
- bool* ok);
- ExpressionT ParseSuperExpression(bool is_new, bool* ok);
- ExpressionT ParseImportExpressions(bool* ok);
- ExpressionT ParseNewTargetExpression(bool* ok);
-
- V8_INLINE void ParseFormalParameter(FormalParametersT* parameters, bool* ok);
- void ParseFormalParameterList(FormalParametersT* parameters, bool* ok);
+ int class_token_pos);
+ ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool tagged);
+ ExpressionT ParseSuperExpression(bool is_new);
+ ExpressionT ParseImportExpressions();
+ ExpressionT ParseNewTargetExpression();
+
+ V8_INLINE void ParseFormalParameter(FormalParametersT* parameters);
+ void ParseFormalParameterList(FormalParametersT* parameters);
void CheckArityRestrictions(int param_count, FunctionKind function_type,
bool has_rest, int formals_start_pos,
- int formals_end_pos, bool* ok);
+ int formals_end_pos);
- BlockT ParseVariableDeclarations(VariableDeclarationContext var_context,
- DeclarationParsingResult* parsing_result,
- ZonePtrList<const AstRawString>* names,
- bool* ok);
+ void ParseVariableDeclarations(VariableDeclarationContext var_context,
+ DeclarationParsingResult* parsing_result,
+ ZonePtrList<const AstRawString>* names);
StatementT ParseAsyncFunctionDeclaration(
- ZonePtrList<const AstRawString>* names, bool default_export, bool* ok);
- StatementT ParseFunctionDeclaration(bool* ok);
+ ZonePtrList<const AstRawString>* names, bool default_export);
+ StatementT ParseFunctionDeclaration();
StatementT ParseHoistableDeclaration(ZonePtrList<const AstRawString>* names,
- bool default_export, bool* ok);
+ bool default_export);
StatementT ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
ZonePtrList<const AstRawString>* names,
- bool default_export, bool* ok);
+ bool default_export);
StatementT ParseClassDeclaration(ZonePtrList<const AstRawString>* names,
- bool default_export, bool* ok);
- StatementT ParseNativeDeclaration(bool* ok);
+ bool default_export);
+ StatementT ParseNativeDeclaration();
// Whether we're parsing a single-expression arrow function or something else.
enum class FunctionBodyType { kExpression, kBlock };
// Consumes the ending }.
- void ParseFunctionBody(StatementListT result, IdentifierT function_name,
+ void ParseFunctionBody(StatementListT* body, IdentifierT function_name,
int pos, const FormalParametersT& parameters,
FunctionKind kind,
FunctionLiteral::FunctionType function_type,
- FunctionBodyType body_type, bool accept_IN, bool* ok);
-
- // Under some circumstances, we allow preparsing to abort if the preparsed
- // function is "long and trivial", and fully parse instead. Our current
- // definition of "long and trivial" is:
- // - over kLazyParseTrialLimit statements
- // - all starting with an identifier (i.e., no if, for, while, etc.)
- static const int kLazyParseTrialLimit = 200;
+ FunctionBodyType body_type);
// TODO(nikolaos, marja): The first argument should not really be passed
// by value. The method is expected to add the parsed statements to the
// list. This works because in the case of the parser, StatementListT is
// a pointer whereas the preparser does not really modify the body.
- V8_INLINE void ParseStatementList(StatementListT body, Token::Value end_token,
- bool* ok) {
- LazyParsingResult result = ParseStatementList(body, end_token, false, ok);
- USE(result);
- DCHECK_EQ(result, kLazyParsingComplete);
- }
- V8_INLINE LazyParsingResult ParseStatementList(StatementListT body,
- Token::Value end_token,
- bool may_abort, bool* ok);
- StatementT ParseStatementListItem(bool* ok);
+ V8_INLINE void ParseStatementList(StatementListT* body,
+ Token::Value end_token);
+ StatementT ParseStatementListItem();
StatementT ParseStatement(ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels,
- bool* ok) {
+ ZonePtrList<const AstRawString>* own_labels) {
return ParseStatement(labels, own_labels,
- kDisallowLabelledFunctionStatement, ok);
+ kDisallowLabelledFunctionStatement);
}
StatementT ParseStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
- AllowLabelledFunctionStatement allow_function,
- bool* ok);
- BlockT ParseBlock(ZonePtrList<const AstRawString>* labels, bool* ok);
+ AllowLabelledFunctionStatement allow_function);
+ BlockT ParseBlock(ZonePtrList<const AstRawString>* labels);
// Parse a SubStatement in strict mode, or with an extra block scope in
// sloppy mode to handle
// ES#sec-functiondeclarations-in-ifstatement-statement-clauses
- StatementT ParseScopedStatement(ZonePtrList<const AstRawString>* labels,
- bool* ok);
+ StatementT ParseScopedStatement(ZonePtrList<const AstRawString>* labels);
StatementT ParseVariableStatement(VariableDeclarationContext var_context,
- ZonePtrList<const AstRawString>* names,
- bool* ok);
+ ZonePtrList<const AstRawString>* names);
// Magical syntax support.
- ExpressionT ParseV8Intrinsic(bool* ok);
+ ExpressionT ParseV8Intrinsic();
- ExpressionT ParseDoExpression(bool* ok);
-
- StatementT ParseDebuggerStatement(bool* ok);
+ StatementT ParseDebuggerStatement();
StatementT ParseExpressionOrLabelledStatement(
ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
- AllowLabelledFunctionStatement allow_function, bool* ok);
- StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels,
- bool* ok);
- StatementT ParseContinueStatement(bool* ok);
- StatementT ParseBreakStatement(ZonePtrList<const AstRawString>* labels,
- bool* ok);
- StatementT ParseReturnStatement(bool* ok);
- StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels,
- bool* ok);
+ AllowLabelledFunctionStatement allow_function);
+ StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels);
+ StatementT ParseContinueStatement();
+ StatementT ParseBreakStatement(ZonePtrList<const AstRawString>* labels);
+ StatementT ParseReturnStatement();
+ StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels);
StatementT ParseDoWhileStatement(ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels,
- bool* ok);
+ ZonePtrList<const AstRawString>* own_labels);
StatementT ParseWhileStatement(ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels,
- bool* ok);
- StatementT ParseThrowStatement(bool* ok);
- StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels,
- bool* ok);
- V8_INLINE StatementT ParseTryStatement(bool* ok);
+ ZonePtrList<const AstRawString>* own_labels);
+ StatementT ParseThrowStatement();
+ StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels);
+ V8_INLINE StatementT ParseTryStatement();
StatementT ParseForStatement(ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels,
- bool* ok);
+ ZonePtrList<const AstRawString>* own_labels);
StatementT ParseForEachStatementWithDeclarations(
int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope,
- bool* ok);
+ ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope);
StatementT ParseForEachStatementWithoutDeclarations(
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok);
+ ZonePtrList<const AstRawString>* own_labels);
// Parse a C-style for loop: 'for (<init>; <cond>; <next>) { ... }'
// "for (<init>;" is assumed to have been parser already.
ForStatementT ParseStandardForLoop(
int stmt_pos, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond,
- StatementT* next, StatementT* body, bool* ok);
+ StatementT* next, StatementT* body);
// Same as the above, but handles those cases where <init> is a
// lexical variable declaration.
StatementT ParseStandardForLoopWithLexicalDeclarations(
int stmt_pos, StatementT init, ForInfo* for_info,
ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok);
- StatementT ParseForAwaitStatement(ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels,
- bool* ok);
+ ZonePtrList<const AstRawString>* own_labels);
+ StatementT ParseForAwaitStatement(
+ ZonePtrList<const AstRawString>* labels,
+ ZonePtrList<const AstRawString>* own_labels);
+
+ V8_INLINE bool IsLet(const AstRawString* identifier) const {
+ return identifier == ast_value_factory()->let_string();
+ }
+
+ void DesugarBindingInForEachStatement(ForInfo* for_info, BlockT* body_block,
+ ExpressionT* each_variable) {
+ // Annex B.3.5 prohibits the form
+ // `try {} catch(e) { for (var e of {}); }`
+ // So if we are parsing a statement like `for (var ... of ...)`
+ // we need to walk up the scope chain and look for catch scopes
+ // which have a simple binding, then compare their binding against
+ // all of the names declared in the init of the for-of we're
+ // parsing.
+ bool is_for_var_of =
+ for_info->mode == ForEachStatement::ITERATE &&
+ for_info->parsing_result.descriptor.mode == VariableMode::kVar;
+
+ if (is_for_var_of) {
+ Scope* scope = this->scope();
+ while (scope != nullptr && !scope->is_declaration_scope()) {
+ if (scope->is_catch_scope()) {
+ auto name = scope->catch_variable()->raw_name();
+ // If it's a simple binding and the name is declared in the for loop.
+ if (name != ast_value_factory()->dot_catch_string() &&
+ for_info->bound_names.Contains(name)) {
+ impl()->ReportMessageAt(for_info->parsing_result.bindings_loc,
+ MessageTemplate::kVarRedeclaration, name);
+ }
+ }
+ scope = scope->outer_scope();
+ }
+ }
+
+ impl()->DesugarBindingInForEachStatement(for_info, body_block,
+ each_variable);
+ }
bool IsNextLetKeyword();
- bool IsTrivialExpression();
// 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 CheckAndRewriteReferenceExpression(
- ExpressionT expression, int beg_pos, int end_pos,
- MessageTemplate::Template message, ParseErrorType type, bool* ok);
+ ExpressionT RewriteInvalidReferenceExpression(
+ ExpressionT expression, int beg_pos, int end_pos, MessageTemplate message,
+ ParseErrorType type = kReferenceError);
bool IsValidReferenceExpression(ExpressionT expression);
@@ -1318,33 +1212,6 @@ class ParserBase {
return true;
}
- bool IsValidPattern(ExpressionT expression) {
- return expression->IsObjectLiteral() || expression->IsArrayLiteral();
- }
-
- // Due to hoisting, the value of a 'var'-declared variable may actually change
- // even if the code contains only the "initial" assignment, namely when that
- // assignment occurs inside a loop. For example:
- //
- // let i = 10;
- // do { var x = i } while (i--):
- //
- // As a simple and very conservative approximation of this, we explicitly mark
- // as maybe-assigned any non-lexical variable whose initializing "declaration"
- // does not syntactically occur in the function scope. (In the example above,
- // it occurs in a block scope.)
- //
- // Note that non-lexical variables include temporaries, which may also get
- // assigned inside a loop due to the various rewritings that the parser
- // performs.
- //
- // This also handles marking of loop variables in for-in and for-of loops,
- // as determined by declaration_kind.
- //
- static void MarkLoopVariableAsAssigned(
- Scope* scope, Variable* var,
- typename DeclarationDescriptor::Kind declaration_kind);
-
FunctionKind FunctionKindForImpl(bool is_method, ParseFunctionFlags flags) {
static const FunctionKind kFunctionKinds[][2][2] = {
{
@@ -1422,106 +1289,64 @@ class ParserBase {
return factory()->NewReturnStatement(expr, pos, end_pos);
}
- // Validation per ES6 object literals.
- class ObjectLiteralChecker {
- public:
- explicit ObjectLiteralChecker(ParserBase* parser)
- : parser_(parser), has_seen_proto_(false) {}
+ ModuleDescriptor* module() const {
+ return scope()->AsModuleScope()->module();
+ }
+ Scope* scope() const { return scope_; }
- void CheckDuplicateProto(Token::Value property);
+ // Stack of expression expression_scopes.
+ // The top of the stack is always pointed to by expression_scope().
+ V8_INLINE ExpressionScope* expression_scope() const {
+ DCHECK_NOT_NULL(expression_scope_);
+ return expression_scope_;
+ }
- private:
- bool IsProto() const {
- return this->scanner()->CurrentMatchesContextualEscaped(
- Token::PROTO_UNDERSCORED);
+ class AcceptINScope final {
+ public:
+ AcceptINScope(ParserBase* parser, bool accept_IN)
+ : parser_(parser), previous_accept_IN_(parser->accept_IN_) {
+ parser_->accept_IN_ = accept_IN;
}
- ParserBase* parser() const { return parser_; }
- Scanner* scanner() const { return parser_->scanner(); }
+ ~AcceptINScope() { parser_->accept_IN_ = previous_accept_IN_; }
+ private:
ParserBase* parser_;
- bool has_seen_proto_;
+ bool previous_accept_IN_;
};
- // Validation per ES6 class literals.
- class ClassLiteralChecker {
+ class ParameterParsingScope {
public:
- explicit ClassLiteralChecker(ParserBase* parser)
- : parser_(parser), has_seen_constructor_(false) {}
-
- void CheckClassMethodName(Token::Value property, ParsePropertyKind type,
- ParseFunctionFlags flags, bool is_static,
- bool* ok);
- void CheckClassFieldName(bool is_static, bool* ok);
-
- private:
- bool IsConstructor() {
- return this->scanner()->CurrentMatchesContextualEscaped(
- Token::CONSTRUCTOR);
- }
- bool IsPrivateConstructor() {
- return this->scanner()->CurrentMatchesContextualEscaped(
- Token::PRIVATE_CONSTRUCTOR);
- }
- bool IsPrototype() {
- return this->scanner()->CurrentMatchesContextualEscaped(Token::PROTOTYPE);
+ ParameterParsingScope(Impl* parser, FormalParametersT* parameters)
+ : parser_(parser), parent_parameters_(parser_->parameters_) {
+ parser_->parameters_ = parameters;
}
- ParserBase* parser() const { return parser_; }
- Scanner* scanner() const { return parser_->scanner(); }
+ ~ParameterParsingScope() { parser_->parameters_ = parent_parameters_; }
- ParserBase* parser_;
- bool has_seen_constructor_;
+ private:
+ Impl* parser_;
+ FormalParametersT* parent_parameters_;
};
- ModuleDescriptor* module() const {
- return scope()->AsModuleScope()->module();
- }
- Scope* scope() const { return scope_; }
-
- // Stack of expression classifiers.
- // The top of the stack is always pointed to by classifier().
- V8_INLINE ExpressionClassifier* classifier() const {
- DCHECK_NOT_NULL(classifier_);
- return classifier_;
- }
-
- // Accumulates the classifier that is on top of the stack (inner) to
- // the one that is right below (outer) and pops the inner.
- V8_INLINE void Accumulate(unsigned productions) {
- DCHECK_NOT_NULL(classifier_);
- ExpressionClassifier* previous = classifier_->previous();
- DCHECK_NOT_NULL(previous);
- previous->Accumulate(classifier_, productions);
- classifier_ = previous;
- }
+ class FunctionBodyParsingScope {
+ public:
+ explicit FunctionBodyParsingScope(Impl* parser)
+ : parser_(parser), expression_scope_(parser_->expression_scope_) {
+ parser_->expression_scope_ = nullptr;
+ }
- V8_INLINE void AccumulateNonBindingPatternErrors() {
- this->Accumulate(ExpressionClassifier::AllProductions &
- ~(ExpressionClassifier::BindingPatternProduction |
- ExpressionClassifier::LetPatternProduction));
- }
+ ~FunctionBodyParsingScope() {
+ parser_->expression_scope_ = expression_scope_;
+ }
- // Pops and discards the classifier that is on top of the stack
- // without accumulating.
- V8_INLINE void DiscardExpressionClassifier() {
- DCHECK_NOT_NULL(classifier_);
- classifier_->Discard();
- classifier_ = classifier_->previous();
- }
+ private:
+ Impl* parser_;
+ ExpressionScope* expression_scope_;
+ };
- // Accumulate errors that can be arbitrarily deep in an expression.
- // These correspond to the ECMAScript spec's 'Contains' operation
- // on productions. This includes:
- //
- // - YieldExpression is disallowed in arrow parameters in a generator.
- // - AwaitExpression is disallowed in arrow parameters in an async function.
- // - AwaitExpression is disallowed in async arrow parameters.
- //
- V8_INLINE void AccumulateFormalParameterContainmentErrors() {
- Accumulate(ExpressionClassifier::FormalParameterInitializerProduction |
- ExpressionClassifier::AsyncArrowFormalParametersProduction);
- }
+ std::vector<void*>* pointer_buffer() { return &pointer_buffer_; }
+ std::vector<void*>* variable_buffer() { return &variable_buffer_; }
// Parser base's protected field members.
@@ -1543,22 +1368,60 @@ class ParserBase {
private:
Zone* zone_;
- ExpressionClassifier* classifier_;
+ ExpressionScope* expression_scope_;
- Scanner* scanner_;
+ std::vector<void*> pointer_buffer_;
+ std::vector<void*> variable_buffer_;
- FunctionLiteral::EagerCompileHint default_eager_compile_hint_;
+ Scanner* scanner_;
int function_literal_id_;
int script_id_;
+ FunctionLiteral::EagerCompileHint default_eager_compile_hint_;
+
+ // This struct is used to move information about the next arrow function from
+ // the place where the arrow head was parsed to where the body will be parsed.
+ // Nothing can be parsed between the head and the body, so it will be consumed
+ // immediately after it's produced.
+ // Preallocating the struct as part of the parser minimizes the cost of
+ // supporting arrow functions on non-arrow expressions.
+ struct NextArrowFunctionInfo {
+ Scanner::Location strict_parameter_error_location =
+ Scanner::Location::invalid();
+ MessageTemplate strict_parameter_error_message = MessageTemplate::kNone;
+ DeclarationScope* scope = nullptr;
+
+ bool HasInitialState() const { return scope == nullptr; }
+
+ void Reset() {
+ scope = nullptr;
+ ClearStrictParameterError();
+ DCHECK(HasInitialState());
+ }
+
+ // Tracks strict-mode parameter violations of sloppy-mode arrow heads in
+ // case the function ends up becoming strict mode. Only one global place to
+ // track this is necessary since arrow functions with none-simple parameters
+ // cannot become strict-mode later on.
+ void ClearStrictParameterError() {
+ strict_parameter_error_location = Scanner::Location::invalid();
+ strict_parameter_error_message = MessageTemplate::kNone;
+ }
+ };
+
+ FormalParametersT* parameters_;
+ NextArrowFunctionInfo next_arrow_function_info_;
+
+ bool accept_IN_ = true;
+
bool allow_natives_;
- bool allow_harmony_do_expressions_;
bool allow_harmony_public_fields_;
bool allow_harmony_static_fields_;
bool allow_harmony_dynamic_import_;
bool allow_harmony_import_meta_;
bool allow_harmony_private_fields_;
+ bool allow_harmony_private_methods_;
bool allow_eval_cache_;
};
@@ -1572,8 +1435,6 @@ ParserBase<Impl>::FunctionState::FunctionState(
function_state_stack_(function_state_stack),
outer_function_state_(*function_state_stack),
scope_(scope),
- destructuring_assignments_to_rewrite_(scope->zone()),
- reported_errors_(16, scope->zone()),
dont_optimize_reason_(BailoutReason::kNoReason),
next_function_is_likely_called_(false),
previous_function_was_likely_called_(false),
@@ -1592,218 +1453,109 @@ ParserBase<Impl>::FunctionState::~FunctionState() {
}
template <typename Impl>
-void ParserBase<Impl>::GetUnexpectedTokenMessage(
- Token::Value token, MessageTemplate::Template* message,
- Scanner::Location* location, const char** arg,
- MessageTemplate::Template default_) {
- *arg = nullptr;
- switch (token) {
- case Token::EOS:
- *message = MessageTemplate::kUnexpectedEOS;
- break;
- case Token::SMI:
- case Token::NUMBER:
- case Token::BIGINT:
- *message = MessageTemplate::kUnexpectedTokenNumber;
- break;
- case Token::STRING:
- *message = MessageTemplate::kUnexpectedTokenString;
- break;
- case Token::PRIVATE_NAME:
- case Token::IDENTIFIER:
- *message = MessageTemplate::kUnexpectedTokenIdentifier;
- break;
- case Token::AWAIT:
- case Token::ENUM:
- *message = MessageTemplate::kUnexpectedReserved;
- 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;
- break;
- case Token::TEMPLATE_SPAN:
- case Token::TEMPLATE_TAIL:
- *message = MessageTemplate::kUnexpectedTemplateString;
- break;
- case Token::ESCAPED_STRICT_RESERVED_WORD:
- case Token::ESCAPED_KEYWORD:
- *message = MessageTemplate::kInvalidEscapedReservedWord;
- break;
- case Token::ILLEGAL:
- if (scanner()->has_error()) {
- *message = scanner()->error();
- *location = scanner()->error_location();
- } else {
- *message = MessageTemplate::kInvalidOrUnexpectedToken;
- }
- break;
- case Token::REGEXP_LITERAL:
- *message = MessageTemplate::kUnexpectedTokenRegExp;
- break;
- default:
- const char* name = Token::String(token);
- DCHECK_NOT_NULL(name);
- *arg = name;
- break;
- }
-}
-
-template <typename Impl>
void ParserBase<Impl>::ReportUnexpectedToken(Token::Value token) {
- return ReportUnexpectedTokenAt(scanner_->location(), token);
-}
-
-template <typename Impl>
-void ParserBase<Impl>::ReportUnexpectedTokenAt(
- Scanner::Location source_location, Token::Value token,
- MessageTemplate::Template message) {
- const char* arg;
- GetUnexpectedTokenMessage(token, &message, &source_location, &arg);
- impl()->ReportMessageAt(source_location, message, arg);
-}
-
-template <typename Impl>
-typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier(
- AllowRestrictedIdentifiers allow_restricted_identifiers, bool* ok) {
- ExpressionClassifier classifier(this);
- auto result = ParseAndClassifyIdentifier(CHECK_OK_CUSTOM(NullIdentifier));
-
- if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) {
- ValidateAssignmentPattern(CHECK_OK_CUSTOM(NullIdentifier));
- ValidateBindingPattern(CHECK_OK_CUSTOM(NullIdentifier));
- }
-
- return result;
+ return impl()->ReportUnexpectedTokenAt(scanner_->location(), token);
}
template <typename Impl>
typename ParserBase<Impl>::IdentifierT
-ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
- Token::Value next = Next();
+ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) {
+ DCHECK_EQ(scanner()->current_token(), next);
STATIC_ASSERT(Token::IDENTIFIER + 1 == Token::ASYNC);
- if (IsInRange(next, Token::IDENTIFIER, Token::ASYNC)) {
+ if (V8_LIKELY(IsInRange(next, Token::IDENTIFIER, Token::ASYNC))) {
IdentifierT name = impl()->GetSymbol();
-
- // 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 (impl()->IsEvalOrArguments(name)) {
- if (impl()->IsArguments(name) && scope()->ShouldBanArguments()) {
- ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer);
- *ok = false;
- return impl()->NullIdentifier();
- }
-
- classifier()->RecordStrictModeFormalParameterError(
- scanner()->location(), MessageTemplate::kStrictEvalArguments);
- if (is_strict(language_mode())) {
- classifier()->RecordBindingPatternError(
- scanner()->location(), MessageTemplate::kStrictEvalArguments);
- }
+ if (V8_UNLIKELY(impl()->IsArguments(name) &&
+ scope()->ShouldBanArguments())) {
+ ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer);
+ return impl()->EmptyIdentifierString();
}
+ return name;
+ }
- if (classifier()->duplicate_finder() != nullptr &&
- scanner()->IsDuplicateSymbol(classifier()->duplicate_finder(),
- ast_value_factory())) {
- classifier()->RecordDuplicateFormalParameterError(scanner()->location());
- }
+ if (!Token::IsValidIdentifier(next, language_mode(), is_generator(),
+ parsing_module_ || is_async_function())) {
+ ReportUnexpectedToken(next);
+ return impl()->EmptyIdentifierString();
+ }
- return name;
- } else if (next == Token::AWAIT && !parsing_module_ && !is_async_function()) {
- classifier()->RecordAsyncArrowFormalParametersError(
+ if (next == Token::AWAIT) {
+ expression_scope()->RecordAsyncArrowParametersError(
scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
return impl()->GetSymbol();
- } else if (is_sloppy(language_mode()) &&
- (Token::IsStrictReservedWord(next) ||
- (next == Token::YIELD && !is_generator()))) {
- classifier()->RecordStrictModeFormalParameterError(
- scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
- if (scanner()->IsLet()) {
- classifier()->RecordLetPatternError(
- scanner()->location(), MessageTemplate::kLetInLexicalBinding);
- }
- return impl()->GetSymbol();
- } else {
- ReportUnexpectedToken(next);
- *ok = false;
- return impl()->NullIdentifier();
}
+
+ DCHECK(Token::IsStrictReservedWord(next));
+ expression_scope()->RecordStrictModeParameterError(
+ scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
+ return impl()->GetSymbol();
}
template <class Impl>
-typename ParserBase<Impl>::IdentifierT
-ParserBase<Impl>::ParseIdentifierOrStrictReservedWord(
- FunctionKind function_kind, bool* is_strict_reserved, bool* is_await,
- bool* ok) {
+typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier(
+ FunctionKind function_kind) {
Token::Value next = Next();
- if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_ &&
- !IsAsyncFunction(function_kind)) ||
- next == Token::ASYNC) {
- *is_strict_reserved = false;
- *is_await = next == Token::AWAIT;
- } else if (Token::IsStrictReservedWord(next) ||
- (next == Token::YIELD && !IsGeneratorFunction(function_kind))) {
- *is_strict_reserved = true;
- } else {
+
+ if (!Token::IsValidIdentifier(
+ next, language_mode(), IsGeneratorFunction(function_kind),
+ parsing_module_ || IsAsyncFunction(function_kind))) {
ReportUnexpectedToken(next);
- *ok = false;
- return impl()->NullIdentifier();
+ return impl()->EmptyIdentifierString();
}
return impl()->GetSymbol();
}
template <typename Impl>
-typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifierName(
- bool* ok) {
- Token::Value next = Next();
- if (!Token::IsAnyIdentifier(next) && next != Token::ESCAPED_KEYWORD &&
- !Token::IsKeyword(next)) {
- ReportUnexpectedToken(next);
- *ok = false;
- return impl()->NullIdentifier();
+typename ParserBase<Impl>::IdentifierT
+ParserBase<Impl>::ParseNonRestrictedIdentifier() {
+ IdentifierT result = ParseIdentifier();
+
+ if (is_strict(language_mode()) &&
+ V8_UNLIKELY(impl()->IsEvalOrArguments(result))) {
+ impl()->ReportMessageAt(scanner()->location(),
+ MessageTemplate::kStrictEvalArguments);
}
- return impl()->GetSymbol();
+ return result;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParsePropertyName() {
+ Token::Value next = Next();
+ if (V8_LIKELY(Token::IsPropertyName(next))) return impl()->GetSymbol();
+
+ ReportUnexpectedToken(next);
+ return impl()->EmptyIdentifierString();
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseIdentifierNameOrPrivateName(bool* ok) {
+ParserBase<Impl>::ParsePropertyOrPrivatePropertyName() {
int pos = position();
IdentifierT name;
ExpressionT key;
- if (allow_harmony_private_fields() && peek() == Token::PRIVATE_NAME) {
- Consume(Token::PRIVATE_NAME);
+ Token::Value next = Next();
+ if (V8_LIKELY(Token::IsPropertyName(next))) {
name = impl()->GetSymbol();
- auto key_proxy =
- impl()->ExpressionFromIdentifier(name, pos, InferName::kNo);
- key_proxy->set_is_private_field();
- key = key_proxy;
- } else {
- name = ParseIdentifierName(CHECK_OK);
key = factory()->NewStringLiteral(name, pos);
+ } else if (allow_harmony_private_fields() && next == Token::PRIVATE_NAME) {
+ name = impl()->GetSymbol();
+ key = impl()->ExpressionFromIdentifier(name, pos, InferName::kNo);
+ } else {
+ ReportUnexpectedToken(next);
+ return impl()->FailureExpression();
}
impl()->PushLiteralName(name);
return key;
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral() {
int pos = peek_position();
if (!scanner()->ScanRegExpPattern()) {
Next();
ReportMessage(MessageTemplate::kUnterminatedRegExp);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
IdentifierT js_pattern = impl()->GetNextSymbol();
@@ -1811,8 +1563,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
if (flags.IsNothing()) {
Next();
ReportMessage(MessageTemplate::kMalformedRegExpFlags);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
int js_flags = flags.FromJust();
Next();
@@ -1820,8 +1571,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern() {
// Pattern ::
// Identifier
// ArrayLiteral
@@ -1832,29 +1582,35 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern(
ExpressionT result;
if (Token::IsAnyIdentifier(token)) {
- IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
- result = impl()->ExpressionFromIdentifier(name, beg_pos);
- } else {
- classifier()->RecordNonSimpleParameter();
-
- if (token == Token::LBRACK) {
- result = ParseArrayLiteral(CHECK_OK);
- } else if (token == Token::LBRACE) {
- result = ParseObjectLiteral(CHECK_OK);
- } else {
- ReportUnexpectedToken(Next());
- *ok = false;
- return impl()->NullExpression();
+ IdentifierT name = ParseAndClassifyIdentifier(Next());
+ if (V8_UNLIKELY(is_strict(language_mode()) &&
+ impl()->IsEvalOrArguments(name))) {
+ impl()->ReportMessageAt(scanner()->location(),
+ MessageTemplate::kStrictEvalArguments);
+ return impl()->FailureExpression();
}
+ return impl()->ExpressionFromIdentifier(name, beg_pos);
+ }
+
+ CheckStackOverflow();
+
+ if (token == Token::LBRACK) {
+ result = ParseArrayLiteral();
+ } else if (token == Token::LBRACE) {
+ result = ParseObjectLiteral();
+ } else {
+ ReportUnexpectedToken(Next());
+ return impl()->FailureExpression();
}
- ValidateBindingPattern(CHECK_OK);
return result;
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
- bool* is_async, bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParsePrimaryExpression() {
+ CheckStackOverflow();
+
// PrimaryExpression ::
// 'this'
// 'null'
@@ -1874,136 +1630,115 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
int beg_pos = peek_position();
Token::Value token = peek();
- switch (token) {
- case Token::THIS: {
- BindingPatternUnexpectedToken();
- Consume(Token::THIS);
- return impl()->ThisExpression(beg_pos);
+
+ if (Token::IsAnyIdentifier(token)) {
+ Consume(token);
+
+ FunctionKind kind = FunctionKind::kArrowFunction;
+
+ if (V8_UNLIKELY(token == Token::ASYNC &&
+ !scanner()->HasLineTerminatorBeforeNext())) {
+ // async function ...
+ if (peek() == Token::FUNCTION) return ParseAsyncFunctionLiteral();
+
+ // async Identifier => ...
+ if (peek_any_identifier() && PeekAhead() == Token::ARROW) {
+ token = Next();
+ beg_pos = position();
+ kind = FunctionKind::kAsyncArrowFunction;
+ }
}
- case Token::NULL_LITERAL:
- case Token::TRUE_LITERAL:
- case Token::FALSE_LITERAL:
- case Token::SMI:
- case Token::NUMBER:
- case Token::BIGINT: {
- // Ensure continuous enum range.
- DCHECK(Token::IsLiteral(token));
- BindingPatternUnexpectedToken();
- return impl()->ExpressionFromLiteral(Next(), beg_pos);
- }
- case Token::STRING: {
- DCHECK(Token::IsLiteral(token));
- BindingPatternUnexpectedToken();
- Consume(Token::STRING);
- return impl()->ExpressionFromString(beg_pos);
+ if (V8_UNLIKELY(peek() == Token::ARROW)) {
+ ArrowHeadParsingScope parsing_scope(impl(), kind);
+ IdentifierT name = ParseAndClassifyIdentifier(token);
+ ClassifyParameter(name, beg_pos, end_position());
+ ExpressionT result =
+ impl()->ExpressionFromIdentifier(name, beg_pos, InferName::kNo);
+ next_arrow_function_info_.scope = parsing_scope.ValidateAndCreateScope();
+ return result;
}
- case Token::ASYNC:
- if (!scanner()->HasLineTerminatorAfterNext() &&
- PeekAhead() == Token::FUNCTION) {
- BindingPatternUnexpectedToken();
- Consume(Token::ASYNC);
- return ParseAsyncFunctionLiteral(ok);
- }
- // CoverCallExpressionAndAsyncArrowHead
- *is_async = true;
- V8_FALLTHROUGH;
- case Token::IDENTIFIER:
- case Token::LET:
- case Token::STATIC:
- case Token::YIELD:
- case Token::AWAIT:
- case Token::FUTURE_STRICT_RESERVED_WORD:
- case Token::ESCAPED_STRICT_RESERVED_WORD: {
- // Ensure continuous enum range.
- DCHECK(IsInRange(token, Token::IDENTIFIER,
- Token::ESCAPED_STRICT_RESERVED_WORD));
- // Using eval or arguments in this context is OK even in strict mode.
- IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
- return impl()->ExpressionFromIdentifier(name, beg_pos);
+ IdentifierT name = ParseAndClassifyIdentifier(token);
+ return impl()->ExpressionFromIdentifier(name, beg_pos);
+ }
+
+ if (Token::IsLiteral(token)) {
+ return impl()->ExpressionFromLiteral(Next(), beg_pos);
+ }
+
+ switch (token) {
+ case Token::THIS: {
+ Consume(Token::THIS);
+ return impl()->ThisExpression(beg_pos);
}
case Token::ASSIGN_DIV:
case Token::DIV:
- classifier()->RecordBindingPatternError(
- scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp);
- return ParseRegExpLiteral(ok);
+ return ParseRegExpLiteral();
case Token::LBRACK:
- return ParseArrayLiteral(ok);
+ return ParseArrayLiteral();
case Token::LBRACE:
- return ParseObjectLiteral(ok);
+ return ParseObjectLiteral();
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.
- bool pattern_error = !classifier()->is_valid_binding_pattern();
- classifier()->RecordPatternError(scanner()->peek_location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::LPAREN));
- if (pattern_error) ArrowFormalParametersUnexpectedToken();
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));
+ // ()=>x. The continuation that consumes the => is in
+ // ParseAssignmentExpressionCoverGrammar.
+ if (peek() != Token::ARROW) ReportUnexpectedToken(Token::RPAREN);
+ next_arrow_function_info_.scope =
+ NewFunctionScope(FunctionKind::kArrowFunction);
return factory()->NewEmptyParentheses(beg_pos);
}
+ Scope::Snapshot scope_snapshot(scope());
+ ArrowHeadParsingScope maybe_arrow(impl(), FunctionKind::kArrowFunction);
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
if (peek() == Token::FUNCTION ||
(peek() == Token::ASYNC && PeekAhead() == Token::FUNCTION)) {
function_state_->set_next_function_is_likely_called();
}
- ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK);
- Expect(Token::RPAREN, ok);
+ AcceptINScope scope(this, true);
+ ExpressionT expr = ParseExpressionCoverGrammar();
+ expr->mark_parenthesized();
+ Expect(Token::RPAREN);
+
+ if (peek() == Token::ARROW) {
+ next_arrow_function_info_.scope = maybe_arrow.ValidateAndCreateScope();
+ scope_snapshot.Reparent(next_arrow_function_info_.scope);
+ } else {
+ maybe_arrow.ValidateExpression();
+ }
+
return expr;
}
case Token::CLASS: {
- BindingPatternUnexpectedToken();
Consume(Token::CLASS);
int class_token_pos = position();
IdentifierT name = impl()->NullIdentifier();
bool is_strict_reserved_name = false;
Scanner::Location class_name_location = Scanner::Location::invalid();
if (peek_any_identifier()) {
- bool is_await = false;
- name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
- &is_await, CHECK_OK);
+ name = ParseAndClassifyIdentifier(Next());
class_name_location = scanner()->location();
- if (is_await) {
- classifier()->RecordAsyncArrowFormalParametersError(
- scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
- }
+ is_strict_reserved_name =
+ Token::IsStrictReservedWord(scanner()->current_token());
}
return ParseClassLiteral(name, class_name_location,
- is_strict_reserved_name, class_token_pos, ok);
+ is_strict_reserved_name, class_token_pos);
}
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL:
- BindingPatternUnexpectedToken();
- return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false, ok);
+ return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false);
case Token::MOD:
if (allow_natives() || extension_ != nullptr) {
- BindingPatternUnexpectedToken();
- return ParseV8Intrinsic(ok);
- }
- break;
-
- case Token::DO:
- if (allow_harmony_do_expressions()) {
- BindingPatternUnexpectedToken();
- return ParseDoExpression(ok);
+ return ParseV8Intrinsic();
}
break;
@@ -2012,72 +1747,49 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
}
ReportUnexpectedToken(Next());
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
- bool* ok) {
- ExpressionClassifier classifier(this);
- ExpressionT result = ParseExpressionCoverGrammar(true, CHECK_OK);
- ValidateExpression(ok);
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression() {
+ ExpressionParsingScope expression_scope(impl());
+ AcceptINScope scope(this, true);
+ ExpressionT result = ParseExpressionCoverGrammar();
+ expression_scope.ValidateExpression();
return result;
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) {
+ParserBase<Impl>::ParseAssignmentExpression() {
+ ExpressionParsingScope expression_scope(impl());
+ ExpressionT result = ParseAssignmentExpressionCoverGrammar();
+ expression_scope.ValidateExpression();
+ return result;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseExpressionCoverGrammar() {
// Expression ::
// AssignmentExpression
// Expression ',' AssignmentExpression
- ExpressionT result = impl()->NullExpression();
+ ExpressionListT list(pointer_buffer());
+ ExpressionT expression;
+ AccumulationScope accumulation_scope(expression_scope());
while (true) {
- int comma_pos = position();
- ExpressionClassifier binding_classifier(this);
- ExpressionT right;
- if (Check(Token::ELLIPSIS)) {
- // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
- // as the formal parameters of'(x, y, ...z) => foo', and is not itself a
- // valid expression.
- classifier()->RecordExpressionError(scanner()->location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::ELLIPSIS));
- int ellipsis_pos = position();
- int pattern_pos = peek_position();
- ExpressionT pattern = ParseBindingPattern(CHECK_OK);
- if (peek() == Token::ASSIGN) {
- ReportMessage(MessageTemplate::kRestDefaultInitializer);
- *ok = false;
- return result;
- }
- right = factory()->NewSpread(pattern, ellipsis_pos, pattern_pos);
- } else {
- right = ParseAssignmentExpression(accept_IN, CHECK_OK);
- }
- // No need to accumulate binding pattern-related errors, since
- // an Expression can't be a binding pattern anyway.
- AccumulateNonBindingPatternErrors();
- if (!impl()->IsIdentifier(right)) classifier()->RecordNonSimpleParameter();
- if (impl()->IsNull(result)) {
- // First time through the loop.
- result = right;
- } else if (impl()->CollapseNaryExpression(&result, right, Token::COMMA,
- comma_pos,
- SourceRange::Empty())) {
- // Do nothing, "result" is already updated.
- } else {
- result =
- factory()->NewBinaryOperation(Token::COMMA, result, right, comma_pos);
+ if (V8_UNLIKELY(peek() == Token::ELLIPSIS)) {
+ return ParseArrowParametersWithRest(&list, &accumulation_scope);
}
- if (!Check(Token::COMMA)) break;
+ int expr_pos = peek_position();
+ expression = ParseAssignmentExpressionCoverGrammar();
- if (right->IsSpread()) {
- classifier()->RecordArrowFormalParametersError(
- scanner()->location(), MessageTemplate::kParamAfterRest);
- }
+ ClassifyArrowParameter(&accumulation_scope, expr_pos, expression);
+ list.Add(expression);
+
+ if (!Check(Token::COMMA)) break;
if (peek() == Token::RPAREN && PeekAhead() == Token::ARROW) {
// a trailing comma is allowed at the end of an arrow parameter list
@@ -2092,19 +1804,64 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) {
}
}
- return result;
+ // Return the single element if the list is empty. We need to do this because
+ // callers of this function care about the type of the result if there was
+ // only a single assignment expression. The preparser would lose this
+ // information otherwise.
+ if (list.length() == 1) return expression;
+ return impl()->ExpressionListToExpression(list);
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseArrowParametersWithRest(
+ typename ParserBase<Impl>::ExpressionListT* list,
+ AccumulationScope* accumulation_scope) {
+ Consume(Token::ELLIPSIS);
+
+ Scanner::Location ellipsis = scanner()->location();
+ int pattern_pos = peek_position();
+ ExpressionT pattern = ParseBindingPattern();
+ ClassifyArrowParameter(accumulation_scope, pattern_pos, pattern);
+
+ expression_scope()->RecordNonSimpleParameter();
+
+ if (V8_UNLIKELY(peek() == Token::ASSIGN)) {
+ ReportMessage(MessageTemplate::kRestDefaultInitializer);
+ return impl()->FailureExpression();
+ }
+
+ ExpressionT spread =
+ factory()->NewSpread(pattern, ellipsis.beg_pos, pattern_pos);
+ if (V8_UNLIKELY(peek() == Token::COMMA)) {
+ ReportMessage(MessageTemplate::kParamAfterRest);
+ return impl()->FailureExpression();
+ }
+
+ // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
+ // as the formal parameters of'(x, y, ...z) => foo', and is not itself a
+ // valid expression.
+ if (peek() != Token::RPAREN || PeekAhead() != Token::ARROW) {
+ impl()->ReportUnexpectedTokenAt(ellipsis, Token::ELLIPSIS);
+ return impl()->FailureExpression();
+ }
+
+ list->Add(spread);
+ return impl()->ExpressionListToExpression(*list);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral() {
// ArrayLiteral ::
// '[' Expression? (',' Expression?)* ']'
int pos = peek_position();
- ExpressionListT values = impl()->NewExpressionList(4);
+ ExpressionListT values(pointer_buffer());
int first_spread_index = -1;
Consume(Token::LBRACK);
+
+ AccumulationScope accumulation_scope(expression_scope());
+
while (!Check(Token::RBRACK)) {
ExpressionT elem;
if (peek() == Token::COMMA) {
@@ -2112,115 +1869,80 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
} else if (Check(Token::ELLIPSIS)) {
int start_pos = position();
int expr_pos = peek_position();
- ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK);
+ AcceptINScope scope(this, true);
+ ExpressionT argument =
+ ParsePossibleDestructuringSubPattern(&accumulation_scope);
elem = factory()->NewSpread(argument, start_pos, expr_pos);
if (first_spread_index < 0) {
- first_spread_index = values->length();
+ first_spread_index = values.length();
}
if (argument->IsAssignment()) {
- classifier()->RecordPatternError(
+ expression_scope()->RecordPatternError(
Scanner::Location(start_pos, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
- } else {
- CheckDestructuringElement(argument, start_pos, end_position());
}
if (peek() == Token::COMMA) {
- classifier()->RecordPatternError(
+ expression_scope()->RecordPatternError(
Scanner::Location(start_pos, end_position()),
MessageTemplate::kElementAfterRest);
}
} else {
- int beg_pos = peek_position();
- elem = ParseAssignmentExpression(true, CHECK_OK);
- CheckDestructuringElement(elem, beg_pos, end_position());
+ AcceptINScope scope(this, true);
+ elem = ParsePossibleDestructuringSubPattern(&accumulation_scope);
}
- values->Add(elem, zone_);
+ values.Add(elem);
if (peek() != Token::RBRACK) {
- Expect(Token::COMMA, CHECK_OK);
+ Expect(Token::COMMA);
+ if (elem->IsFailureExpression()) return elem;
}
}
return factory()->NewArrayLiteral(values, first_spread_index, pos);
}
-inline bool ParsePropertyKindFromToken(Token::Value token,
- ParsePropertyKind* kind) {
- // This returns true, setting the property kind, iff the given token is one
- // which must occur after a property name, indicating that the previous token
- // was in fact a name and not a modifier (like the "get" in "get x").
- switch (token) {
- case Token::COLON:
- *kind = ParsePropertyKind::kValue;
- return true;
- case Token::COMMA:
- case Token::RBRACE:
- case Token::ASSIGN:
- *kind = ParsePropertyKind::kShorthand;
- return true;
- case Token::LPAREN:
- *kind = ParsePropertyKind::kMethod;
- return true;
- case Token::MUL:
- case Token::SEMICOLON:
- *kind = ParsePropertyKind::kClassField;
- return true;
- case Token::PRIVATE_NAME:
- *kind = ParsePropertyKind::kClassField;
- return true;
- default:
- break;
- }
- return false;
-}
-
-inline bool ParseAsAccessor(Token::Value token, Token::Value contextual_token,
- ParsePropertyKind* kind) {
- if (ParsePropertyKindFromToken(token, kind)) return false;
-
- if (contextual_token == Token::GET) {
- *kind = ParsePropertyKind::kAccessorGetter;
- } else if (contextual_token == Token::SET) {
- *kind = ParsePropertyKind::kAccessorSetter;
- } else {
- return false;
- }
-
- return true;
-}
-
template <class Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
- IdentifierT* name, ParsePropertyKind* kind, ParseFunctionFlags* flags,
- bool* is_computed_name, bool* ok) {
- DCHECK_EQ(ParsePropertyKind::kNotSet, *kind);
- DCHECK_EQ(*flags, ParseFunctionFlag::kIsNormal);
- DCHECK(!*is_computed_name);
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty(
+ ParsePropertyInfo* prop_info) {
+ DCHECK_EQ(prop_info->kind, ParsePropertyKind::kNotSet);
+ DCHECK_EQ(prop_info->function_flags, ParseFunctionFlag::kIsNormal);
+ DCHECK(!prop_info->is_computed_name);
if (Check(Token::ASYNC)) {
Token::Value token = peek();
- if ((token != Token::MUL && ParsePropertyKindFromToken(token, kind)) ||
+ if ((token != Token::MUL && prop_info->ParsePropertyKindFromToken(token)) ||
scanner()->HasLineTerminatorBeforeNext()) {
- *name = impl()->GetSymbol();
- impl()->PushLiteralName(*name);
- return factory()->NewStringLiteral(*name, position());
+ prop_info->name = impl()->GetSymbol();
+ impl()->PushLiteralName(prop_info->name);
+ return factory()->NewStringLiteral(prop_info->name, position());
}
- *flags = ParseFunctionFlag::kIsAsync;
- *kind = ParsePropertyKind::kMethod;
+ prop_info->function_flags = ParseFunctionFlag::kIsAsync;
+ prop_info->kind = ParsePropertyKind::kMethod;
}
if (Check(Token::MUL)) {
- *flags |= ParseFunctionFlag::kIsGenerator;
- *kind = ParsePropertyKind::kMethod;
- }
-
- if (*kind == ParsePropertyKind::kNotSet && Check(Token::IDENTIFIER) &&
- !ParseAsAccessor(peek(), scanner()->current_contextual_token(), kind)) {
- *name = impl()->GetSymbol();
- impl()->PushLiteralName(*name);
- return factory()->NewStringLiteral(*name, position());
+ prop_info->function_flags |= ParseFunctionFlag::kIsGenerator;
+ prop_info->kind = ParsePropertyKind::kMethod;
+ }
+
+ if (prop_info->kind == ParsePropertyKind::kNotSet &&
+ Check(Token::IDENTIFIER)) {
+ IdentifierT symbol = impl()->GetSymbol();
+ if (!prop_info->ParsePropertyKindFromToken(peek())) {
+ if (impl()->IdentifierEquals(symbol, ast_value_factory()->get_string())) {
+ prop_info->kind = ParsePropertyKind::kAccessorGetter;
+ } else if (impl()->IdentifierEquals(symbol,
+ ast_value_factory()->set_string())) {
+ prop_info->kind = ParsePropertyKind::kAccessorSetter;
+ }
+ }
+ if (!IsAccessor(prop_info->kind)) {
+ prop_info->name = symbol;
+ impl()->PushLiteralName(prop_info->name);
+ return factory()->NewStringLiteral(prop_info->name, position());
+ }
}
int pos = peek_position();
@@ -2237,10 +1959,27 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
bool is_array_index;
uint32_t index;
switch (peek()) {
+ case Token::PRIVATE_NAME:
+ prop_info->is_private = true;
+ is_array_index = false;
+ Consume(Token::PRIVATE_NAME);
+ if (prop_info->kind == ParsePropertyKind::kNotSet) {
+ prop_info->ParsePropertyKindFromToken(peek());
+ }
+ prop_info->name = impl()->GetSymbol();
+ if (prop_info->position == PropertyPosition::kObjectLiteral ||
+ (!allow_harmony_private_methods() &&
+ (IsAccessor(prop_info->kind) ||
+ prop_info->kind == ParsePropertyKind::kMethod))) {
+ ReportUnexpectedToken(Next());
+ return impl()->FailureExpression();
+ }
+ break;
+
case Token::STRING:
Consume(Token::STRING);
- *name = impl()->GetSymbol();
- is_array_index = impl()->IsArrayIndex(*name, &index);
+ prop_info->name = impl()->GetSymbol();
+ is_array_index = impl()->IsArrayIndex(prop_info->name, &index);
break;
case Token::SMI:
@@ -2248,82 +1987,76 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
index = scanner()->smi_value();
is_array_index = true;
// Token::SMI were scanned from their canonical representation.
- *name = impl()->GetSymbol();
+ prop_info->name = impl()->GetSymbol();
break;
case Token::NUMBER: {
Consume(Token::NUMBER);
- *name = impl()->GetNumberAsSymbol();
- is_array_index = impl()->IsArrayIndex(*name, &index);
+ prop_info->name = impl()->GetNumberAsSymbol();
+ is_array_index = impl()->IsArrayIndex(prop_info->name, &index);
break;
}
case Token::LBRACK: {
- *name = impl()->NullIdentifier();
- *is_computed_name = true;
+ prop_info->name = impl()->NullIdentifier();
+ prop_info->is_computed_name = true;
Consume(Token::LBRACK);
- ExpressionClassifier computed_name_classifier(this);
- ExpressionT expression = ParseAssignmentExpression(true, CHECK_OK);
- ValidateExpression(CHECK_OK);
- AccumulateFormalParameterContainmentErrors();
- Expect(Token::RBRACK, CHECK_OK);
- if (*kind == ParsePropertyKind::kNotSet) {
- ParsePropertyKindFromToken(peek(), kind);
+ AcceptINScope scope(this, true);
+ ExpressionT expression = ParseAssignmentExpression();
+ Expect(Token::RBRACK);
+ if (prop_info->kind == ParsePropertyKind::kNotSet) {
+ prop_info->ParsePropertyKindFromToken(peek());
}
return expression;
}
case Token::ELLIPSIS:
- if (*kind == ParsePropertyKind::kNotSet) {
- *name = impl()->NullIdentifier();
+ if (prop_info->kind == ParsePropertyKind::kNotSet) {
+ prop_info->name = impl()->NullIdentifier();
Consume(Token::ELLIPSIS);
- ExpressionT expression = ParseAssignmentExpression(true, CHECK_OK);
- *kind = ParsePropertyKind::kSpread;
-
- if (!impl()->IsIdentifier(expression)) {
- classifier()->RecordBindingPatternError(
- scanner()->location(),
+ AcceptINScope scope(this, true);
+ int start_pos = peek_position();
+ ExpressionT expression =
+ ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope);
+ prop_info->kind = ParsePropertyKind::kSpread;
+
+ if (!IsValidReferenceExpression(expression)) {
+ expression_scope()->RecordDeclarationError(
+ Scanner::Location(start_pos, end_position()),
MessageTemplate::kInvalidRestBindingPattern);
- }
-
- if (!expression->IsValidReferenceExpression()) {
- classifier()->RecordAssignmentPatternError(
- scanner()->location(),
+ expression_scope()->RecordPatternError(
+ Scanner::Location(start_pos, end_position()),
MessageTemplate::kInvalidRestAssignmentPattern);
}
if (peek() != Token::RBRACE) {
- classifier()->RecordPatternError(scanner()->location(),
- MessageTemplate::kElementAfterRest);
+ expression_scope()->RecordPatternError(
+ scanner()->location(), MessageTemplate::kElementAfterRest);
}
return expression;
}
V8_FALLTHROUGH;
default:
- *name = ParseIdentifierName(CHECK_OK);
+ prop_info->name = ParsePropertyName();
is_array_index = false;
break;
}
- if (*kind == ParsePropertyKind::kNotSet) {
- ParsePropertyKindFromToken(peek(), kind);
+ if (prop_info->kind == ParsePropertyKind::kNotSet) {
+ prop_info->ParsePropertyKindFromToken(peek());
}
- impl()->PushLiteralName(*name);
+ impl()->PushLiteralName(prop_info->name);
return is_array_index ? factory()->NewNumberLiteral(index, pos)
- : factory()->NewStringLiteral(*name, pos);
+ : factory()->NewStringLiteral(prop_info->name, pos);
}
template <typename Impl>
typename ParserBase<Impl>::ClassLiteralPropertyT
-ParserBase<Impl>::ParseClassPropertyDefinition(
- ClassLiteralChecker* checker, ClassInfo* class_info, IdentifierT* name,
- bool has_extends, bool* is_computed_name,
- ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok) {
+ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
+ ParsePropertyInfo* prop_info,
+ bool has_extends) {
DCHECK_NOT_NULL(class_info);
- ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal;
- *is_static = false;
- *property_kind = ClassLiteralProperty::METHOD;
- ParsePropertyKind kind = ParsePropertyKind::kNotSet;
+ DCHECK_EQ(prop_info->position, PropertyPosition::kClassLiteral);
Token::Value name_token = peek();
DCHECK_IMPLIES(name_token == Token::PRIVATE_NAME,
@@ -2331,48 +2064,39 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
int property_beg_pos = scanner()->peek_location().beg_pos;
int name_token_position = property_beg_pos;
- *name = impl()->NullIdentifier();
ExpressionT name_expression;
if (name_token == Token::STATIC) {
Consume(Token::STATIC);
name_token_position = scanner()->peek_location().beg_pos;
if (peek() == Token::LPAREN) {
- kind = ParsePropertyKind::kMethod;
- *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
- name_expression = factory()->NewStringLiteral(*name, position());
+ prop_info->kind = ParsePropertyKind::kMethod;
+ // TODO(bakkot) specialize on 'static'
+ prop_info->name = impl()->GetSymbol();
+ name_expression =
+ factory()->NewStringLiteral(prop_info->name, position());
} else if (peek() == Token::ASSIGN || peek() == Token::SEMICOLON ||
peek() == Token::RBRACE) {
- *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
- name_expression = factory()->NewStringLiteral(*name, position());
- } else if (peek() == Token::PRIVATE_NAME) {
- DCHECK(allow_harmony_private_fields());
- // TODO(gsathya): Make a better error message for this.
- ReportUnexpectedToken(Next());
- *ok = false;
- return impl()->NullLiteralProperty();
- } else {
- *is_static = true;
+ // TODO(bakkot) specialize on 'static'
+ prop_info->name = impl()->GetSymbol();
name_expression =
- ParsePropertyName(name, &kind, &function_flags, is_computed_name,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ factory()->NewStringLiteral(prop_info->name, position());
+ } else {
+ prop_info->is_static = true;
+ name_expression = ParseProperty(prop_info);
}
- } else if (name_token == Token::PRIVATE_NAME) {
- Consume(Token::PRIVATE_NAME);
- *name = impl()->GetSymbol();
- name_expression = factory()->NewStringLiteral(*name, position());
} else {
- name_expression =
- ParsePropertyName(name, &kind, &function_flags, is_computed_name,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ name_expression = ParseProperty(prop_info);
}
- if (!class_info->has_name_static_property && *is_static &&
- impl()->IsName(*name)) {
+ if (!class_info->has_name_static_property && prop_info->is_static &&
+ impl()->IsName(prop_info->name)) {
class_info->has_name_static_property = true;
}
- switch (kind) {
+ switch (prop_info->kind) {
+ case ParsePropertyKind::kAssign:
case ParsePropertyKind::kClassField:
+ case ParsePropertyKind::kShorthandOrClassField:
case ParsePropertyKind::kNotSet: // This case is a name followed by a name
// or other property. Here we have to
// assume that's an uninitialized field
@@ -2381,34 +2105,33 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
// semicolon. If not, there will be a
// syntax error after parsing the first
// name as an uninitialized field.
- case ParsePropertyKind::kShorthand:
- case ParsePropertyKind::kValue:
if (allow_harmony_public_fields() || allow_harmony_private_fields()) {
- *property_kind = name_token == Token::PRIVATE_NAME
- ? ClassLiteralProperty::PRIVATE_FIELD
- : ClassLiteralProperty::PUBLIC_FIELD;
- if (*is_static && !allow_harmony_static_fields()) {
+ prop_info->kind = ParsePropertyKind::kClassField;
+ DCHECK_IMPLIES(prop_info->is_computed_name, !prop_info->is_private);
+
+ if (prop_info->is_static && !allow_harmony_static_fields()) {
ReportUnexpectedToken(Next());
- *ok = false;
return impl()->NullLiteralProperty();
}
- if (!*is_computed_name) {
- checker->CheckClassFieldName(*is_static,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+
+ if (!prop_info->is_computed_name) {
+ CheckClassFieldName(prop_info->name, prop_info->is_static);
}
- ExpressionT initializer =
- ParseClassFieldInitializer(class_info, property_beg_pos, *is_static,
- CHECK_OK_CUSTOM(NullLiteralProperty));
- ExpectSemicolon(CHECK_OK_CUSTOM(NullLiteralProperty));
+
+ ExpressionT initializer = ParseMemberInitializer(
+ class_info, property_beg_pos, prop_info->is_static);
+ ExpectSemicolon();
+
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
- name_expression, initializer, *property_kind, *is_static,
- *is_computed_name);
- impl()->SetFunctionNameFromPropertyName(result, *name);
+ name_expression, initializer, ClassLiteralProperty::FIELD,
+ prop_info->is_static, prop_info->is_computed_name,
+ prop_info->is_private);
+ impl()->SetFunctionNameFromPropertyName(result, prop_info->name);
+
return result;
} else {
ReportUnexpectedToken(Next());
- *ok = false;
return impl()->NullLiteralProperty();
}
@@ -2421,89 +2144,89 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
// async '*' PropertyName '(' StrictFormalParameters ')'
// '{' FunctionBody '}'
- if (!*is_computed_name) {
- checker->CheckClassMethodName(name_token, ParsePropertyKind::kMethod,
- function_flags, *is_static,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ if (!prop_info->is_computed_name) {
+ CheckClassMethodName(prop_info->name, ParsePropertyKind::kMethod,
+ prop_info->function_flags, prop_info->is_static,
+ &class_info->has_seen_constructor);
}
- FunctionKind kind = MethodKindFor(function_flags);
+ FunctionKind kind = MethodKindFor(prop_info->function_flags);
- if (!*is_static && impl()->IsConstructor(*name)) {
+ if (!prop_info->is_static && impl()->IsConstructor(prop_info->name)) {
class_info->has_seen_constructor = true;
kind = has_extends ? FunctionKind::kDerivedConstructor
: FunctionKind::kBaseConstructor;
}
ExpressionT value = impl()->ParseFunctionLiteral(
- *name, scanner()->location(), kSkipFunctionNameCheck, kind,
+ prop_info->name, scanner()->location(), kSkipFunctionNameCheck, kind,
name_token_position, FunctionLiteral::kAccessorOrMethod,
- language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
+ language_mode(), nullptr);
- *property_kind = ClassLiteralProperty::METHOD;
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
- name_expression, value, *property_kind, *is_static,
- *is_computed_name);
- impl()->SetFunctionNameFromPropertyName(result, *name);
+ name_expression, value, ClassLiteralProperty::METHOD,
+ prop_info->is_static, prop_info->is_computed_name,
+ prop_info->is_private);
+ impl()->SetFunctionNameFromPropertyName(result, prop_info->name);
return result;
}
case ParsePropertyKind::kAccessorGetter:
case ParsePropertyKind::kAccessorSetter: {
- DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
- bool is_get = kind == ParsePropertyKind::kAccessorGetter;
+ DCHECK_EQ(prop_info->function_flags, ParseFunctionFlag::kIsNormal);
+ bool is_get = prop_info->kind == ParsePropertyKind::kAccessorGetter;
- if (!*is_computed_name) {
- checker->CheckClassMethodName(name_token, kind,
- ParseFunctionFlag::kIsNormal, *is_static,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ if (!prop_info->is_computed_name) {
+ CheckClassMethodName(prop_info->name, prop_info->kind,
+ ParseFunctionFlag::kIsNormal, prop_info->is_static,
+ &class_info->has_seen_constructor);
// 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.
- name_expression =
- factory()->NewStringLiteral(*name, name_expression->position());
+ name_expression = factory()->NewStringLiteral(
+ prop_info->name, name_expression->position());
}
FunctionKind kind = is_get ? FunctionKind::kGetterFunction
: FunctionKind::kSetterFunction;
FunctionLiteralT value = impl()->ParseFunctionLiteral(
- *name, scanner()->location(), kSkipFunctionNameCheck, kind,
+ prop_info->name, scanner()->location(), kSkipFunctionNameCheck, kind,
name_token_position, FunctionLiteral::kAccessorOrMethod,
- language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
+ language_mode(), nullptr);
- *property_kind =
+ ClassLiteralProperty::Kind property_kind =
is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER;
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
- name_expression, value, *property_kind, *is_static,
- *is_computed_name);
+ name_expression, value, property_kind, prop_info->is_static,
+ prop_info->is_computed_name, prop_info->is_private);
const AstRawString* prefix =
is_get ? ast_value_factory()->get_space_string()
: ast_value_factory()->set_space_string();
- impl()->SetFunctionNameFromPropertyName(result, *name, prefix);
+ impl()->SetFunctionNameFromPropertyName(result, prop_info->name, prefix);
return result;
}
+ case ParsePropertyKind::kValue:
+ case ParsePropertyKind::kShorthand:
case ParsePropertyKind::kSpread:
- ReportUnexpectedTokenAt(
+ impl()->ReportUnexpectedTokenAt(
Scanner::Location(name_token_position, name_expression->position()),
name_token);
- *ok = false;
return impl()->NullLiteralProperty();
}
UNREACHABLE();
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos,
- bool is_static, bool* ok) {
- DeclarationScope* initializer_scope = is_static
- ? class_info->static_fields_scope
- : class_info->instance_fields_scope;
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
+ ClassInfo* class_info, int beg_pos, bool is_static) {
+ DeclarationScope* initializer_scope =
+ is_static ? class_info->static_fields_scope
+ : class_info->instance_members_scope;
if (initializer_scope == nullptr) {
initializer_scope =
- NewFunctionScope(FunctionKind::kClassFieldsInitializerFunction);
+ NewFunctionScope(FunctionKind::kClassMembersInitializerFunction);
// TODO(gsathya): Make scopes be non contiguous.
initializer_scope->set_start_position(beg_pos);
initializer_scope->SetLanguageMode(LanguageMode::kStrict);
@@ -2513,11 +2236,9 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos,
if (Check(Token::ASSIGN)) {
FunctionState initializer_state(&function_state_, &scope_,
initializer_scope);
- ExpressionClassifier expression_classifier(this);
- initializer =
- ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression));
- ValidateExpression(CHECK_OK_CUSTOM(NullExpression));
+ AcceptINScope scope(this, true);
+ initializer = ParseAssignmentExpression();
} else {
initializer = factory()->NewUndefinedLiteral(kNoSourcePosition);
}
@@ -2527,8 +2248,8 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos,
class_info->static_fields_scope = initializer_scope;
class_info->has_static_class_fields = true;
} else {
- class_info->instance_fields_scope = initializer_scope;
- class_info->has_instance_class_fields = true;
+ class_info->instance_members_scope = initializer_scope;
+ class_info->has_instance_members = true;
}
return initializer;
@@ -2536,30 +2257,25 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos,
template <typename Impl>
typename ParserBase<Impl>::ObjectLiteralPropertyT
-ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
- bool* is_computed_name,
- bool* is_rest_property,
- bool* ok) {
- ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal;
- ParsePropertyKind kind = ParsePropertyKind::kNotSet;
-
- IdentifierT name = impl()->NullIdentifier();
+ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info,
+ bool* has_seen_proto) {
+ DCHECK_EQ(prop_info->position, PropertyPosition::kObjectLiteral);
Token::Value name_token = peek();
- int next_beg_pos = peek_position();
- int next_end_pos = peek_end_position();
+ Scanner::Location next_loc = scanner()->peek_location();
- ExpressionT name_expression =
- ParsePropertyName(&name, &kind, &function_flags, is_computed_name,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ ExpressionT name_expression = ParseProperty(prop_info);
+ IdentifierT name = prop_info->name;
+ ParseFunctionFlags function_flags = prop_info->function_flags;
+ ParsePropertyKind kind = prop_info->kind;
- switch (kind) {
+ switch (prop_info->kind) {
case ParsePropertyKind::kSpread:
DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
- DCHECK(!*is_computed_name);
+ DCHECK(!prop_info->is_computed_name);
DCHECK_EQ(Token::ELLIPSIS, name_token);
- *is_computed_name = true;
- *is_rest_property = true;
+ prop_info->is_computed_name = true;
+ prop_info->is_rest = true;
return factory()->NewObjectLiteralProperty(
factory()->NewTheHoleLiteral(), name_expression,
@@ -2568,21 +2284,27 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
case ParsePropertyKind::kValue: {
DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
- if (!*is_computed_name) {
- checker->CheckDuplicateProto(name_token);
+ if (!prop_info->is_computed_name &&
+ impl()->IdentifierEquals(name, ast_value_factory()->proto_string())) {
+ if (*has_seen_proto) {
+ expression_scope()->RecordExpressionError(
+ scanner()->location(), MessageTemplate::kDuplicateProto);
+ }
+ *has_seen_proto = true;
}
Consume(Token::COLON);
- int beg_pos = peek_position();
+ AcceptINScope scope(this, true);
ExpressionT value =
- ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullLiteralProperty));
- CheckDestructuringElement(value, beg_pos, end_position());
+ ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope);
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
- name_expression, value, *is_computed_name);
+ name_expression, value, prop_info->is_computed_name);
impl()->SetFunctionNameFromPropertyName(result, name);
return result;
}
+ case ParsePropertyKind::kAssign:
+ case ParsePropertyKind::kShorthandOrClassField:
case ParsePropertyKind::kShorthand: {
// PropertyDefinition
// IdentifierReference
@@ -2592,56 +2314,43 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
// IdentifierReference Initializer?
DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
- if (!Token::IsIdentifier(name_token, language_mode(),
- this->is_generator(),
- parsing_module_ || is_async_function())) {
+ if (!Token::IsValidIdentifier(name_token, language_mode(), is_generator(),
+ parsing_module_ || is_async_function())) {
ReportUnexpectedToken(Next());
- *ok = false;
return impl()->NullLiteralProperty();
}
- DCHECK(!*is_computed_name);
-
- if (classifier()->duplicate_finder() != nullptr &&
- scanner()->IsDuplicateSymbol(classifier()->duplicate_finder(),
- ast_value_factory())) {
- classifier()->RecordDuplicateFormalParameterError(
- scanner()->location());
- }
-
- if (impl()->IsEvalOrArguments(name) && is_strict(language_mode())) {
- classifier()->RecordBindingPatternError(
- scanner()->location(), MessageTemplate::kStrictEvalArguments);
- }
+ DCHECK(!prop_info->is_computed_name);
if (name_token == Token::LET) {
- classifier()->RecordLetPatternError(
+ expression_scope()->RecordLexicalDeclarationError(
scanner()->location(), MessageTemplate::kLetInLexicalBinding);
}
if (name_token == Token::AWAIT) {
DCHECK(!is_async_function());
- classifier()->RecordAsyncArrowFormalParametersError(
- Scanner::Location(next_beg_pos, next_end_pos),
- MessageTemplate::kAwaitBindingIdentifier);
+ expression_scope()->RecordAsyncArrowParametersError(
+ next_loc, MessageTemplate::kAwaitBindingIdentifier);
+ }
+ ExpressionT lhs =
+ impl()->ExpressionFromIdentifier(name, next_loc.beg_pos);
+ if (!IsAssignableIdentifier(lhs)) {
+ expression_scope()->RecordPatternError(
+ next_loc, MessageTemplate::kStrictEvalArguments);
}
- ExpressionT lhs = impl()->ExpressionFromIdentifier(name, next_beg_pos);
- CheckDestructuringElement(lhs, next_beg_pos, next_end_pos);
ExpressionT value;
if (peek() == Token::ASSIGN) {
Consume(Token::ASSIGN);
- ExpressionClassifier rhs_classifier(this);
- ExpressionT rhs = ParseAssignmentExpression(
- true, CHECK_OK_CUSTOM(NullLiteralProperty));
- ValidateExpression(CHECK_OK_CUSTOM(NullLiteralProperty));
- AccumulateFormalParameterContainmentErrors();
- value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
- kNoSourcePosition);
- classifier()->RecordExpressionError(
- Scanner::Location(next_beg_pos, end_position()),
+ {
+ AcceptINScope scope(this, true);
+ ExpressionT rhs = ParseAssignmentExpression();
+ value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
+ kNoSourcePosition);
+ impl()->SetFunctionNameFromIdentifierRef(rhs, lhs);
+ }
+ expression_scope()->RecordExpressionError(
+ Scanner::Location(next_loc.beg_pos, end_position()),
MessageTemplate::kInvalidCoverInitializedName);
-
- impl()->SetFunctionNameFromIdentifierRef(rhs, lhs);
} else {
value = lhs;
}
@@ -2657,20 +2366,20 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
- classifier()->RecordPatternError(
- Scanner::Location(next_beg_pos, end_position()),
+ expression_scope()->RecordPatternError(
+ Scanner::Location(next_loc.beg_pos, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
FunctionKind kind = MethodKindFor(function_flags);
ExpressionT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- next_beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
- nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
+ next_loc.beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
+ nullptr);
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
name_expression, value, ObjectLiteralProperty::COMPUTED,
- *is_computed_name);
+ prop_info->is_computed_name);
impl()->SetFunctionNameFromPropertyName(result, name);
return result;
}
@@ -2680,11 +2389,11 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
bool is_get = kind == ParsePropertyKind::kAccessorGetter;
- classifier()->RecordPatternError(
- Scanner::Location(next_beg_pos, end_position()),
+ expression_scope()->RecordPatternError(
+ Scanner::Location(next_loc.beg_pos, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
- if (!*is_computed_name) {
+ if (!prop_info->is_computed_name) {
// 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.
@@ -2697,14 +2406,14 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
FunctionLiteralT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- next_beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
- nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
+ next_loc.beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
+ nullptr);
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
name_expression, value,
is_get ? ObjectLiteralProperty::GETTER
: ObjectLiteralProperty::SETTER,
- *is_computed_name);
+ prop_info->is_computed_name);
const AstRawString* prefix =
is_get ? ast_value_factory()->get_space_string()
: ast_value_factory()->set_space_string();
@@ -2715,42 +2424,41 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
case ParsePropertyKind::kClassField:
case ParsePropertyKind::kNotSet:
ReportUnexpectedToken(Next());
- *ok = false;
return impl()->NullLiteralProperty();
}
UNREACHABLE();
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral() {
// ObjectLiteral ::
// '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
int pos = peek_position();
- typename Types::ObjectPropertyList properties =
- impl()->NewObjectPropertyList(4);
+ ObjectPropertyListT properties(pointer_buffer());
int number_of_boilerplate_properties = 0;
bool has_computed_names = false;
bool has_rest_property = false;
- ObjectLiteralChecker checker(this);
+ bool has_seen_proto = false;
Consume(Token::LBRACE);
+ AccumulationScope accumulation_scope(expression_scope());
while (!Check(Token::RBRACE)) {
FuncNameInferrerState fni_state(&fni_);
- bool is_computed_name = false;
- bool is_rest_property = false;
- ObjectLiteralPropertyT property = ParseObjectPropertyDefinition(
- &checker, &is_computed_name, &is_rest_property, CHECK_OK);
+ ParsePropertyInfo prop_info(this, &accumulation_scope);
+ prop_info.position = PropertyPosition::kObjectLiteral;
+ ObjectLiteralPropertyT property =
+ ParseObjectPropertyDefinition(&prop_info, &has_seen_proto);
+ if (impl()->IsNull(property)) return impl()->FailureExpression();
- if (is_computed_name) {
+ if (prop_info.is_computed_name) {
has_computed_names = true;
}
- if (is_rest_property) {
+ if (prop_info.is_rest) {
has_rest_property = true;
}
@@ -2760,11 +2468,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
number_of_boilerplate_properties++;
}
- properties->Add(property, zone());
+ properties.Add(property);
if (peek() != Token::RBRACE) {
- // Need {} because of the CHECK_OK macro.
- Expect(Token::COMMA, CHECK_OK);
+ Expect(Token::COMMA);
}
fni_.Infer();
@@ -2775,8 +2482,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
// this runtime function. Here, we make sure that the number of
// properties is less than number of arguments allowed for a runtime
// call.
- if (has_rest_property && properties->length() > Code::kMaxArguments) {
- this->classifier()->RecordPatternError(Scanner::Location(pos, position()),
+ if (has_rest_property && properties.length() > Code::kMaxArguments) {
+ expression_scope()->RecordPatternError(Scanner::Location(pos, position()),
MessageTemplate::kTooManyArguments);
}
@@ -2785,78 +2492,61 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
- Scanner::Location* first_spread_arg_loc, bool maybe_arrow,
- bool* is_simple_parameter_list, bool* ok) {
+void ParserBase<Impl>::ParseArguments(
+ typename ParserBase<Impl>::ExpressionListT* args, bool* has_spread,
+ ParsingArrowHeadFlag maybe_arrow) {
// Arguments ::
// '(' (AssignmentExpression)*[','] ')'
- Scanner::Location spread_arg = Scanner::Location::invalid();
- ExpressionListT result = impl()->NewExpressionList(4);
- Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList));
+ *has_spread = false;
+ Consume(Token::LPAREN);
+ AccumulationScope accumulation_scope(expression_scope());
+
while (peek() != Token::RPAREN) {
int start_pos = peek_position();
bool is_spread = Check(Token::ELLIPSIS);
int expr_pos = peek_position();
- ExpressionT argument =
- ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpressionList));
- if (!impl()->IsIdentifier(argument)) *is_simple_parameter_list = false;
+ AcceptINScope scope(this, true);
+ ExpressionT argument = ParseAssignmentExpressionCoverGrammar();
- if (!maybe_arrow) {
- ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList));
+ if (V8_UNLIKELY(maybe_arrow == kMaybeArrowHead)) {
+ ClassifyArrowParameter(&accumulation_scope, expr_pos, argument);
+ if (is_spread) {
+ expression_scope()->RecordNonSimpleParameter();
+ if (argument->IsAssignment()) {
+ expression_scope()->RecordAsyncArrowParametersError(
+ scanner()->location(), MessageTemplate::kRestDefaultInitializer);
+ }
+ if (peek() == Token::COMMA) {
+ expression_scope()->RecordAsyncArrowParametersError(
+ scanner()->peek_location(), MessageTemplate::kParamAfterRest);
+ }
+ }
}
if (is_spread) {
- *is_simple_parameter_list = false;
- if (!spread_arg.IsValid()) {
- spread_arg.beg_pos = start_pos;
- spread_arg.end_pos = peek_position();
- }
- if (argument->IsAssignment()) {
- classifier()->RecordAsyncArrowFormalParametersError(
- scanner()->location(), MessageTemplate::kRestDefaultInitializer);
- }
+ *has_spread = true;
argument = factory()->NewSpread(argument, start_pos, expr_pos);
}
- result->Add(argument, zone_);
-
- if (peek() != Token::COMMA) break;
-
- Next();
-
- if (argument->IsSpread()) {
- classifier()->RecordAsyncArrowFormalParametersError(
- scanner()->location(), MessageTemplate::kParamAfterRest);
- }
+ args->Add(argument);
+ if (!Check(Token::COMMA)) break;
}
- if (result->length() > Code::kMaxArguments) {
+ if (args->length() > Code::kMaxArguments) {
ReportMessage(MessageTemplate::kTooManyArguments);
- *ok = false;
- return impl()->NullExpressionList();
+ return;
}
Scanner::Location location = scanner_->location();
- if (Token::RPAREN != Next()) {
+ if (!Check(Token::RPAREN)) {
impl()->ReportMessageAt(location, MessageTemplate::kUnterminatedArgList);
- *ok = false;
- return impl()->NullExpressionList();
- }
- *first_spread_arg_loc = spread_arg;
-
- if (!maybe_arrow || peek() != Token::ARROW) {
- if (maybe_arrow) {
- ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList));
- }
}
-
- return result;
}
// Precedence = 2
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
+ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() {
// AssignmentExpression ::
// ConditionalExpression
// ArrowFunction
@@ -2865,188 +2555,120 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
int lhs_beg_pos = peek_position();
if (peek() == Token::YIELD && is_generator()) {
- return ParseYieldExpression(accept_IN, ok);
+ return ParseYieldExpression();
}
FuncNameInferrerState fni_state(&fni_);
- ExpressionClassifier arrow_formals_classifier(
- this, classifier()->duplicate_finder());
- Scope::Snapshot scope_snapshot(scope());
- int rewritable_length = static_cast<int>(
- function_state_->destructuring_assignments_to_rewrite().size());
+ DCHECK_IMPLIES(!has_error(), next_arrow_function_info_.HasInitialState());
- bool is_async = peek() == Token::ASYNC &&
- !scanner()->HasLineTerminatorAfterNext() &&
- IsValidArrowFormalParametersStart(PeekAhead());
+ ExpressionT expression = ParseConditionalExpression();
- bool parenthesized_formals = peek() == Token::LPAREN;
- if (!is_async && !parenthesized_formals) {
- ArrowFormalParametersUnexpectedToken();
- }
-
- // Parse a simple, faster sub-grammar (primary expression) if it's evident
- // that we have only a trivial expression to parse.
- ExpressionT expression;
- if (IsTrivialExpression()) {
- expression = ParsePrimaryExpression(&is_async, CHECK_OK);
- } else {
- expression = ParseConditionalExpression(accept_IN, CHECK_OK);
- }
+ Token::Value op = peek();
- if (is_async && impl()->IsIdentifier(expression) && peek_any_identifier() &&
- PeekAhead() == Token::ARROW) {
- // async Identifier => AsyncConciseBody
- IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
- expression =
- impl()->ExpressionFromIdentifier(name, position(), InferName::kNo);
- // Remove `async` keyword from inferred name stack.
- fni_.RemoveAsyncKeywordFromEnd();
- }
-
- if (peek() == Token::ARROW) {
- Scanner::Location arrow_loc = scanner()->peek_location();
- ValidateArrowFormalParameters(expression, parenthesized_formals, is_async,
- CHECK_OK);
- // This reads strangely, but is correct: it checks whether any
- // sub-expression of the parameter list failed to be a valid formal
- // parameter initializer. Since YieldExpressions are banned anywhere
- // in an arrow parameter list, this is correct.
- // TODO(adamk): Rename "FormalParameterInitializerError" to refer to
- // "YieldExpression", which is its only use.
- ValidateFormalParameterInitializer(CHECK_OK);
+ if (!Token::IsArrowOrAssignmentOp(op)) return expression;
+ // Arrow functions.
+ if (V8_UNLIKELY(op == Token::ARROW)) {
Scanner::Location loc(lhs_beg_pos, end_position());
- DeclarationScope* scope =
- NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction
- : FunctionKind::kArrowFunction);
- // Because the arrow's parameters were parsed in the outer scope,
- // we need to fix up the scope chain appropriately.
- scope_snapshot.Reparent(scope);
-
- FormalParametersT parameters(scope);
- if (!classifier()->is_simple_parameter_list()) {
- scope->SetHasNonSimpleParameters();
- parameters.is_simple = false;
+ if (!impl()->IsIdentifier(expression) && !expression->is_parenthesized()) {
+ impl()->ReportMessageAt(
+ Scanner::Location(expression->position(), position()),
+ MessageTemplate::kMalformedArrowFunParamList);
+ return impl()->FailureExpression();
}
+ DeclarationScope* scope = next_arrow_function_info_.scope;
scope->set_start_position(lhs_beg_pos);
- Scanner::Location duplicate_loc = Scanner::Location::invalid();
- impl()->DeclareArrowFunctionFormalParameters(&parameters, expression, loc,
- &duplicate_loc, CHECK_OK);
- if (duplicate_loc.IsValid()) {
- classifier()->RecordDuplicateFormalParameterError(duplicate_loc);
- }
- expression = ParseArrowFunctionLiteral(accept_IN, parameters,
- rewritable_length, CHECK_OK);
- Accumulate(ExpressionClassifier::AsyncArrowFormalParametersProduction);
- classifier()->RecordPatternError(arrow_loc,
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::ARROW));
- fni_.Infer();
-
- return expression;
- }
+ FormalParametersT parameters(scope);
+ parameters.set_strict_parameter_error(
+ next_arrow_function_info_.strict_parameter_error_location,
+ next_arrow_function_info_.strict_parameter_error_message);
+ parameters.is_simple = scope->has_simple_parameters();
+ next_arrow_function_info_.Reset();
- // "expression" was not itself an arrow function parameter list, but it might
- // form part of one. Propagate speculative formal parameter error locations
- // (including those for binding patterns, since formal parameters can
- // themselves contain binding patterns).
- unsigned productions = ExpressionClassifier::AllProductions &
- ~ExpressionClassifier::ArrowFormalParametersProduction;
+ impl()->DeclareArrowFunctionFormalParameters(&parameters, expression, loc);
- // Parenthesized identifiers and property references are allowed as part
- // of a larger assignment pattern, even though parenthesized patterns
- // themselves are not allowed, e.g., "[(x)] = []". Only accumulate
- // assignment pattern errors if the parsed expression is more complex.
- if (IsValidReferenceExpression(expression)) {
- productions &= ~ExpressionClassifier::AssignmentPatternProduction;
- }
+ expression = ParseArrowFunctionLiteral(parameters);
- const bool is_destructuring_assignment =
- IsValidPattern(expression) && peek() == Token::ASSIGN;
- if (is_destructuring_assignment) {
- // This is definitely not an expression so don't accumulate
- // expression-related errors.
- productions &= ~ExpressionClassifier::ExpressionProduction;
+ return expression;
}
- Accumulate(productions);
- if (!Token::IsAssignmentOp(peek())) return expression;
-
- if (is_destructuring_assignment) {
- ValidateAssignmentPattern(CHECK_OK);
+ if (V8_LIKELY(impl()->IsAssignableIdentifier(expression))) {
+ if (expression->is_parenthesized()) {
+ expression_scope()->RecordDeclarationError(
+ Scanner::Location(lhs_beg_pos, end_position()),
+ MessageTemplate::kInvalidDestructuringTarget);
+ }
+ expression_scope()->MarkIdentifierAsAssigned();
+ } else if (expression->IsProperty()) {
+ expression_scope()->RecordDeclarationError(
+ Scanner::Location(lhs_beg_pos, end_position()),
+ MessageTemplate::kInvalidPropertyBindingPattern);
+ } else if (expression->IsPattern() && op == Token::ASSIGN) {
+ // Destructuring assignmment.
+ if (expression->is_parenthesized()) {
+ expression_scope()->RecordPatternError(
+ Scanner::Location(lhs_beg_pos, end_position()),
+ MessageTemplate::kInvalidDestructuringTarget);
+ }
+ expression_scope()->ValidateAsPattern(expression, lhs_beg_pos,
+ end_position());
} else {
- expression = CheckAndRewriteReferenceExpression(
+ DCHECK(!IsValidReferenceExpression(expression));
+ expression = RewriteInvalidReferenceExpression(
expression, lhs_beg_pos, end_position(),
- MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
+ MessageTemplate::kInvalidLhsInAssignment);
}
- impl()->MarkExpressionAsAssigned(expression);
+ Consume(op);
+ int op_position = position();
- Token::Value op = Next(); // Get assignment operator.
- if (op != Token::ASSIGN) {
- classifier()->RecordPatternError(scanner()->location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(op));
- }
- int pos = position();
-
- ExpressionClassifier rhs_classifier(this);
+ ExpressionT right = ParseAssignmentExpression();
- ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK);
- ValidateExpression(CHECK_OK);
- AccumulateFormalParameterContainmentErrors();
-
- // 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 && impl()->IsThisProperty(expression)) {
- function_state_->AddProperty();
- }
-
- impl()->CheckAssigningFunctionLiteralToProperty(expression, right);
+ if (op == Token::ASSIGN) {
+ // 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 (impl()->IsThisProperty(expression)) function_state_->AddProperty();
+
+ impl()->CheckAssigningFunctionLiteralToProperty(expression, right);
+
+ // Check if the right hand side is a call to avoid inferring a
+ // name if we're dealing with "a = function(){...}();"-like
+ // expression.
+ if (right->IsCall() || right->IsCallNew()) {
+ fni_.RemoveLastFunction();
+ } else {
+ fni_.Infer();
+ }
- // 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::ASSIGN && !right->IsCall() && !right->IsCallNew()) {
- fni_.Infer();
+ impl()->SetFunctionNameFromIdentifierRef(right, expression);
} else {
+ expression_scope()->RecordPatternError(
+ Scanner::Location(lhs_beg_pos, end_position()),
+ MessageTemplate::kInvalidDestructuringTarget);
fni_.RemoveLastFunction();
}
- if (op == Token::ASSIGN) {
- impl()->SetFunctionNameFromIdentifierRef(right, expression);
- }
-
- DCHECK_NE(op, Token::INIT);
- ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
-
- if (is_destructuring_assignment) {
- DCHECK_NE(op, Token::ASSIGN_EXP);
- auto rewritable = factory()->NewRewritableExpression(result, scope());
- impl()->QueueDestructuringAssignmentForRewriting(rewritable);
- result = rewritable;
- }
-
- return result;
+ return factory()->NewAssignment(op, expression, right, op_position);
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
- bool accept_IN, bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseYieldExpression() {
// YieldExpression ::
// 'yield' ([no line terminator] '*'? AssignmentExpression)?
int pos = peek_position();
- classifier()->RecordPatternError(
- scanner()->peek_location(), MessageTemplate::kInvalidDestructuringTarget);
- classifier()->RecordFormalParameterInitializerError(
+ expression_scope()->RecordParameterInitializerError(
scanner()->peek_location(), MessageTemplate::kYieldInParameter);
- Expect(Token::YIELD, CHECK_OK);
+ Consume(Token::YIELD);
+
+ CheckStackOverflow();
+
// The following initialization is necessary.
ExpressionT expression = impl()->NullExpression();
bool delegating = false; // yield*
@@ -3069,8 +2691,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
// Delegating yields require an RHS; fall through.
V8_FALLTHROUGH;
default:
- expression = ParseAssignmentExpression(accept_IN, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ expression = ParseAssignmentExpressionCoverGrammar();
break;
}
}
@@ -3099,80 +2720,65 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
// Precedence = 3
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
- bool* ok) {
+ParserBase<Impl>::ParseConditionalExpression() {
// ConditionalExpression ::
// LogicalOrExpression
// LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
int pos = peek_position();
// We start using the binary expression parser for prec >= 4 only!
- ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
+ ExpressionT expression = ParseBinaryExpression(4);
return peek() == Token::CONDITIONAL
- ? ParseConditionalContinuation(expression, accept_IN, pos, ok)
+ ? ParseConditionalContinuation(expression, pos)
: expression;
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseConditionalContinuation(ExpressionT expression,
- bool accept_IN, int pos,
- bool* ok) {
+ int pos) {
SourceRange then_range, else_range;
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
ExpressionT left;
{
SourceRangeScope range_scope(scanner(), &then_range);
Consume(Token::CONDITIONAL);
- ExpressionClassifier classifier(this);
// In parsing the first assignment expression in conditional
// expressions we always accept the 'in' keyword; see ECMA-262,
// section 11.12, page 58.
- left = ParseAssignmentExpression(true, CHECK_OK);
- AccumulateNonBindingPatternErrors();
+ AcceptINScope scope(this, true);
+ left = ParseAssignmentExpression();
}
- ValidateExpression(CHECK_OK);
ExpressionT right;
{
SourceRangeScope range_scope(scanner(), &else_range);
- Expect(Token::COLON, CHECK_OK);
- ExpressionClassifier classifier(this);
- right = ParseAssignmentExpression(accept_IN, CHECK_OK);
- AccumulateNonBindingPatternErrors();
+ Expect(Token::COLON);
+ right = ParseAssignmentExpression();
}
- ValidateExpression(CHECK_OK);
ExpressionT expr = factory()->NewConditional(expression, left, right, pos);
impl()->RecordConditionalSourceRange(expr, then_range, else_range);
return expr;
}
-
// Precedence >= 4
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
- int prec, bool accept_IN, bool* ok) {
- DCHECK_GE(prec, 4);
- SourceRange right_range;
- ExpressionT x = ParseUnaryExpression(CHECK_OK);
- for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseBinaryContinuation(ExpressionT x, int prec, int prec1) {
+ do {
// prec1 >= 4
- while (Precedence(peek(), accept_IN) == prec1) {
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
-
- SourceRangeScope right_range_scope(scanner(), &right_range);
- Token::Value op = Next();
- int pos = position();
-
- const bool is_right_associative = op == Token::EXP;
- const int next_prec = is_right_associative ? prec1 : prec1 + 1;
- ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK);
- right_range_scope.Finalize();
- ValidateExpression(CHECK_OK);
+ while (Token::Precedence(peek(), accept_IN_) == prec1) {
+ SourceRange right_range;
+ int pos = peek_position();
+ ExpressionT y;
+ Token::Value op;
+ {
+ SourceRangeScope right_range_scope(scanner(), &right_range);
+ op = Next();
+
+ const bool is_right_associative = op == Token::EXP;
+ const int next_prec = is_right_associative ? prec1 : prec1 + 1;
+ y = ParseBinaryExpression(next_prec);
+ }
// For now we distinguish between comparisons and other binary
// operations. (We could combine the two and get rid of this
@@ -3200,16 +2806,28 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
}
}
}
- }
+ --prec1;
+ } while (prec1 >= prec);
+
return x;
}
+// Precedence >= 4
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryOpExpression(
- bool* ok) {
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
+ int prec) {
+ DCHECK_GE(prec, 4);
+ ExpressionT x = ParseUnaryExpression();
+ int prec1 = Token::Precedence(peek(), accept_IN_);
+ if (prec1 >= prec) {
+ return ParseBinaryContinuation(x, prec, prec1);
+ }
+ return x;
+}
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseUnaryOrPrefixExpression() {
Token::Value op = Next();
int pos = position();
@@ -3218,66 +2836,64 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryOpExpression(
function_state_->set_next_function_is_likely_called();
}
- ExpressionT expression = ParseUnaryExpression(CHECK_OK);
- ValidateExpression(CHECK_OK);
+ CheckStackOverflow();
+
+ int expression_position = peek_position();
+ ExpressionT expression = ParseUnaryExpression();
+
+ if (Token::IsUnaryOp(op)) {
+ if (op == Token::DELETE) {
+ if (impl()->IsIdentifier(expression) && is_strict(language_mode())) {
+ // "delete identifier" is a syntax error in strict mode.
+ ReportMessage(MessageTemplate::kStrictDelete);
+ return impl()->FailureExpression();
+ }
- if (op == Token::DELETE) {
- if (impl()->IsIdentifier(expression) && is_strict(language_mode())) {
- // "delete identifier" is a syntax error in strict mode.
- ReportMessage(MessageTemplate::kStrictDelete);
- *ok = false;
- return impl()->NullExpression();
+ if (impl()->IsPropertyWithPrivateFieldKey(expression)) {
+ ReportMessage(MessageTemplate::kDeletePrivateField);
+ return impl()->FailureExpression();
+ }
}
- if (impl()->IsPropertyWithPrivateFieldKey(expression)) {
- ReportMessage(MessageTemplate::kDeletePrivateField);
- *ok = false;
- return impl()->NullExpression();
+ if (peek() == Token::EXP) {
+ impl()->ReportMessageAt(
+ Scanner::Location(pos, peek_end_position()),
+ MessageTemplate::kUnexpectedTokenUnaryExponentiation);
+ return impl()->FailureExpression();
}
- }
- if (peek() == Token::EXP) {
- ReportUnexpectedToken(Next());
- *ok = false;
- return impl()->NullExpression();
+ // Allow the parser's implementation to rewrite the expression.
+ return impl()->BuildUnaryExpression(expression, op, pos);
}
- // Allow the parser's implementation to rewrite the expression.
- return impl()->BuildUnaryExpression(expression, op, pos);
-}
+ DCHECK(Token::IsCountOp(op));
-template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrefixExpression(
- bool* ok) {
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
- Token::Value op = Next();
- int beg_pos = peek_position();
- ExpressionT expression = ParseUnaryExpression(CHECK_OK);
- expression = CheckAndRewriteReferenceExpression(
- expression, beg_pos, end_position(),
- MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
- impl()->MarkExpressionAsAssigned(expression);
- ValidateExpression(CHECK_OK);
+ if (V8_LIKELY(IsValidReferenceExpression(expression))) {
+ if (impl()->IsIdentifier(expression)) {
+ expression_scope()->MarkIdentifierAsAssigned();
+ }
+ } else {
+ expression = RewriteInvalidReferenceExpression(
+ expression, expression_position, end_position(),
+ MessageTemplate::kInvalidLhsInPrefixOp);
+ }
return factory()->NewCountOperation(op, true /* prefix */, expression,
position());
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAwaitExpression(
- bool* ok) {
- classifier()->RecordFormalParameterInitializerError(
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseAwaitExpression() {
+ expression_scope()->RecordParameterInitializerError(
scanner()->peek_location(),
MessageTemplate::kAwaitExpressionFormalParameter);
int await_pos = peek_position();
Consume(Token::AWAIT);
- ExpressionT value = ParseUnaryExpression(CHECK_OK);
+ CheckStackOverflow();
- classifier()->RecordBindingPatternError(
- Scanner::Location(await_pos, end_position()),
- MessageTemplate::kInvalidDestructuringTarget);
+ ExpressionT value = ParseUnaryExpression();
ExpressionT expr = factory()->NewAwait(value, await_pos);
function_state_->AddSuspend();
@@ -3286,8 +2902,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAwaitExpression(
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseUnaryExpression() {
// UnaryExpression ::
// PostfixExpression
// 'delete' UnaryExpression
@@ -3302,31 +2918,30 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
// [+Await] AwaitExpression[?Yield]
Token::Value op = peek();
- if (Token::IsUnaryOp(op)) return ParseUnaryOpExpression(ok);
- if (Token::IsCountOp(op)) return ParsePrefixExpression(ok);
+ if (Token::IsUnaryOrCountOp(op)) return ParseUnaryOrPrefixExpression();
if (is_async_function() && op == Token::AWAIT) {
- return ParseAwaitExpression(ok);
+ return ParseAwaitExpression();
}
- return ParsePostfixExpression(ok);
+ return ParsePostfixExpression();
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParsePostfixExpression() {
// PostfixExpression ::
// LeftHandSideExpression ('++' | '--')?
int lhs_beg_pos = peek_position();
- ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK);
+ ExpressionT expression = ParseLeftHandSideExpression();
if (!scanner()->HasLineTerminatorBeforeNext() && Token::IsCountOp(peek())) {
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
-
- expression = CheckAndRewriteReferenceExpression(
- expression, lhs_beg_pos, end_position(),
- MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
- impl()->MarkExpressionAsAssigned(expression);
- ValidateExpression(CHECK_OK);
+ if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) {
+ expression = RewriteInvalidReferenceExpression(
+ expression, lhs_beg_pos, end_position(),
+ MessageTemplate::kInvalidLhsInPostfixOp);
+ }
+ if (impl()->IsIdentifier(expression)) {
+ expression_scope()->MarkIdentifierAsAssigned();
+ }
Token::Value next = Next();
expression =
@@ -3340,36 +2955,83 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
+ParserBase<Impl>::ParseLeftHandSideExpression() {
// LeftHandSideExpression ::
// (NewExpression | MemberExpression) ...
- bool is_async = false;
- ExpressionT result =
- ParseMemberWithNewPrefixesExpression(&is_async, CHECK_OK);
+ ExpressionT result = ParseMemberWithNewPrefixesExpression();
+ if (!Token::IsPropertyOrCall(peek())) return result;
+ return ParseLeftHandSideContinuation(result);
+}
- while (true) {
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
+ DCHECK(Token::IsPropertyOrCall(peek()));
+
+ if (V8_UNLIKELY(peek() == Token::LPAREN && impl()->IsIdentifier(result) &&
+ scanner()->current_token() == Token::ASYNC &&
+ !scanner()->HasLineTerminatorBeforeNext())) {
+ DCHECK(impl()->IsAsync(impl()->AsIdentifier(result)));
+ int pos = position();
+
+ ArrowHeadParsingScope maybe_arrow(impl(),
+ FunctionKind::kAsyncArrowFunction);
+ Scope::Snapshot scope_snapshot(scope());
+
+ ExpressionListT args(pointer_buffer());
+ bool has_spread;
+ ParseArguments(&args, &has_spread, kMaybeArrowHead);
+ if (V8_LIKELY(peek() == Token::ARROW)) {
+ fni_.RemoveAsyncKeywordFromEnd();
+ next_arrow_function_info_.scope = maybe_arrow.ValidateAndCreateScope();
+ scope_snapshot.Reparent(next_arrow_function_info_.scope);
+ // async () => ...
+ if (!args.length()) return factory()->NewEmptyParentheses(pos);
+ // async ( Arguments ) => ...
+ ExpressionT result = impl()->ExpressionListToExpression(args);
+ result->mark_parenthesized();
+ return result;
+ }
+
+ if (has_spread) {
+ result = impl()->SpreadCall(result, args, pos, Call::NOT_EVAL);
+ } else {
+ result = factory()->NewCall(result, args, pos, Call::NOT_EVAL);
+ }
+
+ maybe_arrow.ValidateExpression();
+
+ fni_.RemoveLastFunction();
+ if (!Token::IsPropertyOrCall(peek())) return result;
+ }
+
+ do {
switch (peek()) {
+ /* Property */
case Token::LBRACK: {
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
Consume(Token::LBRACK);
int pos = position();
- ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ AcceptINScope scope(this, true);
+ ExpressionT index = ParseExpressionCoverGrammar();
result = factory()->NewProperty(result, index, pos);
- Expect(Token::RBRACK, CHECK_OK);
+ Expect(Token::RBRACK);
break;
}
+ /* Property */
+ case Token::PERIOD: {
+ Consume(Token::PERIOD);
+ int pos = position();
+ ExpressionT key = ParsePropertyOrPrivatePropertyName();
+ result = factory()->NewProperty(result, key, pos);
+ break;
+ }
+
+ /* Call */
case Token::LPAREN: {
int pos;
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- if (scanner()->current_token() == Token::IDENTIFIER ||
- scanner()->current_token() == Token::SUPER ||
- scanner()->current_token() == Token::ASYNC) {
+ if (Token::IsCallable(scanner()->current_token())) {
// For call of an identifier we want to report position of
// the identifier as position of the call in the stack trace.
pos = position();
@@ -3385,43 +3047,16 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
// function literal eagerly, we can also compile it eagerly.
if (result->IsFunctionLiteral()) {
result->AsFunctionLiteral()->SetShouldEagerCompile();
- result->AsFunctionLiteral()->mark_as_iife();
- }
- }
- Scanner::Location spread_pos;
- ExpressionListT args;
- if (V8_UNLIKELY(is_async && impl()->IsIdentifier(result))) {
- ExpressionClassifier async_classifier(this);
- bool is_simple_parameter_list = true;
- args = ParseArguments(&spread_pos, true, &is_simple_parameter_list,
- CHECK_OK);
- if (peek() == Token::ARROW) {
- fni_.RemoveAsyncKeywordFromEnd();
- ValidateBindingPattern(CHECK_OK);
- ValidateFormalParameterInitializer(CHECK_OK);
- if (!classifier()->is_valid_async_arrow_formal_parameters()) {
- ReportClassifierError(
- classifier()->async_arrow_formal_parameters_error());
- *ok = false;
- return impl()->NullExpression();
- }
- if (args->length()) {
- // async ( Arguments ) => ...
- if (!is_simple_parameter_list) {
- async_classifier.previous()->RecordNonSimpleParameter();
- }
- return impl()->ExpressionListToExpression(args);
+ if (scope()->is_script_scope()) {
+ // A non-top-level iife is likely to be executed multiple times
+ // and so shouldn`t be optimized as one-shot.
+ result->AsFunctionLiteral()->mark_as_oneshot_iife();
}
- // async () => ...
- return factory()->NewEmptyParentheses(pos);
- } else {
- AccumulateFormalParameterContainmentErrors();
}
- } else {
- args = ParseArguments(&spread_pos, CHECK_OK);
}
-
- ArrowFormalParametersUnexpectedToken();
+ bool has_spread;
+ ExpressionListT args(pointer_buffer());
+ ParseArguments(&args, &has_spread);
// Keep track of eval() calls since they disable all local variable
// optimizations.
@@ -3433,7 +3068,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
Call::PossiblyEval is_possibly_eval =
CheckPossibleEvalCall(result, scope());
- if (spread_pos.IsValid()) {
+ if (has_spread) {
result = impl()->SpreadCall(result, args, pos, is_possibly_eval);
} else {
result = factory()->NewCall(result, args, pos, is_possibly_eval);
@@ -3443,36 +3078,19 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
break;
}
- case Token::PERIOD: {
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
- Consume(Token::PERIOD);
- int pos = position();
- ExpressionT key = ParseIdentifierNameOrPrivateName(CHECK_OK);
- result = factory()->NewProperty(result, key, pos);
- break;
- }
-
- case Token::TEMPLATE_SPAN:
- case Token::TEMPLATE_TAIL: {
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
- result = ParseTemplateLiteral(result, position(), true, CHECK_OK);
- break;
- }
-
+ /* Call */
default:
- return result;
+ DCHECK(Token::IsTemplate(peek()));
+ result = ParseTemplateLiteral(result, position(), true);
+ break;
}
- }
+ } while (Token::IsPropertyOrCall(peek()));
+ return result;
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression(bool* is_async,
- bool* ok) {
+ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression() {
// NewExpression ::
// ('new')+ MemberExpression
//
@@ -3492,57 +3110,94 @@ ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression(bool* is_async,
// 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
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
Consume(Token::NEW);
int new_pos = position();
ExpressionT result;
+
+ CheckStackOverflow();
+
if (peek() == Token::SUPER) {
const bool is_new = true;
- result = ParseSuperExpression(is_new, CHECK_OK);
+ result = ParseSuperExpression(is_new);
} else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT &&
(!allow_harmony_import_meta() || PeekAhead() == Token::LPAREN)) {
impl()->ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kImportCallNotNewExpression);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
} else if (peek() == Token::PERIOD) {
- *is_async = false;
- result = ParseNewTargetExpression(CHECK_OK);
- return ParseMemberExpressionContinuation(result, is_async, ok);
+ result = ParseNewTargetExpression();
+ return ParseMemberExpressionContinuation(result);
} else {
- result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK);
+ result = ParseMemberWithNewPrefixesExpression();
}
- ValidateExpression(CHECK_OK);
if (peek() == Token::LPAREN) {
// NewExpression with arguments.
- Scanner::Location spread_pos;
- ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK);
+ {
+ ExpressionListT args(pointer_buffer());
+ bool has_spread;
+ ParseArguments(&args, &has_spread);
- if (spread_pos.IsValid()) {
- result = impl()->SpreadCallNew(result, args, new_pos);
- } else {
- result = factory()->NewCallNew(result, args, new_pos);
+ if (has_spread) {
+ result = impl()->SpreadCallNew(result, args, new_pos);
+ } else {
+ result = factory()->NewCallNew(result, args, new_pos);
+ }
}
// The expression can still continue with . or [ after the arguments.
- return ParseMemberExpressionContinuation(result, is_async, ok);
+ return ParseMemberExpressionContinuation(result);
}
// NewExpression without arguments.
- return factory()->NewCallNew(result, impl()->NewExpressionList(0), new_pos);
+ ExpressionListT args(pointer_buffer());
+ return factory()->NewCallNew(result, args, new_pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseMemberWithNewPrefixesExpression() {
+ return peek() == Token::NEW ? ParseMemberWithPresentNewPrefixesExpression()
+ : ParseMemberExpression();
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
- bool* ok) {
- return peek() == Token::NEW
- ? ParseMemberWithPresentNewPrefixesExpression(is_async, ok)
- : ParseMemberExpression(is_async, ok);
+ParserBase<Impl>::ParseFunctionExpression() {
+ Consume(Token::FUNCTION);
+ int function_token_position = position();
+
+ FunctionKind function_kind = Check(Token::MUL)
+ ? FunctionKind::kGeneratorFunction
+ : FunctionKind::kNormalFunction;
+ IdentifierT name = impl()->NullIdentifier();
+ bool is_strict_reserved_name = Token::IsStrictReservedWord(peek());
+ Scanner::Location function_name_location = Scanner::Location::invalid();
+ FunctionLiteral::FunctionType function_type =
+ FunctionLiteral::kAnonymousExpression;
+ if (impl()->ParsingDynamicFunctionDeclaration()) {
+ // We don't want dynamic functions to actually declare their name
+ // "anonymous". We just want that name in the toString().
+ Consume(Token::IDENTIFIER);
+ DCHECK_IMPLIES(!has_error(),
+ scanner()->CurrentSymbol(ast_value_factory()) ==
+ ast_value_factory()->anonymous_string());
+ } else if (peek_any_identifier()) {
+ name = ParseIdentifier(function_kind);
+ function_name_location = scanner()->location();
+ function_type = FunctionLiteral::kNamedExpression;
+ }
+ FunctionLiteralT result = impl()->ParseFunctionLiteral(
+ name, function_name_location,
+ is_strict_reserved_name ? kFunctionNameIsStrictReserved
+ : kFunctionNameValidityUnknown,
+ function_kind, function_token_position, function_type, language_mode(),
+ nullptr);
+ // TODO(verwaest): FailureFunctionLiteral?
+ if (impl()->IsNull(result)) return impl()->FailureExpression();
+ return result;
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
- bool* is_async, bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseMemberExpression() {
// MemberExpression ::
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
@@ -3558,99 +3213,60 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
// Parse the initial primary or function expression.
ExpressionT result;
if (peek() == Token::FUNCTION) {
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
-
- Consume(Token::FUNCTION);
- int function_token_position = position();
-
- FunctionKind function_kind = Check(Token::MUL)
- ? FunctionKind::kGeneratorFunction
- : FunctionKind::kNormalFunction;
- IdentifierT name = impl()->NullIdentifier();
- bool is_strict_reserved_name = false;
- Scanner::Location function_name_location = Scanner::Location::invalid();
- FunctionLiteral::FunctionType function_type =
- FunctionLiteral::kAnonymousExpression;
- if (impl()->ParsingDynamicFunctionDeclaration()) {
- // We don't want dynamic functions to actually declare their name
- // "anonymous". We just want that name in the toString().
- if (stack_overflow()) {
- *ok = false;
- return impl()->NullExpression();
- }
- Consume(Token::IDENTIFIER);
- DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS));
- } else if (peek_any_identifier()) {
- bool is_await = false;
- name = ParseIdentifierOrStrictReservedWord(
- function_kind, &is_strict_reserved_name, &is_await, CHECK_OK);
- function_name_location = scanner()->location();
- function_type = FunctionLiteral::kNamedExpression;
- }
- result = impl()->ParseFunctionLiteral(
- name, function_name_location,
- is_strict_reserved_name ? kFunctionNameIsStrictReserved
- : kFunctionNameValidityUnknown,
- function_kind, function_token_position, function_type, language_mode(),
- nullptr, CHECK_OK);
+ result = ParseFunctionExpression();
} else if (peek() == Token::SUPER) {
const bool is_new = false;
- result = ParseSuperExpression(is_new, CHECK_OK);
+ result = ParseSuperExpression(is_new);
} else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) {
- result = ParseImportExpressions(CHECK_OK);
+ result = ParseImportExpressions();
} else {
- result = ParsePrimaryExpression(is_async, CHECK_OK);
+ result = ParsePrimaryExpression();
}
- return ParseMemberExpressionContinuation(result, is_async, ok);
+ return ParseMemberExpressionContinuation(result);
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseImportExpressions(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseImportExpressions() {
DCHECK(allow_harmony_dynamic_import());
- classifier()->RecordPatternError(scanner()->peek_location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::IMPORT));
-
Consume(Token::IMPORT);
int pos = position();
if (allow_harmony_import_meta() && peek() == Token::PERIOD) {
- ExpectMetaProperty(Token::META, "import.meta", pos, CHECK_OK);
+ ExpectMetaProperty(ast_value_factory()->meta_string(), "import.meta", pos);
if (!parsing_module_) {
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kImportMetaOutsideModule);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
return impl()->ImportMetaExpression(pos);
}
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(Token::LPAREN);
if (peek() == Token::RPAREN) {
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kImportMissingSpecifier);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
- ExpressionT arg = ParseAssignmentExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ AcceptINScope scope(this, true);
+ ExpressionT arg = ParseAssignmentExpressionCoverGrammar();
+ Expect(Token::RPAREN);
+
return factory()->NewImportCallExpression(arg, pos);
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
- bool is_new, bool* ok) {
- Expect(Token::SUPER, CHECK_OK);
+ bool is_new) {
+ Consume(Token::SUPER);
int pos = position();
DeclarationScope* scope = GetReceiverScope();
FunctionKind kind = scope->function_kind();
if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
IsClassConstructor(kind)) {
- if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
+ if (Token::IsProperty(peek())) {
scope->RecordSuperPropertyUsage();
return impl()->NewSuperPropertyReference(pos);
}
@@ -3665,39 +3281,31 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kUnexpectedSuper);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
template <typename Impl>
-void ParserBase<Impl>::ExpectMetaProperty(Token::Value property_name,
- const char* full_name, int pos,
- bool* ok) {
+void ParserBase<Impl>::ExpectMetaProperty(const AstRawString* property_name,
+ const char* full_name, int pos) {
Consume(Token::PERIOD);
- ExpectContextualKeyword(property_name, CHECK_OK_CUSTOM(Void));
- if (scanner()->literal_contains_escapes()) {
+ ExpectContextualKeyword(property_name);
+ if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
impl()->ReportMessageAt(Scanner::Location(pos, end_position()),
MessageTemplate::kInvalidEscapedMetaProperty,
full_name);
- *ok = false;
}
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseNewTargetExpression(bool* ok) {
+ParserBase<Impl>::ParseNewTargetExpression() {
int pos = position();
- ExpectMetaProperty(Token::TARGET, "new.target", pos, CHECK_OK);
-
- classifier()->RecordAssignmentPatternError(
- Scanner::Location(pos, end_position()),
- MessageTemplate::kInvalidDestructuringTarget);
+ ExpectMetaProperty(ast_value_factory()->target_string(), "new.target", pos);
if (!GetReceiverScope()->is_function_scope()) {
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kUnexpectedNewTarget);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
return impl()->NewTargetExpression(pos);
@@ -3705,45 +3313,31 @@ ParserBase<Impl>::ParseNewTargetExpression(bool* ok) {
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
- bool* is_async, bool* ok) {
+ParserBase<Impl>::DoParseMemberExpressionContinuation(ExpressionT expression) {
+ DCHECK(Token::IsMember(peek()));
// Parses this part of MemberExpression:
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
- while (true) {
+ do {
switch (peek()) {
case Token::LBRACK: {
- *is_async = false;
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
-
Consume(Token::LBRACK);
int pos = position();
- ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ AcceptINScope scope(this, true);
+ ExpressionT index = ParseExpressionCoverGrammar();
expression = factory()->NewProperty(expression, index, pos);
impl()->PushPropertyName(index);
- Expect(Token::RBRACK, CHECK_OK);
+ Expect(Token::RBRACK);
break;
}
case Token::PERIOD: {
- *is_async = false;
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
-
Consume(Token::PERIOD);
int pos = peek_position();
- ExpressionT key = ParseIdentifierNameOrPrivateName(CHECK_OK);
+ ExpressionT key = ParsePropertyOrPrivatePropertyName();
expression = factory()->NewProperty(expression, key, pos);
break;
}
- case Token::TEMPLATE_SPAN:
- case Token::TEMPLATE_TAIL: {
- *is_async = false;
- ValidateExpression(CHECK_OK);
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
+ default: {
+ DCHECK(Token::IsTemplate(peek()));
int pos;
if (scanner()->current_token() == Token::IDENTIFIER) {
pos = position();
@@ -3755,61 +3349,47 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
expression->AsFunctionLiteral()->SetShouldEagerCompile();
}
}
- expression = ParseTemplateLiteral(expression, pos, true, CHECK_OK);
+ expression = ParseTemplateLiteral(expression, pos, true);
break;
}
- case Token::ILLEGAL: {
- ReportUnexpectedTokenAt(scanner()->peek_location(), Token::ILLEGAL);
- *ok = false;
- return impl()->NullExpression();
- }
- default:
- return expression;
}
- }
- DCHECK(false);
- return impl()->NullExpression();
+ } while (Token::IsMember(peek()));
+ return expression;
}
template <typename Impl>
-void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters,
- bool* ok) {
+void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters) {
// FormalParameter[Yield,GeneratorParameter] :
// BindingElement[?Yield, ?GeneratorParameter]
- bool is_rest = parameters->has_rest;
-
FuncNameInferrerState fni_state(&fni_);
- ExpressionT pattern = ParseBindingPattern(CHECK_OK_CUSTOM(Void));
- if (!impl()->IsIdentifier(pattern)) {
+ int pos = peek_position();
+ ExpressionT pattern = ParseBindingPattern();
+ if (impl()->IsIdentifier(pattern)) {
+ ClassifyParameter(impl()->AsIdentifier(pattern), pos, end_position());
+ } else {
parameters->is_simple = false;
- ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void));
}
ExpressionT initializer = impl()->NullExpression();
if (Check(Token::ASSIGN)) {
- if (is_rest) {
+ parameters->is_simple = false;
+
+ if (parameters->has_rest) {
ReportMessage(MessageTemplate::kRestDefaultInitializer);
- *ok = false;
return;
}
- ExpressionClassifier init_classifier(this);
- initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void));
- ValidateExpression(CHECK_OK_CUSTOM(Void));
- ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void));
- parameters->is_simple = false;
- DiscardExpressionClassifier();
- classifier()->RecordNonSimpleParameter();
+ AcceptINScope scope(this, true);
+ initializer = ParseAssignmentExpression();
impl()->SetFunctionNameFromIdentifierRef(initializer, pattern);
}
impl()->AddFormalParameter(parameters, pattern, initializer, end_position(),
- is_rest);
+ parameters->has_rest);
}
template <typename Impl>
-void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters,
- bool* ok) {
+void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters) {
// FormalParameters[Yield] :
// [empty]
// FunctionRestParameter[?Yield]
@@ -3820,26 +3400,25 @@ void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters,
// FormalParameterList[Yield] :
// FormalParameter[?Yield]
// FormalParameterList[?Yield] , FormalParameter[?Yield]
+ ParameterParsingScope scope(impl(), parameters);
DCHECK_EQ(0, parameters->arity);
if (peek() != Token::RPAREN) {
while (true) {
- if (parameters->arity > Code::kMaxArguments) {
+ // Add one since we're going to be adding a parameter.
+ if (parameters->arity + 1 > Code::kMaxArguments) {
ReportMessage(MessageTemplate::kTooManyParameters);
- *ok = false;
return;
}
parameters->has_rest = Check(Token::ELLIPSIS);
- ParseFormalParameter(parameters, CHECK_OK_CUSTOM(Void));
+ ParseFormalParameter(parameters);
if (parameters->has_rest) {
parameters->is_simple = false;
- classifier()->RecordNonSimpleParameter();
if (peek() == Token::COMMA) {
impl()->ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
- *ok = false;
return;
}
break;
@@ -3852,15 +3431,14 @@ void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters,
}
}
- impl()->DeclareFormalParameters(parameters->scope, parameters->params,
- parameters->is_simple);
+ impl()->DeclareFormalParameters(parameters);
}
template <typename Impl>
-typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
+void ParserBase<Impl>::ParseVariableDeclarations(
VariableDeclarationContext var_context,
DeclarationParsingResult* parsing_result,
- ZonePtrList<const AstRawString>* names, bool* ok) {
+ ZonePtrList<const AstRawString>* names) {
// VariableDeclarations ::
// ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
//
@@ -3869,15 +3447,10 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
// declaration syntax.
DCHECK_NOT_NULL(parsing_result);
- parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
+ parsing_result->descriptor.kind = NORMAL_VARIABLE;
parsing_result->descriptor.declaration_pos = peek_position();
parsing_result->descriptor.initialization_pos = peek_position();
- BlockT init_block = impl()->NullStatement();
- if (var_context != kForStatement) {
- init_block = factory()->NewBlock(1, true);
- }
-
switch (peek()) {
case Token::VAR:
parsing_result->descriptor.mode = VariableMode::kVar;
@@ -3898,40 +3471,29 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
break;
}
- parsing_result->descriptor.scope = scope();
+ VariableDeclarationParsingScope declaration(
+ impl(), parsing_result->descriptor.mode, names);
int bindings_start = peek_position();
do {
// Parse binding pattern.
FuncNameInferrerState fni_state(&fni_);
- ExpressionT pattern = impl()->NullExpression();
int decl_pos = peek_position();
- {
- ExpressionClassifier pattern_classifier(this);
- pattern = ParseBindingPattern(CHECK_OK_CUSTOM(NullStatement));
+ ExpressionT pattern = ParseBindingPattern();
- if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
- ValidateLetPattern(CHECK_OK_CUSTOM(NullStatement));
- }
- }
Scanner::Location variable_loc = scanner()->location();
- bool single_name = impl()->IsIdentifier(pattern);
- if (single_name) {
- impl()->PushVariableName(impl()->AsIdentifier(pattern));
- }
-
ExpressionT value = impl()->NullExpression();
int initializer_position = kNoSourcePosition;
int value_beg_position = kNoSourcePosition;
if (Check(Token::ASSIGN)) {
value_beg_position = peek_position();
- ExpressionClassifier classifier(this);
- value = ParseAssignmentExpression(var_context != kForStatement,
- CHECK_OK_CUSTOM(NullStatement));
- ValidateExpression(CHECK_OK_CUSTOM(NullStatement));
+ {
+ AcceptINScope scope(this, var_context != kForStatement);
+ value = ParseAssignmentExpression();
+ }
variable_loc.end_pos = end_position();
if (!parsing_result->first_initializer_loc.IsValid()) {
@@ -3939,7 +3501,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
}
// Don't infer if it is "a = function(){...}();"-like expression.
- if (single_name) {
+ if (impl()->IsIdentifier(pattern)) {
if (!value->IsCall() && !value->IsCallNew()) {
fni_.Infer();
} else {
@@ -3960,8 +3522,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
Scanner::Location(decl_pos, end_position()),
MessageTemplate::kDeclarationMissingInitializer,
!impl()->IsIdentifier(pattern) ? "destructuring" : "const");
- *ok = false;
- return impl()->NullStatement();
+ return;
}
// 'let x' initializes 'x' to undefined.
if (parsing_result->descriptor.mode == VariableMode::kLet) {
@@ -3976,61 +3537,50 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
typename DeclarationParsingResult::Declaration decl(
pattern, initializer_position, value);
decl.value_beg_position = value_beg_position;
- if (var_context == kForStatement) {
- // Save the declaration for further handling in ParseForStatement.
- parsing_result->declarations.push_back(decl);
- } else {
- // Immediately declare the variable otherwise. This avoids O(N^2)
- // behavior (where N is the number of variables in a single
- // declaration) in the PatternRewriter having to do with removing
- // and adding VariableProxies to the Scope (see bug 4699).
- impl()->DeclareAndInitializeVariables(
- init_block, &parsing_result->descriptor, &decl, names,
- CHECK_OK_CUSTOM(NullStatement));
- }
+ parsing_result->declarations.push_back(decl);
} while (Check(Token::COMMA));
parsing_result->bindings_loc =
Scanner::Location(bindings_start, end_position());
-
- DCHECK(*ok);
- return init_block;
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
-ParserBase<Impl>::ParseFunctionDeclaration(bool* ok) {
+ParserBase<Impl>::ParseFunctionDeclaration() {
Consume(Token::FUNCTION);
+
int pos = position();
ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal;
if (Check(Token::MUL)) {
impl()->ReportMessageAt(
scanner()->location(),
MessageTemplate::kGeneratorInSingleStatementContext);
- *ok = false;
return impl()->NullStatement();
}
- return ParseHoistableDeclaration(pos, flags, nullptr, false, ok);
+ return ParseHoistableDeclaration(pos, flags, nullptr, false);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseHoistableDeclaration(
- ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) {
- Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
+ ZonePtrList<const AstRawString>* names, bool default_export) {
+ Consume(Token::FUNCTION);
+
int pos = position();
ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal;
if (Check(Token::MUL)) {
flags |= ParseFunctionFlag::kIsGenerator;
}
- return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
+ return ParseHoistableDeclaration(pos, flags, names, default_export);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseHoistableDeclaration(
int pos, ParseFunctionFlags flags, ZonePtrList<const AstRawString>* names,
- bool default_export, bool* ok) {
+ bool default_export) {
+ CheckStackOverflow();
+
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
// 'function' '(' FormalParameters ')' '{' FunctionBody '}'
@@ -4057,10 +3607,8 @@ ParserBase<Impl>::ParseHoistableDeclaration(
impl()->GetDefaultStrings(&name, &variable_name);
name_validity = kSkipFunctionNameCheck;
} else {
- bool is_strict_reserved;
- bool is_await = false;
- name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await,
- CHECK_OK_CUSTOM(NullStatement));
+ bool is_strict_reserved = Token::IsStrictReservedWord(peek());
+ name = ParseIdentifier();
name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown;
variable_name = name;
@@ -4073,8 +3621,7 @@ ParserBase<Impl>::ParseHoistableDeclaration(
FunctionLiteralT function = impl()->ParseFunctionLiteral(
name, scanner()->location(), name_validity, kind, pos,
- FunctionLiteral::kDeclaration, language_mode(), nullptr,
- CHECK_OK_CUSTOM(NullStatement));
+ FunctionLiteral::kDeclaration, language_mode(), nullptr);
// In ES6, a function behaves as a lexical binding, except in
// a script scope, or the initial scope of eval or another function.
@@ -4092,12 +3639,13 @@ ParserBase<Impl>::ParseHoistableDeclaration(
flags == ParseFunctionFlag::kIsNormal;
return impl()->DeclareFunction(variable_name, function, mode, pos,
- is_sloppy_block_function, names, ok);
+ end_position(), is_sloppy_block_function,
+ names);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration(
- ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) {
+ ZonePtrList<const AstRawString>* names, bool default_export) {
// ClassDeclaration ::
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
// 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
@@ -4118,24 +3666,22 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration(
int class_token_pos = position();
IdentifierT name = impl()->NullIdentifier();
- bool is_strict_reserved = false;
+ bool is_strict_reserved = Token::IsStrictReservedWord(peek());
IdentifierT variable_name = impl()->NullIdentifier();
if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) {
impl()->GetDefaultStrings(&name, &variable_name);
} else {
- bool is_await = false;
- name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await,
- CHECK_OK_CUSTOM(NullStatement));
+ name = ParseIdentifier();
variable_name = name;
}
- ExpressionClassifier no_classifier(this);
- ExpressionT value =
- ParseClassLiteral(name, scanner()->location(), is_strict_reserved,
- class_token_pos, CHECK_OK_CUSTOM(NullStatement));
+ ExpressionParsingScope no_expression_scope(impl());
+ ExpressionT value = ParseClassLiteral(name, scanner()->location(),
+ is_strict_reserved, class_token_pos);
+ no_expression_scope.ValidateExpression();
int end_pos = position();
return impl()->DeclareClass(variable_name, value, names, class_token_pos,
- end_pos, ok);
+ end_pos);
}
// Language extension which is only enabled for source files loaded
@@ -4143,86 +3689,84 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration(
// declaration is resolved by looking up the function through a
// callback provided by the extension.
template <typename Impl>
-typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseNativeDeclaration(
- bool* ok) {
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseNativeDeclaration() {
function_state_->DisableOptimization(BailoutReason::kNativeFunctionLiteral);
int pos = peek_position();
- Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
+ Consume(Token::FUNCTION);
// Allow "eval" or "arguments" for backward compatibility.
- IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers,
- CHECK_OK_CUSTOM(NullStatement));
- Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullStatement));
+ IdentifierT name = ParseIdentifier();
+ Expect(Token::LPAREN);
if (peek() != Token::RPAREN) {
do {
- ParseIdentifier(kAllowRestrictedIdentifiers,
- CHECK_OK_CUSTOM(NullStatement));
+ ParseIdentifier();
} while (Check(Token::COMMA));
}
- Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullStatement));
- Expect(Token::SEMICOLON, CHECK_OK_CUSTOM(NullStatement));
- return impl()->DeclareNative(name, pos, ok);
+ Expect(Token::RPAREN);
+ Expect(Token::SEMICOLON);
+ return impl()->DeclareNative(name, pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseAsyncFunctionDeclaration(
- ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) {
+ ZonePtrList<const AstRawString>* names, bool default_export) {
// AsyncFunctionDeclaration ::
// async [no LineTerminator here] function BindingIdentifier[Await]
// ( FormalParameters[Await] ) { AsyncFunctionBody }
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
int pos = position();
- if (scanner()->HasLineTerminatorBeforeNext()) {
- *ok = false;
- impl()->ReportUnexpectedToken(scanner()->current_token());
- return impl()->NullStatement();
- }
- Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
+ DCHECK(!scanner()->HasLineTerminatorBeforeNext());
+ Consume(Token::FUNCTION);
ParseFunctionFlags flags = ParseFunctionFlag::kIsAsync;
- return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
+ return ParseHoistableDeclaration(pos, flags, names, default_export);
}
template <typename Impl>
void ParserBase<Impl>::ParseFunctionBody(
- typename ParserBase<Impl>::StatementListT result, IdentifierT function_name,
- int pos, const FormalParametersT& parameters, FunctionKind kind,
- FunctionLiteral::FunctionType function_type, FunctionBodyType body_type,
- bool accept_IN, bool* ok) {
- DeclarationScope* function_scope = scope()->AsDeclarationScope();
+ StatementListT* body, IdentifierT function_name, int pos,
+ const FormalParametersT& parameters, FunctionKind kind,
+ FunctionLiteral::FunctionType function_type, FunctionBodyType body_type) {
+ FunctionBodyParsingScope body_parsing_scope(impl());
+
+ if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables();
+
+ DeclarationScope* function_scope = parameters.scope;
DeclarationScope* inner_scope = function_scope;
- BlockT inner_block = impl()->NullStatement();
- StatementListT body = result;
- if (!parameters.is_simple) {
+ // Building the parameter initialization block declares the parameters.
+ // TODO(verwaest): Rely on ArrowHeadParsingScope instead.
+ if (V8_UNLIKELY(!parameters.is_simple)) {
+ if (has_error()) return;
+ BlockT init_block = impl()->BuildParameterInitializationBlock(parameters);
+ if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) {
+ init_block = impl()->BuildRejectPromiseOnException(init_block);
+ }
+ body->Add(init_block);
+ if (has_error()) return;
+
inner_scope = NewVarblockScope();
inner_scope->set_start_position(scanner()->location().beg_pos);
- inner_block = factory()->NewBlock(8, true);
- inner_block->set_scope(inner_scope);
- body = inner_block->statements();
}
+ StatementListT inner_body(pointer_buffer());
+
{
BlockState block_state(&scope_, inner_scope);
- if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables();
-
if (body_type == FunctionBodyType::kExpression) {
- ExpressionClassifier classifier(this);
- ExpressionT expression =
- ParseAssignmentExpression(accept_IN, CHECK_OK_VOID);
- ValidateExpression(CHECK_OK_VOID);
+ ExpressionT expression = ParseAssignmentExpression();
if (IsAsyncFunction(kind)) {
BlockT block = factory()->NewBlock(1, true);
- impl()->RewriteAsyncFunctionBody(body, block, expression,
- CHECK_OK_VOID);
+ impl()->RewriteAsyncFunctionBody(&inner_body, block, expression);
} else {
- body->Add(BuildReturnStatement(expression, expression->position()),
- zone());
+ inner_body.Add(
+ BuildReturnStatement(expression, expression->position()));
}
} else {
- DCHECK(accept_IN);
+ DCHECK(accept_IN_);
DCHECK_EQ(FunctionBodyType::kBlock, body_type);
// If we are parsing the source as if it is wrapped in a function, the
// source ends without a closing brace.
@@ -4231,63 +3775,64 @@ void ParserBase<Impl>::ParseFunctionBody(
: Token::RBRACE;
if (IsAsyncGeneratorFunction(kind)) {
- impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind, body,
- CHECK_OK_VOID);
+ impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind,
+ &inner_body);
} else if (IsGeneratorFunction(kind)) {
- impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body,
- CHECK_OK_VOID);
+ impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, &inner_body);
} else if (IsAsyncFunction(kind)) {
- ParseAsyncFunctionBody(inner_scope, body, CHECK_OK_VOID);
+ ParseAsyncFunctionBody(inner_scope, &inner_body);
} else {
- ParseStatementList(body, closing_token, CHECK_OK_VOID);
+ ParseStatementList(&inner_body, closing_token);
}
if (IsDerivedConstructor(kind)) {
- body->Add(factory()->NewReturnStatement(impl()->ThisExpression(),
- kNoSourcePosition),
- zone());
+ inner_body.Add(factory()->NewReturnStatement(impl()->ThisExpression(),
+ kNoSourcePosition));
}
- Expect(closing_token, CHECK_OK_VOID);
+ Expect(closing_token);
}
}
scope()->set_end_position(end_position());
- if (!parameters.is_simple) {
+ bool allow_duplicate_parameters = false;
+
+ if (V8_LIKELY(parameters.is_simple)) {
+ DCHECK_EQ(inner_scope, function_scope);
+ if (is_sloppy(function_scope->language_mode())) {
+ impl()->InsertSloppyBlockFunctionVarBindings(function_scope);
+ }
+ allow_duplicate_parameters =
+ is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind);
+ } else {
DCHECK_NOT_NULL(inner_scope);
DCHECK_EQ(function_scope, scope());
DCHECK_EQ(function_scope, inner_scope->outer_scope());
impl()->SetLanguageMode(function_scope, inner_scope->language_mode());
- BlockT init_block =
- impl()->BuildParameterInitializationBlock(parameters, CHECK_OK_VOID);
if (is_sloppy(inner_scope->language_mode())) {
impl()->InsertSloppyBlockFunctionVarBindings(inner_scope);
}
- // TODO(littledan): Merge the two rejection blocks into one
- if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) {
- init_block = impl()->BuildRejectPromiseOnException(init_block);
- }
-
inner_scope->set_end_position(end_position());
if (inner_scope->FinalizeBlockScope() != nullptr) {
- impl()->CheckConflictingVarDeclarations(inner_scope, CHECK_OK_VOID);
+ BlockT inner_block = factory()->NewBlock(true, inner_body);
+ inner_body.Rewind();
+ inner_body.Add(inner_block);
+ inner_block->set_scope(inner_scope);
+ const AstRawString* conflict = inner_scope->FindVariableDeclaredIn(
+ function_scope, VariableMode::kLastLexicalVariableMode);
+ if (conflict != nullptr) {
+ impl()->ReportVarRedeclarationIn(conflict, inner_scope);
+ }
+ impl()->CheckConflictingVarDeclarations(inner_scope);
impl()->InsertShadowingVarBindingInitializers(inner_block);
- } else {
- inner_block->set_scope(nullptr);
- }
- inner_scope = nullptr;
-
- result->Add(init_block, zone());
- result->Add(inner_block, zone());
- } else {
- DCHECK_EQ(inner_scope, function_scope);
- if (is_sloppy(function_scope->language_mode())) {
- impl()->InsertSloppyBlockFunctionVarBindings(function_scope);
}
}
+ ValidateFormalParameters(language_mode(), parameters,
+ allow_duplicate_parameters);
+
if (!IsArrowFunction(kind)) {
// Declare arguments after parsing the function since lexical 'arguments'
// masks the arguments object. Declare arguments before declaring the
@@ -4296,6 +3841,8 @@ void ParserBase<Impl>::ParseFunctionBody(
}
impl()->DeclareFunctionNameVar(function_name, function_type, function_scope);
+
+ inner_body.MergeInto(body);
}
template <typename Impl>
@@ -4303,26 +3850,23 @@ void ParserBase<Impl>::CheckArityRestrictions(int param_count,
FunctionKind function_kind,
bool has_rest,
int formals_start_pos,
- int formals_end_pos, bool* ok) {
+ int formals_end_pos) {
if (IsGetterFunction(function_kind)) {
if (param_count != 0) {
impl()->ReportMessageAt(
Scanner::Location(formals_start_pos, formals_end_pos),
MessageTemplate::kBadGetterArity);
- *ok = false;
}
} else if (IsSetterFunction(function_kind)) {
if (param_count != 1) {
impl()->ReportMessageAt(
Scanner::Location(formals_start_pos, formals_end_pos),
MessageTemplate::kBadSetterArity);
- *ok = false;
}
if (has_rest) {
impl()->ReportMessageAt(
Scanner::Location(formals_start_pos, formals_end_pos),
MessageTemplate::kBadSetterRestParameter);
- *ok = false;
}
}
}
@@ -4353,25 +3897,9 @@ bool ParserBase<Impl>::IsNextLetKeyword() {
}
template <typename Impl>
-bool ParserBase<Impl>::IsTrivialExpression() {
- if (Token::IsTrivialExpressionToken(peek())) {
- // PeekAhead() may not always be called, so we only call it after checking
- // peek().
- Token::Value peek_ahead = PeekAhead();
- if (peek_ahead == Token::COMMA || peek_ahead == Token::RPAREN ||
- peek_ahead == Token::SEMICOLON || peek_ahead == Token::RBRACK ||
- Token::IsAssignmentOp(peek_ahead)) {
- return true;
- }
- }
- return false;
-}
-
-template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseArrowFunctionLiteral(
- bool accept_IN, const FormalParametersT& formal_parameters,
- int rewritable_length, bool* ok) {
+ const FormalParametersT& formal_parameters) {
const RuntimeCallCounterId counters[2][2] = {
{RuntimeCallCounterId::kParseBackgroundArrowFunctionLiteral,
RuntimeCallCounterId::kParseArrowFunctionLiteral},
@@ -4383,16 +3911,15 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
base::ElapsedTimer timer;
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
- if (peek() == Token::ARROW && scanner_->HasLineTerminatorBeforeNext()) {
+ DCHECK_IMPLIES(!has_error(), peek() == Token::ARROW);
+ if (scanner_->HasLineTerminatorBeforeNext()) {
// 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 impl()->NullExpression();
+ impl()->ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW);
+ return impl()->FailureExpression();
}
- StatementListT body = impl()->NullStatementList();
int expected_property_count = -1;
int suspend_count = 0;
int function_literal_id = GetNextFunctionLiteralId();
@@ -4407,93 +3934,102 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
bool is_lazy_top_level_function =
can_preparse && impl()->AllowsLazyParsingWithoutUnresolvedVariables();
bool has_braces = true;
- ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr;
+ ProducedPreparseData* produced_preparse_data = nullptr;
+ StatementListT body(pointer_buffer());
{
FunctionState function_state(&function_state_, &scope_,
formal_parameters.scope);
- // Move any queued destructuring assignments which appeared
- // in this function's parameter list into its own function_state.
- function_state.AdoptDestructuringAssignmentsFromParentState(
- rewritable_length);
-
- Expect(Token::ARROW, CHECK_OK);
+ Consume(Token::ARROW);
if (peek() == Token::LBRACE) {
// Multiple statement body
DCHECK_EQ(scope(), formal_parameters.scope);
+
if (is_lazy_top_level_function) {
// FIXME(marja): Arrow function parameters will be parsed even if the
// body is preparsed; move relevant parts of parameter handling to
// simulate consistent parameter handling.
+ // Building the parameter initialization block declares the parameters.
+ // TODO(verwaest): Rely on ArrowHeadParsingScope instead.
+ if (!formal_parameters.is_simple) {
+ impl()->BuildParameterInitializationBlock(formal_parameters);
+ if (has_error()) return impl()->FailureExpression();
+ }
+
// For arrow functions, we don't need to retrieve data about function
// parameters.
int dummy_num_parameters = -1;
DCHECK_NE(kind & FunctionKind::kArrowFunction, 0);
- FunctionLiteral::EagerCompileHint hint;
bool did_preparse_successfully = impl()->SkipFunction(
nullptr, kind, FunctionLiteral::kAnonymousExpression,
formal_parameters.scope, &dummy_num_parameters,
- &produced_preparsed_scope_data, false, false, &hint, CHECK_OK);
+ &produced_preparse_data);
- DCHECK_NULL(produced_preparsed_scope_data);
+ DCHECK_NULL(produced_preparse_data);
if (did_preparse_successfully) {
- // Discard any queued destructuring assignments which appeared
- // in this function's parameter list, and which were adopted
- // into this function state, above.
- function_state.RewindDestructuringAssignments(0);
+ // Validate parameter names. We can do this only after preparsing the
+ // function, since the function can declare itself strict.
+ ValidateFormalParameters(language_mode(), formal_parameters, false);
} else {
// In case we did not sucessfully preparse the function because of an
// unidentified error we do a full reparse to return the error.
+ // Parse again in the outer scope, since the language mode may change.
+ BlockState block_state(&scope_, scope()->outer_scope());
+ ExpressionT expression = ParseConditionalExpression();
+ // Reparsing the head may have caused a stack overflow.
+ if (has_error()) return impl()->FailureExpression();
+
+ DeclarationScope* function_scope = next_arrow_function_info_.scope;
+ FunctionState function_state(&function_state_, &scope_,
+ function_scope);
+ Scanner::Location loc(function_scope->start_position(),
+ end_position());
+ FormalParametersT parameters(function_scope);
+ parameters.is_simple = function_scope->has_simple_parameters();
+ impl()->DeclareArrowFunctionFormalParameters(&parameters, expression,
+ loc);
+ next_arrow_function_info_.Reset();
+
+ Consume(Token::ARROW);
Consume(Token::LBRACE);
- body = impl()->NewStatementList(8);
- ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition,
- formal_parameters, kind,
+
+ AcceptINScope scope(this, true);
+ ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition,
+ parameters, kind,
FunctionLiteral::kAnonymousExpression,
- FunctionBodyType::kBlock, true, ok);
- CHECK(!*ok);
- return impl()->NullExpression();
+ FunctionBodyType::kBlock);
+ CHECK(has_error());
+ return impl()->FailureExpression();
}
} else {
Consume(Token::LBRACE);
- body = impl()->NewStatementList(8);
- ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition,
+ AcceptINScope scope(this, true);
+ ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition,
formal_parameters, kind,
FunctionLiteral::kAnonymousExpression,
- FunctionBodyType::kBlock, true, CHECK_OK);
+ FunctionBodyType::kBlock);
expected_property_count = function_state.expected_property_count();
}
} else {
// Single-expression body
has_braces = false;
- body = impl()->NewStatementList(1);
- ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition,
+ ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition,
formal_parameters, kind,
FunctionLiteral::kAnonymousExpression,
- FunctionBodyType::kExpression, accept_IN, CHECK_OK);
+ FunctionBodyType::kExpression);
expected_property_count = function_state.expected_property_count();
}
formal_parameters.scope->set_end_position(end_position());
- // 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;
- ValidateFormalParameters(language_mode(), allow_duplicate_parameters,
- CHECK_OK);
-
// Validate strict mode.
if (is_strict(language_mode())) {
CheckStrictOctalLiteral(formal_parameters.scope->start_position(),
- end_position(), CHECK_OK);
+ end_position());
}
- impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
-
- impl()->RewriteDestructuringAssignments();
suspend_count = function_state.suspend_count();
}
@@ -4504,7 +4040,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression, eager_compile_hint,
formal_parameters.scope->start_position(), has_braces,
- function_literal_id, produced_preparsed_scope_data);
+ function_literal_id, produced_preparse_data);
function_literal->set_suspend_count(suspend_count);
function_literal->set_function_token_position(
@@ -4528,7 +4064,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
IdentifierT name, Scanner::Location class_name_location,
- bool name_is_strict_reserved, int class_token_pos, bool* ok) {
+ bool name_is_strict_reserved, int class_token_pos) {
bool is_anonymous = impl()->IsNull(name);
// All parts of a ClassDeclaration and ClassExpression are strict code.
@@ -4536,14 +4072,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
if (name_is_strict_reserved) {
impl()->ReportMessageAt(class_name_location,
MessageTemplate::kUnexpectedStrictReserved);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
if (impl()->IsEvalOrArguments(name)) {
impl()->ReportMessageAt(class_name_location,
MessageTemplate::kStrictEvalArguments);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
}
@@ -4553,77 +4087,79 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
ClassInfo class_info(this);
class_info.is_anonymous = is_anonymous;
- impl()->DeclareClassVariable(name, &class_info, class_token_pos, CHECK_OK);
+ impl()->DeclareClassVariable(name, &class_info, class_token_pos);
scope()->set_start_position(end_position());
if (Check(Token::EXTENDS)) {
FuncNameInferrerState fni_state(&fni_);
- ExpressionClassifier extends_classifier(this);
- class_info.extends = ParseLeftHandSideExpression(CHECK_OK);
- ValidateExpression(CHECK_OK);
- AccumulateFormalParameterContainmentErrors();
+ ExpressionParsingScope scope(impl());
+ class_info.extends = ParseLeftHandSideExpression();
+ scope.ValidateExpression();
}
- ClassLiteralChecker checker(this);
-
- Expect(Token::LBRACE, CHECK_OK);
+ Expect(Token::LBRACE);
const bool has_extends = !impl()->IsNull(class_info.extends);
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
FuncNameInferrerState fni_state(&fni_);
- bool is_computed_name = false; // Classes do not care about computed
- // property names here.
- bool is_static;
- ClassLiteralProperty::Kind property_kind;
- ExpressionClassifier property_classifier(this);
- IdentifierT property_name;
// If we haven't seen the constructor yet, it potentially is the next
// property.
bool is_constructor = !class_info.has_seen_constructor;
- ClassLiteralPropertyT property = ParseClassPropertyDefinition(
- &checker, &class_info, &property_name, has_extends, &is_computed_name,
- &property_kind, &is_static, CHECK_OK);
- if (!class_info.has_static_computed_names && is_static &&
- is_computed_name) {
+ ParsePropertyInfo prop_info(this);
+ prop_info.position = PropertyPosition::kClassLiteral;
+ ClassLiteralPropertyT property =
+ ParseClassPropertyDefinition(&class_info, &prop_info, has_extends);
+
+ if (has_error()) return impl()->FailureExpression();
+
+ ClassLiteralProperty::Kind property_kind =
+ ClassPropertyKindFor(prop_info.kind);
+ if (!class_info.has_static_computed_names && prop_info.is_static &&
+ prop_info.is_computed_name) {
class_info.has_static_computed_names = true;
}
- if (is_computed_name &&
- property_kind == ClassLiteralProperty::PUBLIC_FIELD) {
- class_info.computed_field_count++;
- }
is_constructor &= class_info.has_seen_constructor;
- ValidateExpression(CHECK_OK);
- AccumulateFormalParameterContainmentErrors();
- impl()->DeclareClassProperty(name, property, property_name, property_kind,
- is_static, is_constructor, is_computed_name,
- &class_info, CHECK_OK);
+ if (V8_UNLIKELY(property_kind == ClassLiteralProperty::FIELD)) {
+ if (prop_info.is_computed_name) {
+ DCHECK(!prop_info.is_private);
+ class_info.computed_field_count++;
+ }
+
+ impl()->DeclareClassField(property, prop_info.name, prop_info.is_static,
+ prop_info.is_computed_name,
+ prop_info.is_private, &class_info);
+ } else {
+ impl()->DeclareClassProperty(name, property, is_constructor, &class_info);
+ }
impl()->InferFunctionName();
}
- Expect(Token::RBRACE, CHECK_OK);
+ Expect(Token::RBRACE);
int end_pos = end_position();
block_scope->set_end_position(end_pos);
return impl()->RewriteClassLiteral(block_scope, name, &class_info,
- class_token_pos, end_pos, ok);
+ class_token_pos, end_pos);
}
template <typename Impl>
-void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body,
- bool* ok) {
- BlockT block = factory()->NewBlock(8, true);
-
- ParseStatementList(block->statements(), Token::RBRACE, CHECK_OK_VOID);
+void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope,
+ StatementListT* body) {
+ BlockT block = impl()->NullBlock();
+ {
+ StatementListT statements(pointer_buffer());
+ ParseStatementList(&statements, Token::RBRACE);
+ block = factory()->NewBlock(true, statements);
+ }
impl()->RewriteAsyncFunctionBody(
- body, block, factory()->NewUndefinedLiteral(kNoSourcePosition),
- CHECK_OK_VOID);
+ body, block, factory()->NewUndefinedLiteral(kNoSourcePosition));
scope->set_end_position(end_position());
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
+ParserBase<Impl>::ParseAsyncFunctionLiteral() {
// AsyncFunctionLiteral ::
// async [no LineTerminator here] function ( FormalParameters[Await] )
// { AsyncFunctionBody }
@@ -4632,43 +4168,41 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
// ( FormalParameters[Await] ) { AsyncFunctionBody }
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
int pos = position();
- Expect(Token::FUNCTION, CHECK_OK);
- bool is_strict_reserved = false;
+ Consume(Token::FUNCTION);
IdentifierT name = impl()->NullIdentifier();
FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
ParseFunctionFlags flags = ParseFunctionFlag::kIsAsync;
if (Check(Token::MUL)) flags |= ParseFunctionFlag::kIsGenerator;
const FunctionKind kind = FunctionKindFor(flags);
+ bool is_strict_reserved = Token::IsStrictReservedWord(peek());
if (impl()->ParsingDynamicFunctionDeclaration()) {
// We don't want dynamic functions to actually declare their name
// "anonymous". We just want that name in the toString().
- if (stack_overflow()) {
- *ok = false;
- return impl()->NullExpression();
- }
+
+ // Consuming token we did not peek yet, which could lead to a ILLEGAL token
+ // in the case of a stackoverflow.
Consume(Token::IDENTIFIER);
- DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS));
+ DCHECK_IMPLIES(!has_error(),
+ scanner()->CurrentSymbol(ast_value_factory()) ==
+ ast_value_factory()->anonymous_string());
} else if (peek_any_identifier()) {
type = FunctionLiteral::kNamedExpression;
- bool is_await = false;
- name = ParseIdentifierOrStrictReservedWord(kind, &is_strict_reserved,
- &is_await, CHECK_OK);
- // If the function name is "await", ParseIdentifierOrStrictReservedWord
- // recognized the error.
- DCHECK(!is_await);
- }
- return impl()->ParseFunctionLiteral(
+ name = ParseIdentifier(kind);
+ }
+ FunctionLiteralT result = impl()->ParseFunctionLiteral(
name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
- kind, pos, type, language_mode(), nullptr, ok);
+ kind, pos, type, language_mode(), nullptr);
+ if (impl()->IsNull(result)) return impl()->FailureExpression();
+ return result;
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
- ExpressionT tag, int start, bool tagged, bool* ok) {
+ ExpressionT tag, int start, bool tagged) {
// 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.
@@ -4696,7 +4230,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
Consume(Token::TEMPLATE_TAIL);
int pos = position();
typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos);
- bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK);
+ bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes);
impl()->AddTemplateSpan(&ts, is_valid, true);
return impl()->CloseTemplateLiteral(&ts, start, tag);
}
@@ -4704,7 +4238,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
Consume(Token::TEMPLATE_SPAN);
int pos = position();
typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos);
- bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK);
+ bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes);
impl()->AddTemplateSpan(&ts, is_valid, false);
Token::Value next;
@@ -4714,29 +4248,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
do {
next = peek();
- if (next == Token::EOS) {
- impl()->ReportMessageAt(Scanner::Location(start, peek_position()),
- MessageTemplate::kUnterminatedTemplate);
- *ok = false;
- return impl()->NullExpression();
- } else if (next == Token::ILLEGAL) {
- impl()->ReportMessageAt(
- Scanner::Location(position() + 1, peek_position()),
- MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
- *ok = false;
- return impl()->NullExpression();
- }
int expr_pos = peek_position();
- ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ AcceptINScope scope(this, true);
+ ExpressionT expression = ParseExpressionCoverGrammar();
impl()->AddTemplateExpression(&ts, expression);
if (peek() != Token::RBRACE) {
impl()->ReportMessageAt(Scanner::Location(expr_pos, peek_position()),
MessageTemplate::kUnterminatedTemplateExpr);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
}
// If we didn't die parsing that expression, our next token should be a
@@ -4745,53 +4266,34 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
Next();
pos = position();
- if (next == Token::EOS) {
- impl()->ReportMessageAt(Scanner::Location(start, pos),
- MessageTemplate::kUnterminatedTemplate);
- *ok = false;
- return impl()->NullExpression();
- } else if (next == Token::ILLEGAL) {
- impl()->ReportMessageAt(
- Scanner::Location(position() + 1, peek_position()),
- MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
- *ok = false;
- return impl()->NullExpression();
- }
-
- bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK);
+ bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes);
impl()->AddTemplateSpan(&ts, is_valid, next == Token::TEMPLATE_TAIL);
} while (next == Token::TEMPLATE_SPAN);
- DCHECK_EQ(next, Token::TEMPLATE_TAIL);
+ DCHECK_IMPLIES(!has_error(), next == Token::TEMPLATE_TAIL);
// Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
return impl()->CloseTemplateLiteral(&ts, start, tag);
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::CheckAndRewriteReferenceExpression(
- ExpressionT expression, int beg_pos, int end_pos,
- MessageTemplate::Template message, bool* ok) {
- return CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos,
- message, kReferenceError, ok);
-}
+ParserBase<Impl>::RewriteInvalidReferenceExpression(ExpressionT expression,
+ int beg_pos, int end_pos,
+ MessageTemplate message,
+ ParseErrorType type) {
+ DCHECK(!IsValidReferenceExpression(expression));
+ if (impl()->IsIdentifier(expression)) {
+ DCHECK(is_strict(language_mode()));
+ DCHECK(impl()->IsEvalOrArguments(impl()->AsIdentifier(expression)));
-template <typename Impl>
-typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::CheckAndRewriteReferenceExpression(
- ExpressionT expression, int beg_pos, int end_pos,
- MessageTemplate::Template message, ParseErrorType type, bool* ok) {
- if (impl()->IsIdentifier(expression) && is_strict(language_mode()) &&
- impl()->IsEvalOrArguments(impl()->AsIdentifier(expression))) {
ReportMessageAt(Scanner::Location(beg_pos, end_pos),
MessageTemplate::kStrictEvalArguments, kSyntaxError);
- *ok = false;
- return impl()->NullExpression();
- }
- if (expression->IsValidReferenceExpression()) {
- return expression;
+ return impl()->FailureExpression();
}
if (expression->IsCall() && !expression->AsCall()->is_tagged_template()) {
+ expression_scope()->RecordPatternError(
+ Scanner::Location(beg_pos, end_pos),
+ MessageTemplate::kInvalidDestructuringTarget);
// If it is a call, make it a runtime error for legacy web compatibility.
// Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480
// Rewrite `expr' to `expr[throw ReferenceError]'.
@@ -4803,8 +4305,35 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression(
return factory()->NewProperty(expression, error, beg_pos);
}
ReportMessageAt(Scanner::Location(beg_pos, end_pos), message, type);
- *ok = false;
- return impl()->NullExpression();
+ return impl()->FailureExpression();
+}
+
+template <typename Impl>
+void ParserBase<Impl>::ClassifyParameter(IdentifierT parameter, int begin,
+ int end) {
+ if (impl()->IsEvalOrArguments(parameter)) {
+ expression_scope()->RecordStrictModeParameterError(
+ Scanner::Location(begin, end), MessageTemplate::kStrictEvalArguments);
+ }
+}
+
+template <typename Impl>
+void ParserBase<Impl>::ClassifyArrowParameter(
+ AccumulationScope* accumulation_scope, int position,
+ ExpressionT parameter) {
+ accumulation_scope->Accumulate();
+ if (parameter->is_parenthesized() ||
+ !(impl()->IsIdentifier(parameter) || parameter->IsPattern() ||
+ parameter->IsAssignment())) {
+ expression_scope()->RecordDeclarationError(
+ Scanner::Location(position, end_position()),
+ MessageTemplate::kInvalidDestructuringTarget);
+ } else if (impl()->IsIdentifier(parameter)) {
+ ClassifyParameter(impl()->AsIdentifier(parameter), position,
+ end_position());
+ } else {
+ expression_scope()->RecordNonSimpleParameter();
+ }
}
template <typename Impl>
@@ -4813,147 +4342,133 @@ bool ParserBase<Impl>::IsValidReferenceExpression(ExpressionT expression) {
}
template <typename Impl>
-void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression,
- int begin, int end) {
- if (!IsValidPattern(expression) && !expression->IsAssignment() &&
- !IsValidReferenceExpression(expression)) {
- classifier()->RecordAssignmentPatternError(
- Scanner::Location(begin, end),
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParsePossibleDestructuringSubPattern(
+ AccumulationScope* scope) {
+ if (scope) scope->Accumulate();
+ int begin = peek_position();
+ ExpressionT result = ParseAssignmentExpressionCoverGrammar();
+
+ if (IsValidReferenceExpression(result)) {
+ // Parenthesized identifiers and property references are allowed as part of
+ // a larger assignment pattern, even though parenthesized patterns
+ // themselves are not allowed, e.g., "[(x)] = []". Only accumulate
+ // assignment pattern errors if the parsed expression is more complex.
+ if (impl()->IsIdentifier(result)) {
+ if (result->is_parenthesized()) {
+ expression_scope()->RecordDeclarationError(
+ Scanner::Location(begin, end_position()),
+ MessageTemplate::kInvalidDestructuringTarget);
+ }
+ IdentifierT identifier = impl()->AsIdentifier(result);
+ ClassifyParameter(identifier, begin, end_position());
+ } else {
+ DCHECK(result->IsProperty());
+ expression_scope()->RecordDeclarationError(
+ Scanner::Location(begin, end_position()),
+ MessageTemplate::kInvalidPropertyBindingPattern);
+ if (scope != nullptr) scope->ValidateExpression();
+ }
+ } else if (result->is_parenthesized() ||
+ (!result->IsPattern() && !result->IsAssignment())) {
+ expression_scope()->RecordPatternError(
+ Scanner::Location(begin, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
}
+
+ return result;
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic(
- bool* ok) {
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic() {
// CallRuntime ::
// '%' Identifier Arguments
int pos = peek_position();
- Expect(Token::MOD, CHECK_OK);
+ Consume(Token::MOD);
// Allow "eval" or "arguments" for backward compatibility.
- IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
- Scanner::Location spread_pos;
- ExpressionClassifier classifier(this);
- ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK);
-
- if (spread_pos.IsValid()) {
- *ok = false;
- ReportMessageAt(spread_pos, MessageTemplate::kIntrinsicWithSpread,
- kSyntaxError);
- return impl()->NullExpression();
+ IdentifierT name = ParseIdentifier();
+ if (peek() != Token::LPAREN) {
+ impl()->ReportUnexpectedToken(peek());
+ return impl()->FailureExpression();
}
+ bool has_spread;
+ ExpressionListT args(pointer_buffer());
+ ParseArguments(&args, &has_spread);
- return impl()->NewV8Intrinsic(name, args, pos, ok);
-}
-
-template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseDoExpression(
- bool* ok) {
- // AssignmentExpression ::
- // do '{' StatementList '}'
+ if (has_spread) {
+ ReportMessageAt(Scanner::Location(pos, position()),
+ MessageTemplate::kIntrinsicWithSpread, kSyntaxError);
+ return impl()->FailureExpression();
+ }
- int pos = peek_position();
- Expect(Token::DO, CHECK_OK);
- BlockT block = ParseBlock(nullptr, CHECK_OK);
- return impl()->RewriteDoExpression(block, pos, ok);
+ return impl()->NewV8Intrinsic(name, args, pos);
}
-// Redefinition of CHECK_OK for parsing statements.
-#undef CHECK_OK
-#define CHECK_OK CHECK_OK_CUSTOM(NullStatement)
-
template <typename Impl>
-typename ParserBase<Impl>::LazyParsingResult
-ParserBase<Impl>::ParseStatementList(StatementListT body,
- Token::Value end_token, bool may_abort,
- bool* ok) {
+void ParserBase<Impl>::ParseStatementList(StatementListT* body,
+ Token::Value end_token) {
// StatementList ::
// (StatementListItem)* <end_token>
+ DCHECK_NOT_NULL(body);
- // 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.
- typename Types::TargetScope target_scope(this);
- int count_statements = 0;
+ while (peek() == Token::STRING) {
+ bool use_strict = false;
+ bool use_asm = false;
- DCHECK(!impl()->IsNull(body));
- bool directive_prologue = true; // Parsing directive prologue.
+ Scanner::Location token_loc = scanner()->peek_location();
- while (peek() != end_token) {
- if (directive_prologue && peek() != Token::STRING) {
- directive_prologue = false;
+ if (scanner()->NextLiteralEquals("use strict")) {
+ use_strict = true;
+ } else if (scanner()->NextLiteralEquals("use asm")) {
+ use_asm = true;
}
- bool starts_with_identifier = peek() == Token::IDENTIFIER;
- Scanner::Location token_loc = scanner()->peek_location();
- StatementT stat =
- ParseStatementListItem(CHECK_OK_CUSTOM(Return, kLazyParsingComplete));
-
- if (impl()->IsNull(stat) || stat->IsEmptyStatement()) {
- directive_prologue = false; // End of directive prologue.
- continue;
- }
-
- if (directive_prologue) {
- // The length of the token is used to distinguish between strings literals
- // that evaluate equal to directives but contain either escape sequences
- // (e.g., "use \x73trict") or line continuations (e.g., "use \(newline)
- // strict").
- if (impl()->IsUseStrictDirective(stat) &&
- token_loc.end_pos - token_loc.beg_pos == sizeof("use strict") + 1) {
- // Directive "use strict" (ES5 14.1).
- RaiseLanguageMode(LanguageMode::kStrict);
- 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
- impl()->ReportMessageAt(
- token_loc, MessageTemplate::kIllegalLanguageModeDirective,
- "use strict");
- *ok = false;
- return kLazyParsingComplete;
- }
- } else if (impl()->IsUseAsmDirective(stat) &&
- token_loc.end_pos - token_loc.beg_pos ==
- sizeof("use asm") + 1) {
- // Directive "use asm".
- impl()->SetAsmModule();
- } else if (impl()->IsStringLiteral(stat)) {
- // Possibly an unknown directive.
- // Should not change mode, but will increment usage counters
- // as appropriate. Ditto usages below.
- RaiseLanguageMode(LanguageMode::kSloppy);
- } else {
- // End of the directive prologue.
- directive_prologue = false;
- RaiseLanguageMode(LanguageMode::kSloppy);
+ StatementT stat = ParseStatementListItem();
+ if (impl()->IsNull(stat)) return;
+
+ body->Add(stat);
+
+ if (!impl()->IsStringLiteral(stat)) break;
+
+ if (use_strict) {
+ // Directive "use strict" (ES5 14.1).
+ RaiseLanguageMode(LanguageMode::kStrict);
+ 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
+ impl()->ReportMessageAt(token_loc,
+ MessageTemplate::kIllegalLanguageModeDirective,
+ "use strict");
+ return;
}
+ } else if (use_asm) {
+ // Directive "use asm".
+ impl()->SetAsmModule();
} else {
+ // Possibly an unknown directive.
+ // Should not change mode, but will increment usage counters
+ // as appropriate. Ditto usages below.
RaiseLanguageMode(LanguageMode::kSloppy);
}
+ }
- // If we're allowed to abort, we will do so when we see a "long and
- // trivial" function. Our current definition of "long and trivial" is:
- // - over kLazyParseTrialLimit statements
- // - all starting with an identifier (i.e., no if, for, while, etc.)
- if (may_abort) {
- if (!starts_with_identifier) {
- may_abort = false;
- } else if (++count_statements > kLazyParseTrialLimit) {
- return kLazyParsingAborted;
- }
- }
-
- body->Add(stat, zone());
+ // 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.
+ TargetScopeT target_scope(this);
+ while (peek() != end_token) {
+ StatementT stat = ParseStatementListItem();
+ if (impl()->IsNull(stat)) return;
+ if (stat->IsEmptyStatement()) continue;
+ body->Add(stat);
}
- return kLazyParsingComplete;
}
template <typename Impl>
-typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem(
- bool* ok) {
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseStatementListItem() {
// ECMA 262 6th Edition
// StatementListItem[Yield, Return] :
// Statement[?Yield, ?Return]
@@ -4973,36 +4488,36 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem(
switch (peek()) {
case Token::FUNCTION:
- return ParseHoistableDeclaration(nullptr, false, ok);
+ return ParseHoistableDeclaration(nullptr, false);
case Token::CLASS:
Consume(Token::CLASS);
- return ParseClassDeclaration(nullptr, false, ok);
+ return ParseClassDeclaration(nullptr, false);
case Token::VAR:
case Token::CONST:
- return ParseVariableStatement(kStatementListItem, nullptr, ok);
+ return ParseVariableStatement(kStatementListItem, nullptr);
case Token::LET:
if (IsNextLetKeyword()) {
- return ParseVariableStatement(kStatementListItem, nullptr, ok);
+ return ParseVariableStatement(kStatementListItem, nullptr);
}
break;
case Token::ASYNC:
if (PeekAhead() == Token::FUNCTION &&
!scanner()->HasLineTerminatorAfterNext()) {
Consume(Token::ASYNC);
- return ParseAsyncFunctionDeclaration(nullptr, false, ok);
+ return ParseAsyncFunctionDeclaration(nullptr, false);
}
break;
default:
break;
}
- return ParseStatement(nullptr, nullptr, kAllowLabelledFunctionStatement, ok);
+ return ParseStatement(nullptr, nullptr, kAllowLabelledFunctionStatement);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
- AllowLabelledFunctionStatement allow_function, bool* ok) {
+ AllowLabelledFunctionStatement allow_function) {
// Statement ::
// Block
// VariableStatement
@@ -5031,46 +4546,48 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
// parsed into an empty statement.
switch (peek()) {
case Token::LBRACE:
- return ParseBlock(labels, ok);
+ return ParseBlock(labels);
case Token::SEMICOLON:
Next();
- return factory()->NewEmptyStatement(kNoSourcePosition);
+ return factory()->EmptyStatement();
case Token::IF:
- return ParseIfStatement(labels, ok);
+ return ParseIfStatement(labels);
case Token::DO:
- return ParseDoWhileStatement(labels, own_labels, ok);
+ return ParseDoWhileStatement(labels, own_labels);
case Token::WHILE:
- return ParseWhileStatement(labels, own_labels, ok);
+ return ParseWhileStatement(labels, own_labels);
case Token::FOR:
if (V8_UNLIKELY(is_async_function() && PeekAhead() == Token::AWAIT)) {
- return ParseForAwaitStatement(labels, own_labels, ok);
+ return ParseForAwaitStatement(labels, own_labels);
}
- return ParseForStatement(labels, own_labels, ok);
+ return ParseForStatement(labels, own_labels);
case Token::CONTINUE:
- return ParseContinueStatement(ok);
+ return ParseContinueStatement();
case Token::BREAK:
- return ParseBreakStatement(labels, ok);
+ return ParseBreakStatement(labels);
case Token::RETURN:
- return ParseReturnStatement(ok);
+ return ParseReturnStatement();
case Token::THROW:
- return ParseThrowStatement(ok);
+ return ParseThrowStatement();
case Token::TRY: {
// It is somewhat complicated to have labels on try-statements.
// When breaking out of a try-finally statement, one must take
// great care not to treat it as a fall-through. It is much easier
// just to wrap the entire try-statement in a statement block and
// put the labels there.
- if (labels == nullptr) return ParseTryStatement(ok);
- BlockT result = factory()->NewBlock(1, false, labels);
- typename Types::Target target(this, result);
- StatementT statement = ParseTryStatement(CHECK_OK);
- result->statements()->Add(statement, zone());
+ if (labels == nullptr) return ParseTryStatement();
+ StatementListT statements(pointer_buffer());
+ BlockT result = factory()->NewBlock(false, labels);
+ TargetT target(this, result);
+ StatementT statement = ParseTryStatement();
+ statements.Add(statement);
+ result->InitializeStatements(statements, zone());
return result;
}
case Token::WITH:
- return ParseWithStatement(labels, ok);
+ return ParseWithStatement(labels);
case Token::SWITCH:
- return ParseSwitchStatement(labels, ok);
+ return ParseSwitchStatement(labels);
case Token::FUNCTION:
// FunctionDeclaration only allowed as a StatementListItem, not in
// an arbitrary Statement position. Exceptions such as
@@ -5081,72 +4598,77 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
is_strict(language_mode())
? MessageTemplate::kStrictFunction
: MessageTemplate::kSloppyFunction);
- *ok = false;
return impl()->NullStatement();
case Token::DEBUGGER:
- return ParseDebuggerStatement(ok);
+ return ParseDebuggerStatement();
case Token::VAR:
- return ParseVariableStatement(kStatement, nullptr, ok);
+ return ParseVariableStatement(kStatement, nullptr);
case Token::ASYNC:
if (!scanner()->HasLineTerminatorAfterNext() &&
PeekAhead() == Token::FUNCTION) {
impl()->ReportMessageAt(
scanner()->peek_location(),
MessageTemplate::kAsyncFunctionInSingleStatementContext);
- *ok = false;
return impl()->NullStatement();
}
V8_FALLTHROUGH;
default:
return ParseExpressionOrLabelledStatement(labels, own_labels,
- allow_function, ok);
+ allow_function);
}
}
template <typename Impl>
typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
- ZonePtrList<const AstRawString>* labels, bool* ok) {
+ ZonePtrList<const AstRawString>* labels) {
// Block ::
// '{' StatementList '}'
- // Construct block expecting 16 statements.
- BlockT body = factory()->NewBlock(16, false, labels);
-
// Parse the statements and collect escaping labels.
- Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullStatement));
+ BlockT body = factory()->NewBlock(false, labels);
+ StatementListT statements(pointer_buffer());
+
+ CheckStackOverflow();
+
{
BlockState block_state(zone(), &scope_);
- scope()->set_start_position(scanner()->location().beg_pos);
- typename Types::Target target(this, body);
+ scope()->set_start_position(peek_position());
+ TargetT target(this, body);
+
+ Expect(Token::LBRACE);
while (peek() != Token::RBRACE) {
- StatementT stat = ParseStatementListItem(CHECK_OK_CUSTOM(NullStatement));
- if (!impl()->IsNull(stat) && !stat->IsEmptyStatement()) {
- body->statements()->Add(stat, zone());
- }
+ StatementT stat = ParseStatementListItem();
+ if (impl()->IsNull(stat)) return body;
+ if (stat->IsEmptyStatement()) continue;
+ statements.Add(stat);
}
- Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullStatement));
+ Expect(Token::RBRACE);
+
int end_pos = end_position();
scope()->set_end_position(end_pos);
+
impl()->RecordBlockSourceRange(body, end_pos);
body->set_scope(scope()->FinalizeBlockScope());
}
+
+ body->InitializeStatements(statements, zone_);
return body;
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement(
- ZonePtrList<const AstRawString>* labels, bool* ok) {
+ ZonePtrList<const AstRawString>* labels) {
if (is_strict(language_mode()) || peek() != Token::FUNCTION) {
- return ParseStatement(labels, nullptr, ok);
+ return ParseStatement(labels, nullptr);
} else {
// Make a block around the statement for a lexical binding
// is introduced by a FunctionDeclaration.
BlockState block_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos);
BlockT block = factory()->NewBlock(1, false);
- StatementT body = ParseFunctionDeclaration(CHECK_OK);
+ StatementT body = ParseFunctionDeclaration();
block->statements()->Add(body, zone());
scope()->set_end_position(end_position());
block->set_scope(scope()->FinalizeBlockScope());
@@ -5157,7 +4679,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement(
VariableDeclarationContext var_context,
- ZonePtrList<const AstRawString>* names, bool* ok) {
+ ZonePtrList<const AstRawString>* names) {
// VariableStatement ::
// VariableDeclarations ';'
@@ -5174,15 +4696,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement(
// is inside an initializer block, it is ignored.
DeclarationParsingResult parsing_result;
- StatementT result =
- ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK);
- ExpectSemicolon(ok);
- return result;
+ ParseVariableDeclarations(var_context, &parsing_result, names);
+ ExpectSemicolon();
+ return impl()->BuildInitializationBlock(&parsing_result);
}
template <typename Impl>
-typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDebuggerStatement(
- bool* ok) {
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseDebuggerStatement() {
// 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.
@@ -5190,8 +4711,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDebuggerStatement(
// 'debugger' ';'
int pos = peek_position();
- Expect(Token::DEBUGGER, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
+ Consume(Token::DEBUGGER);
+ ExpectSemicolon();
return factory()->NewDebuggerStatement(pos);
}
@@ -5200,7 +4721,7 @@ typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseExpressionOrLabelledStatement(
ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
- AllowLabelledFunctionStatement allow_function, bool* ok) {
+ AllowLabelledFunctionStatement allow_function) {
// ExpressionStatement | LabelledStatement ::
// Expression ';'
// Identifier ':' Statement
@@ -5216,7 +4737,6 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
UNREACHABLE(); // Always handled by the callers.
case Token::CLASS:
ReportUnexpectedToken(Next());
- *ok = false;
return impl()->NullStatement();
case Token::LET: {
Token::Value next_next = PeekAhead();
@@ -5230,7 +4750,6 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
}
impl()->ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kUnexpectedLexicalDeclaration);
- *ok = false;
return impl()->NullStatement();
}
default:
@@ -5238,20 +4757,20 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
}
bool starts_with_identifier = peek_any_identifier();
- ExpressionT expr = ParseExpression(CHECK_OK);
+ ExpressionT expr = ParseExpression();
if (peek() == Token::COLON && starts_with_identifier &&
impl()->IsIdentifier(expr)) {
// The whole expression was a single identifier, and not, e.g.,
// something starting with an identifier or a parenthesized identifier.
impl()->DeclareLabel(&labels, &own_labels,
- impl()->AsIdentifierExpression(expr), CHECK_OK);
+ impl()->AsIdentifierExpression(expr));
Consume(Token::COLON);
// ES#sec-labelled-function-declarations Labelled Function Declarations
if (peek() == Token::FUNCTION && is_sloppy(language_mode()) &&
allow_function == kAllowLabelledFunctionStatement) {
- return ParseFunctionDeclaration(ok);
+ return ParseFunctionDeclaration();
}
- return ParseStatement(labels, own_labels, allow_function, ok);
+ return ParseStatement(labels, own_labels, allow_function);
}
// If we have an extension, we allow a native function declaration.
@@ -5260,39 +4779,46 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
if (extension_ != nullptr && peek() == Token::FUNCTION &&
!scanner()->HasLineTerminatorBeforeNext() && impl()->IsNative(expr) &&
!scanner()->literal_contains_escapes()) {
- return ParseNativeDeclaration(ok);
+ return ParseNativeDeclaration();
}
// Parsed expression statement, followed by semicolon.
- ExpectSemicolon(CHECK_OK);
+ ExpectSemicolon();
+ if (expr->IsFailureExpression()) return impl()->NullStatement();
return factory()->NewExpressionStatement(expr, pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
- ZonePtrList<const AstRawString>* labels, bool* ok) {
+ ZonePtrList<const AstRawString>* labels) {
// IfStatement ::
// 'if' '(' Expression ')' Statement ('else' Statement)?
int pos = peek_position();
- Expect(Token::IF, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- ExpressionT condition = ParseExpression(CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Consume(Token::IF);
+ Expect(Token::LPAREN);
+ ExpressionT condition = ParseExpression();
+ Expect(Token::RPAREN);
SourceRange then_range, else_range;
StatementT then_statement = impl()->NullStatement();
{
SourceRangeScope range_scope(scanner(), &then_range);
- then_statement = ParseScopedStatement(labels, CHECK_OK);
+ // Make a copy of {labels} to avoid conflicts with any
+ // labels that may be applied to the else clause below.
+ auto labels_copy =
+ labels == nullptr
+ ? labels
+ : new (zone()) ZonePtrList<const AstRawString>(*labels, zone());
+ then_statement = ParseScopedStatement(labels_copy);
}
StatementT else_statement = impl()->NullStatement();
if (Check(Token::ELSE)) {
- else_statement = ParseScopedStatement(labels, CHECK_OK);
+ else_statement = ParseScopedStatement(labels);
else_range = SourceRange::ContinuationOf(then_range, end_position());
} else {
- else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
+ else_statement = factory()->EmptyStatement();
}
StatementT stmt =
factory()->NewIfStatement(condition, then_statement, else_statement, pos);
@@ -5301,37 +4827,34 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
}
template <typename Impl>
-typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement(
- bool* ok) {
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseContinueStatement() {
// ContinueStatement ::
// 'continue' Identifier? ';'
int pos = peek_position();
- Expect(Token::CONTINUE, CHECK_OK);
+ Consume(Token::CONTINUE);
IdentifierT label = impl()->NullIdentifier();
Token::Value tok = peek();
- if (!scanner()->HasLineTerminatorBeforeNext() && tok != Token::SEMICOLON &&
- tok != Token::RBRACE && tok != Token::EOS) {
+ if (!scanner()->HasLineTerminatorBeforeNext() &&
+ !Token::IsAutoSemicolon(tok)) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
- label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+ label = ParseIdentifier();
}
- typename Types::IterationStatement target =
- impl()->LookupContinueTarget(label, CHECK_OK);
+ IterationStatementT target = impl()->LookupContinueTarget(label);
if (impl()->IsNull(target)) {
// Illegal continue statement.
- MessageTemplate::Template message = MessageTemplate::kIllegalContinue;
- typename Types::BreakableStatement breakable_target =
- impl()->LookupBreakTarget(label, CHECK_OK);
+ MessageTemplate message = MessageTemplate::kIllegalContinue;
+ BreakableStatementT breakable_target = impl()->LookupBreakTarget(label);
if (impl()->IsNull(label)) {
message = MessageTemplate::kNoIterationStatement;
} else if (impl()->IsNull(breakable_target)) {
message = MessageTemplate::kUnknownLabel;
}
ReportMessage(message, label);
- *ok = false;
return impl()->NullStatement();
}
- ExpectSemicolon(CHECK_OK);
+ ExpectSemicolon();
StatementT stmt = factory()->NewContinueStatement(target, pos);
impl()->RecordJumpStatementSourceRange(stmt, end_position());
return stmt;
@@ -5339,53 +4862,50 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement(
- ZonePtrList<const AstRawString>* labels, bool* ok) {
+ ZonePtrList<const AstRawString>* labels) {
// BreakStatement ::
// 'break' Identifier? ';'
int pos = peek_position();
- Expect(Token::BREAK, CHECK_OK);
+ Consume(Token::BREAK);
IdentifierT label = impl()->NullIdentifier();
Token::Value tok = peek();
- if (!scanner()->HasLineTerminatorBeforeNext() && tok != Token::SEMICOLON &&
- tok != Token::RBRACE && tok != Token::EOS) {
+ if (!scanner()->HasLineTerminatorBeforeNext() &&
+ !Token::IsAutoSemicolon(tok)) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
- label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+ label = ParseIdentifier();
}
// Parse labeled break statements that target themselves into
// empty statements, e.g. 'l1: l2: l3: break l2;'
if (!impl()->IsNull(label) && impl()->ContainsLabel(labels, label)) {
- ExpectSemicolon(CHECK_OK);
- return factory()->NewEmptyStatement(pos);
+ ExpectSemicolon();
+ return factory()->EmptyStatement();
}
- typename Types::BreakableStatement target =
- impl()->LookupBreakTarget(label, CHECK_OK);
+ BreakableStatementT target = impl()->LookupBreakTarget(label);
if (impl()->IsNull(target)) {
// Illegal break statement.
- MessageTemplate::Template message = MessageTemplate::kIllegalBreak;
+ MessageTemplate message = MessageTemplate::kIllegalBreak;
if (!impl()->IsNull(label)) {
message = MessageTemplate::kUnknownLabel;
}
ReportMessage(message, label);
- *ok = false;
return impl()->NullStatement();
}
- ExpectSemicolon(CHECK_OK);
+ ExpectSemicolon();
StatementT stmt = factory()->NewBreakStatement(target, pos);
impl()->RecordJumpStatementSourceRange(stmt, end_position());
return stmt;
}
template <typename Impl>
-typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
- bool* ok) {
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement() {
// ReturnStatement ::
// 'return' [no line terminator] 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);
+ Consume(Token::RETURN);
Scanner::Location loc = scanner()->location();
switch (GetDeclarationScope()->scope_type()) {
@@ -5393,7 +4913,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
case EVAL_SCOPE:
case MODULE_SCOPE:
impl()->ReportMessageAt(loc, MessageTemplate::kIllegalReturn);
- *ok = false;
return impl()->NullStatement();
default:
break;
@@ -5401,15 +4920,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
Token::Value tok = peek();
ExpressionT return_value = impl()->NullExpression();
- if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::SEMICOLON ||
- tok == Token::RBRACE || tok == Token::EOS) {
+ if (scanner()->HasLineTerminatorBeforeNext() || Token::IsAutoSemicolon(tok)) {
if (IsDerivedConstructor(function_state_->kind())) {
return_value = impl()->ThisExpression(loc.beg_pos);
}
} else {
- return_value = ParseExpression(CHECK_OK);
+ return_value = ParseExpression();
}
- ExpectSemicolon(CHECK_OK);
+ ExpectSemicolon();
+
return_value = impl()->RewriteReturn(return_value, loc.beg_pos);
int continuation_pos = end_position();
StatementT stmt =
@@ -5420,29 +4939,28 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
- ZonePtrList<const AstRawString>* labels, bool* ok) {
+ ZonePtrList<const AstRawString>* labels) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
- Expect(Token::WITH, CHECK_OK);
+ Consume(Token::WITH);
int pos = position();
if (is_strict(language_mode())) {
ReportMessage(MessageTemplate::kStrictWith);
- *ok = false;
return impl()->NullStatement();
}
- Expect(Token::LPAREN, CHECK_OK);
- ExpressionT expr = ParseExpression(CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(Token::LPAREN);
+ ExpressionT expr = ParseExpression();
+ Expect(Token::RPAREN);
Scope* with_scope = NewScope(WITH_SCOPE);
StatementT body = impl()->NullStatement();
{
BlockState block_state(&scope_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos);
- body = ParseStatement(labels, nullptr, CHECK_OK);
+ body = ParseStatement(labels, nullptr);
with_scope->set_end_position(end_position());
}
return factory()->NewWithStatement(with_scope, expr, body, pos);
@@ -5451,27 +4969,30 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok) {
+ ZonePtrList<const AstRawString>* own_labels) {
// DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';'
+ typename FunctionState::LoopScope loop_scope(function_state_);
auto loop =
factory()->NewDoWhileStatement(labels, own_labels, peek_position());
- typename Types::Target target(this, loop);
+ TargetT target(this, loop);
SourceRange body_range;
StatementT body = impl()->NullStatement();
- Expect(Token::DO, CHECK_OK);
+ Consume(Token::DO);
+
+ CheckStackOverflow();
{
SourceRangeScope range_scope(scanner(), &body_range);
- body = ParseStatement(nullptr, nullptr, CHECK_OK);
+ body = ParseStatement(nullptr, nullptr);
}
- Expect(Token::WHILE, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(Token::WHILE);
+ Expect(Token::LPAREN);
- ExpressionT cond = ParseExpression(CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ ExpressionT cond = ParseExpression();
+ Expect(Token::RPAREN);
// Allow do-statements to be terminated with and without
// semi-colons. This allows code such as 'do;while(0)return' to
@@ -5488,23 +5009,24 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok) {
+ ZonePtrList<const AstRawString>* own_labels) {
// WhileStatement ::
// 'while' '(' Expression ')' Statement
+ typename FunctionState::LoopScope loop_scope(function_state_);
auto loop = factory()->NewWhileStatement(labels, own_labels, peek_position());
- typename Types::Target target(this, loop);
+ TargetT target(this, loop);
SourceRange body_range;
StatementT body = impl()->NullStatement();
- Expect(Token::WHILE, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- ExpressionT cond = ParseExpression(CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Consume(Token::WHILE);
+ Expect(Token::LPAREN);
+ ExpressionT cond = ParseExpression();
+ Expect(Token::RPAREN);
{
SourceRangeScope range_scope(scanner(), &body_range);
- body = ParseStatement(nullptr, nullptr, CHECK_OK);
+ body = ParseStatement(nullptr, nullptr);
}
loop->Initialize(cond, body);
@@ -5514,20 +5036,18 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
}
template <typename Impl>
-typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement(
- bool* ok) {
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement() {
// ThrowStatement ::
// 'throw' Expression ';'
- Expect(Token::THROW, CHECK_OK);
+ Consume(Token::THROW);
int pos = position();
if (scanner()->HasLineTerminatorBeforeNext()) {
ReportMessage(MessageTemplate::kNewlineAfterThrow);
- *ok = false;
return impl()->NullStatement();
}
- ExpressionT exception = ParseExpression(CHECK_OK);
- ExpectSemicolon(CHECK_OK);
+ ExpressionT exception = ParseExpression();
+ ExpectSemicolon();
StatementT stmt = impl()->NewThrowStatement(exception, pos);
impl()->RecordThrowSourceRange(stmt, end_position());
@@ -5537,7 +5057,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
- ZonePtrList<const AstRawString>* labels, bool* ok) {
+ ZonePtrList<const AstRawString>* labels) {
// SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}'
// CaseClause ::
@@ -5546,10 +5066,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
int switch_pos = peek_position();
- Expect(Token::SWITCH, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- ExpressionT tag = ParseExpression(CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Consume(Token::SWITCH);
+ Expect(Token::LPAREN);
+ ExpressionT tag = ParseExpression();
+ Expect(Token::RPAREN);
auto switch_statement =
factory()->NewSwitchStatement(labels, tag, switch_pos);
@@ -5558,38 +5078,41 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
BlockState cases_block_state(zone(), &scope_);
scope()->set_start_position(switch_pos);
scope()->SetNonlinear();
- typename Types::Target target(this, switch_statement);
+ TargetT target(this, switch_statement);
bool default_seen = false;
- Expect(Token::LBRACE, CHECK_OK);
+ Expect(Token::LBRACE);
while (peek() != Token::RBRACE) {
// An empty label indicates the default case.
ExpressionT label = impl()->NullExpression();
+ StatementListT statements(pointer_buffer());
SourceRange clause_range;
- SourceRangeScope range_scope(scanner(), &clause_range);
- if (Check(Token::CASE)) {
- label = ParseExpression(CHECK_OK);
- } else {
- Expect(Token::DEFAULT, CHECK_OK);
- if (default_seen) {
- ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch);
- *ok = false;
- return impl()->NullStatement();
+ {
+ SourceRangeScope range_scope(scanner(), &clause_range);
+ if (Check(Token::CASE)) {
+ label = ParseExpression();
+ } else {
+ Expect(Token::DEFAULT);
+ if (default_seen) {
+ ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch);
+ return impl()->NullStatement();
+ }
+ default_seen = true;
+ }
+ Expect(Token::COLON);
+ while (peek() != Token::CASE && peek() != Token::DEFAULT &&
+ peek() != Token::RBRACE) {
+ StatementT stat = ParseStatementListItem();
+ if (impl()->IsNull(stat)) return stat;
+ if (stat->IsEmptyStatement()) continue;
+ statements.Add(stat);
}
- default_seen = true;
- }
- Expect(Token::COLON, CHECK_OK);
- StatementListT statements = impl()->NewStatementList(5);
- while (peek() != Token::CASE && peek() != Token::DEFAULT &&
- peek() != Token::RBRACE) {
- StatementT stat = ParseStatementListItem(CHECK_OK);
- statements->Add(stat, zone());
}
auto clause = factory()->NewCaseClause(label, statements);
- impl()->RecordCaseClauseSourceRange(clause, range_scope.Finalize());
+ impl()->RecordCaseClauseSourceRange(clause, clause_range);
switch_statement->cases()->Add(clause, zone());
}
- Expect(Token::RBRACE, CHECK_OK);
+ Expect(Token::RBRACE);
int end_pos = end_position();
scope()->set_end_position(end_pos);
@@ -5603,8 +5126,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
}
template <typename Impl>
-typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
- bool* ok) {
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() {
// TryStatement ::
// 'try' Block Catch
// 'try' Block Finally
@@ -5616,22 +5138,21 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
// Finally ::
// 'finally' Block
- Expect(Token::TRY, CHECK_OK);
+ Consume(Token::TRY);
int pos = position();
- BlockT try_block = ParseBlock(nullptr, CHECK_OK);
+ BlockT try_block = ParseBlock(nullptr);
CatchInfo catch_info(this);
if (peek() != Token::CATCH && peek() != Token::FINALLY) {
ReportMessage(MessageTemplate::kNoCatchOrFinally);
- *ok = false;
return impl()->NullStatement();
}
SourceRange catch_range, finally_range;
- BlockT catch_block = impl()->NullStatement();
+ BlockT catch_block = impl()->NullBlock();
{
SourceRangeScope catch_range_scope(scanner(), &catch_range);
if (Check(Token::CATCH)) {
@@ -5644,57 +5165,74 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
{
BlockState catch_block_state(&scope_, catch_info.scope);
-
- catch_block = factory()->NewBlock(16, false);
+ StatementListT catch_statements(pointer_buffer());
// Create a block scope to hold any lexical declarations created
// as part of destructuring the catch parameter.
{
BlockState catch_variable_block_state(zone(), &scope_);
- scope()->set_start_position(scanner()->location().beg_pos);
+ scope()->set_start_position(position());
- // This does not simply call ParsePrimaryExpression to avoid
- // ExpressionFromIdentifier from being called in the first
- // branch, which would introduce an unresolved symbol and mess
- // with arrow function names.
if (peek_any_identifier()) {
- catch_info.name =
- ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
+ IdentifierT identifier = ParseNonRestrictedIdentifier();
+ RETURN_IF_PARSE_ERROR;
+ catch_info.variable = impl()->DeclareCatchVariableName(
+ catch_info.scope, identifier);
} else {
- ExpressionClassifier pattern_classifier(this);
- catch_info.pattern = ParseBindingPattern(CHECK_OK);
+ catch_info.variable = catch_info.scope->DeclareCatchVariableName(
+ ast_value_factory()->dot_catch_string());
+ VariableDeclarationParsingScope destructuring(
+ impl(), VariableMode::kLet, nullptr);
+ catch_info.pattern = ParseBindingPattern();
+ RETURN_IF_PARSE_ERROR;
+ catch_statements.Add(impl()->RewriteCatchPattern(&catch_info));
}
- Expect(Token::RPAREN, CHECK_OK);
- impl()->RewriteCatchPattern(&catch_info, CHECK_OK);
- if (!impl()->IsNull(catch_info.init_block)) {
- catch_block->statements()->Add(catch_info.init_block, zone());
+ Expect(Token::RPAREN);
+
+ BlockT inner_block = ParseBlock(nullptr);
+ catch_statements.Add(inner_block);
+
+ // Check for `catch(e) { let e; }` and similar errors.
+ Scope* inner_scope = inner_block->scope();
+ if (inner_scope != nullptr) {
+ const AstRawString* conflict = nullptr;
+ if (impl()->IsNull(catch_info.pattern)) {
+ const AstRawString* name = catch_info.variable->raw_name();
+ if (inner_scope->LookupLocal(name)) conflict = name;
+ } else {
+ conflict = inner_scope->FindVariableDeclaredIn(
+ scope(), VariableMode::kVar);
+ }
+ if (conflict != nullptr) {
+ impl()->ReportVarRedeclarationIn(conflict, inner_scope);
+ }
}
- catch_info.inner_block = ParseBlock(nullptr, CHECK_OK);
- catch_block->statements()->Add(catch_info.inner_block, zone());
- impl()->ValidateCatchBlock(catch_info, CHECK_OK);
scope()->set_end_position(end_position());
+ catch_block = factory()->NewBlock(false, catch_statements);
catch_block->set_scope(scope()->FinalizeBlockScope());
}
}
catch_info.scope->set_end_position(end_position());
} else {
- catch_block = ParseBlock(nullptr, CHECK_OK);
+ catch_block = ParseBlock(nullptr);
}
}
}
- BlockT finally_block = impl()->NullStatement();
- DCHECK(peek() == Token::FINALLY || !impl()->IsNull(catch_block));
+ BlockT finally_block = impl()->NullBlock();
+ DCHECK(has_error() || peek() == Token::FINALLY ||
+ !impl()->IsNull(catch_block));
{
SourceRangeScope range_scope(scanner(), &finally_range);
if (Check(Token::FINALLY)) {
- finally_block = ParseBlock(nullptr, CHECK_OK);
+ finally_block = ParseBlock(nullptr);
}
}
+ RETURN_IF_PARSE_ERROR;
return impl()->RewriteTryStatement(try_block, catch_block, catch_range,
finally_block, finally_range, catch_info,
pos);
@@ -5703,7 +5241,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok) {
+ ZonePtrList<const AstRawString>* own_labels) {
// Either a standard for loop
// for (<init>; <cond>; <next>) { ... }
// or a for-each loop
@@ -5711,18 +5249,19 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
//
// We parse a declaration/expression after the 'for (' and then read the first
// expression/declaration before we know if this is a for or a for-each.
+ typename FunctionState::LoopScope loop_scope(function_state_);
int stmt_pos = peek_position();
ForInfo for_info(this);
- Expect(Token::FOR, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Consume(Token::FOR);
+ Expect(Token::LPAREN);
if (peek() == Token::CONST || (peek() == Token::LET && IsNextLetKeyword())) {
// The initializer contains lexical declarations,
// so create an in-between scope.
BlockState for_state(zone(), &scope_);
- scope()->set_start_position(scanner()->location().beg_pos);
+ scope()->set_start_position(position());
// Also record whether inner functions or evals are found inside
// this loop, as this information is used to simplify the desugaring
@@ -5736,78 +5275,94 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
{
BlockState inner_state(&scope_, inner_block_scope);
ParseVariableDeclarations(kForStatement, &for_info.parsing_result,
- nullptr, CHECK_OK);
+ &for_info.bound_names);
}
DCHECK(IsLexicalVariableMode(for_info.parsing_result.descriptor.mode));
- for_info.position = scanner()->location().beg_pos;
+ for_info.position = position();
if (CheckInOrOf(&for_info.mode)) {
scope()->set_is_hidden();
return ParseForEachStatementWithDeclarations(
- stmt_pos, &for_info, labels, own_labels, inner_block_scope, ok);
+ stmt_pos, &for_info, labels, own_labels, inner_block_scope);
}
- Expect(Token::SEMICOLON, CHECK_OK);
+ Expect(Token::SEMICOLON);
- StatementT init = impl()->BuildInitializationBlock(
- &for_info.parsing_result, &for_info.bound_names, CHECK_OK);
+ // Parse the remaining code in the inner block scope since the declaration
+ // above was parsed there. We'll finalize the unnecessary outer block scope
+ // after parsing the rest of the loop.
+ StatementT result = impl()->NullStatement();
+ inner_block_scope->set_start_position(scope()->start_position());
+ {
+ BlockState inner_state(&scope_, inner_block_scope);
+ StatementT init =
+ impl()->BuildInitializationBlock(&for_info.parsing_result);
- Scope* finalized = inner_block_scope->FinalizeBlockScope();
- // No variable declarations will have been created in inner_block_scope.
+ result = ParseStandardForLoopWithLexicalDeclarations(
+ stmt_pos, init, &for_info, labels, own_labels);
+ }
+ Scope* finalized = scope()->FinalizeBlockScope();
DCHECK_NULL(finalized);
USE(finalized);
- return ParseStandardForLoopWithLexicalDeclarations(
- stmt_pos, init, &for_info, labels, own_labels, ok);
+ return result;
}
StatementT init = impl()->NullStatement();
if (peek() == Token::VAR) {
- ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr,
- CHECK_OK);
+ ParseVariableDeclarations(kForStatement, &for_info.parsing_result,
+ &for_info.bound_names);
DCHECK_EQ(for_info.parsing_result.descriptor.mode, VariableMode::kVar);
for_info.position = scanner()->location().beg_pos;
if (CheckInOrOf(&for_info.mode)) {
return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels,
- own_labels, nullptr, ok);
+ own_labels, scope());
}
- init = impl()->BuildInitializationBlock(&for_info.parsing_result, nullptr,
- CHECK_OK);
+ init = impl()->BuildInitializationBlock(&for_info.parsing_result);
} else if (peek() != Token::SEMICOLON) {
// The initializer does not contain declarations.
int lhs_beg_pos = peek_position();
- ExpressionClassifier classifier(this);
- ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK);
- int lhs_end_pos = end_position();
-
- bool is_for_each = CheckInOrOf(&for_info.mode);
- bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
- expression->IsObjectLiteral());
-
- if (is_destructuring) {
- ValidateAssignmentPattern(CHECK_OK);
- } else {
- ValidateExpression(CHECK_OK);
+ int lhs_end_pos;
+ bool is_for_each;
+ ExpressionT expression;
+ {
+ ExpressionParsingScope parsing_scope(impl());
+ AcceptINScope scope(this, false);
+ expression = ParseExpressionCoverGrammar();
+ // Initializer is reference followed by in/of.
+ lhs_end_pos = end_position();
+ is_for_each = CheckInOrOf(&for_info.mode);
+ if (is_for_each) {
+ if (expression->IsPattern()) {
+ parsing_scope.ValidatePattern(expression, lhs_beg_pos, lhs_end_pos);
+ } else {
+ expression = parsing_scope.ValidateAndRewriteReference(
+ expression, lhs_beg_pos, lhs_end_pos);
+ }
+ } else {
+ parsing_scope.ValidateExpression();
+ }
}
if (is_for_each) {
return ParseForEachStatementWithoutDeclarations(
stmt_pos, expression, lhs_beg_pos, lhs_end_pos, &for_info, labels,
- own_labels, ok);
+ own_labels);
}
// Initializer is just an expression.
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
}
- Expect(Token::SEMICOLON, CHECK_OK);
+ Expect(Token::SEMICOLON);
// Standard 'for' loop, we have parsed the initializer at this point.
ExpressionT cond = impl()->NullExpression();
StatementT next = impl()->NullStatement();
StatementT body = impl()->NullStatement();
- ForStatementT loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond,
- &next, &body, CHECK_OK);
+ ForStatementT loop =
+ ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, &body);
+ RETURN_IF_PARSE_ERROR;
loop->Initialize(init, cond, next, body);
return loop;
}
@@ -5816,14 +5371,12 @@ template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseForEachStatementWithDeclarations(
int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope,
- bool* ok) {
+ ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope) {
// Just one declaration followed by in/of.
if (for_info->parsing_result.declarations.size() != 1) {
impl()->ReportMessageAt(for_info->parsing_result.bindings_loc,
MessageTemplate::kForInOfLoopMultiBindings,
ForEachStatement::VisitModeString(for_info->mode));
- *ok = false;
return impl()->NullStatement();
}
if (for_info->parsing_result.first_initializer_loc.IsValid() &&
@@ -5835,80 +5388,66 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
impl()->ReportMessageAt(for_info->parsing_result.first_initializer_loc,
MessageTemplate::kForInOfLoopInitializer,
ForEachStatement::VisitModeString(for_info->mode));
- *ok = false;
return impl()->NullStatement();
}
- // Reset the declaration_kind to ensure proper processing during declaration.
- for_info->parsing_result.descriptor.declaration_kind =
- DeclarationDescriptor::FOR_EACH;
-
BlockT init_block = impl()->RewriteForVarInLegacy(*for_info);
auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels,
stmt_pos);
- typename Types::Target target(this, loop);
+ TargetT target(this, loop);
ExpressionT enumerable = impl()->NullExpression();
if (for_info->mode == ForEachStatement::ITERATE) {
- ExpressionClassifier classifier(this);
- enumerable = ParseAssignmentExpression(true, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ AcceptINScope scope(this, true);
+ enumerable = ParseAssignmentExpression();
} else {
- enumerable = ParseExpression(CHECK_OK);
+ enumerable = ParseExpression();
}
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(Token::RPAREN);
- Scope* for_scope = nullptr;
- if (inner_block_scope != nullptr) {
- for_scope = inner_block_scope->outer_scope();
- DCHECK_EQ(for_scope, scope());
- inner_block_scope->set_start_position(scanner()->location().beg_pos);
+ if (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode)) {
+ inner_block_scope->set_start_position(position());
}
ExpressionT each_variable = impl()->NullExpression();
- BlockT body_block = impl()->NullStatement();
+ BlockT body_block = impl()->NullBlock();
{
- BlockState block_state(
- &scope_, inner_block_scope != nullptr ? inner_block_scope : scope_);
+ BlockState block_state(&scope_, inner_block_scope);
SourceRange body_range;
- SourceRangeScope range_scope(scanner(), &body_range);
-
- StatementT body = ParseStatement(nullptr, nullptr, CHECK_OK);
- impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
+ StatementT body = impl()->NullStatement();
+ {
+ SourceRangeScope range_scope(scanner(), &body_range);
+ body = ParseStatement(nullptr, nullptr);
+ }
+ impl()->RecordIterationStatementSourceRange(loop, body_range);
- impl()->DesugarBindingInForEachStatement(for_info, &body_block,
- &each_variable, CHECK_OK);
+ DesugarBindingInForEachStatement(for_info, &body_block, &each_variable);
body_block->statements()->Add(body, zone());
- if (inner_block_scope != nullptr) {
- inner_block_scope->set_end_position(end_position());
- body_block->set_scope(inner_block_scope->FinalizeBlockScope());
+ if (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode)) {
+ scope()->set_end_position(end_position());
+ body_block->set_scope(scope()->FinalizeBlockScope());
}
}
- StatementT final_loop = impl()->InitializeForEachStatement(
- loop, each_variable, enumerable, body_block);
+ loop->Initialize(each_variable, enumerable, body_block);
- init_block =
- impl()->CreateForEachStatementTDZ(init_block, *for_info, CHECK_OK);
-
- if (for_scope != nullptr) {
- for_scope->set_end_position(end_position());
- for_scope = for_scope->FinalizeBlockScope();
- }
+ init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info);
// Parsed for-in loop w/ variable declarations.
if (!impl()->IsNull(init_block)) {
- init_block->statements()->Add(final_loop, zone());
- init_block->set_scope(for_scope);
+ init_block->statements()->Add(loop, zone());
+ if (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode)) {
+ scope()->set_end_position(end_position());
+ init_block->set_scope(scope()->FinalizeBlockScope());
+ }
return init_block;
}
- DCHECK_NULL(for_scope);
- return final_loop;
+ return loop;
}
template <typename Impl>
@@ -5916,38 +5455,31 @@ typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok) {
- // Initializer is reference followed by in/of.
- if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) {
- expression = CheckAndRewriteReferenceExpression(
- expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
- kSyntaxError, CHECK_OK);
- }
-
+ ZonePtrList<const AstRawString>* own_labels) {
auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels,
stmt_pos);
- typename Types::Target target(this, loop);
+ TargetT target(this, loop);
ExpressionT enumerable = impl()->NullExpression();
if (for_info->mode == ForEachStatement::ITERATE) {
- ExpressionClassifier classifier(this);
- enumerable = ParseAssignmentExpression(true, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ AcceptINScope scope(this, true);
+ enumerable = ParseAssignmentExpression();
} else {
- enumerable = ParseExpression(CHECK_OK);
+ enumerable = ParseExpression();
}
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(Token::RPAREN);
StatementT body = impl()->NullStatement();
+ SourceRange body_range;
{
- SourceRange body_range;
SourceRangeScope range_scope(scanner(), &body_range);
-
- body = ParseStatement(nullptr, nullptr, CHECK_OK);
- impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
+ body = ParseStatement(nullptr, nullptr);
}
- return impl()->InitializeForEachStatement(loop, expression, enumerable, body);
+ impl()->RecordIterationStatementSourceRange(loop, body_range);
+ RETURN_IF_PARSE_ERROR;
+ loop->Initialize(expression, enumerable, body);
+ return loop;
}
template <typename Impl>
@@ -5955,7 +5487,7 @@ typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
int stmt_pos, StatementT init, ForInfo* for_info,
ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok) {
+ ZonePtrList<const AstRawString>* own_labels) {
// The condition and the next statement of the for loop must be parsed
// in a new scope.
Scope* inner_scope = NewScope(BLOCK_SCOPE);
@@ -5966,8 +5498,9 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
{
BlockState block_state(&scope_, inner_scope);
scope()->set_start_position(scanner()->location().beg_pos);
- loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next,
- &body, CHECK_OK);
+ loop =
+ ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, &body);
+ RETURN_IF_PARSE_ERROR;
scope()->set_end_position(end_position());
}
@@ -5976,7 +5509,7 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
function_state_->contains_function_or_eval()) {
scope()->set_is_hidden();
return impl()->DesugarLexicalBindingsInForStatement(
- loop, init, cond, next, body, inner_scope, *for_info, ok);
+ loop, init, cond, next, body, inner_scope, *for_info);
} else {
inner_scope = inner_scope->FinalizeBlockScope();
DCHECK_NULL(inner_scope);
@@ -6012,25 +5545,25 @@ template <typename Impl>
typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
int stmt_pos, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond,
- StatementT* next, StatementT* body, bool* ok) {
+ StatementT* next, StatementT* body) {
ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos);
- typename Types::Target target(this, loop);
+ TargetT target(this, loop);
if (peek() != Token::SEMICOLON) {
- *cond = ParseExpression(CHECK_OK);
+ *cond = ParseExpression();
}
- Expect(Token::SEMICOLON, CHECK_OK);
+ Expect(Token::SEMICOLON);
if (peek() != Token::RPAREN) {
- ExpressionT exp = ParseExpression(CHECK_OK);
+ ExpressionT exp = ParseExpression();
*next = factory()->NewExpressionStatement(exp, exp->position());
}
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(Token::RPAREN);
SourceRange body_range;
{
SourceRangeScope range_scope(scanner(), &body_range);
- *body = ParseStatement(nullptr, nullptr, CHECK_OK);
+ *body = ParseStatement(nullptr, nullptr);
}
impl()->RecordIterationStatementSourceRange(loop, body_range);
@@ -6038,22 +5571,12 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
}
template <typename Impl>
-void ParserBase<Impl>::MarkLoopVariableAsAssigned(
- Scope* scope, Variable* var,
- typename DeclarationDescriptor::Kind declaration_kind) {
- if (!IsLexicalVariableMode(var->mode()) &&
- (!scope->is_function_scope() ||
- declaration_kind == DeclarationDescriptor::FOR_EACH)) {
- var->set_maybe_assigned();
- }
-}
-
-template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, bool* ok) {
+ ZonePtrList<const AstRawString>* own_labels) {
// for await '(' ForDeclaration of AssignmentExpression ')'
DCHECK(is_async_function());
+ typename FunctionState::LoopScope loop_scope(function_state_);
int stmt_pos = peek_position();
@@ -6062,14 +5585,19 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
// Create an in-between scope for let-bound iteration variables.
BlockState for_state(zone(), &scope_);
- Expect(Token::FOR, CHECK_OK);
- Expect(Token::AWAIT, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(Token::FOR);
+ Expect(Token::AWAIT);
+ Expect(Token::LPAREN);
scope()->set_start_position(scanner()->location().beg_pos);
scope()->set_is_hidden();
- auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos);
- typename Types::Target target(this, loop);
+ auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos,
+ IteratorType::kAsync);
+ // Two suspends: one for next() and one for return()
+ function_state_->AddSuspend();
+ function_state_->AddSuspend();
+
+ TargetT target(this, loop);
ExpressionT each_variable = impl()->NullExpression();
@@ -6088,7 +5616,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
{
BlockState inner_state(&scope_, inner_block_scope);
ParseVariableDeclarations(kForStatement, &for_info.parsing_result,
- nullptr, CHECK_OK);
+ &for_info.bound_names);
}
for_info.position = scanner()->location().beg_pos;
@@ -6097,7 +5625,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
impl()->ReportMessageAt(for_info.parsing_result.bindings_loc,
MessageTemplate::kForInOfLoopMultiBindings,
"for-await-of");
- *ok = false;
return impl()->NullStatement();
}
@@ -6106,7 +5633,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
impl()->ReportMessageAt(for_info.parsing_result.first_initializer_loc,
MessageTemplate::kForInOfLoopInitializer,
"for-await-of");
- *ok = false;
return impl()->NullStatement();
}
} else {
@@ -6115,33 +5641,29 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
// Statement
int lhs_beg_pos = peek_position();
BlockState inner_state(&scope_, inner_block_scope);
- ExpressionClassifier classifier(this);
- ExpressionT lhs = each_variable = ParseLeftHandSideExpression(CHECK_OK);
+ ExpressionParsingScope parsing_scope(impl());
+ ExpressionT lhs = each_variable = ParseLeftHandSideExpression();
int lhs_end_pos = end_position();
- if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) {
- ValidateAssignmentPattern(CHECK_OK);
+ if (lhs->IsPattern()) {
+ parsing_scope.ValidatePattern(lhs, lhs_beg_pos, lhs_end_pos);
} else {
- ValidateExpression(CHECK_OK);
- each_variable = CheckAndRewriteReferenceExpression(
- lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
- kSyntaxError, CHECK_OK);
+ each_variable = parsing_scope.ValidateAndRewriteReference(
+ lhs, lhs_beg_pos, lhs_end_pos);
}
}
- ExpectContextualKeyword(Token::OF, CHECK_OK);
- int each_keyword_pos = scanner()->location().beg_pos;
+ ExpectContextualKeyword(ast_value_factory()->of_string());
const bool kAllowIn = true;
ExpressionT iterable = impl()->NullExpression();
{
- ExpressionClassifier classifier(this);
- iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ AcceptINScope scope(this, kAllowIn);
+ iterable = ParseAssignmentExpression();
}
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(Token::RPAREN);
StatementT body = impl()->NullStatement();
{
@@ -6149,16 +5671,16 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
scope()->set_start_position(scanner()->location().beg_pos);
SourceRange body_range;
- SourceRangeScope range_scope(scanner(), &body_range);
-
- body = ParseStatement(nullptr, nullptr, CHECK_OK);
- scope()->set_end_position(end_position());
- impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
+ {
+ SourceRangeScope range_scope(scanner(), &body_range);
+ body = ParseStatement(nullptr, nullptr);
+ scope()->set_end_position(end_position());
+ }
+ impl()->RecordIterationStatementSourceRange(loop, body_range);
if (has_declarations) {
- BlockT body_block = impl()->NullStatement();
- impl()->DesugarBindingInForEachStatement(&for_info, &body_block,
- &each_variable, CHECK_OK);
+ BlockT body_block = impl()->NullBlock();
+ DesugarBindingInForEachStatement(&for_info, &body_block, &each_variable);
body_block->statements()->Add(body, zone());
body_block->set_scope(scope()->FinalizeBlockScope());
body = body_block;
@@ -6168,103 +5690,85 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
USE(block_scope);
}
}
- const bool finalize = true;
- StatementT final_loop = impl()->InitializeForOfStatement(
- loop, each_variable, iterable, body, finalize, IteratorType::kAsync,
- each_keyword_pos);
+
+ loop->Initialize(each_variable, iterable, body);
if (!has_declarations) {
Scope* for_scope = scope()->FinalizeBlockScope();
DCHECK_NULL(for_scope);
USE(for_scope);
- return final_loop;
+ return loop;
}
- BlockT init_block = impl()->CreateForEachStatementTDZ(impl()->NullStatement(),
- for_info, CHECK_OK);
+ BlockT init_block =
+ impl()->CreateForEachStatementTDZ(impl()->NullBlock(), for_info);
scope()->set_end_position(end_position());
Scope* for_scope = scope()->FinalizeBlockScope();
// Parsed for-in loop w/ variable declarations.
if (!impl()->IsNull(init_block)) {
- init_block->statements()->Add(final_loop, zone());
+ init_block->statements()->Add(loop, zone());
init_block->set_scope(for_scope);
return init_block;
}
DCHECK_NULL(for_scope);
- return final_loop;
-}
-
-template <typename Impl>
-void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto(
- Token::Value property) {
- if (property == Token::SMI || property == Token::NUMBER) return;
-
- if (IsProto()) {
- if (has_seen_proto_) {
- this->parser()->classifier()->RecordExpressionError(
- this->scanner()->location(), MessageTemplate::kDuplicateProto);
- return;
- }
- has_seen_proto_ = true;
- }
+ return loop;
}
template <typename Impl>
-void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
- Token::Value property, ParsePropertyKind type, ParseFunctionFlags flags,
- bool is_static, bool* ok) {
+void ParserBase<Impl>::CheckClassMethodName(IdentifierT name,
+ ParsePropertyKind type,
+ ParseFunctionFlags flags,
+ bool is_static,
+ bool* has_seen_constructor) {
DCHECK(type == ParsePropertyKind::kMethod || IsAccessor(type));
- if (property == Token::SMI || property == Token::NUMBER) return;
+ AstValueFactory* avf = ast_value_factory();
if (is_static) {
- if (IsPrototype()) {
- this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
- *ok = false;
+ if (impl()->IdentifierEquals(name, avf->prototype_string())) {
+ ReportMessage(MessageTemplate::kStaticPrototype);
return;
}
- } else if (IsConstructor()) {
+ } else if (impl()->IdentifierEquals(name,
+ avf->private_constructor_string())) {
+ ReportMessage(MessageTemplate::kConstructorIsPrivate);
+ return;
+ } else if (impl()->IdentifierEquals(name, avf->constructor_string())) {
if (flags != ParseFunctionFlag::kIsNormal || IsAccessor(type)) {
- MessageTemplate::Template msg =
- (flags & ParseFunctionFlag::kIsGenerator) != 0
- ? MessageTemplate::kConstructorIsGenerator
- : (flags & ParseFunctionFlag::kIsAsync) != 0
- ? MessageTemplate::kConstructorIsAsync
- : MessageTemplate::kConstructorIsAccessor;
- this->parser()->ReportMessage(msg);
- *ok = false;
+ MessageTemplate msg = (flags & ParseFunctionFlag::kIsGenerator) != 0
+ ? MessageTemplate::kConstructorIsGenerator
+ : (flags & ParseFunctionFlag::kIsAsync) != 0
+ ? MessageTemplate::kConstructorIsAsync
+ : MessageTemplate::kConstructorIsAccessor;
+ ReportMessage(msg);
return;
}
- if (has_seen_constructor_) {
- this->parser()->ReportMessage(MessageTemplate::kDuplicateConstructor);
- *ok = false;
+ if (*has_seen_constructor) {
+ ReportMessage(MessageTemplate::kDuplicateConstructor);
return;
}
- has_seen_constructor_ = true;
+ *has_seen_constructor = true;
return;
}
}
template <typename Impl>
-void ParserBase<Impl>::ClassLiteralChecker::CheckClassFieldName(bool is_static,
- bool* ok) {
- if (is_static && IsPrototype()) {
- this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
- *ok = false;
+void ParserBase<Impl>::CheckClassFieldName(IdentifierT name, bool is_static) {
+ AstValueFactory* avf = ast_value_factory();
+ if (is_static && impl()->IdentifierEquals(name, avf->prototype_string())) {
+ ReportMessage(MessageTemplate::kStaticPrototype);
return;
}
- if (IsConstructor() || IsPrivateConstructor()) {
- this->parser()->ReportMessage(MessageTemplate::kConstructorClassField);
- *ok = false;
+ if (impl()->IdentifierEquals(name, avf->constructor_string()) ||
+ impl()->IdentifierEquals(name, avf->private_constructor_string())) {
+ ReportMessage(MessageTemplate::kConstructorClassField);
return;
}
}
-#undef CHECK_OK
-#undef CHECK_OK_CUSTOM
-#undef CHECK_OK_VOID
+#undef RETURN_IF_PARSE_ERROR
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc
index 5687633f2f..d6d55af2b6 100644
--- a/deps/v8/src/parsing/parser.cc
+++ b/deps/v8/src/parsing/parser.cc
@@ -12,14 +12,14 @@
#include "src/ast/ast.h"
#include "src/ast/source-range-ast-visitor.h"
#include "src/bailout-reason.h"
+#include "src/base/overflowing-math.h"
#include "src/base/platform/platform.h"
#include "src/char-predicates-inl.h"
#include "src/compiler-dispatcher/compiler-dispatcher.h"
#include "src/conversions-inl.h"
#include "src/log.h"
-#include "src/messages.h"
+#include "src/message-template.h"
#include "src/objects/scope-info.h"
-#include "src/parsing/duplicate-finder.h"
#include "src/parsing/expression-scope-reparenter.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/rewriter.h"
@@ -43,31 +43,31 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
// Set start and end position to the same value
function_scope->set_start_position(pos);
function_scope->set_end_position(pos);
- ZonePtrList<Statement>* body = nullptr;
+ ScopedPtrList<Statement> body(pointer_buffer());
{
FunctionState function_state(&function_state_, &scope_, function_scope);
- body = new (zone()) ZonePtrList<Statement>(call_super ? 2 : 1, zone());
if (call_super) {
// Create a SuperCallReference and handle in BytecodeGenerator.
auto constructor_args_name = ast_value_factory()->empty_string();
- bool is_duplicate;
bool is_rest = true;
bool is_optional = false;
Variable* constructor_args = function_scope->DeclareParameter(
constructor_args_name, VariableMode::kTemporary, is_optional, is_rest,
- &is_duplicate, ast_value_factory(), pos);
+ ast_value_factory(), pos);
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(1, zone());
- Spread* spread_args = factory()->NewSpread(
- factory()->NewVariableProxy(constructor_args), pos, pos);
+ Expression* call;
+ {
+ ScopedPtrList<Expression> args(pointer_buffer());
+ Spread* spread_args = factory()->NewSpread(
+ factory()->NewVariableProxy(constructor_args), pos, pos);
- args->Add(spread_args, zone());
- Expression* super_call_ref = NewSuperCallReference(pos);
- Expression* call = factory()->NewCall(super_call_ref, args, pos);
- body->Add(factory()->NewReturnStatement(call, pos), zone());
+ args.Add(spread_args);
+ Expression* super_call_ref = NewSuperCallReference(pos);
+ call = factory()->NewCall(super_call_ref, args, pos);
+ }
+ body.Add(factory()->NewReturnStatement(call, pos));
}
expected_property_count = function_state.expected_property_count();
@@ -81,28 +81,65 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
return function_literal;
}
-// ----------------------------------------------------------------------------
-// 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_VALUE(x) ok); \
- if (!*ok) return x; \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
-
-#define CHECK_OK CHECK_OK_VALUE(nullptr)
-#define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
-
-#define CHECK_FAILED /**/); \
- if (failed_) return nullptr; \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
+void Parser::ReportUnexpectedTokenAt(Scanner::Location location,
+ Token::Value token,
+ MessageTemplate message) {
+ const char* arg = nullptr;
+ switch (token) {
+ case Token::EOS:
+ message = MessageTemplate::kUnexpectedEOS;
+ break;
+ case Token::SMI:
+ case Token::NUMBER:
+ case Token::BIGINT:
+ message = MessageTemplate::kUnexpectedTokenNumber;
+ break;
+ case Token::STRING:
+ message = MessageTemplate::kUnexpectedTokenString;
+ break;
+ case Token::PRIVATE_NAME:
+ case Token::IDENTIFIER:
+ message = MessageTemplate::kUnexpectedTokenIdentifier;
+ break;
+ case Token::AWAIT:
+ case Token::ENUM:
+ message = MessageTemplate::kUnexpectedReserved;
+ 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;
+ break;
+ case Token::TEMPLATE_SPAN:
+ case Token::TEMPLATE_TAIL:
+ message = MessageTemplate::kUnexpectedTemplateString;
+ break;
+ case Token::ESCAPED_STRICT_RESERVED_WORD:
+ case Token::ESCAPED_KEYWORD:
+ message = MessageTemplate::kInvalidEscapedReservedWord;
+ break;
+ case Token::ILLEGAL:
+ if (scanner()->has_error()) {
+ message = scanner()->error();
+ location = scanner()->error_location();
+ } else {
+ message = MessageTemplate::kInvalidOrUnexpectedToken;
+ }
+ break;
+ case Token::REGEXP_LITERAL:
+ message = MessageTemplate::kUnexpectedTokenRegExp;
+ break;
+ default:
+ const char* name = Token::String(token);
+ DCHECK_NOT_NULL(name);
+ arg = name;
+ break;
+ }
+ ReportMessageAt(location, message, arg);
+}
// ----------------------------------------------------------------------------
// Implementation of Parser
@@ -124,7 +161,7 @@ bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x,
*x = factory()->NewNumberLiteral(x_val * y_val, pos);
return true;
case Token::DIV:
- *x = factory()->NewNumberLiteral(x_val / y_val, pos);
+ *x = factory()->NewNumberLiteral(base::Divide(x_val, y_val), pos);
return true;
case Token::BIT_OR: {
int value = DoubleToInt32(x_val) | DoubleToInt32(y_val);
@@ -200,6 +237,7 @@ bool Parser::CollapseNaryExpression(Expression** x, Expression* y,
// TODO(leszeks): Do some literal collapsing here if we're appending Smi or
// String literals.
nary->AddSubsequent(y, pos);
+ nary->clear_parenthesized();
AppendNaryOperationSourceRange(nary, range);
return true;
@@ -232,12 +270,11 @@ Expression* Parser::BuildUnaryExpression(Expression* expression,
}
Expression* Parser::NewThrowError(Runtime::FunctionId id,
- MessageTemplate::Template message,
+ MessageTemplate message,
const AstRawString* arg, int pos) {
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(2, zone());
- args->Add(factory()->NewSmiLiteral(message, pos), zone());
- args->Add(factory()->NewStringLiteral(arg, pos), zone());
+ ScopedPtrList<Expression> args(pointer_buffer());
+ args.Add(factory()->NewSmiLiteral(static_cast<int>(message), pos));
+ args.Add(factory()->NewStringLiteral(arg, pos));
CallRuntime* call_constructor = factory()->NewCallRuntime(id, args, pos);
return factory()->NewThrow(call_constructor, pos);
}
@@ -271,12 +308,12 @@ Expression* Parser::NewTargetExpression(int pos) {
}
Expression* Parser::ImportMetaExpression(int pos) {
- return factory()->NewCallRuntime(
- Runtime::kInlineGetImportMetaObject,
- new (zone()) ZonePtrList<Expression>(0, zone()), pos);
+ ScopedPtrList<Expression> args(pointer_buffer());
+ return factory()->NewCallRuntime(Runtime::kInlineGetImportMetaObject, args,
+ pos);
}
-Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
+Expression* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
switch (token) {
case Token::NULL_LITERAL:
return factory()->NewNullLiteral(pos);
@@ -295,15 +332,18 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
case Token::BIGINT:
return factory()->NewBigIntLiteral(
AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos);
+ case Token::STRING: {
+ return factory()->NewStringLiteral(GetSymbol(), pos);
+ }
default:
DCHECK(false);
}
- return nullptr;
+ return FailureExpression();
}
Expression* Parser::NewV8Intrinsic(const AstRawString* name,
- ZonePtrList<Expression>* args, int pos,
- bool* ok) {
+ const ScopedPtrList<Expression>& args,
+ int pos) {
if (extension_ != nullptr) {
// The extension structures are only accessible while parsing the
// very first time, not when reparsing because of lazy compilation.
@@ -318,26 +358,11 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name,
// Check for possible name clash.
DCHECK_EQ(Context::kNotFound,
Context::IntrinsicIndexForName(name->raw_data(), name->length()));
- // 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() != nullptr) {
- return args->at(0);
- } else {
- ReportMessage(MessageTemplate::kNotIsvar);
- *ok = false;
- return nullptr;
- }
- }
// Check that the expected number of arguments are being passed.
- if (function->nargs != -1 && function->nargs != args->length()) {
+ if (function->nargs != -1 && function->nargs != args.length()) {
ReportMessage(MessageTemplate::kRuntimeWrongNumArgs);
- *ok = false;
- return nullptr;
+ return FailureExpression();
}
return factory()->NewCallRuntime(function, args, pos);
@@ -349,8 +374,7 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name,
// Check that the function is defined.
if (context_index == Context::kNotFound) {
ReportMessage(MessageTemplate::kNotDefined, name);
- *ok = false;
- return nullptr;
+ return FailureExpression();
}
return factory()->NewCallRuntime(context_index, args, pos);
@@ -363,15 +387,16 @@ Parser::Parser(ParseInfo* info)
info->runtime_call_stats(), info->logger(),
info->script().is_null() ? -1 : info->script()->id(),
info->is_module(), true),
- scanner_(info->unicode_cache(), info->character_stream(),
- info->is_module()),
+ info_(info),
+ scanner_(info->character_stream(), info->is_module()),
preparser_zone_(info->zone()->allocator(), ZONE_NAME),
reusable_preparser_(nullptr),
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
source_range_map_(info->source_range_map()),
target_stack_(nullptr),
total_preparse_skipped_(0),
- consumed_preparsed_scope_data_(info->consumed_preparsed_scope_data()),
+ consumed_preparse_data_(info->consumed_preparse_data()),
+ preparse_data_buffer_(),
parameters_end_pos_(info->parameters_end_pos()) {
// Even though we were passed ParseInfo, we should not store it in
// Parser - this makes sure that Isolate is not accidentally accessed via
@@ -387,21 +412,22 @@ Parser::Parser(ParseInfo* info)
// of functions without an outer context when setting a breakpoint through
// Debug::FindSharedFunctionInfoInScript
// We also compile eagerly for kProduceExhaustiveCodeCache.
- bool can_compile_lazily = FLAG_lazy && !info->is_eager();
+ bool can_compile_lazily = info->allow_lazy_compile() && !info->is_eager();
set_default_eager_compile_hint(can_compile_lazily
? FunctionLiteral::kShouldLazyCompile
: FunctionLiteral::kShouldEagerCompile);
- allow_lazy_ = FLAG_lazy && info->allow_lazy_parsing() && !info->is_native() &&
- info->extension() == nullptr && can_compile_lazily;
- set_allow_natives(FLAG_allow_natives_syntax || info->is_native());
- set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
- set_allow_harmony_public_fields(FLAG_harmony_public_fields);
- set_allow_harmony_static_fields(FLAG_harmony_static_fields);
- set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import);
- set_allow_harmony_import_meta(FLAG_harmony_import_meta);
- set_allow_harmony_numeric_separator(FLAG_harmony_numeric_separator);
- set_allow_harmony_private_fields(FLAG_harmony_private_fields);
+ allow_lazy_ = info->allow_lazy_compile() && info->allow_lazy_parsing() &&
+ !info->is_native() && info->extension() == nullptr &&
+ can_compile_lazily;
+ set_allow_natives(info->allow_natives_syntax() || info->is_native());
+ set_allow_harmony_public_fields(info->allow_harmony_public_fields());
+ set_allow_harmony_static_fields(info->allow_harmony_static_fields());
+ set_allow_harmony_dynamic_import(info->allow_harmony_dynamic_import());
+ set_allow_harmony_import_meta(info->allow_harmony_import_meta());
+ set_allow_harmony_numeric_separator(info->allow_harmony_numeric_separator());
+ set_allow_harmony_private_fields(info->allow_harmony_private_fields());
+ set_allow_harmony_private_methods(info->allow_harmony_private_methods());
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@@ -411,8 +437,6 @@ Parser::Parser(ParseInfo* info)
void Parser::InitializeEmptyScopeChain(ParseInfo* info) {
DCHECK_NULL(original_scope_);
DCHECK_NULL(info->script_scope());
- // TODO(wingo): Add an outer SCRIPT_SCOPE corresponding to the native
- // context, which will have the "this" binding for script scopes.
DeclarationScope* script_scope = NewScriptScope();
info->set_script_scope(script_scope);
original_scope_ = script_scope;
@@ -420,14 +444,15 @@ void Parser::InitializeEmptyScopeChain(ParseInfo* info) {
void Parser::DeserializeScopeChain(
Isolate* isolate, ParseInfo* info,
- MaybeHandle<ScopeInfo> maybe_outer_scope_info) {
+ MaybeHandle<ScopeInfo> maybe_outer_scope_info,
+ Scope::DeserializationMode mode) {
InitializeEmptyScopeChain(info);
Handle<ScopeInfo> outer_scope_info;
if (maybe_outer_scope_info.ToHandle(&outer_scope_info)) {
DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
original_scope_ = Scope::DeserializeScopeChain(
isolate, zone(), *outer_scope_info, info->script_scope(),
- ast_value_factory(), Scope::DeserializationMode::kScopesOnly);
+ ast_value_factory(), mode);
}
}
@@ -436,10 +461,11 @@ namespace {
void MaybeResetCharacterStream(ParseInfo* info, FunctionLiteral* literal) {
// Don't reset the character stream if there is an asm.js module since it will
// be used again by the asm-parser.
- if (!FLAG_stress_validate_asm &&
- (literal == nullptr || !literal->scope()->ContainsAsmModule())) {
- info->ResetCharacterStream();
+ if (info->contains_asm_module()) {
+ if (FLAG_stress_validate_asm) return;
+ if (literal != nullptr && literal->scope()->ContainsAsmModule()) return;
}
+ info->ResetCharacterStream();
}
void MaybeProcessSourceRanges(ParseInfo* parse_info, Expression* root,
@@ -469,9 +495,13 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
// Initialize parser state.
- DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info());
+ DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info(),
+ Scope::DeserializationMode::kIncludingVariables);
scanner_.Initialize();
+ if (FLAG_harmony_hashbang && !info->is_eval()) {
+ scanner_.SkipHashBang();
+ }
FunctionLiteral* result = DoParseProgram(isolate, info);
MaybeResetCharacterStream(info, result);
MaybeProcessSourceRanges(info, result, stack_limit_);
@@ -481,7 +511,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) {
double ms = timer.Elapsed().InMillisecondsF();
const char* event_name = "parse-eval";
- Script* script = *info->script();
+ Script script = *info->script();
int start = -1;
int end = -1;
if (!info->is_eval()) {
@@ -524,78 +554,80 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
scope->set_start_position(0);
FunctionState function_state(&function_state_, &scope_, scope);
- ZonePtrList<Statement>* body =
- new (zone()) ZonePtrList<Statement>(16, zone());
- bool ok = true;
+ ScopedPtrList<Statement> body(pointer_buffer());
int beg_pos = scanner()->location().beg_pos;
if (parsing_module_) {
DCHECK(info->is_module());
// Declare the special module parameter.
auto name = ast_value_factory()->empty_string();
- bool is_duplicate = false;
bool is_rest = false;
bool is_optional = false;
+ VariableMode mode = VariableMode::kVar;
+ bool was_added;
+ scope->DeclareLocal(name, mode, PARAMETER_VARIABLE, &was_added,
+ Variable::DefaultInitializationFlag(mode));
+ DCHECK(was_added);
auto var = scope->DeclareParameter(name, VariableMode::kVar, is_optional,
- is_rest, &is_duplicate,
- ast_value_factory(), beg_pos);
- DCHECK(!is_duplicate);
+ is_rest, ast_value_factory(), beg_pos);
var->AllocateTo(VariableLocation::PARAMETER, 0);
PrepareGeneratorVariables();
Expression* initial_yield =
BuildInitialYield(kNoSourcePosition, kGeneratorFunction);
- body->Add(
- factory()->NewExpressionStatement(initial_yield, kNoSourcePosition),
- zone());
-
- ParseModuleItemList(body, &ok);
- ok = ok && module()->Validate(this->scope()->AsModuleScope(),
- pending_error_handler(), zone());
+ body.Add(
+ factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
+
+ ParseModuleItemList(&body);
+ if (!has_error() &&
+ !module()->Validate(this->scope()->AsModuleScope(),
+ pending_error_handler(), zone())) {
+ scanner()->set_parser_error();
+ }
} else if (info->is_wrapped_as_function()) {
- ParseWrapped(isolate, info, body, scope, zone(), &ok);
+ ParseWrapped(isolate, info, &body, scope, zone());
} else {
// Don't count the mode in the use counters--give the program a chance
// to enable script-wide strict mode below.
this->scope()->SetLanguageMode(info->language_mode());
- ParseStatementList(body, Token::EOS, &ok);
+ ParseStatementList(&body, Token::EOS);
}
// 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);
+ scope->set_end_position(peek_position());
- if (ok && is_strict(language_mode())) {
- CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
+ if (is_strict(language_mode())) {
+ CheckStrictOctalLiteral(beg_pos, end_position());
}
- if (ok && is_sloppy(language_mode())) {
+ if (is_sloppy(language_mode())) {
// 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);
}
- if (ok) {
- CheckConflictingVarDeclarations(scope, &ok);
+ // Internalize the ast strings in the case of eval so we can check for
+ // conflicting var declarations with outer scope-info-backed scopes.
+ if (info->is_eval()) {
+ DCHECK(parsing_on_main_thread_);
+ info->ast_value_factory()->Internalize(isolate);
}
+ CheckConflictingVarDeclarations(scope);
- if (ok && info->parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
- if (body->length() != 1 ||
- !body->at(0)->IsExpressionStatement() ||
- !body->at(0)->AsExpressionStatement()->
- expression()->IsFunctionLiteral()) {
+ if (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) {
- RewriteDestructuringAssignments();
- int parameter_count = parsing_module_ ? 1 : 0;
- result = factory()->NewScriptOrEvalFunctionLiteral(
- scope, body, function_state.expected_property_count(),
- parameter_count);
- result->set_suspend_count(function_state.suspend_count());
- }
+ int parameter_count = parsing_module_ ? 1 : 0;
+ result = factory()->NewScriptOrEvalFunctionLiteral(
+ scope, body, function_state.expected_property_count(), parameter_count);
+ result->set_suspend_count(function_state.suspend_count());
}
info->set_max_function_literal_id(GetLastFunctionLiteralId());
@@ -603,6 +635,7 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
// Make sure the target stack is empty.
DCHECK_NULL(target_stack_);
+ if (has_error()) return nullptr;
return result;
}
@@ -623,8 +656,8 @@ ZonePtrList<const AstRawString>* Parser::PrepareWrappedArguments(
}
void Parser::ParseWrapped(Isolate* isolate, ParseInfo* info,
- ZonePtrList<Statement>* body,
- DeclarationScope* outer_scope, Zone* zone, bool* ok) {
+ ScopedPtrList<Statement>* body,
+ DeclarationScope* outer_scope, Zone* zone) {
DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr);
DCHECK(info->is_wrapped_as_function());
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
@@ -642,11 +675,11 @@ void Parser::ParseWrapped(Isolate* isolate, ParseInfo* info,
FunctionLiteral* function_literal = ParseFunctionLiteral(
function_name, location, kSkipFunctionNameCheck, kNormalFunction,
kNoSourcePosition, FunctionLiteral::kWrapped, LanguageMode::kSloppy,
- arguments_for_wrapped_function, CHECK_OK_VOID);
+ arguments_for_wrapped_function);
Statement* return_statement = factory()->NewReturnStatement(
function_literal, kNoSourcePosition, kNoSourcePosition);
- body->Add(return_statement, zone);
+ body->Add(return_statement);
}
FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
@@ -660,7 +693,8 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
base::ElapsedTimer timer;
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
- DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info());
+ DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info(),
+ Scope::DeserializationMode::kIncludingVariables);
DCHECK_EQ(factory()->zone(), info->zone());
// Initialize parser state.
@@ -736,7 +770,6 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
is_strict(info->language_mode()));
FunctionLiteral::FunctionType function_type = ComputeFunctionType(info);
FunctionKind kind = info->function_kind();
- bool ok = true;
if (IsArrowFunction(kind)) {
if (IsAsyncFunction(kind)) {
@@ -759,70 +792,56 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
SetLanguageMode(scope, info->language_mode());
scope->set_start_position(info->start_position());
- ExpressionClassifier formals_classifier(this);
ParserFormalParameters formals(scope);
- // The outer FunctionState should not contain destructuring assignments.
- DCHECK_EQ(0,
- function_state.destructuring_assignments_to_rewrite().size());
{
+ ParameterDeclarationParsingScope formals_scope(this);
// Parsing patterns as variable reference expression creates
// NewUnresolved references in current scope. Enter arrow function
// scope for formal parameter parsing.
BlockState block_state(&scope_, scope);
if (Check(Token::LPAREN)) {
// '(' StrictFormalParameters ')'
- ParseFormalParameterList(&formals, &ok);
- if (ok) ok = Check(Token::RPAREN);
+ ParseFormalParameterList(&formals);
+ Expect(Token::RPAREN);
} else {
// BindingIdentifier
- ParseFormalParameter(&formals, &ok);
- if (ok) {
- DeclareFormalParameters(formals.scope, formals.params,
- formals.is_simple);
- }
+ ParameterParsingScope scope(impl(), &formals);
+ ParseFormalParameter(&formals);
+ DeclareFormalParameters(&formals);
}
+ formals.duplicate_loc = formals_scope.duplicate_location();
}
- if (ok) {
- if (GetLastFunctionLiteralId() != info->function_literal_id() - 1) {
- // If there were FunctionLiterals in the parameters, we need to
- // renumber them to shift down so the next function literal id for
- // the arrow function is the one requested.
- AstFunctionLiteralIdReindexer reindexer(
- stack_limit_,
- (info->function_literal_id() - 1) - GetLastFunctionLiteralId());
- for (auto p : formals.params) {
- if (p->pattern != nullptr) reindexer.Reindex(p->pattern);
- if (p->initializer != nullptr) reindexer.Reindex(p->initializer);
+ if (GetLastFunctionLiteralId() != info->function_literal_id() - 1) {
+ if (has_error()) return nullptr;
+ // If there were FunctionLiterals in the parameters, we need to
+ // renumber them to shift down so the next function literal id for
+ // the arrow function is the one requested.
+ AstFunctionLiteralIdReindexer reindexer(
+ stack_limit_,
+ (info->function_literal_id() - 1) - GetLastFunctionLiteralId());
+ for (auto p : formals.params) {
+ if (p->pattern != nullptr) reindexer.Reindex(p->pattern);
+ if (p->initializer() != nullptr) {
+ reindexer.Reindex(p->initializer());
}
- ResetFunctionLiteralId();
- SkipFunctionLiterals(info->function_literal_id() - 1);
}
+ ResetFunctionLiteralId();
+ SkipFunctionLiterals(info->function_literal_id() - 1);
+ }
- // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
- // not be observable, or else the preparser would have failed.
- const bool accept_IN = true;
- // Any destructuring assignments in the current FunctionState
- // actually belong to the arrow function itself.
- const int rewritable_length = 0;
- Expression* expression = ParseArrowFunctionLiteral(
- accept_IN, formals, rewritable_length, &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 == 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;
- }
- }
+ Expression* expression = ParseArrowFunctionLiteral(formals);
+ // 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 == 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 if (IsDefaultConstructor(kind)) {
DCHECK_EQ(scope(), outer);
@@ -836,15 +855,15 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
result = ParseFunctionLiteral(
raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind,
kNoSourcePosition, function_type, info->language_mode(),
- arguments_for_wrapped_function, &ok);
+ arguments_for_wrapped_function);
}
- if (ok) {
- result->set_requires_instance_fields_initializer(
- info->requires_instance_fields_initializer());
+ if (has_error()) return nullptr;
+ result->set_requires_instance_members_initializer(
+ info->requires_instance_members_initializer());
+ if (info->is_oneshot_iife()) {
+ result->mark_as_oneshot_iife();
}
- // Make sure the results agree.
- DCHECK(ok == (result != nullptr));
}
// Make sure the target stack is empty.
@@ -854,7 +873,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
return result;
}
-Statement* Parser::ParseModuleItem(bool* ok) {
+Statement* Parser::ParseModuleItem() {
// ecma262/#prod-ModuleItem
// ModuleItem :
// ImportDeclaration
@@ -864,7 +883,7 @@ Statement* Parser::ParseModuleItem(bool* ok) {
Token::Value next = peek();
if (next == Token::EXPORT) {
- return ParseExportDeclaration(ok);
+ return ParseExportDeclaration();
}
if (next == Token::IMPORT) {
@@ -873,15 +892,15 @@ Statement* Parser::ParseModuleItem(bool* ok) {
Token::Value peek_ahead = PeekAhead();
if ((!allow_harmony_dynamic_import() || peek_ahead != Token::LPAREN) &&
(!allow_harmony_import_meta() || peek_ahead != Token::PERIOD)) {
- ParseImportDeclaration(CHECK_OK);
- return factory()->NewEmptyStatement(kNoSourcePosition);
+ ParseImportDeclaration();
+ return factory()->EmptyStatement();
}
}
- return ParseStatementListItem(ok);
+ return ParseStatementListItem();
}
-void Parser::ParseModuleItemList(ZonePtrList<Statement>* body, bool* ok) {
+void Parser::ParseModuleItemList(ScopedPtrList<Statement>* body) {
// ecma262/#prod-Module
// Module :
// ModuleBody?
@@ -892,24 +911,23 @@ void Parser::ParseModuleItemList(ZonePtrList<Statement>* body, bool* ok) {
DCHECK(scope()->is_module_scope());
while (peek() != Token::EOS) {
- Statement* stat = ParseModuleItem(CHECK_OK_VOID);
- if (stat && !stat->IsEmpty()) {
- body->Add(stat, zone());
- }
+ Statement* stat = ParseModuleItem();
+ if (stat == nullptr) return;
+ if (stat->IsEmptyStatement()) continue;
+ body->Add(stat);
}
}
-
-const AstRawString* Parser::ParseModuleSpecifier(bool* ok) {
+const AstRawString* Parser::ParseModuleSpecifier() {
// ModuleSpecifier :
// StringLiteral
- Expect(Token::STRING, CHECK_OK);
+ Expect(Token::STRING);
return GetSymbol();
}
ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause(
- Scanner::Location* reserved_loc, bool* ok) {
+ Scanner::Location* reserved_loc) {
// ExportClause :
// '{' '}'
// '{' ExportsList '}'
@@ -925,22 +943,22 @@ ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause(
ZoneChunkList<ExportClauseData>* export_data =
new (zone()) ZoneChunkList<ExportClauseData>(zone());
- Expect(Token::LBRACE, CHECK_OK);
+ Expect(Token::LBRACE);
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, LanguageMode::kStrict, false,
- parsing_module_)) {
+ !Token::IsValidIdentifier(name_tok, LanguageMode::kStrict, false,
+ parsing_module_)) {
*reserved_loc = scanner()->location();
}
- const AstRawString* local_name = ParseIdentifierName(CHECK_OK);
+ const AstRawString* local_name = ParsePropertyName();
const AstRawString* export_name = nullptr;
Scanner::Location location = scanner()->location();
- if (CheckContextualKeyword(Token::AS)) {
- export_name = ParseIdentifierName(CHECK_OK);
+ if (CheckContextualKeyword(ast_value_factory()->as_string())) {
+ export_name = ParsePropertyName();
// Set the location to the whole "a as b" string, so that it makes sense
// both for errors due to "a" and for errors due to "b".
location.end_pos = scanner()->location().end_pos;
@@ -950,15 +968,17 @@ ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause(
}
export_data->push_back({export_name, local_name, location});
if (peek() == Token::RBRACE) break;
- Expect(Token::COMMA, CHECK_OK);
+ if (V8_UNLIKELY(!Check(Token::COMMA))) {
+ ReportUnexpectedToken(Next());
+ break;
+ }
}
- Expect(Token::RBRACE, CHECK_OK);
+ Expect(Token::RBRACE);
return export_data;
}
-ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos,
- bool* ok) {
+ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos) {
// NamedImports :
// '{' '}'
// '{' ImportsList '}'
@@ -972,47 +992,45 @@ ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos,
// BindingIdentifier
// IdentifierName 'as' BindingIdentifier
- Expect(Token::LBRACE, CHECK_OK);
+ Expect(Token::LBRACE);
auto result = new (zone()) ZonePtrList<const NamedImport>(1, zone());
while (peek() != Token::RBRACE) {
- const AstRawString* import_name = ParseIdentifierName(CHECK_OK);
+ const AstRawString* import_name = ParsePropertyName();
const AstRawString* local_name = import_name;
Scanner::Location location = scanner()->location();
// 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(Token::AS)) {
- local_name = ParseIdentifierName(CHECK_OK);
+ if (CheckContextualKeyword(ast_value_factory()->as_string())) {
+ local_name = ParsePropertyName();
}
- if (!Token::IsIdentifier(scanner()->current_token(), LanguageMode::kStrict,
- false, parsing_module_)) {
- *ok = false;
+ if (!Token::IsValidIdentifier(scanner()->current_token(),
+ LanguageMode::kStrict, false,
+ parsing_module_)) {
ReportMessage(MessageTemplate::kUnexpectedReserved);
return nullptr;
} else if (IsEvalOrArguments(local_name)) {
- *ok = false;
ReportMessage(MessageTemplate::kStrictEvalArguments);
return nullptr;
}
DeclareVariable(local_name, VariableMode::kConst, kNeedsInitialization,
- position(), CHECK_OK);
+ position());
NamedImport* import =
new (zone()) NamedImport(import_name, local_name, location);
result->Add(import, zone());
if (peek() == Token::RBRACE) break;
- Expect(Token::COMMA, CHECK_OK);
+ Expect(Token::COMMA);
}
- Expect(Token::RBRACE, CHECK_OK);
+ Expect(Token::RBRACE);
return result;
}
-
-void Parser::ParseImportDeclaration(bool* ok) {
+void Parser::ParseImportDeclaration() {
// ImportDeclaration :
// 'import' ImportClause 'from' ModuleSpecifier ';'
// 'import' ModuleSpecifier ';'
@@ -1028,15 +1046,15 @@ void Parser::ParseImportDeclaration(bool* ok) {
// '*' 'as' ImportedBinding
int pos = peek_position();
- Expect(Token::IMPORT, CHECK_OK_VOID);
+ Expect(Token::IMPORT);
Token::Value tok = peek();
// 'import' ModuleSpecifier ';'
if (tok == Token::STRING) {
Scanner::Location specifier_loc = scanner()->peek_location();
- const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK_VOID);
- ExpectSemicolon(CHECK_OK_VOID);
+ const AstRawString* module_specifier = ParseModuleSpecifier();
+ ExpectSemicolon();
module()->AddEmptyImport(module_specifier, specifier_loc);
return;
}
@@ -1045,11 +1063,10 @@ void Parser::ParseImportDeclaration(bool* ok) {
const AstRawString* import_default_binding = nullptr;
Scanner::Location import_default_binding_loc;
if (tok != Token::MUL && tok != Token::LBRACE) {
- import_default_binding =
- ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK_VOID);
+ import_default_binding = ParseNonRestrictedIdentifier();
import_default_binding_loc = scanner()->location();
DeclareVariable(import_default_binding, VariableMode::kConst,
- kNeedsInitialization, pos, CHECK_OK_VOID);
+ kNeedsInitialization, pos);
}
// Parse NameSpaceImport or NamedImports if present.
@@ -1060,30 +1077,28 @@ void Parser::ParseImportDeclaration(bool* ok) {
switch (peek()) {
case Token::MUL: {
Consume(Token::MUL);
- ExpectContextualKeyword(Token::AS, CHECK_OK_VOID);
- module_namespace_binding =
- ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK_VOID);
+ ExpectContextualKeyword(ast_value_factory()->as_string());
+ module_namespace_binding = ParseNonRestrictedIdentifier();
module_namespace_binding_loc = scanner()->location();
DeclareVariable(module_namespace_binding, VariableMode::kConst,
- kCreatedInitialized, pos, CHECK_OK_VOID);
+ kCreatedInitialized, pos);
break;
}
case Token::LBRACE:
- named_imports = ParseNamedImports(pos, CHECK_OK_VOID);
+ named_imports = ParseNamedImports(pos);
break;
default:
- *ok = false;
ReportUnexpectedToken(scanner()->current_token());
return;
}
}
- ExpectContextualKeyword(Token::FROM, CHECK_OK_VOID);
+ ExpectContextualKeyword(ast_value_factory()->from_string());
Scanner::Location specifier_loc = scanner()->peek_location();
- const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK_VOID);
- ExpectSemicolon(CHECK_OK_VOID);
+ const AstRawString* module_specifier = ParseModuleSpecifier();
+ ExpectSemicolon();
// Now that we have all the information, we can make the appropriate
// declarations.
@@ -1119,42 +1134,40 @@ void Parser::ParseImportDeclaration(bool* ok) {
}
}
-
-Statement* Parser::ParseExportDefault(bool* ok) {
+Statement* Parser::ParseExportDefault() {
// Supports the following productions, starting after the 'default' token:
// 'export' 'default' HoistableDeclaration
// 'export' 'default' ClassDeclaration
// 'export' 'default' AssignmentExpression[In] ';'
- Expect(Token::DEFAULT, CHECK_OK);
+ Expect(Token::DEFAULT);
Scanner::Location default_loc = scanner()->location();
ZonePtrList<const AstRawString> local_names(1, zone());
Statement* result = nullptr;
switch (peek()) {
case Token::FUNCTION:
- result = ParseHoistableDeclaration(&local_names, true, CHECK_OK);
+ result = ParseHoistableDeclaration(&local_names, true);
break;
case Token::CLASS:
Consume(Token::CLASS);
- result = ParseClassDeclaration(&local_names, true, CHECK_OK);
+ result = ParseClassDeclaration(&local_names, true);
break;
case Token::ASYNC:
if (PeekAhead() == Token::FUNCTION &&
!scanner()->HasLineTerminatorAfterNext()) {
Consume(Token::ASYNC);
- result = ParseAsyncFunctionDeclaration(&local_names, true, CHECK_OK);
+ result = ParseAsyncFunctionDeclaration(&local_names, true);
break;
}
V8_FALLTHROUGH;
default: {
int pos = position();
- ExpressionClassifier classifier(this);
- Expression* value = ParseAssignmentExpression(true, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ AcceptINScope scope(this, true);
+ Expression* value = ParseAssignmentExpression();
SetFunctionName(value, ast_value_factory()->default_string());
const AstRawString* local_name =
@@ -1163,57 +1176,98 @@ Statement* Parser::ParseExportDefault(bool* ok) {
// It's fine to declare this as VariableMode::kConst because the user has
// no way of writing to it.
- Declaration* decl =
- DeclareVariable(local_name, VariableMode::kConst, pos, CHECK_OK);
- decl->proxy()->var()->set_initializer_position(position());
+ VariableProxy* proxy =
+ DeclareVariable(local_name, VariableMode::kConst, pos);
+ proxy->var()->set_initializer_position(position());
Assignment* assignment = factory()->NewAssignment(
- Token::INIT, decl->proxy(), value, kNoSourcePosition);
+ Token::INIT, proxy, value, kNoSourcePosition);
result = IgnoreCompletion(
factory()->NewExpressionStatement(assignment, kNoSourcePosition));
- ExpectSemicolon(CHECK_OK);
+ ExpectSemicolon();
break;
}
}
- DCHECK_EQ(local_names.length(), 1);
- module()->AddExport(local_names.first(),
- ast_value_factory()->default_string(), default_loc,
- zone());
+ if (result != nullptr) {
+ DCHECK_EQ(local_names.length(), 1);
+ module()->AddExport(local_names.first(),
+ ast_value_factory()->default_string(), default_loc,
+ zone());
+ }
- DCHECK_NOT_NULL(result);
return result;
}
-Statement* Parser::ParseExportDeclaration(bool* ok) {
+const AstRawString* Parser::NextInternalNamespaceExportName() {
+ const char* prefix = ".ns-export";
+ std::string s(prefix);
+ s.append(std::to_string(number_of_named_namespace_exports_++));
+ return ast_value_factory()->GetOneByteString(s.c_str());
+}
+
+void Parser::ParseExportStar() {
+ int pos = position();
+ Consume(Token::MUL);
+
+ if (!FLAG_harmony_namespace_exports ||
+ !PeekContextualKeyword(ast_value_factory()->as_string())) {
+ // 'export' '*' 'from' ModuleSpecifier ';'
+ Scanner::Location loc = scanner()->location();
+ ExpectContextualKeyword(ast_value_factory()->from_string());
+ Scanner::Location specifier_loc = scanner()->peek_location();
+ const AstRawString* module_specifier = ParseModuleSpecifier();
+ ExpectSemicolon();
+ module()->AddStarExport(module_specifier, loc, specifier_loc, zone());
+ return;
+ }
+ if (!FLAG_harmony_namespace_exports) return;
+
+ // 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier ';'
+ //
+ // Desugaring:
+ // export * as x from "...";
+ // ~>
+ // import * as .x from "..."; export {.x as x};
+
+ ExpectContextualKeyword(ast_value_factory()->as_string());
+ const AstRawString* export_name = ParsePropertyName();
+ Scanner::Location export_name_loc = scanner()->location();
+ const AstRawString* local_name = NextInternalNamespaceExportName();
+ Scanner::Location local_name_loc = Scanner::Location::invalid();
+ DeclareVariable(local_name, VariableMode::kConst, kCreatedInitialized, pos);
+
+ ExpectContextualKeyword(ast_value_factory()->from_string());
+ Scanner::Location specifier_loc = scanner()->peek_location();
+ const AstRawString* module_specifier = ParseModuleSpecifier();
+ ExpectSemicolon();
+
+ module()->AddStarImport(local_name, module_specifier, local_name_loc,
+ specifier_loc, zone());
+ module()->AddExport(local_name, export_name, export_name_loc, zone());
+}
+
+Statement* Parser::ParseExportDeclaration() {
// ExportDeclaration:
// 'export' '*' 'from' ModuleSpecifier ';'
+ // 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier ';'
// 'export' ExportClause ('from' ModuleSpecifier)? ';'
// 'export' VariableStatement
// 'export' Declaration
// 'export' 'default' ... (handled in ParseExportDefault)
- Expect(Token::EXPORT, CHECK_OK);
- int pos = position();
-
+ Expect(Token::EXPORT);
Statement* result = nullptr;
ZonePtrList<const AstRawString> names(1, zone());
Scanner::Location loc = scanner()->peek_location();
switch (peek()) {
case Token::DEFAULT:
- return ParseExportDefault(ok);
-
- case Token::MUL: {
- Consume(Token::MUL);
- loc = scanner()->location();
- ExpectContextualKeyword(Token::FROM, CHECK_OK);
- Scanner::Location specifier_loc = scanner()->peek_location();
- const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- module()->AddStarExport(module_specifier, loc, specifier_loc, zone());
- return factory()->NewEmptyStatement(pos);
- }
+ return ParseExportDefault();
+
+ case Token::MUL:
+ ParseExportStar();
+ return factory()->EmptyStatement();
case Token::LBRACE: {
// There are two cases here:
@@ -1229,19 +1283,18 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
// non-FromClause case.
Scanner::Location reserved_loc = Scanner::Location::invalid();
ZoneChunkList<ExportClauseData>* export_data =
- ParseExportClause(&reserved_loc, CHECK_OK);
+ ParseExportClause(&reserved_loc);
const AstRawString* module_specifier = nullptr;
Scanner::Location specifier_loc;
- if (CheckContextualKeyword(Token::FROM)) {
+ if (CheckContextualKeyword(ast_value_factory()->from_string())) {
specifier_loc = scanner()->peek_location();
- module_specifier = ParseModuleSpecifier(CHECK_OK);
+ module_specifier = ParseModuleSpecifier();
} else if (reserved_loc.IsValid()) {
// No FromClause, so reserved words are invalid in ExportClause.
- *ok = false;
ReportMessageAt(reserved_loc, MessageTemplate::kUnexpectedReserved);
return nullptr;
}
- ExpectSemicolon(CHECK_OK);
+ ExpectSemicolon();
if (module_specifier == nullptr) {
for (const ExportClauseData& data : *export_data) {
module()->AddExport(data.local_name, data.export_name, data.location,
@@ -1256,33 +1309,34 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
zone());
}
}
- return factory()->NewEmptyStatement(pos);
+ return factory()->EmptyStatement();
}
case Token::FUNCTION:
- result = ParseHoistableDeclaration(&names, false, CHECK_OK);
+ result = ParseHoistableDeclaration(&names, false);
break;
case Token::CLASS:
Consume(Token::CLASS);
- result = ParseClassDeclaration(&names, false, CHECK_OK);
+ result = ParseClassDeclaration(&names, false);
break;
case Token::VAR:
case Token::LET:
case Token::CONST:
- result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
+ result = ParseVariableStatement(kStatementListItem, &names);
break;
case Token::ASYNC:
- // TODO(neis): Why don't we have the same check here as in
- // ParseStatementListItem?
Consume(Token::ASYNC);
- result = ParseAsyncFunctionDeclaration(&names, false, CHECK_OK);
- break;
+ if (peek() == Token::FUNCTION &&
+ !scanner()->HasLineTerminatorBeforeNext()) {
+ result = ParseAsyncFunctionDeclaration(&names, false);
+ break;
+ }
+ V8_FALLTHROUGH;
default:
- *ok = false;
ReportUnexpectedToken(scanner()->current_token());
return nullptr;
}
@@ -1293,126 +1347,117 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
descriptor->AddExport(names[i], names[i], loc, zone());
}
- DCHECK_NOT_NULL(result);
return result;
}
-VariableProxy* Parser::NewUnresolved(const AstRawString* name, int begin_pos,
- VariableKind kind) {
- return scope()->NewUnresolved(factory(), name, begin_pos, kind);
-}
-
-VariableProxy* Parser::NewUnresolved(const AstRawString* name) {
- return scope()->NewUnresolved(factory(), name, scanner()->location().beg_pos);
-}
-
-Declaration* Parser::DeclareVariable(const AstRawString* name,
- VariableMode mode, int pos, bool* ok) {
+VariableProxy* Parser::DeclareVariable(const AstRawString* name,
+ VariableMode mode, int pos) {
return DeclareVariable(name, mode, Variable::DefaultInitializationFlag(mode),
- pos, ok);
+ pos);
}
-Declaration* Parser::DeclareVariable(const AstRawString* name,
- VariableMode mode, InitializationFlag init,
- int pos, bool* ok) {
+VariableProxy* Parser::DeclareVariable(const AstRawString* name,
+ VariableMode mode,
+ InitializationFlag init, int pos) {
DCHECK_NOT_NULL(name);
- VariableProxy* proxy = factory()->NewVariableProxy(
- name, NORMAL_VARIABLE, scanner()->location().beg_pos);
+ VariableProxy* proxy =
+ factory()->NewVariableProxy(name, NORMAL_VARIABLE, position());
+ bool was_added;
+ DeclareVariable(proxy, NORMAL_VARIABLE, mode, init, scope(), &was_added, pos,
+ end_position());
+ return proxy;
+}
+
+void Parser::DeclareVariable(VariableProxy* proxy, VariableKind kind,
+ VariableMode mode, InitializationFlag init,
+ Scope* scope, bool* was_added, int begin,
+ int end) {
Declaration* declaration;
- if (mode == VariableMode::kVar && !scope()->is_declaration_scope()) {
- DCHECK(scope()->is_block_scope() || scope()->is_with_scope());
- declaration = factory()->NewNestedVariableDeclaration(proxy, scope(), pos);
+ if (mode == VariableMode::kVar && !scope->is_declaration_scope()) {
+ DCHECK(scope->is_block_scope() || scope->is_with_scope());
+ declaration = factory()->NewNestedVariableDeclaration(scope, begin);
} else {
- declaration = factory()->NewVariableDeclaration(proxy, pos);
+ declaration = factory()->NewVariableDeclaration(begin);
}
- Declare(declaration, DeclarationDescriptor::NORMAL, mode, init, ok, nullptr,
- scanner()->location().end_pos);
- if (!*ok) return nullptr;
- return declaration;
+ return Declare(declaration, proxy, kind, mode, init, scope, was_added, end);
}
-Variable* Parser::Declare(Declaration* declaration,
- DeclarationDescriptor::Kind declaration_kind,
- VariableMode mode, InitializationFlag init, bool* ok,
- Scope* scope, int var_end_pos) {
- if (scope == nullptr) {
- scope = this->scope();
- }
+void Parser::Declare(Declaration* declaration, VariableProxy* proxy,
+ VariableKind variable_kind, VariableMode mode,
+ InitializationFlag init, Scope* scope, bool* was_added,
+ int var_end_pos) {
+ bool local_ok = true;
bool sloppy_mode_block_scope_function_redefinition = false;
- Variable* variable = scope->DeclareVariable(
- declaration, mode, init, &sloppy_mode_block_scope_function_redefinition,
- ok);
- if (!*ok) {
+ scope->DeclareVariable(
+ declaration, proxy, mode, variable_kind, init, was_added,
+ &sloppy_mode_block_scope_function_redefinition, &local_ok);
+ if (!local_ok) {
// If we only have the start position of a proxy, we can't highlight the
// whole variable name. Pretend its length is 1 so that we highlight at
// least the first character.
- Scanner::Location loc(declaration->proxy()->position(),
- var_end_pos != kNoSourcePosition
- ? var_end_pos
- : declaration->proxy()->position() + 1);
- if (declaration_kind == DeclarationDescriptor::PARAMETER) {
+ Scanner::Location loc(proxy->position(), var_end_pos != kNoSourcePosition
+ ? var_end_pos
+ : proxy->position() + 1);
+ if (variable_kind == PARAMETER_VARIABLE) {
ReportMessageAt(loc, MessageTemplate::kParamDupe);
} else {
ReportMessageAt(loc, MessageTemplate::kVarRedeclaration,
- declaration->proxy()->raw_name());
+ declaration->var()->raw_name());
}
- return nullptr;
- }
- if (sloppy_mode_block_scope_function_redefinition) {
+ } else if (sloppy_mode_block_scope_function_redefinition) {
++use_counts_[v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition];
}
- return variable;
}
-Block* Parser::BuildInitializationBlock(
- DeclarationParsingResult* parsing_result,
- ZonePtrList<const AstRawString>* names, bool* ok) {
- Block* result = factory()->NewBlock(1, true);
+Statement* Parser::BuildInitializationBlock(
+ DeclarationParsingResult* parsing_result) {
+ ScopedPtrList<Statement> statements(pointer_buffer());
for (const auto& declaration : parsing_result->declarations) {
- DeclareAndInitializeVariables(result, &(parsing_result->descriptor),
- &declaration, names, CHECK_OK);
+ InitializeVariables(&statements, parsing_result->descriptor.kind,
+ &declaration);
}
- return result;
+ return factory()->NewBlock(true, statements);
}
Statement* Parser::DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, VariableMode mode,
- int pos, bool is_sloppy_block_function,
- ZonePtrList<const AstRawString>* names,
- bool* ok) {
+ int beg_pos, int end_pos,
+ bool is_sloppy_block_function,
+ ZonePtrList<const AstRawString>* names) {
VariableProxy* proxy =
- factory()->NewVariableProxy(variable_name, NORMAL_VARIABLE, pos);
- Declaration* declaration =
- factory()->NewFunctionDeclaration(proxy, function, pos);
- Declare(declaration, DeclarationDescriptor::NORMAL, mode, kCreatedInitialized,
- CHECK_OK);
+ factory()->NewVariableProxy(variable_name, NORMAL_VARIABLE, beg_pos);
+ Declaration* declaration = factory()->NewFunctionDeclaration(
+ function, is_sloppy_block_function, beg_pos);
+ bool was_added;
+ Declare(declaration, proxy, NORMAL_VARIABLE, mode, kCreatedInitialized,
+ scope(), &was_added);
if (names) names->Add(variable_name, zone());
if (is_sloppy_block_function) {
SloppyBlockFunctionStatement* statement =
- factory()->NewSloppyBlockFunctionStatement();
+ factory()->NewSloppyBlockFunctionStatement(end_pos);
GetDeclarationScope()->DeclareSloppyBlockFunction(variable_name, scope(),
statement);
return statement;
}
- return factory()->NewEmptyStatement(kNoSourcePosition);
+ return factory()->EmptyStatement();
}
Statement* Parser::DeclareClass(const AstRawString* variable_name,
Expression* value,
ZonePtrList<const AstRawString>* names,
- int class_token_pos, int end_pos, bool* ok) {
- Declaration* decl = DeclareVariable(variable_name, VariableMode::kLet,
- class_token_pos, CHECK_OK);
- decl->proxy()->var()->set_initializer_position(end_pos);
+ int class_token_pos, int end_pos) {
+ VariableProxy* proxy =
+ DeclareVariable(variable_name, VariableMode::kLet, class_token_pos);
+ proxy->var()->set_initializer_position(end_pos);
if (names) names->Add(variable_name, zone());
- Assignment* assignment = factory()->NewAssignment(Token::INIT, decl->proxy(),
- value, class_token_pos);
+ Assignment* assignment =
+ factory()->NewAssignment(Token::INIT, proxy, value, class_token_pos);
return IgnoreCompletion(
factory()->NewExpressionStatement(assignment, kNoSourcePosition));
}
-Statement* Parser::DeclareNative(const AstRawString* name, int pos, bool* ok) {
+Statement* Parser::DeclareNative(const AstRawString* name, int pos) {
// 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
@@ -1422,18 +1467,17 @@ Statement* Parser::DeclareNative(const AstRawString* name, int pos, bool* ok) {
// 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.
- Declaration* decl = DeclareVariable(name, VariableMode::kVar, pos, CHECK_OK);
+ VariableProxy* proxy = DeclareVariable(name, VariableMode::kVar, pos);
NativeFunctionLiteral* lit =
factory()->NewNativeFunctionLiteral(name, extension_, kNoSourcePosition);
return factory()->NewExpressionStatement(
- factory()->NewAssignment(Token::INIT, decl->proxy(), lit,
- kNoSourcePosition),
+ factory()->NewAssignment(Token::INIT, proxy, lit, kNoSourcePosition),
pos);
}
void Parser::DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>** own_labels,
- VariableProxy* var, bool* ok) {
+ VariableProxy* var) {
DCHECK(IsIdentifier(var));
const AstRawString* label = var->raw_name();
@@ -1444,7 +1488,6 @@ void Parser::DeclareLabel(ZonePtrList<const AstRawString>** labels,
// make later anyway so we should go back and fix this then.
if (ContainsLabel(*labels, label) || TargetStackContainsLabel(label)) {
ReportMessage(MessageTemplate::kLabelRedeclaration, label);
- *ok = false;
return;
}
@@ -1464,7 +1507,7 @@ void Parser::DeclareLabel(ZonePtrList<const AstRawString>** labels,
// 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);
+ scope()->DeleteUnresolved(var);
}
bool Parser::ContainsLabel(ZonePtrList<const AstRawString>* labels,
@@ -1513,16 +1556,6 @@ Expression* Parser::RewriteReturn(Expression* return_value, int pos) {
return return_value;
}
-Expression* Parser::RewriteDoExpression(Block* body, int pos, bool* ok) {
- Variable* result = NewTemporary(ast_value_factory()->dot_result_string());
- DoExpression* expr = factory()->NewDoExpression(body, result, pos);
- if (!Rewriter::Rewrite(this, GetClosureScope(), expr, ast_value_factory())) {
- *ok = false;
- return nullptr;
- }
- return expr;
-}
-
Statement* Parser::RewriteSwitchStatement(SwitchStatement* switch_statement,
Scope* scope) {
// In order to get the CaseClauses to execute in their own lexical scope,
@@ -1561,53 +1594,34 @@ Statement* Parser::RewriteSwitchStatement(SwitchStatement* switch_statement,
return switch_block;
}
-void Parser::RewriteCatchPattern(CatchInfo* catch_info, bool* ok) {
- if (catch_info->name == nullptr) {
- DCHECK_NOT_NULL(catch_info->pattern);
- catch_info->name = ast_value_factory()->dot_catch_string();
- }
- Variable* catch_variable =
- catch_info->scope->DeclareLocal(catch_info->name, VariableMode::kVar);
- if (catch_info->pattern != nullptr) {
- DeclarationDescriptor descriptor;
- descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
- descriptor.scope = scope();
- descriptor.mode = VariableMode::kLet;
- descriptor.declaration_pos = catch_info->pattern->position();
- descriptor.initialization_pos = catch_info->pattern->position();
-
- // Initializer position for variables declared by the pattern.
- const int initializer_position = position();
+Block* Parser::RewriteCatchPattern(CatchInfo* catch_info) {
+ DCHECK_NOT_NULL(catch_info->pattern);
- DeclarationParsingResult::Declaration decl(
- catch_info->pattern, initializer_position,
- factory()->NewVariableProxy(catch_variable));
+ // Initializer position for variables declared by the pattern.
+ const int initializer_position = position();
- catch_info->init_block = factory()->NewBlock(8, true);
- DeclareAndInitializeVariables(catch_info->init_block, &descriptor, &decl,
- &catch_info->bound_names, ok);
- } else {
- catch_info->bound_names.Add(catch_info->name, zone());
- }
+ DeclarationParsingResult::Declaration decl(
+ catch_info->pattern, initializer_position,
+ factory()->NewVariableProxy(catch_info->variable));
+
+ ScopedPtrList<Statement> init_statements(pointer_buffer());
+ InitializeVariables(&init_statements, NORMAL_VARIABLE, &decl);
+ return factory()->NewBlock(true, init_statements);
}
-void Parser::ValidateCatchBlock(const CatchInfo& catch_info, bool* ok) {
- // Check for `catch(e) { let e; }` and similar errors.
- Scope* inner_block_scope = catch_info.inner_block->scope();
- if (inner_block_scope != nullptr) {
- Declaration* decl = inner_block_scope->CheckLexDeclarationsConflictingWith(
- catch_info.bound_names);
- if (decl != nullptr) {
- const AstRawString* name = decl->proxy()->raw_name();
- int position = decl->proxy()->position();
+void Parser::ReportVarRedeclarationIn(const AstRawString* name, Scope* scope) {
+ for (Declaration* decl : *scope->declarations()) {
+ if (decl->var()->raw_name() == name) {
+ int position = decl->position();
Scanner::Location location =
position == kNoSourcePosition
? Scanner::Location::invalid()
- : Scanner::Location(position, position + 1);
+ : Scanner::Location(position, position + name->length());
ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
- *ok = false;
+ return;
}
}
+ UNREACHABLE();
}
Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
@@ -1647,18 +1661,17 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
}
}
-void Parser::ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind,
- ZonePtrList<Statement>* body,
- bool* ok) {
+void Parser::ParseAndRewriteGeneratorFunctionBody(
+ int pos, FunctionKind kind, ScopedPtrList<Statement>* body) {
// For ES6 Generators, we just prepend the initial yield.
Expression* initial_yield = BuildInitialYield(pos, kind);
- body->Add(factory()->NewExpressionStatement(initial_yield, kNoSourcePosition),
- zone());
- ParseStatementList(body, Token::RBRACE, ok);
+ body->Add(
+ factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
+ ParseStatementList(body, Token::RBRACE);
}
void Parser::ParseAndRewriteAsyncGeneratorFunctionBody(
- int pos, FunctionKind kind, ZonePtrList<Statement>* body, bool* ok) {
+ int pos, FunctionKind kind, ScopedPtrList<Statement>* body) {
// For ES2017 Async Generators, we produce:
//
// try {
@@ -1681,58 +1694,69 @@ void Parser::ParseAndRewriteAsyncGeneratorFunctionBody(
// "done" iterator result object containing a Promise-unwrapped value.
DCHECK(IsAsyncGeneratorFunction(kind));
- Block* try_block = factory()->NewBlock(3, false);
- Expression* initial_yield = BuildInitialYield(pos, kind);
- try_block->statements()->Add(
- factory()->NewExpressionStatement(initial_yield, kNoSourcePosition),
- zone());
- ParseStatementList(try_block->statements(), Token::RBRACE, ok);
- if (!*ok) return;
+ Block* try_block;
+ {
+ ScopedPtrList<Statement> statements(pointer_buffer());
+ Expression* initial_yield = BuildInitialYield(pos, kind);
+ statements.Add(
+ factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
+ ParseStatementList(&statements, Token::RBRACE);
+
+ // Don't create iterator result for async generators, as the resume methods
+ // will create it.
+ // TODO(leszeks): This will create another suspend point, which is
+ // unnecessary if there is already an unconditional return in the body.
+ Statement* final_return = BuildReturnStatement(
+ factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
+ statements.Add(final_return);
- // Don't create iterator result for async generators, as the resume methods
- // will create it.
- // TODO(leszeks): This will create another suspend point, which is unnecessary
- // if there is already an unconditional return in the body.
- Statement* final_return = BuildReturnStatement(
- factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
- try_block->statements()->Add(final_return, zone());
+ try_block = factory()->NewBlock(false, statements);
+ }
// For AsyncGenerators, a top-level catch block will reject the Promise.
Scope* catch_scope = NewHiddenCatchScope();
- ZonePtrList<Expression>* reject_args =
- new (zone()) ZonePtrList<Expression>(2, zone());
- reject_args->Add(factory()->NewVariableProxy(
- function_state_->scope()->generator_object_var()),
- zone());
- reject_args->Add(factory()->NewVariableProxy(catch_scope->catch_variable()),
- zone());
+ Block* catch_block;
+ {
+ ScopedPtrList<Expression> reject_args(pointer_buffer());
+ reject_args.Add(factory()->NewVariableProxy(
+ function_state_->scope()->generator_object_var()));
+ reject_args.Add(factory()->NewVariableProxy(catch_scope->catch_variable()));
- Expression* reject_call = factory()->NewCallRuntime(
- Runtime::kInlineAsyncGeneratorReject, reject_args, kNoSourcePosition);
- Block* catch_block = IgnoreCompletion(
- factory()->NewReturnStatement(reject_call, kNoSourcePosition));
+ Expression* reject_call = factory()->NewCallRuntime(
+ Runtime::kInlineAsyncGeneratorReject, reject_args, kNoSourcePosition);
+ catch_block = IgnoreCompletion(
+ factory()->NewReturnStatement(reject_call, kNoSourcePosition));
+ }
- TryStatement* try_catch = factory()->NewTryCatchStatementForAsyncAwait(
- try_block, catch_scope, catch_block, kNoSourcePosition);
+ {
+ ScopedPtrList<Statement> statements(pointer_buffer());
+ TryStatement* try_catch = factory()->NewTryCatchStatementForAsyncAwait(
+ try_block, catch_scope, catch_block, kNoSourcePosition);
+ statements.Add(try_catch);
+ try_block = factory()->NewBlock(false, statements);
+ }
- try_block = factory()->NewBlock(1, false);
- try_block->statements()->Add(try_catch, zone());
+ Expression* close_call;
+ {
+ ScopedPtrList<Expression> close_args(pointer_buffer());
+ VariableProxy* call_proxy = factory()->NewVariableProxy(
+ function_state_->scope()->generator_object_var());
+ close_args.Add(call_proxy);
+ close_call = factory()->NewCallRuntime(Runtime::kInlineGeneratorClose,
+ close_args, kNoSourcePosition);
+ }
- Block* finally_block = factory()->NewBlock(1, false);
- ZonePtrList<Expression>* close_args =
- new (zone()) ZonePtrList<Expression>(1, zone());
- VariableProxy* call_proxy = factory()->NewVariableProxy(
- function_state_->scope()->generator_object_var());
- close_args->Add(call_proxy, zone());
- Expression* close_call = factory()->NewCallRuntime(
- Runtime::kInlineGeneratorClose, close_args, kNoSourcePosition);
- finally_block->statements()->Add(
- factory()->NewExpressionStatement(close_call, kNoSourcePosition), zone());
+ Block* finally_block;
+ {
+ ScopedPtrList<Statement> statements(pointer_buffer());
+ statements.Add(
+ factory()->NewExpressionStatement(close_call, kNoSourcePosition));
+ finally_block = factory()->NewBlock(false, statements);
+ }
body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
- kNoSourcePosition),
- zone());
+ kNoSourcePosition));
}
void Parser::DeclareFunctionNameVar(const AstRawString* function_name,
@@ -1745,81 +1769,6 @@ void Parser::DeclareFunctionNameVar(const AstRawString* function_name,
}
}
-// [if (IteratorType == kNormal)]
-// !%_IsJSReceiver(result = iterator.next()) &&
-// %ThrowIteratorResultNotAnObject(result)
-// [else if (IteratorType == kAsync)]
-// !%_IsJSReceiver(result = Await(iterator.next())) &&
-// %ThrowIteratorResultNotAnObject(result)
-// [endif]
-Expression* Parser::BuildIteratorNextResult(VariableProxy* iterator,
- VariableProxy* next,
- Variable* result, IteratorType type,
- int pos) {
- Expression* next_property = factory()->NewResolvedProperty(iterator, next);
- ZonePtrList<Expression>* next_arguments =
- new (zone()) ZonePtrList<Expression>(0, zone());
- Expression* next_call =
- factory()->NewCall(next_property, next_arguments, kNoSourcePosition);
- if (type == IteratorType::kAsync) {
- function_state_->AddSuspend();
- next_call = factory()->NewAwait(next_call, pos);
- }
- Expression* result_proxy = factory()->NewVariableProxy(result);
- Expression* left =
- factory()->NewAssignment(Token::ASSIGN, result_proxy, next_call, pos);
-
- // %_IsJSReceiver(...)
- ZonePtrList<Expression>* is_spec_object_args =
- new (zone()) ZonePtrList<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);
- ZonePtrList<Expression>* throw_arguments =
- new (zone()) ZonePtrList<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);
-}
-
-Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt,
- Expression* each,
- Expression* subject,
- Statement* body) {
- ForOfStatement* for_of = stmt->AsForOfStatement();
- if (for_of != nullptr) {
- const bool finalize = true;
- return InitializeForOfStatement(for_of, each, subject, body, finalize,
- IteratorType::kNormal, each->position());
- } else {
- if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
- Variable* temp = NewTemporary(ast_value_factory()->empty_string());
- VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
- Expression* assign_each =
- RewriteDestructuringAssignment(factory()->NewAssignment(
- Token::ASSIGN, each, temp_proxy, kNoSourcePosition));
- auto block = factory()->NewBlock(2, false);
- block->statements()->Add(
- factory()->NewExpressionStatement(assign_each, kNoSourcePosition),
- zone());
- block->statements()->Add(body, zone());
- body = block;
- each = factory()->NewVariableProxy(temp);
- }
- MarkExpressionAsAssigned(each);
- stmt->AsForInStatement()->Initialize(each, subject, body);
- }
- return stmt;
-}
-
// Special case for legacy for
//
// for (var x = initializer in enumerable) body
@@ -1872,65 +1821,25 @@ Block* Parser::RewriteForVarInLegacy(const ForInfo& for_info) {
// }
void Parser::DesugarBindingInForEachStatement(ForInfo* for_info,
Block** body_block,
- Expression** each_variable,
- bool* ok) {
+ Expression** each_variable) {
DCHECK_EQ(1, for_info->parsing_result.declarations.size());
DeclarationParsingResult::Declaration& decl =
for_info->parsing_result.declarations[0];
Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());
- auto each_initialization_block = factory()->NewBlock(1, true);
- {
- auto descriptor = for_info->parsing_result.descriptor;
- descriptor.declaration_pos = kNoSourcePosition;
- descriptor.initialization_pos = kNoSourcePosition;
- descriptor.scope = scope();
- decl.initializer = factory()->NewVariableProxy(temp);
-
- bool is_for_var_of =
- for_info->mode == ForEachStatement::ITERATE &&
- for_info->parsing_result.descriptor.mode == VariableMode::kVar;
- bool collect_names =
- IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) ||
- is_for_var_of;
-
- DeclareAndInitializeVariables(
- each_initialization_block, &descriptor, &decl,
- collect_names ? &for_info->bound_names : nullptr, CHECK_OK_VOID);
-
- // Annex B.3.5 prohibits the form
- // `try {} catch(e) { for (var e of {}); }`
- // So if we are parsing a statement like `for (var ... of ...)`
- // we need to walk up the scope chain and look for catch scopes
- // which have a simple binding, then compare their binding against
- // all of the names declared in the init of the for-of we're
- // parsing.
- if (is_for_var_of) {
- Scope* catch_scope = scope();
- while (catch_scope != nullptr && !catch_scope->is_declaration_scope()) {
- if (catch_scope->is_catch_scope()) {
- auto name = catch_scope->catch_variable()->raw_name();
- // If it's a simple binding and the name is declared in the for loop.
- if (name != ast_value_factory()->dot_catch_string() &&
- for_info->bound_names.Contains(name)) {
- ReportMessageAt(for_info->parsing_result.bindings_loc,
- MessageTemplate::kVarRedeclaration, name);
- *ok = false;
- return;
- }
- }
- catch_scope = catch_scope->outer_scope();
- }
- }
- }
+ ScopedPtrList<Statement> each_initialization_statements(pointer_buffer());
+ decl.initializer = factory()->NewVariableProxy(temp);
+ InitializeVariables(&each_initialization_statements, NORMAL_VARIABLE, &decl);
*body_block = factory()->NewBlock(3, false);
- (*body_block)->statements()->Add(each_initialization_block, zone());
+ (*body_block)
+ ->statements()
+ ->Add(factory()->NewBlock(true, each_initialization_statements), zone());
*each_variable = factory()->NewVariableProxy(temp, for_info->position);
}
// Create a TDZ for any lexically-bound names in for in/of statements.
Block* Parser::CreateForEachStatementTDZ(Block* init_block,
- const ForInfo& for_info, bool* ok) {
+ const ForInfo& for_info) {
if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) {
DCHECK_NULL(init_block);
@@ -1940,142 +1849,17 @@ Block* Parser::CreateForEachStatementTDZ(Block* init_block,
// TODO(adamk): This needs to be some sort of special
// INTERNAL variable that's invisible to the debugger
// but visible to everything else.
- Declaration* tdz_decl =
- DeclareVariable(for_info.bound_names[i], VariableMode::kLet,
- kNoSourcePosition, CHECK_OK);
- tdz_decl->proxy()->var()->set_initializer_position(position());
+ VariableProxy* tdz_proxy = DeclareVariable(
+ for_info.bound_names[i], VariableMode::kLet, kNoSourcePosition);
+ tdz_proxy->var()->set_initializer_position(position());
}
}
return init_block;
}
-Statement* Parser::InitializeForOfStatement(
- ForOfStatement* for_of, Expression* each, Expression* iterable,
- Statement* body, bool finalize, IteratorType type, int next_result_pos) {
- // Create the auxiliary expressions needed for iterating over the iterable,
- // and initialize the given ForOfStatement with them.
- // If finalize is true, also instrument the loop with code that performs the
- // proper ES6 iterator finalization. In that case, the result is not
- // immediately a ForOfStatement.
- const int nopos = kNoSourcePosition;
- auto avfactory = ast_value_factory();
-
- Variable* iterator = NewTemporary(avfactory->dot_iterator_string());
- Variable* next = NewTemporary(avfactory->empty_string());
- Variable* result = NewTemporary(avfactory->dot_result_string());
- Variable* completion = NewTemporary(avfactory->empty_string());
-
- // iterator = GetIterator(iterable, type)
- Expression* assign_iterator;
- {
- assign_iterator = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(iterator),
- factory()->NewGetIterator(iterable, type, iterable->position()),
- iterable->position());
- }
-
- Expression* assign_next;
- {
- assign_next = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(next),
- factory()->NewProperty(factory()->NewVariableProxy(iterator),
- factory()->NewStringLiteral(
- avfactory->next_string(), kNoSourcePosition),
- kNoSourcePosition),
- kNoSourcePosition);
- }
-
- // [if (IteratorType == kNormal)]
- // !%_IsJSReceiver(result = iterator.next()) &&
- // %ThrowIteratorResultNotAnObject(result)
- // [else if (IteratorType == kAsync)]
- // !%_IsJSReceiver(result = Await(iterator.next())) &&
- // %ThrowIteratorResultNotAnObject(result)
- // [endif]
- Expression* next_result;
- {
- VariableProxy* iterator_proxy = factory()->NewVariableProxy(iterator);
- VariableProxy* next_proxy = factory()->NewVariableProxy(next);
- next_result = BuildIteratorNextResult(iterator_proxy, next_proxy, result,
- type, next_result_pos);
- }
-
- // result.done
- Expression* result_done;
- {
- Expression* done_literal = factory()->NewStringLiteral(
- ast_value_factory()->done_string(), kNoSourcePosition);
- Expression* result_proxy = factory()->NewVariableProxy(result);
- result_done =
- factory()->NewProperty(result_proxy, done_literal, kNoSourcePosition);
- }
-
- // result.value
- Expression* result_value;
- {
- Expression* value_literal =
- factory()->NewStringLiteral(avfactory->value_string(), nopos);
- Expression* result_proxy = factory()->NewVariableProxy(result);
- result_value = factory()->NewProperty(result_proxy, value_literal, nopos);
- }
-
- // {{tmp = #result_value, completion = kAbruptCompletion, tmp}}
- // Expression* result_value (gets overwritten)
- if (finalize) {
- Variable* tmp = NewTemporary(avfactory->empty_string());
- Expression* save_result = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(tmp), result_value, nopos);
-
- Expression* set_completion_abrupt = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(completion),
- factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
-
- result_value = factory()->NewBinaryOperation(Token::COMMA, save_result,
- set_completion_abrupt, nopos);
- result_value = factory()->NewBinaryOperation(
- Token::COMMA, result_value, factory()->NewVariableProxy(tmp), nopos);
- }
-
- // each = #result_value;
- Expression* assign_each;
- {
- assign_each =
- factory()->NewAssignment(Token::ASSIGN, each, result_value, nopos);
- if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
- assign_each = RewriteDestructuringAssignment(assign_each->AsAssignment());
- }
- }
-
- // {{completion = kNormalCompletion;}}
- Statement* set_completion_normal;
- if (finalize) {
- Expression* proxy = factory()->NewVariableProxy(completion);
- Expression* assignment = factory()->NewAssignment(
- Token::ASSIGN, proxy,
- factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
-
- set_completion_normal =
- IgnoreCompletion(factory()->NewExpressionStatement(assignment, nopos));
- }
-
- // { #loop-body; #set_completion_normal }
- // Statement* body (gets overwritten)
- if (finalize) {
- Block* block = factory()->NewBlock(2, false);
- block->statements()->Add(body, zone());
- block->statements()->Add(set_completion_normal, zone());
- body = block;
- }
-
- for_of->Initialize(body, iterator, assign_iterator, assign_next, next_result,
- result_done, assign_each);
- return finalize ? FinalizeForOfStatement(for_of, completion, type, nopos)
- : for_of;
-}
-
Statement* Parser::DesugarLexicalBindingsInForStatement(
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
- Statement* body, Scope* inner_scope, const ForInfo& for_info, bool* ok) {
+ Statement* body, Scope* inner_scope, const ForInfo& for_info) {
// 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
@@ -2177,18 +1961,18 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// For each let variable x:
// make statement: let/const x = temp_x.
for (int i = 0; i < for_info.bound_names.length(); i++) {
- Declaration* decl = DeclareVariable(
+ VariableProxy* proxy = DeclareVariable(
for_info.bound_names[i], for_info.parsing_result.descriptor.mode,
- kNoSourcePosition, CHECK_OK);
- inner_vars.Add(decl->proxy()->var(), zone());
+ kNoSourcePosition);
+ inner_vars.Add(proxy->var(), zone());
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
Assignment* assignment = factory()->NewAssignment(
- Token::INIT, decl->proxy(), temp_proxy, kNoSourcePosition);
+ Token::INIT, proxy, temp_proxy, kNoSourcePosition);
Statement* assignment_statement =
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
int declaration_pos = for_info.parsing_result.descriptor.declaration_pos;
DCHECK_NE(declaration_pos, kNoSourcePosition);
- decl->proxy()->var()->set_initializer_position(declaration_pos);
+ proxy->var()->set_initializer_position(declaration_pos);
ignore_completion_block->statements()->Add(assignment_statement, zone());
}
@@ -2234,7 +2018,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
if (cond) {
Statement* stop =
factory()->NewBreakStatement(outer_loop, kNoSourcePosition);
- Statement* noop = factory()->NewEmptyStatement(kNoSourcePosition);
+ Statement* noop = factory()->EmptyStatement();
ignore_completion_block->statements()->Add(
factory()->NewIfStatement(cond, noop, stop, cond->position()),
zone());
@@ -2297,7 +2081,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
}
Statement* stop =
factory()->NewBreakStatement(outer_loop, kNoSourcePosition);
- Statement* empty = factory()->NewEmptyStatement(kNoSourcePosition);
+ Statement* empty = factory()->EmptyStatement();
Statement* if_flag_break =
factory()->NewIfStatement(compare, stop, empty, kNoSourcePosition);
inner_block->statements()->Add(IgnoreCompletion(if_flag_break), zone());
@@ -2311,9 +2095,19 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
return outer_block;
}
+void ParserFormalParameters::ValidateDuplicate(Parser* parser) const {
+ if (has_duplicate()) {
+ parser->ReportMessageAt(duplicate_loc, MessageTemplate::kParamDupe);
+ }
+}
+void ParserFormalParameters::ValidateStrictMode(Parser* parser) const {
+ if (strict_error_loc.IsValid()) {
+ parser->ReportMessageAt(strict_error_loc, strict_error_message);
+ }
+}
+
void Parser::AddArrowFunctionFormalParameters(
- ParserFormalParameters* parameters, Expression* expr, int end_pos,
- bool* ok) {
+ ParserFormalParameters* parameters, Expression* expr, int end_pos) {
// ArrowFunctionFormals ::
// Nary(Token::COMMA, VariableProxy*, Tail)
// Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail)
@@ -2339,11 +2133,11 @@ void Parser::AddArrowFunctionFormalParameters(
// the first child expression.
Expression* next = nary->first();
for (size_t i = 0; i < nary->subsequent_length(); ++i) {
- AddArrowFunctionFormalParameters(
- parameters, next, nary->subsequent_op_position(i), CHECK_OK_VOID);
+ AddArrowFunctionFormalParameters(parameters, next,
+ nary->subsequent_op_position(i));
next = nary->subsequent(i);
}
- AddArrowFunctionFormalParameters(parameters, next, end_pos, CHECK_OK_VOID);
+ AddArrowFunctionFormalParameters(parameters, next, end_pos);
return;
}
@@ -2357,8 +2151,7 @@ void Parser::AddArrowFunctionFormalParameters(
Expression* left = binop->left();
Expression* right = binop->right();
int comma_pos = binop->position();
- AddArrowFunctionFormalParameters(parameters, left, comma_pos,
- CHECK_OK_VOID);
+ AddArrowFunctionFormalParameters(parameters, left, comma_pos);
// LHS of comma expression should be unparenthesized.
expr = right;
}
@@ -2376,11 +2169,6 @@ void Parser::AddArrowFunctionFormalParameters(
Expression* initializer = nullptr;
if (expr->IsAssignment()) {
- if (expr->IsRewritableExpression()) {
- // This expression was parsed as a possible destructuring assignment.
- // Mark it as already-rewritten to avoid an unnecessary visit later.
- expr->AsRewritableExpression()->set_rewritten();
- }
Assignment* assignment = expr->AsAssignment();
DCHECK(!assignment->IsCompoundAssignment());
initializer = assignment->value();
@@ -2393,26 +2181,19 @@ void Parser::AddArrowFunctionFormalParameters(
void Parser::DeclareArrowFunctionFormalParameters(
ParserFormalParameters* parameters, Expression* expr,
- const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
- bool* ok) {
- if (expr->IsEmptyParentheses()) return;
+ const Scanner::Location& params_loc) {
+ if (expr->IsEmptyParentheses() || has_error()) return;
- AddArrowFunctionFormalParameters(parameters, expr, params_loc.end_pos,
- CHECK_OK_VOID);
+ AddArrowFunctionFormalParameters(parameters, expr, params_loc.end_pos);
if (parameters->arity > Code::kMaxArguments) {
ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
- *ok = false;
return;
}
- bool has_duplicate = false;
- DeclareFormalParameters(parameters->scope, parameters->params,
- parameters->is_simple, &has_duplicate);
- if (has_duplicate) {
- *duplicate_loc = scanner()->location();
- }
- DCHECK_EQ(parameters->is_simple, parameters->scope->has_simple_parameters());
+ DeclareFormalParameters(parameters);
+ DCHECK_IMPLIES(parameters->is_simple,
+ parameters->scope->has_simple_parameters());
}
void Parser::PrepareGeneratorVariables() {
@@ -2428,7 +2209,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode,
- ZonePtrList<const AstRawString>* arguments_for_wrapped_function, bool* ok) {
+ ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
//
@@ -2493,18 +2274,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// parenthesis before the function means that it will be called
// immediately). bar can be parsed lazily, but we need to parse it in a mode
// that tracks unresolved variables.
- DCHECK_IMPLIES(parse_lazily(), FLAG_lazy);
- DCHECK_IMPLIES(parse_lazily(), allow_lazy_);
+ DCHECK_IMPLIES(parse_lazily(), info()->allow_lazy_compile());
+ DCHECK_IMPLIES(parse_lazily(), has_error() || allow_lazy_);
DCHECK_IMPLIES(parse_lazily(), extension_ == nullptr);
const bool is_lazy =
eager_compile_hint == FunctionLiteral::kShouldLazyCompile;
const bool is_top_level = AllowsLazyParsingWithoutUnresolvedVariables();
+ const bool is_eager_top_level_function = !is_lazy && is_top_level;
const bool is_lazy_top_level_function = is_lazy && is_top_level;
const bool is_lazy_inner_function = is_lazy && !is_top_level;
- const bool is_expression =
- function_type == FunctionLiteral::kAnonymousExpression ||
- function_type == FunctionLiteral::kNamedExpression;
RuntimeCallTimerScope runtime_timer(
runtime_call_stats_,
@@ -2531,22 +2310,28 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Inner functions will be parsed using a temporary Zone. After parsing, we
// will migrate unresolved variable into a Scope in the main Zone.
- const bool should_preparse_inner =
- parse_lazily() && FLAG_lazy_inner_functions && is_lazy_inner_function &&
- (!is_expression || FLAG_aggressive_lazy_inner_functions);
+ const bool should_preparse_inner = parse_lazily() && is_lazy_inner_function;
+
+ // If parallel compile tasks are enabled, and the function is an eager
+ // top level function, then we can pre-parse the function and parse / compile
+ // in a parallel task on a worker thread.
+ bool should_post_parallel_task =
+ parse_lazily() && is_eager_top_level_function &&
+ FLAG_parallel_compile_tasks && info()->parallel_tasks() &&
+ scanner()->stream()->can_be_cloned_for_parallel_access();
// This may be modified later to reflect preparsing decision taken
- bool should_preparse =
- (parse_lazily() && is_lazy_top_level_function) || should_preparse_inner;
+ bool should_preparse = (parse_lazily() && is_lazy_top_level_function) ||
+ should_preparse_inner || should_post_parallel_task;
- ZonePtrList<Statement>* body = nullptr;
+ ScopedPtrList<Statement> body(pointer_buffer());
int expected_property_count = -1;
int suspend_count = -1;
int num_parameters = -1;
int function_length = -1;
bool has_duplicate_parameters = false;
int function_literal_id = GetNextFunctionLiteralId();
- ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr;
+ ProducedPreparseData* produced_preparse_data = nullptr;
// This Scope lives in the main zone. We'll migrate data into that zone later.
Zone* parse_zone = should_preparse ? &preparser_zone_ : zone();
@@ -2556,7 +2341,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
scope->SetScopeName(function_name);
#endif
- if (!is_wrapped) Expect(Token::LPAREN, CHECK_OK);
+ if (!is_wrapped && V8_UNLIKELY(!Check(Token::LPAREN))) {
+ ReportUnexpectedToken(Next());
+ return nullptr;
+ }
scope->set_start_position(position());
// Eager or lazy parse? If is_lazy_top_level_function, we'll parse
@@ -2565,15 +2353,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// which case the parser is expected to have backtracked), or if we didn't
// try to lazy parse in the first place, we'll have to parse eagerly.
bool did_preparse_successfully =
- should_preparse &&
- SkipFunction(function_name, kind, function_type, scope, &num_parameters,
- &produced_preparsed_scope_data, is_lazy_inner_function,
- is_lazy_top_level_function, &eager_compile_hint, CHECK_OK);
+ should_preparse && SkipFunction(function_name, kind, function_type, scope,
+ &num_parameters, &produced_preparse_data);
+
if (!did_preparse_successfully) {
- body = ParseFunction(
- function_name, pos, kind, function_type, scope, &num_parameters,
- &function_length, &has_duplicate_parameters, &expected_property_count,
- &suspend_count, arguments_for_wrapped_function, CHECK_OK);
+ // If skipping aborted, it rewound the scanner until before the LPAREN.
+ // Consume it in that case.
+ if (should_preparse) Consume(Token::LPAREN);
+ should_post_parallel_task = false;
+ ParseFunction(&body, function_name, pos, kind, function_type, scope,
+ &num_parameters, &function_length, &has_duplicate_parameters,
+ &expected_property_count, &suspend_count,
+ arguments_for_wrapped_function);
}
if (V8_UNLIKELY(FLAG_log_function_events)) {
@@ -2589,16 +2380,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
function_name->byte_length());
}
if (V8_UNLIKELY(FLAG_runtime_stats) && did_preparse_successfully) {
- const RuntimeCallCounterId counters[2][2] = {
- {RuntimeCallCounterId::kPreParseBackgroundNoVariableResolution,
- RuntimeCallCounterId::kPreParseNoVariableResolution},
- {RuntimeCallCounterId::kPreParseBackgroundWithVariableResolution,
- RuntimeCallCounterId::kPreParseWithVariableResolution}};
+ const RuntimeCallCounterId counters[2] = {
+ RuntimeCallCounterId::kPreParseBackgroundWithVariableResolution,
+ RuntimeCallCounterId::kPreParseWithVariableResolution};
if (runtime_call_stats_) {
- bool tracked_variables =
- PreParser::ShouldTrackUnresolvedVariables(is_lazy_top_level_function);
runtime_call_stats_->CorrectCurrentCounterId(
- counters[tracked_variables][parsing_on_main_thread_]);
+ counters[parsing_on_main_thread_]);
}
}
@@ -2606,13 +2393,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// since the function can declare itself strict.
language_mode = scope->language_mode();
CheckFunctionName(language_mode, function_name, function_name_validity,
- function_name_location, CHECK_OK);
+ function_name_location);
if (is_strict(language_mode)) {
- CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
- CHECK_OK);
+ CheckStrictOctalLiteral(scope->start_position(), scope->end_position());
}
- CheckConflictingVarDeclarations(scope, CHECK_OK);
+ CheckConflictingVarDeclarations(scope);
FunctionLiteral::ParameterFlag duplicate_parameters =
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
@@ -2622,23 +2408,25 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
function_name, scope, body, expected_property_count, num_parameters,
function_length, duplicate_parameters, function_type, eager_compile_hint,
- pos, true, function_literal_id, produced_preparsed_scope_data);
+ pos, true, function_literal_id, produced_preparse_data);
function_literal->set_function_token_position(function_token_pos);
function_literal->set_suspend_count(suspend_count);
+ if (should_post_parallel_task) {
+ // Start a parallel parse / compile task on the compiler dispatcher.
+ info()->parallel_tasks()->Enqueue(info(), function_name, function_literal);
+ }
+
if (should_infer_name) {
fni_.AddFunction(function_literal);
}
return function_literal;
}
-bool Parser::SkipFunction(
- const AstRawString* function_name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, int* num_parameters,
- ProducedPreParsedScopeData** produced_preparsed_scope_data,
- bool is_inner_function, bool may_abort,
- FunctionLiteral::EagerCompileHint* hint, bool* ok) {
+bool Parser::SkipFunction(const AstRawString* function_name, FunctionKind kind,
+ FunctionLiteral::FunctionType function_type,
+ DeclarationScope* function_scope, int* num_parameters,
+ ProducedPreparseData** produced_preparse_data) {
FunctionState function_state(&function_state_, &scope_, function_scope);
function_scope->set_zone(&preparser_zone_);
@@ -2649,23 +2437,23 @@ bool Parser::SkipFunction(
scanner()->current_token() == Token::ARROW);
// FIXME(marja): There are 2 ways to skip functions now. Unify them.
- if (consumed_preparsed_scope_data_) {
- DCHECK(FLAG_preparser_scope_analysis);
+ if (consumed_preparse_data_) {
int end_position;
LanguageMode language_mode;
int num_inner_functions;
bool uses_super_property;
- *produced_preparsed_scope_data =
- consumed_preparsed_scope_data_->GetDataForSkippableFunction(
+ if (stack_overflow()) return true;
+ *produced_preparse_data =
+ consumed_preparse_data_->GetDataForSkippableFunction(
main_zone(), function_scope->start_position(), &end_position,
num_parameters, &num_inner_functions, &uses_super_property,
&language_mode);
- function_scope->outer_scope()->SetMustUsePreParsedScopeData();
+ function_scope->outer_scope()->SetMustUsePreparseData();
function_scope->set_is_skipped_function(true);
function_scope->set_end_position(end_position);
scanner()->SeekForward(end_position - 1);
- Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
+ Expect(Token::RBRACE);
SetLanguageMode(function_scope, language_mode);
if (uses_super_property) {
function_scope->RecordSuperPropertyUsage();
@@ -2676,53 +2464,47 @@ bool Parser::SkipFunction(
}
Scanner::BookmarkScope bookmark(scanner());
- bookmark.Set();
+ bookmark.Set(function_scope->start_position());
// With no cached data, we partially parse the function, without building an
// AST. This gathers the data needed to build a lazy function.
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse");
- // Aborting inner function preparsing would leave scopes in an inconsistent
- // state; we don't parse inner functions in the abortable mode anyway.
- DCHECK(!is_inner_function || !may_abort);
-
PreParser::PreParseResult result = reusable_preparser()->PreParseFunction(
- function_name, kind, function_type, function_scope, is_inner_function,
- may_abort, use_counts_, produced_preparsed_scope_data, this->script_id());
-
- // Return immediately if pre-parser decided to abort parsing.
- if (result == PreParser::kPreParseAbort) {
- bookmark.Apply();
- function_scope->ResetAfterPreparsing(ast_value_factory(), true);
- *hint = FunctionLiteral::kShouldEagerCompile;
- return false;
- }
+ function_name, kind, function_type, function_scope, use_counts_,
+ produced_preparse_data, this->script_id());
if (result == PreParser::kPreParseStackOverflow) {
// Propagate stack overflow.
set_stack_overflow();
- *ok = false;
- } else if (pending_error_handler()->ErrorUnidentifiableByPreParser()) {
+ } else if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
+ // Make sure we don't re-preparse inner functions of the aborted function.
+ // The error might be in an inner function.
+ allow_lazy_ = false;
+ mode_ = PARSE_EAGERLY;
+ DCHECK(!pending_error_handler()->stack_overflow());
// If we encounter an error that the preparser can not identify we reset to
// the state before preparsing. The caller may then fully parse the function
// to identify the actual error.
bookmark.Apply();
function_scope->ResetAfterPreparsing(ast_value_factory(), true);
- pending_error_handler()->ResetUnidentifiableError();
+ pending_error_handler()->clear_unidentifiable_error();
return false;
} else if (pending_error_handler()->has_pending_error()) {
- *ok = false;
+ DCHECK(!pending_error_handler()->stack_overflow());
+ DCHECK(has_error());
} else {
+ DCHECK(!pending_error_handler()->stack_overflow());
set_allow_eval_cache(reusable_preparser()->allow_eval_cache());
PreParserLogger* logger = reusable_preparser()->logger();
function_scope->set_end_position(logger->end());
- Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
+ Expect(Token::RBRACE);
total_preparse_skipped_ +=
function_scope->end_position() - function_scope->start_position();
*num_parameters = logger->num_parameters();
SkipFunctionLiterals(logger->num_inner_functions());
- function_scope->AnalyzePartially(factory());
+ function_scope->AnalyzePartially(this, factory());
}
return true;
@@ -2734,7 +2516,7 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var,
// throw /* type error kNonCoercible) */;
auto source_position = pattern->position();
const AstRawString* property = ast_value_factory()->empty_string();
- MessageTemplate::Template msg = MessageTemplate::kNonCoercible;
+ MessageTemplate msg = MessageTemplate::kNonCoercible;
for (ObjectLiteralProperty* literal_property : *pattern->properties()) {
Expression* key = literal_property->key();
if (key->IsPropertyName()) {
@@ -2759,7 +2541,7 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var,
IfStatement* if_statement = factory()->NewIfStatement(
condition,
factory()->NewExpressionStatement(throw_type_error, kNoSourcePosition),
- factory()->NewEmptyStatement(kNoSourcePosition), kNoSourcePosition);
+ factory()->EmptyStatement(), kNoSourcePosition);
return if_statement;
}
@@ -2774,13 +2556,6 @@ class InitializerRewriter final
// called by the base class (template).
friend class AstTraversalVisitor<InitializerRewriter>;
- // Just rewrite destructuring assignments wrapped in RewritableExpressions.
- void VisitRewritableExpression(RewritableExpression* to_rewrite) {
- if (to_rewrite->is_rewritten()) return;
- parser_->RewriteDestructuringAssignment(to_rewrite);
- AstTraversalVisitor::VisitRewritableExpression(to_rewrite);
- }
-
// Code in function literals does not need to be eagerly rewritten, it will be
// rewritten when scheduled.
void VisitFunctionLiteral(FunctionLiteral* expr) {}
@@ -2789,60 +2564,58 @@ class InitializerRewriter final
};
void Parser::RewriteParameterInitializer(Expression* expr) {
+ if (has_error()) return;
InitializerRewriter rewriter(stack_limit_, expr, this);
rewriter.Run();
}
-
Block* Parser::BuildParameterInitializationBlock(
- const ParserFormalParameters& parameters, bool* ok) {
+ const ParserFormalParameters& parameters) {
DCHECK(!parameters.is_simple);
DCHECK(scope()->is_function_scope());
DCHECK_EQ(scope(), parameters.scope);
- Block* init_block = factory()->NewBlock(parameters.num_parameters(), true);
+ ScopedPtrList<Statement> init_statements(pointer_buffer());
int index = 0;
for (auto parameter : parameters.params) {
- DeclarationDescriptor descriptor;
- descriptor.declaration_kind = DeclarationDescriptor::PARAMETER;
- descriptor.scope = scope();
- descriptor.mode = VariableMode::kLet;
- 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 kNoSourcePosition, since
- // it's just copying from a temp var to the real param var?
- descriptor.initialization_pos = parameter->pattern->position();
Expression* initial_value =
factory()->NewVariableProxy(parameters.scope->parameter(index));
- if (parameter->initializer != nullptr) {
+ if (parameter->initializer() != nullptr) {
// IS_UNDEFINED($param) ? initializer : $param
- // Ensure initializer is rewritten
- RewriteParameterInitializer(parameter->initializer);
+ if (parameter->initializer()->IsClassLiteral()) {
+ // Initializers could have their own scopes. So set the scope
+ // here if necessary.
+ BlockState block_state(
+ &scope_, parameter->initializer()->AsClassLiteral()->scope());
+
+ // Ensure initializer is rewritten
+ RewriteParameterInitializer(parameter->initializer());
+ } else {
+ // Ensure initializer is rewritten
+ RewriteParameterInitializer(parameter->initializer());
+ }
auto condition = factory()->NewCompareOperation(
Token::EQ_STRICT,
factory()->NewVariableProxy(parameters.scope->parameter(index)),
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
- initial_value = factory()->NewConditional(
- condition, parameter->initializer, initial_value, kNoSourcePosition);
- descriptor.initialization_pos = parameter->initializer->position();
+ initial_value =
+ factory()->NewConditional(condition, parameter->initializer(),
+ initial_value, kNoSourcePosition);
}
Scope* param_scope = scope();
- Block* param_block = init_block;
+ ScopedPtrList<Statement>* param_init_statements = &init_statements;
+
+ base::Optional<ScopedPtrList<Statement>> non_simple_param_init_statements;
if (!parameter->is_simple() &&
scope()->AsDeclarationScope()->calls_sloppy_eval()) {
param_scope = NewVarblockScope();
- param_scope->set_start_position(descriptor.initialization_pos);
+ param_scope->set_start_position(parameter->pattern->position());
param_scope->set_end_position(parameter->initializer_end_position);
param_scope->RecordEvalCall();
- param_block = factory()->NewBlock(8, true);
- param_block->set_scope(param_scope);
- // Pass the appropriate scope in so that PatternRewriter can appropriately
- // rewrite inner initializers of the pattern to param_scope
- descriptor.scope = param_scope;
+ non_simple_param_init_statements.emplace(pointer_buffer());
+ param_init_statements = &non_simple_param_init_statements.value();
// Rewrite the outer initializer to point to param_scope
ReparentExpressionScope(stack_limit(), initial_value, param_scope);
}
@@ -2850,122 +2623,68 @@ Block* Parser::BuildParameterInitializationBlock(
BlockState block_state(&scope_, param_scope);
DeclarationParsingResult::Declaration decl(
parameter->pattern, parameter->initializer_end_position, initial_value);
- DeclareAndInitializeVariables(param_block, &descriptor, &decl, nullptr,
- CHECK_OK);
- if (param_block != init_block) {
+ InitializeVariables(param_init_statements, PARAMETER_VARIABLE, &decl);
+
+ if (param_init_statements != &init_statements) {
+ DCHECK_EQ(param_init_statements,
+ &non_simple_param_init_statements.value());
+ Block* param_block =
+ factory()->NewBlock(true, *non_simple_param_init_statements);
+ non_simple_param_init_statements.reset();
+ param_block->set_scope(param_scope);
param_scope = param_scope->FinalizeBlockScope();
- if (param_scope != nullptr) {
- CheckConflictingVarDeclarations(param_scope, CHECK_OK);
- }
- init_block->statements()->Add(param_block, zone());
+ init_statements.Add(param_block);
}
++index;
}
- return init_block;
+ return factory()->NewBlock(true, init_statements);
}
Scope* Parser::NewHiddenCatchScope() {
Scope* catch_scope = NewScopeWithParent(scope(), CATCH_SCOPE);
+ bool was_added;
catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(),
- VariableMode::kVar);
+ VariableMode::kVar, NORMAL_VARIABLE, &was_added);
+ DCHECK(was_added);
catch_scope->set_is_hidden();
return catch_scope;
}
Block* Parser::BuildRejectPromiseOnException(Block* inner_block) {
- // .promise = %AsyncFunctionPromiseCreate();
// try {
// <inner_block>
// } catch (.catch) {
- // %RejectPromise(.promise, .catch);
- // return .promise;
- // } finally {
- // %AsyncFunctionPromiseRelease(.promise);
+ // return %_AsyncFunctionReject(.generator_object, .catch, can_suspend);
// }
- Block* result = factory()->NewBlock(2, true);
-
- // .promise = %AsyncFunctionPromiseCreate();
- Statement* set_promise;
- {
- Expression* create_promise = factory()->NewCallRuntime(
- Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX,
- new (zone()) ZonePtrList<Expression>(0, zone()), kNoSourcePosition);
- Assignment* assign_promise = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(PromiseVariable()),
- create_promise, kNoSourcePosition);
- set_promise =
- factory()->NewExpressionStatement(assign_promise, kNoSourcePosition);
- }
- result->statements()->Add(set_promise, zone());
+ Block* result = factory()->NewBlock(1, true);
- // catch (.catch) { return %RejectPromise(.promise, .catch), .promise }
+ // catch (.catch) {
+ // return %_AsyncFunctionReject(.generator_object, .catch, can_suspend)
+ // }
Scope* catch_scope = NewHiddenCatchScope();
- Expression* promise_reject = BuildRejectPromise(
- factory()->NewVariableProxy(catch_scope->catch_variable()),
- kNoSourcePosition);
+ Expression* reject_promise;
+ {
+ ScopedPtrList<Expression> args(pointer_buffer());
+ args.Add(factory()->NewVariableProxy(
+ function_state_->scope()->generator_object_var()));
+ args.Add(factory()->NewVariableProxy(catch_scope->catch_variable()));
+ args.Add(factory()->NewBooleanLiteral(function_state_->CanSuspend(),
+ kNoSourcePosition));
+ reject_promise = factory()->NewCallRuntime(
+ Runtime::kInlineAsyncFunctionReject, args, kNoSourcePosition);
+ }
Block* catch_block = IgnoreCompletion(
- factory()->NewReturnStatement(promise_reject, kNoSourcePosition));
+ factory()->NewReturnStatement(reject_promise, kNoSourcePosition));
TryStatement* try_catch_statement =
factory()->NewTryCatchStatementForAsyncAwait(
inner_block, catch_scope, catch_block, kNoSourcePosition);
-
- // There is no TryCatchFinally node, so wrap it in an outer try/finally
- Block* outer_try_block = IgnoreCompletion(try_catch_statement);
-
- // finally { %AsyncFunctionPromiseRelease(.promise, can_suspend) }
- Block* finally_block;
- {
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(factory()->NewVariableProxy(PromiseVariable()), zone());
- args->Add(factory()->NewBooleanLiteral(function_state_->CanSuspend(),
- kNoSourcePosition),
- zone());
- Expression* call_promise_release = factory()->NewCallRuntime(
- Context::ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, args, kNoSourcePosition);
- Statement* promise_release = factory()->NewExpressionStatement(
- call_promise_release, kNoSourcePosition);
- finally_block = IgnoreCompletion(promise_release);
- }
-
- Statement* try_finally_statement = factory()->NewTryFinallyStatement(
- outer_try_block, finally_block, kNoSourcePosition);
-
- result->statements()->Add(try_finally_statement, zone());
+ result->statements()->Add(try_catch_statement, zone());
return result;
}
-Expression* Parser::BuildRejectPromise(Expression* value, int pos) {
- // %promise_internal_reject(.promise, value, false), .promise
- // Disables the additional debug event for the rejection since a debug event
- // already happened for the exception that got us here.
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(3, zone());
- args->Add(factory()->NewVariableProxy(PromiseVariable()), zone());
- args->Add(value, zone());
- args->Add(factory()->NewBooleanLiteral(false, pos), zone());
- Expression* call_runtime =
- factory()->NewCallRuntime(Runtime::kInlineRejectPromise, args, pos);
- return factory()->NewBinaryOperation(
- Token::COMMA, call_runtime,
- factory()->NewVariableProxy(PromiseVariable()), pos);
-}
-
-Variable* Parser::PromiseVariable() {
- // Based on the various compilation paths, there are many different code
- // paths which may be the first to access the Promise temporary. Whichever
- // comes first should create it and stash it in the FunctionState.
- Variable* promise = function_state_->scope()->promise_var();
- if (promise == nullptr) {
- promise = function_state_->scope()->DeclarePromiseVar(
- ast_value_factory()->dot_promise_string());
- }
- return promise;
-}
-
Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) {
Expression* yield_result = factory()->NewVariableProxy(
function_state_->scope()->generator_object_var());
@@ -2977,22 +2696,19 @@ Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) {
Suspend::kOnExceptionThrow);
}
-ZonePtrList<Statement>* Parser::ParseFunction(
- const AstRawString* function_name, int pos, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
+void Parser::ParseFunction(
+ ScopedPtrList<Statement>* body, const AstRawString* function_name, int pos,
+ FunctionKind kind, FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters, int* function_length,
bool* has_duplicate_parameters, int* expected_property_count,
int* suspend_count,
- ZonePtrList<const AstRawString>* arguments_for_wrapped_function, bool* ok) {
+ ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
FunctionState function_state(&function_state_, &scope_, function_scope);
bool is_wrapped = function_type == FunctionLiteral::kWrapped;
- DuplicateFinder duplicate_finder;
- ExpressionClassifier formals_classifier(this, &duplicate_finder);
-
int expected_parameters_end_pos = parameters_end_pos_;
if (expected_parameters_end_pos != kNoSourcePosition) {
// This is the first function encountered in a CreateDynamicFunction eval.
@@ -3004,173 +2720,147 @@ ZonePtrList<Statement>* Parser::ParseFunction(
ParserFormalParameters formals(function_scope);
- if (is_wrapped) {
- // For a function implicitly wrapped in function header and footer, the
- // function arguments are provided separately to the source, and are
- // declared directly here.
- int arguments_length = arguments_for_wrapped_function->length();
- for (int i = 0; i < arguments_length; i++) {
- const bool is_rest = false;
- Expression* argument = ExpressionFromIdentifier(
- arguments_for_wrapped_function->at(i), kNoSourcePosition);
- AddFormalParameter(&formals, argument, NullExpression(),
- kNoSourcePosition, is_rest);
- }
- DCHECK_EQ(arguments_length, formals.num_parameters());
- DeclareFormalParameters(formals.scope, formals.params, formals.is_simple);
- } else {
- // For a regular function, the function arguments are parsed from source.
- DCHECK_NULL(arguments_for_wrapped_function);
- ParseFormalParameterList(&formals, CHECK_OK);
- if (expected_parameters_end_pos != kNoSourcePosition) {
- // Check for '(' or ')' shenanigans in the parameter string for dynamic
- // functions.
- int position = peek_position();
- if (position < expected_parameters_end_pos) {
- ReportMessageAt(Scanner::Location(position, position + 1),
- MessageTemplate::kArgStringTerminatesParametersEarly);
- *ok = false;
- return nullptr;
- } else if (position > expected_parameters_end_pos) {
- ReportMessageAt(Scanner::Location(expected_parameters_end_pos - 2,
- expected_parameters_end_pos),
- MessageTemplate::kUnexpectedEndOfArgString);
- *ok = false;
- return nullptr;
+ {
+ ParameterDeclarationParsingScope formals_scope(this);
+ if (is_wrapped) {
+ // For a function implicitly wrapped in function header and footer, the
+ // function arguments are provided separately to the source, and are
+ // declared directly here.
+ int arguments_length = arguments_for_wrapped_function->length();
+ for (int i = 0; i < arguments_length; i++) {
+ const bool is_rest = false;
+ Expression* argument = ExpressionFromIdentifier(
+ arguments_for_wrapped_function->at(i), kNoSourcePosition);
+ AddFormalParameter(&formals, argument, NullExpression(),
+ kNoSourcePosition, is_rest);
}
- }
- Expect(Token::RPAREN, CHECK_OK);
- int formals_end_position = scanner()->location().end_pos;
+ DCHECK_EQ(arguments_length, formals.num_parameters());
+ DeclareFormalParameters(&formals);
+ } else {
+ // For a regular function, the function arguments are parsed from source.
+ DCHECK_NULL(arguments_for_wrapped_function);
+ ParseFormalParameterList(&formals);
+ if (expected_parameters_end_pos != kNoSourcePosition) {
+ // Check for '(' or ')' shenanigans in the parameter string for dynamic
+ // functions.
+ int position = peek_position();
+ if (position < expected_parameters_end_pos) {
+ ReportMessageAt(Scanner::Location(position, position + 1),
+ MessageTemplate::kArgStringTerminatesParametersEarly);
+ return;
+ } else if (position > expected_parameters_end_pos) {
+ ReportMessageAt(Scanner::Location(expected_parameters_end_pos - 2,
+ expected_parameters_end_pos),
+ MessageTemplate::kUnexpectedEndOfArgString);
+ return;
+ }
+ }
+ Expect(Token::RPAREN);
+ int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(formals.arity, kind, formals.has_rest,
- function_scope->start_position(),
- formals_end_position, CHECK_OK);
- Expect(Token::LBRACE, CHECK_OK);
+ CheckArityRestrictions(formals.arity, kind, formals.has_rest,
+ function_scope->start_position(),
+ formals_end_position);
+ Expect(Token::LBRACE);
+ }
+ formals.duplicate_loc = formals_scope.duplicate_location();
}
+
*num_parameters = formals.num_parameters();
*function_length = formals.function_length;
- ZonePtrList<Statement>* body = new (zone()) ZonePtrList<Statement>(8, zone());
+ AcceptINScope scope(this, true);
ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
- FunctionBodyType::kBlock, true, ok);
+ FunctionBodyType::kBlock);
- // Validate parameter names. We can do this only after parsing the function,
- // since the function can declare itself strict.
- const bool allow_duplicate_parameters =
- is_sloppy(function_scope->language_mode()) && formals.is_simple &&
- !IsConciseMethod(kind);
- ValidateFormalParameters(function_scope->language_mode(),
- allow_duplicate_parameters, CHECK_OK);
-
- RewriteDestructuringAssignments();
-
- *has_duplicate_parameters =
- !classifier()->is_valid_formal_parameter_list_without_duplicates();
+ *has_duplicate_parameters = formals.has_duplicate();
*expected_property_count = function_state.expected_property_count();
*suspend_count = function_state.suspend_count();
- return body;
}
void Parser::DeclareClassVariable(const AstRawString* name,
- ClassInfo* class_info, int class_token_pos,
- bool* ok) {
+ ClassInfo* class_info, int class_token_pos) {
#ifdef DEBUG
scope()->SetScopeName(name);
#endif
if (name != nullptr) {
- VariableProxy* proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE);
- Declaration* declaration =
- factory()->NewVariableDeclaration(proxy, class_token_pos);
- class_info->variable = Declare(
- declaration, DeclarationDescriptor::NORMAL, VariableMode::kConst,
- Variable::DefaultInitializationFlag(VariableMode::kConst), ok);
+ VariableProxy* proxy =
+ DeclareVariable(name, VariableMode::kConst, class_token_pos);
+ class_info->variable = proxy->var();
}
}
// TODO(gsathya): Ideally, this should just bypass scope analysis and
// allocate a slot directly on the context. We should just store this
// index in the AST, instead of storing the variable.
-Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name,
- bool* ok) {
- VariableProxy* proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE);
- Declaration* declaration =
- factory()->NewVariableDeclaration(proxy, kNoSourcePosition);
- Variable* var = Declare(
- declaration, DeclarationDescriptor::NORMAL, VariableMode::kConst,
- Variable::DefaultInitializationFlag(VariableMode::kConst), CHECK_OK);
- var->ForceContextAllocation();
- return var;
+Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name) {
+ VariableProxy* proxy =
+ DeclareVariable(name, VariableMode::kConst, kNoSourcePosition);
+ proxy->var()->ForceContextAllocation();
+ return proxy->var();
}
-// This method declares a property of the given class. It updates the
-// following fields of class_info, as appropriate:
-// - constructor
-// - properties
-void Parser::DeclareClassProperty(const AstRawString* class_name,
- ClassLiteralProperty* property,
- const AstRawString* property_name,
- ClassLiteralProperty::Kind kind,
- bool is_static, bool is_constructor,
- bool is_computed_name, ClassInfo* class_info,
- bool* ok) {
- if (is_constructor) {
- DCHECK(!class_info->constructor);
- class_info->constructor = property->value()->AsFunctionLiteral();
- DCHECK_NOT_NULL(class_info->constructor);
- class_info->constructor->set_raw_name(
- class_name != nullptr ? ast_value_factory()->NewConsString(class_name)
- : nullptr);
- return;
- }
-
- if (kind != ClassLiteralProperty::PUBLIC_FIELD &&
- kind != ClassLiteralProperty::PRIVATE_FIELD) {
- class_info->properties->Add(property, zone());
- return;
- }
-
+void Parser::DeclareClassField(ClassLiteralProperty* property,
+ const AstRawString* property_name,
+ bool is_static, bool is_computed_name,
+ bool is_private, ClassInfo* class_info) {
DCHECK(allow_harmony_public_fields() || allow_harmony_private_fields());
if (is_static) {
- DCHECK(allow_harmony_static_fields());
- DCHECK_EQ(kind, ClassLiteralProperty::PUBLIC_FIELD);
class_info->static_fields->Add(property, zone());
} else {
class_info->instance_fields->Add(property, zone());
}
+ DCHECK_IMPLIES(is_computed_name, !is_private);
if (is_computed_name) {
- DCHECK_EQ(kind, ClassLiteralProperty::PUBLIC_FIELD);
// We create a synthetic variable name here so that scope
// analysis doesn't dedupe the vars.
- Variable* computed_name_var = CreateSyntheticContextVariable(
- ClassFieldVariableName(ast_value_factory(),
- class_info->computed_field_count),
- CHECK_OK_VOID);
+ Variable* computed_name_var =
+ CreateSyntheticContextVariable(ClassFieldVariableName(
+ ast_value_factory(), class_info->computed_field_count));
property->set_computed_name_var(computed_name_var);
class_info->properties->Add(property, zone());
+ } else if (is_private) {
+ Variable* private_name_var = CreateSyntheticContextVariable(property_name);
+ private_name_var->set_initializer_position(property->value()->position());
+ property->set_private_name_var(private_name_var);
+ class_info->properties->Add(property, zone());
}
+}
- if (kind == ClassLiteralProperty::PRIVATE_FIELD) {
- Variable* private_field_name_var =
- CreateSyntheticContextVariable(property_name, CHECK_OK_VOID);
- property->set_private_field_name_var(private_field_name_var);
- class_info->properties->Add(property, zone());
+// This method declares a property of the given class. It updates the
+// following fields of class_info, as appropriate:
+// - constructor
+// - properties
+void Parser::DeclareClassProperty(const AstRawString* class_name,
+ ClassLiteralProperty* property,
+ bool is_constructor, ClassInfo* class_info) {
+ if (is_constructor) {
+ DCHECK(!class_info->constructor);
+ class_info->constructor = property->value()->AsFunctionLiteral();
+ DCHECK_NOT_NULL(class_info->constructor);
+ class_info->constructor->set_raw_name(
+ class_name != nullptr ? ast_value_factory()->NewConsString(class_name)
+ : nullptr);
+ return;
}
+
+ class_info->properties->Add(property, zone());
}
FunctionLiteral* Parser::CreateInitializerFunction(
const char* name, DeclarationScope* scope,
ZonePtrList<ClassLiteral::Property>* fields) {
DCHECK_EQ(scope->function_kind(),
- FunctionKind::kClassFieldsInitializerFunction);
+ FunctionKind::kClassMembersInitializerFunction);
// function() { .. class fields initializer .. }
- ZonePtrList<Statement>* statements = NewStatementList(1);
- InitializeClassFieldsStatement* static_fields =
- factory()->NewInitializeClassFieldsStatement(fields, kNoSourcePosition);
- statements->Add(static_fields, zone());
+ ScopedPtrList<Statement> statements(pointer_buffer());
+ InitializeClassMembersStatement* static_fields =
+ factory()->NewInitializeClassMembersStatement(fields, kNoSourcePosition);
+ statements.Add(static_fields);
return factory()->NewFunctionLiteral(
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
FunctionLiteral::kNoDuplicateParameters,
@@ -3190,7 +2880,7 @@ FunctionLiteral* Parser::CreateInitializerFunction(
Expression* Parser::RewriteClassLiteral(Scope* block_scope,
const AstRawString* name,
ClassInfo* class_info, int pos,
- int end_pos, bool* ok) {
+ int end_pos) {
DCHECK_NOT_NULL(block_scope);
DCHECK_EQ(block_scope->scope_type(), BLOCK_SCOPE);
DCHECK_EQ(block_scope->language_mode(), LanguageMode::kStrict);
@@ -3214,18 +2904,18 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope,
class_info->static_fields);
}
- FunctionLiteral* instance_fields_initializer_function = nullptr;
- if (class_info->has_instance_class_fields) {
- instance_fields_initializer_function = CreateInitializerFunction(
- "<instance_fields_initializer>", class_info->instance_fields_scope,
+ FunctionLiteral* instance_members_initializer_function = nullptr;
+ if (class_info->has_instance_members) {
+ instance_members_initializer_function = CreateInitializerFunction(
+ "<instance_members_initializer>", class_info->instance_members_scope,
class_info->instance_fields);
- class_info->constructor->set_requires_instance_fields_initializer(true);
+ class_info->constructor->set_requires_instance_members_initializer(true);
}
ClassLiteral* class_literal = factory()->NewClassLiteral(
block_scope, class_info->variable, class_info->extends,
class_info->constructor, class_info->properties,
- static_fields_initializer, instance_fields_initializer_function, pos,
+ static_fields_initializer, instance_members_initializer_function, pos,
end_pos, class_info->has_name_static_property,
class_info->has_static_computed_names, class_info->is_anonymous);
@@ -3233,18 +2923,18 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope,
return class_literal;
}
-void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
+void Parser::CheckConflictingVarDeclarations(Scope* scope) {
+ if (has_error()) return;
Declaration* decl = scope->CheckConflictingVarDeclarations();
if (decl != nullptr) {
// In ES6, conflicting variable bindings are early errors.
- const AstRawString* name = decl->proxy()->raw_name();
- int position = decl->proxy()->position();
+ const AstRawString* name = decl->var()->raw_name();
+ int position = decl->position();
Scanner::Location location =
position == kNoSourcePosition
? Scanner::Location::invalid()
: Scanner::Location(position, position + 1);
ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
- *ok = false;
}
}
@@ -3255,7 +2945,7 @@ bool Parser::IsPropertyWithPrivateFieldKey(Expression* expression) {
if (!property->key()->IsVariableProxy()) return false;
VariableProxy* key = property->key()->AsVariableProxy();
- return key->is_private_field();
+ return key->IsPrivateName();
}
void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) {
@@ -3267,11 +2957,11 @@ void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) {
DCHECK(function_scope->is_function_scope());
BlockState block_state(&scope_, inner_scope);
for (Declaration* decl : *inner_scope->declarations()) {
- if (decl->proxy()->var()->mode() != VariableMode::kVar ||
+ if (decl->var()->mode() != VariableMode::kVar ||
!decl->IsVariableDeclaration()) {
continue;
}
- const AstRawString* name = decl->proxy()->raw_name();
+ const AstRawString* name = decl->var()->raw_name();
Variable* parameter = function_scope->LookupLocal(name);
if (parameter == nullptr) continue;
VariableProxy* to = NewUnresolved(name);
@@ -3305,9 +2995,7 @@ bool Parser::TargetStackContainsLabel(const AstRawString* label) {
return false;
}
-
-BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label,
- bool* ok) {
+BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label) {
bool anonymous = label == nullptr;
for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) {
BreakableStatement* stat = t->statement();
@@ -3319,9 +3007,7 @@ BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label,
return nullptr;
}
-
-IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
- bool* ok) {
+IterationStatement* Parser::LookupContinueTarget(const AstRawString* label) {
bool anonymous = label == nullptr;
for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) {
IterationStatement* stat = t->statement()->AsIterationStatement();
@@ -3336,7 +3022,6 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
return nullptr;
}
-
void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) {
Handle<String> source_url = scanner_.SourceUrl(isolate);
if (!source_url.is_null()) {
@@ -3444,59 +3129,57 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
factory()->NewGetTemplateObject(cooked_strings, raw_strings, pos);
// Call TagFn
- ZonePtrList<Expression>* call_args =
- new (zone()) ZonePtrList<Expression>(expressions->length() + 1, zone());
- call_args->Add(template_object, zone());
- call_args->AddAll(*expressions, zone());
+ ScopedPtrList<Expression> call_args(pointer_buffer());
+ call_args.Add(template_object);
+ call_args.AddAll(*expressions);
return factory()->NewTaggedTemplate(tag, call_args, pos);
}
}
namespace {
-bool OnlyLastArgIsSpread(ZonePtrList<Expression>* args) {
- for (int i = 0; i < args->length() - 1; i++) {
- if (args->at(i)->IsSpread()) {
+bool OnlyLastArgIsSpread(const ScopedPtrList<Expression>& args) {
+ for (int i = 0; i < args.length() - 1; i++) {
+ if (args.at(i)->IsSpread()) {
return false;
}
}
- return args->at(args->length() - 1)->IsSpread();
+ return args.at(args.length() - 1)->IsSpread();
}
} // namespace
ArrayLiteral* Parser::ArrayLiteralFromListWithSpread(
- ZonePtrList<Expression>* list) {
+ const ScopedPtrList<Expression>& list) {
// If there's only a single spread argument, a fast path using CallWithSpread
// is taken.
- DCHECK_LT(1, list->length());
+ DCHECK_LT(1, list.length());
// The arguments of the spread call become a single ArrayLiteral.
int first_spread = 0;
- for (; first_spread < list->length() && !list->at(first_spread)->IsSpread();
+ for (; first_spread < list.length() && !list.at(first_spread)->IsSpread();
++first_spread) {
}
- DCHECK_LT(first_spread, list->length());
+ DCHECK_LT(first_spread, list.length());
return factory()->NewArrayLiteral(list, first_spread, kNoSourcePosition);
}
Expression* Parser::SpreadCall(Expression* function,
- ZonePtrList<Expression>* args_list, int pos,
- Call::PossiblyEval is_possibly_eval) {
+ const ScopedPtrList<Expression>& args_list,
+ int pos, Call::PossiblyEval is_possibly_eval) {
// Handle this case in BytecodeGenerator.
if (OnlyLastArgIsSpread(args_list) || function->IsSuperCallReference()) {
return factory()->NewCall(function, args_list, pos);
}
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(3, zone());
+ ScopedPtrList<Expression> args(pointer_buffer());
if (function->IsProperty()) {
// Method calls
if (function->AsProperty()->IsSuperAccess()) {
Expression* home = ThisExpression(kNoSourcePosition);
- args->Add(function, zone());
- args->Add(home, zone());
+ args.Add(function);
+ args.Add(home);
} else {
Variable* temp = NewTemporary(ast_value_factory()->empty_string());
VariableProxy* obj = factory()->NewVariableProxy(temp);
@@ -3504,29 +3187,29 @@ Expression* Parser::SpreadCall(Expression* function,
Token::ASSIGN, obj, function->AsProperty()->obj(), kNoSourcePosition);
function = factory()->NewProperty(
assign_obj, function->AsProperty()->key(), kNoSourcePosition);
- args->Add(function, zone());
+ args.Add(function);
obj = factory()->NewVariableProxy(temp);
- args->Add(obj, zone());
+ args.Add(obj);
}
} else {
// Non-method calls
- args->Add(function, zone());
- args->Add(factory()->NewUndefinedLiteral(kNoSourcePosition), zone());
+ args.Add(function);
+ args.Add(factory()->NewUndefinedLiteral(kNoSourcePosition));
}
- args->Add(ArrayLiteralFromListWithSpread(args_list), zone());
+ args.Add(ArrayLiteralFromListWithSpread(args_list));
return factory()->NewCallRuntime(Context::REFLECT_APPLY_INDEX, args, pos);
}
Expression* Parser::SpreadCallNew(Expression* function,
- ZonePtrList<Expression>* args_list, int pos) {
+ const ScopedPtrList<Expression>& args_list,
+ int pos) {
if (OnlyLastArgIsSpread(args_list)) {
// Handle in BytecodeGenerator.
return factory()->NewCallNew(function, args_list, pos);
}
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(2, zone());
- args->Add(function, zone());
- args->Add(ArrayLiteralFromListWithSpread(args_list), zone());
+ ScopedPtrList<Expression> args(pointer_buffer());
+ args.Add(function);
+ args.Add(ArrayLiteralFromListWithSpread(args_list));
return factory()->NewCallRuntime(Context::REFLECT_CONSTRUCT_INDEX, args, pos);
}
@@ -3549,27 +3232,34 @@ void Parser::SetAsmModule() {
// incremented after parsing is done.
++use_counts_[v8::Isolate::kUseAsm];
DCHECK(scope()->is_declaration_scope());
- scope()->AsDeclarationScope()->set_asm_module();
+ scope()->AsDeclarationScope()->set_is_asm_module();
+ info_->set_contains_asm_module(true);
}
-Expression* Parser::ExpressionListToExpression(ZonePtrList<Expression>* args) {
- Expression* expr = args->at(0);
- for (int i = 1; i < args->length(); ++i) {
- expr = factory()->NewBinaryOperation(Token::COMMA, expr, args->at(i),
- expr->position());
+Expression* Parser::ExpressionListToExpression(
+ const ScopedPtrList<Expression>& args) {
+ Expression* expr = args.at(0);
+ if (args.length() == 1) return expr;
+ if (args.length() == 2) {
+ return factory()->NewBinaryOperation(Token::COMMA, expr, args.at(1),
+ args.at(1)->position());
+ }
+ NaryOperation* result =
+ factory()->NewNaryOperation(Token::COMMA, expr, args.length() - 1);
+ for (int i = 1; i < args.length(); i++) {
+ result->AddSubsequent(args.at(i), args.at(i)->position());
}
- return expr;
+ return result;
}
// This method completes the desugaring of the body of async_function.
-void Parser::RewriteAsyncFunctionBody(ZonePtrList<Statement>* body,
- Block* block, Expression* return_value,
- bool* ok) {
+void Parser::RewriteAsyncFunctionBody(ScopedPtrList<Statement>* body,
+ Block* block, Expression* return_value) {
// function async_function() {
- // .generator_object = %CreateJSGeneratorObject();
+ // .generator_object = %_AsyncFunctionEnter();
// BuildRejectPromiseOnException({
// ... block ...
- // return %ResolvePromise(.promise, expr), .promise;
+ // return %_AsyncFunctionResolve(.generator_object, expr);
// })
// }
@@ -3577,40 +3267,13 @@ void Parser::RewriteAsyncFunctionBody(ZonePtrList<Statement>* body,
return_value, return_value->position()),
zone());
block = BuildRejectPromiseOnException(block);
- body->Add(block, zone());
-}
-
-void Parser::RewriteDestructuringAssignments() {
- const auto& assignments =
- function_state_->destructuring_assignments_to_rewrite();
- auto it = assignments.rbegin();
- for (; it != assignments.rend(); ++it) {
- // Rewrite list in reverse, so that nested assignment patterns are rewritten
- // correctly.
- RewritableExpression* to_rewrite = *it;
- DCHECK_NOT_NULL(to_rewrite);
- if (!to_rewrite->is_rewritten()) {
- // Since this function is called at the end of parsing the program,
- // pair.scope may already have been removed by FinalizeBlockScope in the
- // meantime.
- Scope* scope = to_rewrite->scope()->GetUnremovedScope();
- // Scope at the time of the rewriting and the original parsing
- // should be in the same function.
- DCHECK(scope->GetClosureScope() == scope_->GetClosureScope());
- BlockState block_state(&scope_, scope);
- RewriteDestructuringAssignment(to_rewrite);
- }
- }
-}
-
-void Parser::QueueDestructuringAssignmentForRewriting(
- RewritableExpression* expr) {
- function_state_->AddDestructuringAssignment(expr);
+ body->Add(block);
}
void Parser::SetFunctionNameFromPropertyName(LiteralProperty* property,
const AstRawString* name,
const AstRawString* prefix) {
+ if (has_error()) return;
// Ensure that the function we are going to create has shared name iff
// we are not going to set it later.
if (property->NeedsSetFunctionName()) {
@@ -3636,7 +3299,7 @@ void Parser::SetFunctionNameFromPropertyName(ObjectLiteralProperty* property,
// Ignore "__proto__" as a name when it's being used to set the [[Prototype]]
// of an object literal.
// See ES #sec-__proto__-property-names-in-object-initializers.
- if (property->IsPrototype()) return;
+ if (property->IsPrototype() || has_error()) return;
DCHECK(!property->value()->IsAnonymousFunctionDefinition() ||
property->kind() == ObjectLiteralProperty::COMPUTED);
@@ -3691,440 +3354,10 @@ Statement* Parser::CheckCallable(Variable* var, Expression* error, int pos) {
Statement* throw_call = factory()->NewExpressionStatement(error, pos);
validate_var = factory()->NewIfStatement(
- condition, factory()->NewEmptyStatement(nopos), throw_call, nopos);
+ condition, factory()->EmptyStatement(), throw_call, nopos);
}
return validate_var;
}
-void Parser::BuildIteratorClose(ZonePtrList<Statement>* statements,
- Variable* iterator, Variable* input,
- Variable* var_output, IteratorType type) {
- //
- // This function adds four statements to [statements], corresponding to the
- // following code:
- //
- // let iteratorReturn = iterator.return;
- // if (IS_NULL_OR_UNDEFINED(iteratorReturn) {
- // return {value: input, done: true};
- // }
- // output = %_Call(iteratorReturn, iterator, input);
- // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
- //
-
- const int nopos = kNoSourcePosition;
-
- // let iteratorReturn = iterator.return;
- Variable* var_return = var_output; // Reusing the output variable.
- Statement* get_return;
- {
- Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
- Expression* literal = factory()->NewStringLiteral(
- ast_value_factory()->return_string(), nopos);
- Expression* property =
- factory()->NewProperty(iterator_proxy, literal, nopos);
- Expression* return_proxy = factory()->NewVariableProxy(var_return);
- Expression* assignment =
- factory()->NewAssignment(Token::ASSIGN, return_proxy, property, nopos);
- get_return = factory()->NewExpressionStatement(assignment, nopos);
- }
-
- // if (IS_NULL_OR_UNDEFINED(iteratorReturn) {
- // return {value: input, done: true};
- // }
- Statement* check_return;
- {
- Expression* condition = factory()->NewCompareOperation(
- Token::EQ, factory()->NewVariableProxy(var_return),
- factory()->NewNullLiteral(nopos), nopos);
-
- Expression* value = factory()->NewVariableProxy(input);
-
- Statement* return_input = BuildReturnStatement(value, nopos);
-
- check_return = factory()->NewIfStatement(
- condition, return_input, factory()->NewEmptyStatement(nopos), nopos);
- }
-
- // output = %_Call(iteratorReturn, iterator, input);
- Statement* call_return;
- {
- auto args = new (zone()) ZonePtrList<Expression>(3, zone());
- args->Add(factory()->NewVariableProxy(var_return), zone());
- args->Add(factory()->NewVariableProxy(iterator), zone());
- args->Add(factory()->NewVariableProxy(input), zone());
-
- Expression* call =
- factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
- if (type == IteratorType::kAsync) {
- function_state_->AddSuspend();
- call = factory()->NewAwait(call, nopos);
- }
- Expression* output_proxy = factory()->NewVariableProxy(var_output);
- Expression* assignment =
- factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
- call_return = factory()->NewExpressionStatement(assignment, nopos);
- }
-
- // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
- Statement* validate_output;
- {
- Expression* is_receiver_call;
- {
- auto args = new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(factory()->NewVariableProxy(var_output), zone());
- is_receiver_call =
- factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
- }
-
- Statement* throw_call;
- {
- auto args = new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(factory()->NewVariableProxy(var_output), zone());
- Expression* call = factory()->NewCallRuntime(
- Runtime::kThrowIteratorResultNotAnObject, args, nopos);
- throw_call = factory()->NewExpressionStatement(call, nopos);
- }
-
- validate_output = factory()->NewIfStatement(
- is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
- nopos);
- }
-
- statements->Add(get_return, zone());
- statements->Add(check_return, zone());
- statements->Add(call_return, zone());
- statements->Add(validate_output, zone());
-}
-
-void Parser::FinalizeIteratorUse(Variable* completion, Expression* condition,
- Variable* iter, Block* iterator_use,
- Block* target, IteratorType type) {
- //
- // This function adds two statements to [target], corresponding to the
- // following code:
- //
- // completion = kNormalCompletion;
- // try {
- // try {
- // iterator_use
- // } catch(e) {
- // if (completion === kAbruptCompletion) completion = kThrowCompletion;
- // %ReThrow(e);
- // }
- // } finally {
- // if (condition) {
- // #BuildIteratorCloseForCompletion(iter, completion)
- // }
- // }
- //
-
- const int nopos = kNoSourcePosition;
-
- // completion = kNormalCompletion;
- Statement* initialize_completion;
- {
- Expression* proxy = factory()->NewVariableProxy(completion);
- Expression* assignment = factory()->NewAssignment(
- Token::ASSIGN, proxy,
- factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
- initialize_completion =
- factory()->NewExpressionStatement(assignment, nopos);
- }
-
- // if (completion === kAbruptCompletion) completion = kThrowCompletion;
- Statement* set_completion_throw;
- {
- Expression* condition = factory()->NewCompareOperation(
- Token::EQ_STRICT, factory()->NewVariableProxy(completion),
- factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
-
- Expression* proxy = factory()->NewVariableProxy(completion);
- Expression* assignment = factory()->NewAssignment(
- Token::ASSIGN, proxy,
- factory()->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos);
- Statement* statement = factory()->NewExpressionStatement(assignment, nopos);
- set_completion_throw = factory()->NewIfStatement(
- condition, statement, factory()->NewEmptyStatement(nopos), nopos);
- }
-
- // if (condition) {
- // #BuildIteratorCloseForCompletion(iter, completion)
- // }
- Block* maybe_close;
- {
- Block* block = factory()->NewBlock(2, true);
- Expression* proxy = factory()->NewVariableProxy(completion);
- BuildIteratorCloseForCompletion(block->statements(), iter, proxy, type);
- DCHECK_EQ(block->statements()->length(), 2);
-
- maybe_close = IgnoreCompletion(factory()->NewIfStatement(
- condition, block, factory()->NewEmptyStatement(nopos), nopos));
- }
-
- // try { #try_block }
- // catch(e) {
- // #set_completion_throw;
- // %ReThrow(e);
- // }
- Statement* try_catch;
- {
- Scope* catch_scope = NewHiddenCatchScope();
-
- Statement* rethrow;
- // We use %ReThrow rather than the ordinary throw because we want to
- // preserve the original exception message. This is also why we create a
- // TryCatchStatementForReThrow below (which does not clear the pending
- // message), rather than a TryCatchStatement.
- {
- auto args = new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(factory()->NewVariableProxy(catch_scope->catch_variable()),
- zone());
- rethrow = factory()->NewExpressionStatement(
- factory()->NewCallRuntime(Runtime::kReThrow, args, nopos), nopos);
- }
-
- Block* catch_block = factory()->NewBlock(2, false);
- catch_block->statements()->Add(set_completion_throw, zone());
- catch_block->statements()->Add(rethrow, zone());
-
- try_catch = factory()->NewTryCatchStatementForReThrow(
- iterator_use, catch_scope, catch_block, nopos);
- }
-
- // try { #try_catch } finally { #maybe_close }
- Statement* try_finally;
- {
- Block* try_block = factory()->NewBlock(1, false);
- try_block->statements()->Add(try_catch, zone());
-
- try_finally =
- factory()->NewTryFinallyStatement(try_block, maybe_close, nopos);
- }
-
- target->statements()->Add(initialize_completion, zone());
- target->statements()->Add(try_finally, zone());
-}
-
-void Parser::BuildIteratorCloseForCompletion(ZonePtrList<Statement>* statements,
- Variable* iterator,
- Expression* completion,
- IteratorType type) {
- //
- // This function adds two statements to [statements], corresponding to the
- // following code:
- //
- // let iteratorReturn = iterator.return;
- // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
- // if (completion === kThrowCompletion) {
- // if (!IS_CALLABLE(iteratorReturn)) {
- // throw MakeTypeError(kReturnMethodNotCallable);
- // }
- // [if (IteratorType == kAsync)]
- // try { Await(%_Call(iteratorReturn, iterator) } catch (_) { }
- // [else]
- // try { %_Call(iteratorReturn, iterator) } catch (_) { }
- // [endif]
- // } else {
- // [if (IteratorType == kAsync)]
- // let output = Await(%_Call(iteratorReturn, iterator));
- // [else]
- // let output = %_Call(iteratorReturn, iterator);
- // [endif]
- // if (!IS_RECEIVER(output)) {
- // %ThrowIterResultNotAnObject(output);
- // }
- // }
- // }
- //
-
- const int nopos = kNoSourcePosition;
- // let iteratorReturn = iterator.return;
- Variable* var_return = NewTemporary(ast_value_factory()->empty_string());
- Statement* get_return;
- {
- Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
- Expression* literal = factory()->NewStringLiteral(
- ast_value_factory()->return_string(), nopos);
- Expression* property =
- factory()->NewProperty(iterator_proxy, literal, nopos);
- Expression* return_proxy = factory()->NewVariableProxy(var_return);
- Expression* assignment =
- factory()->NewAssignment(Token::ASSIGN, return_proxy, property, nopos);
- get_return = factory()->NewExpressionStatement(assignment, nopos);
- }
-
- // if (!IS_CALLABLE(iteratorReturn)) {
- // throw MakeTypeError(kReturnMethodNotCallable);
- // }
- Statement* check_return_callable;
- {
- Expression* throw_expr =
- NewThrowTypeError(MessageTemplate::kReturnMethodNotCallable,
- ast_value_factory()->empty_string(), nopos);
- check_return_callable = CheckCallable(var_return, throw_expr, nopos);
- }
-
- // try { %_Call(iteratorReturn, iterator) } catch (_) { }
- Statement* try_call_return;
- {
- auto args = new (zone()) ZonePtrList<Expression>(2, zone());
- args->Add(factory()->NewVariableProxy(var_return), zone());
- args->Add(factory()->NewVariableProxy(iterator), zone());
-
- Expression* call =
- factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
-
- if (type == IteratorType::kAsync) {
- function_state_->AddSuspend();
- call = factory()->NewAwait(call, nopos);
- }
-
- Block* try_block = factory()->NewBlock(1, false);
- try_block->statements()->Add(factory()->NewExpressionStatement(call, nopos),
- zone());
-
- Block* catch_block = factory()->NewBlock(0, false);
- try_call_return =
- factory()->NewTryCatchStatement(try_block, nullptr, catch_block, nopos);
- }
-
- // let output = %_Call(iteratorReturn, iterator);
- // if (!IS_RECEIVER(output)) {
- // %ThrowIteratorResultNotAnObject(output);
- // }
- Block* validate_return;
- {
- Variable* var_output = NewTemporary(ast_value_factory()->empty_string());
- Statement* call_return;
- {
- auto args = new (zone()) ZonePtrList<Expression>(2, zone());
- args->Add(factory()->NewVariableProxy(var_return), zone());
- args->Add(factory()->NewVariableProxy(iterator), zone());
- Expression* call =
- factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
- if (type == IteratorType::kAsync) {
- function_state_->AddSuspend();
- call = factory()->NewAwait(call, nopos);
- }
-
- Expression* output_proxy = factory()->NewVariableProxy(var_output);
- Expression* assignment =
- factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
- call_return = factory()->NewExpressionStatement(assignment, nopos);
- }
-
- Expression* is_receiver_call;
- {
- auto args = new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(factory()->NewVariableProxy(var_output), zone());
- is_receiver_call =
- factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
- }
-
- Statement* throw_call;
- {
- auto args = new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(factory()->NewVariableProxy(var_output), zone());
- Expression* call = factory()->NewCallRuntime(
- Runtime::kThrowIteratorResultNotAnObject, args, nopos);
- throw_call = factory()->NewExpressionStatement(call, nopos);
- }
-
- Statement* check_return = factory()->NewIfStatement(
- is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
- nopos);
-
- validate_return = factory()->NewBlock(2, false);
- validate_return->statements()->Add(call_return, zone());
- validate_return->statements()->Add(check_return, zone());
- }
-
- // if (completion === kThrowCompletion) {
- // #check_return_callable;
- // #try_call_return;
- // } else {
- // #validate_return;
- // }
- Statement* call_return_carefully;
- {
- Expression* condition = factory()->NewCompareOperation(
- Token::EQ_STRICT, completion,
- factory()->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos);
-
- Block* then_block = factory()->NewBlock(2, false);
- then_block->statements()->Add(check_return_callable, zone());
- then_block->statements()->Add(try_call_return, zone());
-
- call_return_carefully = factory()->NewIfStatement(condition, then_block,
- validate_return, nopos);
- }
-
- // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { ... }
- Statement* maybe_call_return;
- {
- Expression* condition = factory()->NewCompareOperation(
- Token::EQ, factory()->NewVariableProxy(var_return),
- factory()->NewNullLiteral(nopos), nopos);
-
- maybe_call_return = factory()->NewIfStatement(
- condition, factory()->NewEmptyStatement(nopos), call_return_carefully,
- nopos);
- }
-
- statements->Add(get_return, zone());
- statements->Add(maybe_call_return, zone());
-}
-
-Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop,
- Variable* var_completion,
- IteratorType type, int pos) {
- //
- // This function replaces the loop with the following wrapping:
- //
- // completion = kNormalCompletion;
- // try {
- // try {
- // #loop;
- // } catch(e) {
- // if (completion === kAbruptCompletion) completion = kThrowCompletion;
- // %ReThrow(e);
- // }
- // } finally {
- // if (!(completion === kNormalCompletion)) {
- // #BuildIteratorCloseForCompletion(#iterator, completion)
- // }
- // }
- //
- // Note that the loop's body and its assign_each already contain appropriate
- // assignments to completion (see InitializeForOfStatement).
- //
-
- const int nopos = kNoSourcePosition;
-
- // !(completion === kNormalCompletion)
- Expression* closing_condition;
- {
- Expression* cmp = factory()->NewCompareOperation(
- Token::EQ_STRICT, factory()->NewVariableProxy(var_completion),
- factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
- closing_condition = factory()->NewUnaryOperation(Token::NOT, cmp, nopos);
- }
-
- Block* final_loop = factory()->NewBlock(2, false);
- {
- Block* try_block = factory()->NewBlock(1, false);
- try_block->statements()->Add(loop, zone());
-
- FinalizeIteratorUse(var_completion, closing_condition, loop->iterator(),
- try_block, final_loop, type);
- }
-
- return final_loop;
-}
-
-#undef CHECK_OK
-#undef CHECK_OK_VOID
-#undef CHECK_FAILED
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h
index 35de0656d3..cc0ceb2607 100644
--- a/deps/v8/src/parsing/parser.h
+++ b/deps/v8/src/parsing/parser.h
@@ -16,6 +16,7 @@
#include "src/parsing/parser-base.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparser.h"
+#include "src/pointer-with-payload.h"
#include "src/zone/zone-chunk-list.h"
namespace v8 {
@@ -24,12 +25,12 @@ class ScriptCompiler;
namespace internal {
-class ConsumedPreParsedScopeData;
+class ConsumedPreparseData;
class ParseInfo;
class ParserTarget;
class ParserTargetScope;
class PendingCompilationErrorHandler;
-class PreParsedScopeData;
+class PreparseData;
class FunctionEntry {
public:
@@ -83,33 +84,55 @@ class Parser;
struct ParserFormalParameters : FormalParametersBase {
struct Parameter : public ZoneObject {
- Parameter(const AstRawString* name, Expression* pattern,
- Expression* initializer, int position,
+ Parameter(Expression* pattern, Expression* initializer, int position,
int initializer_end_position, bool is_rest)
- : name(name),
+ : initializer_and_is_rest(initializer, is_rest),
pattern(pattern),
- initializer(initializer),
position(position),
- initializer_end_position(initializer_end_position),
- is_rest(is_rest) {}
- const AstRawString* name;
+ initializer_end_position(initializer_end_position) {}
+
+ PointerWithPayload<Expression, bool, 1> initializer_and_is_rest;
+
Expression* pattern;
- Expression* initializer;
+ Expression* initializer() const {
+ return initializer_and_is_rest.GetPointer();
+ }
int position;
int initializer_end_position;
- bool is_rest;
+ inline bool is_rest() const { return initializer_and_is_rest.GetPayload(); }
+
Parameter* next_parameter = nullptr;
bool is_simple() const {
- return pattern->IsVariableProxy() && initializer == nullptr && !is_rest;
+ return pattern->IsVariableProxy() && initializer() == nullptr &&
+ !is_rest();
+ }
+
+ const AstRawString* name() const {
+ DCHECK(is_simple());
+ return pattern->AsVariableProxy()->raw_name();
}
Parameter** next() { return &next_parameter; }
Parameter* const* next() const { return &next_parameter; }
};
+ void set_strict_parameter_error(const Scanner::Location& loc,
+ MessageTemplate message) {
+ strict_error_loc = loc;
+ strict_error_message = message;
+ }
+
+ bool has_duplicate() const { return duplicate_loc.IsValid(); }
+ void ValidateDuplicate(Parser* parser) const;
+ void ValidateStrictMode(Parser* parser) const;
+
explicit ParserFormalParameters(DeclarationScope* scope)
: FormalParametersBase(scope) {}
+
base::ThreadedList<Parameter> params;
+ Scanner::Location duplicate_loc = Scanner::Location::invalid();
+ Scanner::Location strict_error_loc = Scanner::Location::invalid();
+ MessageTemplate strict_error_message = MessageTemplate::kNone;
};
template <>
@@ -118,34 +141,32 @@ struct ParserTypes<Parser> {
typedef Parser Impl;
// Return types for traversing functions.
- typedef const AstRawString* Identifier;
- typedef v8::internal::Expression* Expression;
- typedef v8::internal::FunctionLiteral* FunctionLiteral;
- typedef ObjectLiteral::Property* ObjectLiteralProperty;
+ typedef v8::internal::Block* Block;
+ typedef v8::internal::BreakableStatement* BreakableStatement;
typedef ClassLiteral::Property* ClassLiteralProperty;
- typedef v8::internal::Suspend* Suspend;
- typedef v8::internal::RewritableExpression* RewritableExpression;
- typedef ZonePtrList<v8::internal::Expression>* ExpressionList;
- typedef ZonePtrList<ObjectLiteral::Property>* ObjectPropertyList;
typedef ZonePtrList<ClassLiteral::Property>* ClassPropertyList;
+ typedef v8::internal::Expression* Expression;
+ typedef ScopedPtrList<v8::internal::Expression> ExpressionList;
typedef ParserFormalParameters FormalParameters;
- typedef v8::internal::Statement* Statement;
- typedef ZonePtrList<v8::internal::Statement>* StatementList;
- typedef v8::internal::Block* Block;
- typedef v8::internal::BreakableStatement* BreakableStatement;
typedef v8::internal::ForStatement* ForStatement;
+ typedef v8::internal::FunctionLiteral* FunctionLiteral;
+ typedef const AstRawString* Identifier;
typedef v8::internal::IterationStatement* IterationStatement;
- typedef v8::internal::FuncNameInferrer FuncNameInferrer;
- typedef v8::internal::SourceRange SourceRange;
- typedef v8::internal::SourceRangeScope SourceRangeScope;
+ typedef ObjectLiteral::Property* ObjectLiteralProperty;
+ typedef ScopedPtrList<v8::internal::ObjectLiteralProperty> ObjectPropertyList;
+ typedef v8::internal::Statement* Statement;
+ typedef ScopedPtrList<v8::internal::Statement> StatementList;
+ typedef v8::internal::Suspend* Suspend;
// For constructing objects returned by the traversing functions.
typedef AstNodeFactory Factory;
+ // Other implementation-specific functions.
+ typedef v8::internal::FuncNameInferrer FuncNameInferrer;
+ typedef v8::internal::SourceRange SourceRange;
+ typedef v8::internal::SourceRangeScope SourceRangeScope;
typedef ParserTarget Target;
typedef ParserTargetScope TargetScope;
-
- static constexpr bool ExpressionClassifierReportErrors = true;
};
class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
@@ -173,7 +194,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// their corresponding scope infos. Therefore, looking up variables in the
// deserialized scopes is not possible.
void DeserializeScopeChain(Isolate* isolate, ParseInfo* info,
- MaybeHandle<ScopeInfo> maybe_outer_scope_info);
+ MaybeHandle<ScopeInfo> maybe_outer_scope_info,
+ Scope::DeserializationMode mode =
+ Scope::DeserializationMode::kScopesOnly);
// Move statistics to Isolate
void UpdateStatistics(Isolate* isolate, Handle<Script> script);
@@ -181,8 +204,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
private:
friend class ParserBase<Parser>;
- friend class v8::internal::ExpressionClassifierErrorTracker<
- ParserTypes<Parser>>;
+ friend struct ParserFormalParameters;
+ friend class i::ExpressionScope<ParserTypes<Parser>>;
+ friend class i::VariableDeclarationParsingScope<ParserTypes<Parser>>;
+ friend class i::ParameterDeclarationParsingScope<ParserTypes<Parser>>;
+ friend class i::ArrowHeadParsingScope<ParserTypes<Parser>>;
friend bool v8::internal::parsing::ParseProgram(ParseInfo*, Isolate*);
friend bool v8::internal::parsing::ParseFunction(
ParseInfo*, Handle<SharedFunctionInfo> shared_info, Isolate*);
@@ -236,8 +262,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// We manually construct the AST and scopes for a top-level function and the
// function wrapper.
void ParseWrapped(Isolate* isolate, ParseInfo* info,
- ZonePtrList<Statement>* body, DeclarationScope* scope,
- Zone* zone, bool* ok);
+ ScopedPtrList<Statement>* body, DeclarationScope* scope,
+ Zone* zone);
ZonePtrList<const AstRawString>* PrepareWrappedArguments(Isolate* isolate,
ParseInfo* info,
@@ -251,31 +277,33 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
parsing_module_, parsing_on_main_thread_);
#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
SET_ALLOW(natives);
- SET_ALLOW(harmony_do_expressions);
SET_ALLOW(harmony_public_fields);
SET_ALLOW(harmony_static_fields);
SET_ALLOW(harmony_dynamic_import);
SET_ALLOW(harmony_import_meta);
SET_ALLOW(harmony_private_fields);
+ SET_ALLOW(harmony_private_methods);
SET_ALLOW(eval_cache);
#undef SET_ALLOW
+ preparse_data_buffer_.reserve(128);
}
return reusable_preparser_;
}
- void ParseModuleItemList(ZonePtrList<Statement>* body, bool* ok);
- Statement* ParseModuleItem(bool* ok);
- const AstRawString* ParseModuleSpecifier(bool* ok);
- void ParseImportDeclaration(bool* ok);
- Statement* ParseExportDeclaration(bool* ok);
- Statement* ParseExportDefault(bool* ok);
+ void ParseModuleItemList(ScopedPtrList<Statement>* body);
+ Statement* ParseModuleItem();
+ const AstRawString* ParseModuleSpecifier();
+ void ParseImportDeclaration();
+ Statement* ParseExportDeclaration();
+ Statement* ParseExportDefault();
+ void ParseExportStar();
struct ExportClauseData {
const AstRawString* export_name;
const AstRawString* local_name;
Scanner::Location location;
};
ZoneChunkList<ExportClauseData>* ParseExportClause(
- Scanner::Location* reserved_loc, bool* ok);
+ Scanner::Location* reserved_loc);
struct NamedImport : public ZoneObject {
const AstRawString* import_name;
const AstRawString* local_name;
@@ -286,117 +314,87 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
local_name(local_name),
location(location) {}
};
- ZonePtrList<const NamedImport>* ParseNamedImports(int pos, bool* ok);
- Block* BuildInitializationBlock(DeclarationParsingResult* parsing_result,
- ZonePtrList<const AstRawString>* names,
- bool* ok);
+ ZonePtrList<const NamedImport>* ParseNamedImports(int pos);
+ Statement* BuildInitializationBlock(DeclarationParsingResult* parsing_result);
void DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>** own_labels,
- VariableProxy* expr, bool* ok);
+ VariableProxy* expr);
bool ContainsLabel(ZonePtrList<const AstRawString>* labels,
const AstRawString* label);
Expression* RewriteReturn(Expression* return_value, int pos);
Statement* RewriteSwitchStatement(SwitchStatement* switch_statement,
Scope* scope);
- void RewriteCatchPattern(CatchInfo* catch_info, bool* ok);
- void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok);
+ Block* RewriteCatchPattern(CatchInfo* catch_info);
+ void ReportVarRedeclarationIn(const AstRawString* name, Scope* scope);
Statement* RewriteTryStatement(Block* try_block, Block* catch_block,
const SourceRange& catch_range,
Block* finally_block,
const SourceRange& finally_range,
const CatchInfo& catch_info, int pos);
void ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind,
- ZonePtrList<Statement>* body,
- bool* ok);
- void ParseAndRewriteAsyncGeneratorFunctionBody(int pos, FunctionKind kind,
- ZonePtrList<Statement>* body,
- bool* ok);
+ ScopedPtrList<Statement>* body);
+ void ParseAndRewriteAsyncGeneratorFunctionBody(
+ int pos, FunctionKind kind, ScopedPtrList<Statement>* body);
void DeclareFunctionNameVar(const AstRawString* function_name,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope);
Statement* DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, VariableMode mode,
- int pos, bool is_sloppy_block_function,
- ZonePtrList<const AstRawString>* names, bool* ok);
- Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name,
- bool* ok);
+ int beg_pos, int end_pos,
+ bool is_sloppy_block_function,
+ ZonePtrList<const AstRawString>* names);
+ Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name);
FunctionLiteral* CreateInitializerFunction(
const char* name, DeclarationScope* scope,
ZonePtrList<ClassLiteral::Property>* fields);
- V8_INLINE Statement* DeclareClass(const AstRawString* variable_name,
- Expression* value,
- ZonePtrList<const AstRawString>* names,
- int class_token_pos, int end_pos, bool* ok);
- V8_INLINE void DeclareClassVariable(const AstRawString* name,
- ClassInfo* class_info,
- int class_token_pos, bool* ok);
- V8_INLINE void DeclareClassProperty(const AstRawString* class_name,
- ClassLiteralProperty* property,
- const AstRawString* property_name,
- ClassLiteralProperty::Kind kind,
- bool is_static, bool is_constructor,
- bool is_computed_name,
- ClassInfo* class_info, bool* ok);
- V8_INLINE Expression* RewriteClassLiteral(Scope* block_scope,
- const AstRawString* name,
- ClassInfo* class_info, int pos,
- int end_pos, bool* ok);
- V8_INLINE Statement* DeclareNative(const AstRawString* name, int pos,
- bool* ok);
-
- V8_INLINE Block* IgnoreCompletion(Statement* statement);
-
- V8_INLINE Scope* NewHiddenCatchScope();
+
+ bool IdentifierEquals(const AstRawString* identifier,
+ const AstRawString* other) {
+ return identifier == other;
+ }
+
+ Statement* DeclareClass(const AstRawString* variable_name, Expression* value,
+ ZonePtrList<const AstRawString>* names,
+ int class_token_pos, int end_pos);
+ void DeclareClassVariable(const AstRawString* name, ClassInfo* class_info,
+ int class_token_pos);
+ void DeclareClassProperty(const AstRawString* class_name,
+ ClassLiteralProperty* property, bool is_constructor,
+ ClassInfo* class_info);
+ void DeclareClassField(ClassLiteralProperty* property,
+ const AstRawString* property_name, bool is_static,
+ bool is_computed_name, bool is_private,
+ ClassInfo* class_info);
+ Expression* RewriteClassLiteral(Scope* block_scope, const AstRawString* name,
+ ClassInfo* class_info, int pos, int end_pos);
+ Statement* DeclareNative(const AstRawString* name, int pos);
+
+ Block* IgnoreCompletion(Statement* statement);
+
+ Scope* NewHiddenCatchScope();
// PatternRewriter and associated methods defined in pattern-rewriter.cc.
friend class PatternRewriter;
- void DeclareAndInitializeVariables(
- Block* block, const DeclarationDescriptor* declaration_descriptor,
- const DeclarationParsingResult::Declaration* declaration,
- ZonePtrList<const AstRawString>* names, bool* ok);
- void RewriteDestructuringAssignment(RewritableExpression* expr);
- Expression* RewriteDestructuringAssignment(Assignment* assignment);
-
- // [if (IteratorType == kAsync)]
- // !%_IsJSReceiver(result = Await(next.[[Call]](iterator, « »)) &&
- // %ThrowIteratorResultNotAnObject(result)
- // [else]
- // !%_IsJSReceiver(result = next.[[Call]](iterator, « »)) &&
- // %ThrowIteratorResultNotAnObject(result)
- // [endif]
- Expression* BuildIteratorNextResult(VariableProxy* iterator,
- VariableProxy* next, Variable* result,
- IteratorType type, int pos);
-
- // Initialize the components of a for-in / for-of statement.
- Statement* InitializeForEachStatement(ForEachStatement* stmt,
- Expression* each, Expression* subject,
- Statement* body);
- Statement* InitializeForOfStatement(ForOfStatement* stmt, Expression* each,
- Expression* iterable, Statement* body,
- bool finalize, IteratorType type,
- int next_result_pos = kNoSourcePosition);
+ void InitializeVariables(
+ ScopedPtrList<Statement>* statements, VariableKind kind,
+ const DeclarationParsingResult::Declaration* declaration);
Block* RewriteForVarInLegacy(const ForInfo& for_info);
void DesugarBindingInForEachStatement(ForInfo* for_info, Block** body_block,
- Expression** each_variable, bool* ok);
- Block* CreateForEachStatementTDZ(Block* init_block, const ForInfo& for_info,
- bool* ok);
+ Expression** each_variable);
+ Block* CreateForEachStatementTDZ(Block* init_block, const ForInfo& for_info);
Statement* DesugarLexicalBindingsInForStatement(
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
- Statement* body, Scope* inner_scope, const ForInfo& for_info, bool* ok);
-
- Expression* RewriteDoExpression(Block* body, int pos, bool* ok);
+ Statement* body, Scope* inner_scope, const ForInfo& for_info);
FunctionLiteral* ParseFunctionLiteral(
const AstRawString* name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
LanguageMode language_mode,
- ZonePtrList<const AstRawString>* arguments_for_wrapped_function,
- bool* ok);
+ ZonePtrList<const AstRawString>* arguments_for_wrapped_function);
ObjectLiteral* InitializeObjectLiteral(ObjectLiteral* object_literal) {
object_literal->CalculateEmitStore(main_zone());
@@ -412,7 +410,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// 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);
+ void CheckConflictingVarDeclarations(Scope* scope);
bool IsPropertyWithPrivateFieldKey(Expression* property);
@@ -423,22 +421,22 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// Implement sloppy block-scoped functions, ES2015 Annex B 3.3
void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope);
- VariableProxy* NewUnresolved(const AstRawString* name, int begin_pos,
- VariableKind kind = NORMAL_VARIABLE);
- VariableProxy* NewUnresolved(const AstRawString* name);
- Variable* Declare(Declaration* declaration,
- DeclarationDescriptor::Kind declaration_kind,
- VariableMode mode, InitializationFlag init, bool* ok,
- Scope* declaration_scope = nullptr,
- int var_end_pos = kNoSourcePosition);
- Declaration* DeclareVariable(const AstRawString* name, VariableMode mode,
- int pos, bool* ok);
- Declaration* DeclareVariable(const AstRawString* name, VariableMode mode,
- InitializationFlag init, int pos, bool* ok);
+ VariableProxy* DeclareVariable(const AstRawString* name, VariableMode mode,
+ int pos);
+ VariableProxy* DeclareVariable(const AstRawString* name, VariableMode mode,
+ InitializationFlag init, int pos);
+ void DeclareVariable(VariableProxy* proxy, VariableKind kind,
+ VariableMode mode, InitializationFlag init,
+ Scope* declaration_scope, bool* added, int begin,
+ int end = kNoSourcePosition);
+ void Declare(Declaration* declaration, VariableProxy* proxy,
+ VariableKind kind, VariableMode mode, InitializationFlag init,
+ Scope* declaration_scope, bool* added,
+ int var_end_pos = kNoSourcePosition);
bool TargetStackContainsLabel(const AstRawString* label);
- BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
- IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
+ BreakableStatement* LookupBreakTarget(const AstRawString* label);
+ IterationStatement* LookupContinueTarget(const AstRawString* label);
Statement* BuildAssertIsCoercible(Variable* var, ObjectLiteral* pattern);
@@ -448,8 +446,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// Skip over a lazy function, either using cached data if we have it, or
// by parsing the function with PreParser. Consumes the ending }.
- // If may_abort == true, the (pre-)parser may decide to abort skipping
- // in order to force the function to be eagerly parsed, after all.
// In case the preparser detects an error it cannot identify, it resets the
// scanner- and preparser state to the initial one, before PreParsing the
// function.
@@ -460,22 +456,19 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
bool SkipFunction(const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters,
- ProducedPreParsedScopeData** produced_preparsed_scope_data,
- bool is_inner_function, bool may_abort,
- FunctionLiteral::EagerCompileHint* hint, bool* ok);
+ ProducedPreparseData** produced_preparsed_scope_data);
Block* BuildParameterInitializationBlock(
- const ParserFormalParameters& parameters, bool* ok);
+ const ParserFormalParameters& parameters);
Block* BuildRejectPromiseOnException(Block* block);
- ZonePtrList<Statement>* ParseFunction(
- const AstRawString* function_name, int pos, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
+ void ParseFunction(
+ ScopedPtrList<Statement>* body, const AstRawString* function_name,
+ int pos, FunctionKind kind, FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters,
int* function_length, bool* has_duplicate_parameters,
int* expected_property_count, int* suspend_count,
- ZonePtrList<const AstRawString>* arguments_for_wrapped_function,
- bool* ok);
+ ZonePtrList<const AstRawString>* arguments_for_wrapped_function);
void ThrowPendingError(Isolate* isolate, Handle<Script> script);
@@ -497,7 +490,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
}
void AddExpression(Expression* expression, Zone* zone) {
- DCHECK_NOT_NULL(expression);
expressions_.Add(expression, zone);
}
@@ -524,60 +516,40 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* CloseTemplateLiteral(TemplateLiteralState* state, int start,
Expression* tag);
- ArrayLiteral* ArrayLiteralFromListWithSpread(ZonePtrList<Expression>* list);
- Expression* SpreadCall(Expression* function, ZonePtrList<Expression>* args,
- int pos, Call::PossiblyEval is_possibly_eval);
- Expression* SpreadCallNew(Expression* function, ZonePtrList<Expression>* args,
- int pos);
+ ArrayLiteral* ArrayLiteralFromListWithSpread(
+ const ScopedPtrList<Expression>& list);
+ Expression* SpreadCall(Expression* function,
+ const ScopedPtrList<Expression>& args, int pos,
+ Call::PossiblyEval is_possibly_eval);
+ Expression* SpreadCallNew(Expression* function,
+ const ScopedPtrList<Expression>& args, int pos);
Expression* RewriteSuperCall(Expression* call_expression);
void SetLanguageMode(Scope* scope, LanguageMode mode);
void SetAsmModule();
- // Rewrite all DestructuringAssignments in the current FunctionState.
- V8_INLINE void RewriteDestructuringAssignments();
-
Expression* RewriteSpreads(ArrayLiteral* lit);
- V8_INLINE void QueueDestructuringAssignmentForRewriting(
- RewritableExpression* assignment);
-
friend class InitializerRewriter;
void RewriteParameterInitializer(Expression* expr);
Expression* BuildInitialYield(int pos, FunctionKind kind);
Assignment* BuildCreateJSGeneratorObject(int pos, FunctionKind kind);
- Expression* BuildRejectPromise(Expression* value, int pos);
- Variable* PromiseVariable();
- Variable* AsyncGeneratorAwaitVariable();
// Generic AST generator for throwing errors from compiled code.
Expression* NewThrowError(Runtime::FunctionId function_id,
- MessageTemplate::Template message,
- const AstRawString* arg, int pos);
-
- void FinalizeIteratorUse(Variable* completion, Expression* condition,
- Variable* iter, Block* iterator_use, Block* result,
- IteratorType type);
+ MessageTemplate message, const AstRawString* arg,
+ int pos);
Statement* FinalizeForOfStatement(ForOfStatement* loop, Variable* completion,
IteratorType type, int pos);
- void BuildIteratorClose(ZonePtrList<Statement>* statements,
- Variable* iterator, Variable* input, Variable* output,
- IteratorType type);
- void BuildIteratorCloseForCompletion(ZonePtrList<Statement>* statements,
- Variable* iterator,
- Expression* completion,
- IteratorType type);
Statement* CheckCallable(Variable* var, Expression* error, int pos);
- V8_INLINE void RewriteAsyncFunctionBody(ZonePtrList<Statement>* body,
- Block* block,
- Expression* return_value, bool* ok);
+ void RewriteAsyncFunctionBody(ScopedPtrList<Statement>* body, Block* block,
+ Expression* return_value);
void AddArrowFunctionFormalParameters(ParserFormalParameters* parameters,
- Expression* params, int end_pos,
- bool* ok);
+ Expression* params, int end_pos);
void SetFunctionName(Expression* value, const AstRawString* name,
const AstRawString* prefix = nullptr);
@@ -586,6 +558,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return identifier == ast_value_factory()->eval_string();
}
+ V8_INLINE bool IsAsync(const AstRawString* identifier) const {
+ return identifier == ast_value_factory()->async_string();
+ }
+
V8_INLINE bool IsArguments(const AstRawString* identifier) const {
return identifier == ast_value_factory()->arguments_string();
}
@@ -606,7 +582,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// inside a variable proxy). We exclude the case of 'this', which
// has been converted to a variable proxy.
V8_INLINE static bool IsIdentifier(Expression* expression) {
- DCHECK_NOT_NULL(expression);
VariableProxy* operand = expression->AsVariableProxy();
return operand != nullptr && !operand->is_this() &&
!operand->is_new_target();
@@ -646,14 +621,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return string->AsArrayIndex(index);
}
- V8_INLINE bool IsUseStrictDirective(Statement* statement) const {
- return IsStringLiteral(statement, ast_value_factory()->use_strict_string());
- }
-
- V8_INLINE bool IsUseAsmDirective(Statement* statement) const {
- return IsStringLiteral(statement, ast_value_factory()->use_asm_string());
- }
-
// Returns true if the statement is an expression statement containing
// a single string literal. If a second argument is given, the literal
// is also compared with it and the result is true only if they are equal.
@@ -711,21 +678,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
}
}
- // Determine if the expression is a variable proxy and mark it as being used
- // in an assignment or with a increment/decrement operator.
- V8_INLINE static void MarkExpressionAsAssigned(Expression* expression) {
- DCHECK_NOT_NULL(expression);
- if (expression->IsVariableProxy()) {
- expression->AsVariableProxy()->set_is_assigned();
- }
- }
-
// A shortcut for performing a ToString operation
V8_INLINE Expression* ToString(Expression* expr) {
if (expr->IsStringLiteral()) return expr;
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(expr, zone());
+ ScopedPtrList<Expression> args(pointer_buffer());
+ args.Add(expr);
return factory()->NewCallRuntime(Runtime::kInlineToString, args,
expr->position());
}
@@ -752,8 +709,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
int pos);
// Generate AST node that throws a ReferenceError with the given type.
- V8_INLINE Expression* NewThrowReferenceError(
- MessageTemplate::Template message, int pos) {
+ V8_INLINE Expression* NewThrowReferenceError(MessageTemplate message,
+ int pos) {
return NewThrowError(Runtime::kNewReferenceError, message,
ast_value_factory()->empty_string(), pos);
}
@@ -761,33 +718,26 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// 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.
- V8_INLINE Expression* NewThrowSyntaxError(MessageTemplate::Template message,
+ V8_INLINE Expression* NewThrowSyntaxError(MessageTemplate message,
const AstRawString* arg, int pos) {
return NewThrowError(Runtime::kNewSyntaxError, message, arg, pos);
}
// Generate AST node that throws a TypeError with the given
// type. Both arguments must be non-null (in the handle sense).
- V8_INLINE Expression* NewThrowTypeError(MessageTemplate::Template message,
+ V8_INLINE Expression* NewThrowTypeError(MessageTemplate message,
const AstRawString* arg, int pos) {
return NewThrowError(Runtime::kNewTypeError, message, arg, pos);
}
// Reporting errors.
void ReportMessageAt(Scanner::Location source_location,
- MessageTemplate::Template message,
- const char* arg = nullptr,
+ MessageTemplate message, const char* arg = nullptr,
ParseErrorType error_type = kSyntaxError) {
- if (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;
- }
pending_error_handler()->ReportMessageAt(source_location.beg_pos,
source_location.end_pos, message,
arg, error_type);
+ scanner_.set_parser_error();
}
// Dummy implementation. The parser should never have a unidentifiable
@@ -795,21 +745,18 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
V8_INLINE void ReportUnidentifiableError() { UNREACHABLE(); }
void ReportMessageAt(Scanner::Location source_location,
- MessageTemplate::Template message,
- const AstRawString* arg,
+ MessageTemplate message, const AstRawString* arg,
ParseErrorType error_type = kSyntaxError) {
- if (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;
- }
pending_error_handler()->ReportMessageAt(source_location.beg_pos,
source_location.end_pos, message,
arg, error_type);
+ scanner_.set_parser_error();
}
+ void ReportUnexpectedTokenAt(
+ Scanner::Location location, Token::Value token,
+ MessageTemplate message = MessageTemplate::kUnexpectedToken);
+
// "null" return type creators.
V8_INLINE static std::nullptr_t NullIdentifier() { return nullptr; }
V8_INLINE static std::nullptr_t NullExpression() { return nullptr; }
@@ -821,6 +768,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return nullptr;
}
V8_INLINE static std::nullptr_t NullStatement() { return nullptr; }
+ V8_INLINE static std::nullptr_t NullBlock() { return nullptr; }
+ Expression* FailureExpression() { return factory()->FailureExpression(); }
template <typename T>
V8_INLINE static bool IsNull(T subject) {
@@ -860,7 +809,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* NewTargetExpression(int pos);
Expression* ImportMetaExpression(int pos);
- Literal* ExpressionFromLiteral(Token::Value token, int pos);
+ Expression* ExpressionFromLiteral(Token::Value token, int pos);
V8_INLINE VariableProxy* ExpressionFromIdentifier(
const AstRawString* name, int start_position,
@@ -868,13 +817,12 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
if (infer == InferName::kYes) {
fni_.PushVariableName(name);
}
- return NewUnresolved(name, start_position);
+ return expression_scope()->NewVariable(name, start_position);
}
- V8_INLINE Expression* ExpressionFromString(int pos) {
- const AstRawString* symbol = GetSymbol();
- fni_.PushLiteralName(symbol);
- return factory()->NewStringLiteral(symbol, pos);
+ V8_INLINE Variable* DeclareCatchVariableName(Scope* scope,
+ const AstRawString* name) {
+ return scope->DeclareCatchVariableName(name);
}
V8_INLINE ZonePtrList<Expression>* NewExpressionList(int size) const {
@@ -892,9 +840,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return new (zone()) ZonePtrList<Statement>(size, zone());
}
- V8_INLINE Expression* NewV8Intrinsic(const AstRawString* name,
- ZonePtrList<Expression>* args, int pos,
- bool* ok);
+ Expression* NewV8Intrinsic(const AstRawString* name,
+ const ScopedPtrList<Expression>& args, int pos);
V8_INLINE Statement* NewThrowStatement(Expression* exception, int pos) {
return factory()->NewExpressionStatement(
@@ -907,44 +854,37 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
int initializer_end_position,
bool is_rest) {
parameters->UpdateArityAndFunctionLength(initializer != nullptr, is_rest);
- bool has_simple_name = pattern->IsVariableProxy() && initializer == nullptr;
- const AstRawString* name = has_simple_name
- ? pattern->AsVariableProxy()->raw_name()
- : ast_value_factory()->empty_string();
auto parameter = new (parameters->scope->zone())
- ParserFormalParameters::Parameter(name, pattern, initializer,
+ ParserFormalParameters::Parameter(pattern, initializer,
scanner()->location().beg_pos,
initializer_end_position, is_rest);
parameters->params.Add(parameter);
}
- V8_INLINE void DeclareFormalParameters(
- DeclarationScope* scope,
- const base::ThreadedList<ParserFormalParameters::Parameter>& parameters,
- bool is_simple, bool* has_duplicate = nullptr) {
- if (!is_simple) scope->SetHasNonSimpleParameters();
- for (auto parameter : parameters) {
- bool is_optional = parameter->initializer != nullptr;
+ V8_INLINE void DeclareFormalParameters(ParserFormalParameters* parameters) {
+ bool is_simple = parameters->is_simple;
+ DeclarationScope* scope = parameters->scope;
+ if (!is_simple) scope->MakeParametersNonSimple();
+ for (auto parameter : parameters->params) {
+ bool is_optional = parameter->initializer() != nullptr;
// If the parameter list is simple, declare the parameters normally with
// their names. If the parameter list is not simple, declare a temporary
// for each parameter - the corresponding named variable is declared by
// BuildParamerterInitializationBlock.
scope->DeclareParameter(
- is_simple ? parameter->name : ast_value_factory()->empty_string(),
+ is_simple ? parameter->name() : ast_value_factory()->empty_string(),
is_simple ? VariableMode::kVar : VariableMode::kTemporary,
- is_optional, parameter->is_rest, has_duplicate, ast_value_factory(),
+ is_optional, parameter->is_rest(), ast_value_factory(),
parameter->position);
}
}
- void DeclareArrowFunctionFormalParameters(ParserFormalParameters* parameters,
- Expression* params,
- const Scanner::Location& params_loc,
- Scanner::Location* duplicate_loc,
- bool* ok);
+ void DeclareArrowFunctionFormalParameters(
+ ParserFormalParameters* parameters, Expression* params,
+ const Scanner::Location& params_loc);
- Expression* ExpressionListToExpression(ZonePtrList<Expression>* args);
+ Expression* ExpressionListToExpression(const ScopedPtrList<Expression>& args);
void SetFunctionNameFromPropertyName(LiteralProperty* property,
const AstRawString* name,
@@ -956,11 +896,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void SetFunctionNameFromIdentifierRef(Expression* value,
Expression* identifier);
- V8_INLINE ZoneList<typename ExpressionClassifier::Error>*
- GetReportedErrorList() const {
- return function_state_->GetReportedErrorList();
- }
-
V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) {
++use_counts_[feature];
}
@@ -1091,9 +1026,21 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
node, new (zone()) TryFinallyStatementSourceRanges(body_range));
}
+ // Generate the next internal variable name for binding an exported namespace
+ // object (used to implement the "export * as" syntax).
+ const AstRawString* NextInternalNamespaceExportName();
+
+ ParseInfo* info() const { return info_; }
+
+ std::vector<uint8_t>* preparse_data_buffer() {
+ return &preparse_data_buffer_;
+ }
+
// Parser's private field members.
friend class PreParserZoneScope; // Uses reusable_preparser().
+ friend class PreparseDataBuilder; // Uses preparse_data_buffer()
+ ParseInfo* info_;
Scanner scanner_;
Zone preparser_zone_;
PreParser* reusable_preparser_;
@@ -1107,13 +1054,17 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ScriptCompiler::CompileOptions compile_options_;
+ // For NextInternalNamespaceExportName().
+ int number_of_named_namespace_exports_ = 0;
+
// Other information which will be stored in Parser and moved to Isolate after
// parsing.
int use_counts_[v8::Isolate::kUseCounterFeatureCount];
int total_preparse_skipped_;
bool allow_lazy_;
bool temp_zoned_;
- ConsumedPreParsedScopeData* consumed_preparsed_scope_data_;
+ ConsumedPreparseData* consumed_preparse_data_;
+ std::vector<uint8_t> preparse_data_buffer_;
// If not kNoSourcePosition, indicates that the first function literal
// encountered is a dynamic function, see CreateDynamicFunction(). This field
diff --git a/deps/v8/src/parsing/parsing.cc b/deps/v8/src/parsing/parsing.cc
index 378023cbeb..7ff080b2f9 100644
--- a/deps/v8/src/parsing/parsing.cc
+++ b/deps/v8/src/parsing/parsing.cc
@@ -42,7 +42,6 @@ bool ParseProgram(ParseInfo* info, Isolate* isolate) {
info->pending_error_handler()->ReportErrors(isolate, info->script(),
info->ast_value_factory());
} else {
- result->scope()->AttachOuterScopeInfo(info, isolate);
info->set_language_mode(info->literal()->language_mode());
if (info->is_eval()) {
info->set_allow_eval_cache(parser.allow_eval_cache());
@@ -80,7 +79,7 @@ bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
info->pending_error_handler()->ReportErrors(isolate, info->script(),
info->ast_value_factory());
} else {
- result->scope()->AttachOuterScopeInfo(info, isolate);
+ info->ast_value_factory()->Internalize(isolate);
if (info->is_eval()) {
info->set_allow_eval_cache(parser.allow_eval_cache());
}
diff --git a/deps/v8/src/parsing/pattern-rewriter.cc b/deps/v8/src/parsing/pattern-rewriter.cc
index 4465670a8f..0ef570ee52 100644
--- a/deps/v8/src/parsing/pattern-rewriter.cc
+++ b/deps/v8/src/parsing/pattern-rewriter.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "src/ast/ast.h"
-#include "src/messages.h"
+#include "src/message-template.h"
#include "src/objects-inl.h"
#include "src/parsing/expression-scope-reparenter.h"
#include "src/parsing/parser.h"
@@ -12,314 +12,108 @@ namespace v8 {
namespace internal {
+// An AST visitor which performs declaration and assignment related tasks,
+// particularly for destructuring patterns:
+//
+// 1. Declares variables from variable proxies (particularly for destructuring
+// declarations),
+// 2. Marks destructuring-assigned variable proxies as assigned, and
+// 3. Rewrites scopes for parameters containing a sloppy eval.
+//
+// Historically this also rewrote destructuring assignments/declarations as a
+// block of multiple assignments, hence the named, however this is now done
+// during bytecode generation.
+//
+// TODO(leszeks): Rename or remove this class
class PatternRewriter final : public AstVisitor<PatternRewriter> {
public:
- // 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
-
typedef Parser::DeclarationDescriptor DeclarationDescriptor;
- static void DeclareAndInitializeVariables(
- Parser* parser, Block* block,
- const DeclarationDescriptor* declaration_descriptor,
- const Parser::DeclarationParsingResult::Declaration* declaration,
- ZonePtrList<const AstRawString>* names, bool* ok);
-
- static Expression* RewriteDestructuringAssignment(Parser* parser,
- Assignment* to_rewrite,
- Scope* scope);
+ static void InitializeVariables(
+ Parser* parser, VariableKind kind,
+ const Parser::DeclarationParsingResult::Declaration* declaration);
private:
- enum PatternContext : uint8_t { BINDING, ASSIGNMENT };
-
- PatternRewriter(Scope* scope, Parser* parser, PatternContext context,
- const DeclarationDescriptor* descriptor = nullptr,
- ZonePtrList<const AstRawString>* names = nullptr,
- int initializer_position = kNoSourcePosition,
- int value_beg_position = kNoSourcePosition,
- bool declares_parameter_containing_sloppy_eval = false)
- : scope_(scope),
- parser_(parser),
- block_(nullptr),
- descriptor_(descriptor),
- names_(names),
- current_value_(nullptr),
- ok_(nullptr),
+ PatternRewriter(Parser* parser, VariableKind kind, int initializer_position,
+ bool declares_parameter_containing_sloppy_eval)
+ : parser_(parser),
initializer_position_(initializer_position),
- value_beg_position_(value_beg_position),
- context_(context),
declares_parameter_containing_sloppy_eval_(
- declares_parameter_containing_sloppy_eval),
- recursion_level_(0) {}
+ declares_parameter_containing_sloppy_eval) {}
#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node);
// Visiting functions for AST nodes make this an AstVisitor.
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
- PatternContext context() const { return context_; }
-
- void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
- Expression* old_value = current_value_;
- current_value_ = value;
- recursion_level_++;
- Visit(pattern);
- recursion_level_--;
- current_value_ = old_value;
- }
-
- Expression* Rewrite(Assignment* assign) {
+ Expression* Visit(Assignment* assign) {
+ if (parser_->has_error()) return parser_->FailureExpression();
DCHECK_EQ(Token::ASSIGN, assign->op());
- int pos = assign->position();
- DCHECK_NULL(block_);
- block_ = factory()->NewBlock(8, true);
- Variable* temp = nullptr;
Expression* pattern = assign->target();
- Expression* old_value = current_value_;
- current_value_ = assign->value();
if (pattern->IsObjectLiteral()) {
- VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
+ VisitObjectLiteral(pattern->AsObjectLiteral());
} else {
DCHECK(pattern->IsArrayLiteral());
- VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
+ VisitArrayLiteral(pattern->AsArrayLiteral());
}
- DCHECK_NOT_NULL(temp);
- current_value_ = old_value;
- return factory()->NewDoExpression(block_, temp, pos);
+ return assign;
}
- void VisitObjectLiteral(ObjectLiteral* node, Variable** temp_var);
- void VisitArrayLiteral(ArrayLiteral* node, Variable** temp_var);
-
- bool IsBindingContext() const { return context_ == BINDING; }
- bool IsAssignmentContext() const { return context_ == ASSIGNMENT; }
- bool IsSubPattern() const { return recursion_level_ > 1; }
-
void RewriteParameterScopes(Expression* expr);
- Variable* CreateTempVar(Expression* value = nullptr);
+ Scope* scope() const { return parser_->scope(); }
- 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* const scope_;
Parser* const parser_;
- Block* block_;
- const DeclarationDescriptor* descriptor_;
- ZonePtrList<const AstRawString>* names_;
- Expression* current_value_;
- bool* ok_;
const int initializer_position_;
- const int value_beg_position_;
- PatternContext context_;
- const bool declares_parameter_containing_sloppy_eval_ : 1;
- int recursion_level_;
+ const bool declares_parameter_containing_sloppy_eval_;
DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};
-void Parser::DeclareAndInitializeVariables(
- Block* block, const DeclarationDescriptor* declaration_descriptor,
- const DeclarationParsingResult::Declaration* declaration,
- ZonePtrList<const AstRawString>* names, bool* ok) {
- PatternRewriter::DeclareAndInitializeVariables(
- this, block, declaration_descriptor, declaration, names, ok);
-}
-
-void Parser::RewriteDestructuringAssignment(RewritableExpression* to_rewrite) {
- DCHECK(!to_rewrite->is_rewritten());
- Assignment* assignment = to_rewrite->expression()->AsAssignment();
- Expression* result = PatternRewriter::RewriteDestructuringAssignment(
- this, assignment, scope());
- to_rewrite->Rewrite(result);
-}
-
-Expression* Parser::RewriteDestructuringAssignment(Assignment* assignment) {
- DCHECK_NOT_NULL(assignment);
- DCHECK_EQ(Token::ASSIGN, assignment->op());
- return PatternRewriter::RewriteDestructuringAssignment(this, assignment,
- scope());
-}
-
-void PatternRewriter::DeclareAndInitializeVariables(
- Parser* parser, Block* block,
- const DeclarationDescriptor* declaration_descriptor,
- const Parser::DeclarationParsingResult::Declaration* declaration,
- ZonePtrList<const AstRawString>* names, bool* ok) {
- DCHECK(block->ignore_completion_value());
-
- Scope* scope = declaration_descriptor->scope;
- PatternRewriter rewriter(scope, parser, BINDING, declaration_descriptor,
- names, declaration->initializer_position,
- declaration->value_beg_position,
- declaration_descriptor->declaration_kind ==
- DeclarationDescriptor::PARAMETER &&
- scope->is_block_scope());
- rewriter.block_ = block;
- rewriter.ok_ = ok;
-
- rewriter.RecurseIntoSubpattern(declaration->pattern,
- declaration->initializer);
-}
-
-Expression* PatternRewriter::RewriteDestructuringAssignment(
- Parser* parser, Assignment* to_rewrite, Scope* scope) {
- DCHECK(!scope->HasBeenRemoved());
-
- PatternRewriter rewriter(scope, parser, ASSIGNMENT);
- return rewriter.Rewrite(to_rewrite);
-}
-
-void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
- Expression* value = current_value_;
+void Parser::InitializeVariables(
+ ScopedPtrList<Statement>* statements, VariableKind kind,
+ const DeclarationParsingResult::Declaration* declaration) {
+ if (has_error()) return;
- 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());
+ if (!declaration->initializer) {
+ // The parameter scope is only a block scope if the initializer calls sloppy
+ // eval. Since there is no initializer, we can't be calling sloppy eval.
+ DCHECK_IMPLIES(kind == PARAMETER_VARIABLE, scope()->is_function_scope());
return;
}
- DCHECK_NOT_NULL(block_);
- DCHECK_NOT_NULL(descriptor_);
- DCHECK_NOT_NULL(ok_);
-
- Scope* outer_function_scope = nullptr;
- bool success;
- if (declares_parameter_containing_sloppy_eval_) {
- outer_function_scope = scope()->outer_scope();
- success = outer_function_scope->RemoveUnresolved(pattern);
- } else {
- success = scope()->RemoveUnresolved(pattern);
- }
- USE(success);
- DCHECK(success);
-
- // 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).
- const AstRawString* name = pattern->raw_name();
- VariableProxy* proxy = pattern;
- Declaration* declaration;
- if (descriptor_->mode == VariableMode::kVar &&
- !scope()->is_declaration_scope()) {
- DCHECK(scope()->is_block_scope() || scope()->is_with_scope());
- declaration = factory()->NewNestedVariableDeclaration(
- proxy, scope(), descriptor_->declaration_pos);
- } else {
- declaration =
- factory()->NewVariableDeclaration(proxy, descriptor_->declaration_pos);
- }
-
- // When an extra declaration scope needs to be inserted to account for
- // a sloppy eval in a default parameter or function body, the parameter
- // needs to be declared in the function's scope, not in the varblock
- // scope which will be used for the initializer expression.
- Variable* var = parser_->Declare(
- declaration, descriptor_->declaration_kind, descriptor_->mode,
- Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
- outer_function_scope);
- if (!*ok_) return;
- DCHECK_NOT_NULL(var);
- DCHECK(proxy->is_resolved());
- DCHECK_NE(initializer_position_, kNoSourcePosition);
- var->set_initializer_position(initializer_position_);
-
- Scope* declaration_scope = outer_function_scope != nullptr
- ? outer_function_scope
- : (IsLexicalVariableMode(descriptor_->mode)
- ? scope()
- : scope()->GetDeclarationScope());
- if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
- parser_->ReportMessage(MessageTemplate::kTooManyVariables);
- *ok_ = false;
- return;
- }
- if (names_) {
- names_->Add(name, zone());
- }
-
- // If there's no initializer, we're done.
- if (value == nullptr) return;
-
- Scope* var_init_scope = scope();
- Parser::MarkLoopVariableAsAssigned(var_init_scope, proxy->var(),
- descriptor_->declaration_kind);
-
- // A declaration of the form:
- //
- // var v = x;
- //
- // is syntactic sugar for:
- //
- // var v; v = x;
- //
- // In particular, we need to re-lookup 'v' if it may be a different 'v' than
- // the 'v' in the declaration (e.g., if we are inside a 'with' statement or
- // 'catch' block).
-
- // For 'let' and 'const' declared variables the initialization always assigns
- // to the declared variable. But for var declarations that target a different
- // scope we need to do a new lookup.
- if (descriptor_->mode == VariableMode::kVar &&
- var_init_scope != declaration_scope) {
- proxy = var_init_scope->NewUnresolved(factory(), name);
- } else {
- DCHECK_NOT_NULL(proxy);
- DCHECK_NOT_NULL(proxy->var());
- }
- // Add break location for destructured sub-pattern.
- int pos = value_beg_position_;
+ PatternRewriter::InitializeVariables(this, kind, declaration);
+ int pos = declaration->value_beg_position;
if (pos == kNoSourcePosition) {
- pos = IsSubPattern() ? pattern->position() : value->position();
+ pos = declaration->initializer_position;
}
- Assignment* assignment =
- factory()->NewAssignment(Token::INIT, proxy, value, pos);
- block_->statements()->Add(factory()->NewExpressionStatement(assignment, pos),
- zone());
+ Assignment* assignment = factory()->NewAssignment(
+ Token::INIT, declaration->pattern, declaration->initializer, pos);
+ statements->Add(factory()->NewExpressionStatement(assignment, pos));
}
-Variable* 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,
- kNoSourcePosition);
+void PatternRewriter::InitializeVariables(
+ Parser* parser, VariableKind kind,
+ const Parser::DeclarationParsingResult::Declaration* declaration) {
+ PatternRewriter rewriter(
+ parser, kind, declaration->initializer_position,
+ kind == PARAMETER_VARIABLE && parser->scope()->is_block_scope());
- block_->statements()->Add(
- factory()->NewExpressionStatement(assignment, kNoSourcePosition),
- zone());
- }
- return temp;
+ rewriter.Visit(declaration->pattern);
}
-void PatternRewriter::VisitRewritableExpression(RewritableExpression* node) {
- DCHECK(node->expression()->IsAssignment());
- // This is not a top-level destructuring assignment. Mark the node as
- // rewritten to prevent redundant rewriting and visit the underlying
- // expression.
- DCHECK(!node->is_rewritten());
- node->set_rewritten();
- return Visit(node->expression());
+void PatternRewriter::VisitVariableProxy(VariableProxy* proxy) {
+ DCHECK(!parser_->has_error());
+ Variable* var =
+ proxy->is_resolved()
+ ? proxy->var()
+ : scope()->GetDeclarationScope()->LookupLocal(proxy->raw_name());
+
+ DCHECK_NOT_NULL(var);
+
+ DCHECK_NE(initializer_position_, kNoSourcePosition);
+ var->set_initializer_position(initializer_position_);
}
// When an extra declaration scope needs to be inserted to account for
@@ -332,378 +126,35 @@ void PatternRewriter::RewriteParameterScopes(Expression* expr) {
}
}
-void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
- Variable** temp_var) {
- auto temp = *temp_var = CreateTempVar(current_value_);
-
- ZonePtrList<Expression>* rest_runtime_callargs = nullptr;
- if (pattern->has_rest_property()) {
- // non_rest_properties_count = pattern->properties()->length - 1;
- // args_length = 1 + non_rest_properties_count because we need to
- // pass temp as well to the runtime function.
- int args_length = pattern->properties()->length();
- rest_runtime_callargs =
- new (zone()) ZonePtrList<Expression>(args_length, zone());
- rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
- }
-
- block_->statements()->Add(parser_->BuildAssertIsCoercible(temp, pattern),
- zone());
-
+void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
for (ObjectLiteralProperty* property : *pattern->properties()) {
- Expression* value;
-
- if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
- // var { y, [x++]: a, ...c } = temp
- // becomes
- // var y = temp.y;
- // var temp1 = %ToName(x++);
- // var a = temp[temp1];
- // var c;
- // c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
- value = factory()->NewCallRuntime(
- Runtime::kCopyDataPropertiesWithExcludedProperties,
- rest_runtime_callargs, kNoSourcePosition);
- } else {
- Expression* key = property->key();
-
- if (!key->IsLiteral()) {
- // Computed property names contain expressions which might require
- // scope rewriting.
- RewriteParameterScopes(key);
- }
-
- if (pattern->has_rest_property()) {
- Expression* excluded_property = key;
-
- if (property->is_computed_name()) {
- DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
- auto args = new (zone()) ZonePtrList<Expression>(1, zone());
- args->Add(key, zone());
- auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
- Runtime::kToName, args, kNoSourcePosition));
- key = factory()->NewVariableProxy(to_name_key);
- excluded_property = factory()->NewVariableProxy(to_name_key);
- } else {
- DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
- }
-
- DCHECK_NOT_NULL(rest_runtime_callargs);
- rest_runtime_callargs->Add(excluded_property, zone());
- }
-
- value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
- kNoSourcePosition);
+ Expression* key = property->key();
+ if (!key->IsLiteral()) {
+ // Computed property names contain expressions which might require
+ // scope rewriting.
+ RewriteParameterScopes(key);
}
-
- RecurseIntoSubpattern(property->value(), value);
+ Visit(property->value());
}
}
-void PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
- Variable* temp_var = nullptr;
- VisitObjectLiteral(node, &temp_var);
-}
-
-void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
- Variable** temp_var) {
- DCHECK(block_->ignore_completion_value());
-
- auto temp = *temp_var = CreateTempVar(current_value_);
- auto iterator = CreateTempVar(factory()->NewGetIterator(
- factory()->NewVariableProxy(temp), current_value_, IteratorType::kNormal,
- current_value_->position()));
- auto next = CreateTempVar(factory()->NewProperty(
- factory()->NewVariableProxy(iterator),
- factory()->NewStringLiteral(ast_value_factory()->next_string(),
- kNoSourcePosition),
- kNoSourcePosition));
- auto done =
- CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
- auto result = CreateTempVar();
- auto v = CreateTempVar();
- auto completion = CreateTempVar();
- auto nopos = kNoSourcePosition;
-
- // For the purpose of iterator finalization, we temporarily set block_ to a
- // new block. In the main body of this function, we write to block_ (both
- // explicitly and implicitly via recursion). At the end of the function, we
- // wrap this new block in a try-finally statement, restore block_ to its
- // original value, and add the try-finally statement to block_.
- auto target = block_;
- block_ = factory()->NewBlock(8, true);
-
- Spread* spread = nullptr;
+void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
for (Expression* value : *node->values()) {
- if (value->IsSpread()) {
- spread = value->AsSpread();
- break;
- }
-
- // if (!done) {
- // done = true; // If .next, .done or .value throws, don't close.
- // result = IteratorNext(iterator);
- // if (result.done) {
- // v = undefined;
- // } else {
- // v = result.value;
- // done = false;
- // }
- // }
- Statement* if_not_done;
- {
- auto result_done = factory()->NewProperty(
- factory()->NewVariableProxy(result),
- factory()->NewStringLiteral(ast_value_factory()->done_string(),
- kNoSourcePosition),
- kNoSourcePosition);
-
- auto assign_undefined = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(v),
- factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
-
- auto assign_value = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(v),
- factory()->NewProperty(
- factory()->NewVariableProxy(result),
- factory()->NewStringLiteral(ast_value_factory()->value_string(),
- kNoSourcePosition),
- kNoSourcePosition),
- kNoSourcePosition);
-
- auto unset_done = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(done),
- factory()->NewBooleanLiteral(false, kNoSourcePosition),
- kNoSourcePosition);
-
- auto inner_else = factory()->NewBlock(2, true);
- inner_else->statements()->Add(
- factory()->NewExpressionStatement(assign_value, nopos), zone());
- inner_else->statements()->Add(
- factory()->NewExpressionStatement(unset_done, nopos), zone());
-
- auto inner_if = factory()->NewIfStatement(
- result_done,
- factory()->NewExpressionStatement(assign_undefined, nopos),
- inner_else, nopos);
-
- auto next_block = factory()->NewBlock(3, true);
- next_block->statements()->Add(
- factory()->NewExpressionStatement(
- factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(done),
- factory()->NewBooleanLiteral(true, nopos), nopos),
- nopos),
- zone());
- next_block->statements()->Add(
- factory()->NewExpressionStatement(
- parser_->BuildIteratorNextResult(
- factory()->NewVariableProxy(iterator),
- factory()->NewVariableProxy(next), result,
- IteratorType::kNormal, kNoSourcePosition),
- kNoSourcePosition),
- zone());
- next_block->statements()->Add(inner_if, zone());
-
- if_not_done = factory()->NewIfStatement(
- factory()->NewUnaryOperation(
- Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
- next_block, factory()->NewEmptyStatement(kNoSourcePosition),
- kNoSourcePosition);
- }
- block_->statements()->Add(if_not_done, zone());
-
- if (!value->IsTheHoleLiteral()) {
- {
- // completion = kAbruptCompletion;
- Expression* proxy = factory()->NewVariableProxy(completion);
- Expression* assignment = factory()->NewAssignment(
- Token::ASSIGN, proxy,
- factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
- block_->statements()->Add(
- factory()->NewExpressionStatement(assignment, nopos), zone());
- }
-
- RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
-
- {
- // completion = kNormalCompletion;
- Expression* proxy = factory()->NewVariableProxy(completion);
- Expression* assignment = factory()->NewAssignment(
- Token::ASSIGN, proxy,
- factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
- block_->statements()->Add(
- factory()->NewExpressionStatement(assignment, nopos), zone());
- }
- }
- }
-
- if (spread != nullptr) {
- // A spread can only occur as the last component. It is not handled by
- // RecurseIntoSubpattern above.
-
- // let array = [];
- // let index = 0;
- // while (!done) {
- // done = true; // If .next, .done or .value throws, don't close.
- // result = IteratorNext(iterator);
- // if (!result.done) {
- // StoreInArrayLiteral(array, index, result.value);
- // done = false;
- // }
- // index++;
- // }
-
- // let array = [];
- Variable* array;
- {
- auto empty_exprs = new (zone()) ZonePtrList<Expression>(0, zone());
- array = CreateTempVar(
- factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
- }
-
- // let index = 0;
- Variable* index =
- CreateTempVar(factory()->NewSmiLiteral(0, kNoSourcePosition));
-
- // done = true;
- Statement* set_done = factory()->NewExpressionStatement(
- factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(done),
- factory()->NewBooleanLiteral(true, nopos), nopos),
- nopos);
-
- // result = IteratorNext(iterator);
- Statement* get_next = factory()->NewExpressionStatement(
- parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
- factory()->NewVariableProxy(next),
- result, IteratorType::kNormal, nopos),
- nopos);
-
- // StoreInArrayLiteral(array, index, result.value);
- Statement* store;
- {
- auto value = factory()->NewProperty(
- factory()->NewVariableProxy(result),
- factory()->NewStringLiteral(ast_value_factory()->value_string(),
- nopos),
- nopos);
- store = factory()->NewExpressionStatement(
- factory()->NewStoreInArrayLiteral(factory()->NewVariableProxy(array),
- factory()->NewVariableProxy(index),
- value, nopos),
- nopos);
- }
-
- // done = false;
- Statement* unset_done = factory()->NewExpressionStatement(
- factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(done),
- factory()->NewBooleanLiteral(false, nopos), nopos),
- nopos);
-
- // if (!result.done) { #store; #unset_done }
- Statement* maybe_store_and_unset_done;
- {
- Expression* result_done =
- factory()->NewProperty(factory()->NewVariableProxy(result),
- factory()->NewStringLiteral(
- ast_value_factory()->done_string(), nopos),
- nopos);
-
- Block* then = factory()->NewBlock(2, true);
- then->statements()->Add(store, zone());
- then->statements()->Add(unset_done, zone());
-
- maybe_store_and_unset_done = factory()->NewIfStatement(
- factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
- factory()->NewEmptyStatement(nopos), nopos);
- }
-
- // index++;
- Statement* increment_index;
- {
- increment_index = factory()->NewExpressionStatement(
- factory()->NewCountOperation(
- Token::INC, false, factory()->NewVariableProxy(index), nopos),
- nopos);
- }
-
- // while (!done) {
- // #set_done;
- // #get_next;
- // #maybe_store_and_unset_done;
- // #increment_index;
- // }
- WhileStatement* loop =
- factory()->NewWhileStatement(nullptr, nullptr, nopos);
- {
- Expression* condition = factory()->NewUnaryOperation(
- Token::NOT, factory()->NewVariableProxy(done), nopos);
- Block* body = factory()->NewBlock(4, true);
- body->statements()->Add(set_done, zone());
- body->statements()->Add(get_next, zone());
- body->statements()->Add(maybe_store_and_unset_done, zone());
- body->statements()->Add(increment_index, zone());
- loop->Initialize(condition, body);
- }
-
- block_->statements()->Add(loop, zone());
- RecurseIntoSubpattern(spread->expression(),
- factory()->NewVariableProxy(array));
+ if (value->IsTheHoleLiteral()) continue;
+ Visit(value);
}
-
- Expression* closing_condition = factory()->NewUnaryOperation(
- Token::NOT, factory()->NewVariableProxy(done), nopos);
-
- parser_->FinalizeIteratorUse(completion, closing_condition, iterator, block_,
- target, IteratorType::kNormal);
- block_ = target;
-}
-
-void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
- Variable* temp_var = nullptr;
- VisitArrayLiteral(node, &temp_var);
}
void 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_);
-
- Expression* is_undefined = factory()->NewCompareOperation(
- Token::EQ_STRICT, factory()->NewVariableProxy(temp),
- factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
- value = factory()->NewConditional(is_undefined, initializer,
- factory()->NewVariableProxy(temp),
- kNoSourcePosition);
-
// Initializer may have been parsed in the wrong scope.
- RewriteParameterScopes(initializer);
-
- RecurseIntoSubpattern(node->target(), value);
-}
-
-
-// =============== AssignmentPattern only ==================
-
-void PatternRewriter::VisitProperty(v8::internal::Property* node) {
- DCHECK(IsAssignmentContext());
- auto value = current_value_;
-
- Assignment* assignment =
- factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
+ RewriteParameterScopes(node->value());
- block_->statements()->Add(
- factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
+ Visit(node->target());
}
+void PatternRewriter::VisitSpread(Spread* node) { Visit(node->expression()); }
// =============== UNREACHABLE =============================
@@ -734,17 +185,16 @@ NOT_A_PATTERN(ForOfStatement)
NOT_A_PATTERN(ForStatement)
NOT_A_PATTERN(FunctionDeclaration)
NOT_A_PATTERN(FunctionLiteral)
-NOT_A_PATTERN(GetIterator)
NOT_A_PATTERN(GetTemplateObject)
NOT_A_PATTERN(IfStatement)
NOT_A_PATTERN(ImportCallExpression)
NOT_A_PATTERN(Literal)
NOT_A_PATTERN(NativeFunctionLiteral)
+NOT_A_PATTERN(Property)
NOT_A_PATTERN(RegExpLiteral)
NOT_A_PATTERN(ResolvedProperty)
NOT_A_PATTERN(ReturnStatement)
NOT_A_PATTERN(SloppyBlockFunctionStatement)
-NOT_A_PATTERN(Spread)
NOT_A_PATTERN(StoreInArrayLiteral)
NOT_A_PATTERN(SuperPropertyReference)
NOT_A_PATTERN(SuperCallReference)
@@ -761,7 +211,7 @@ NOT_A_PATTERN(WithStatement)
NOT_A_PATTERN(Yield)
NOT_A_PATTERN(YieldStar)
NOT_A_PATTERN(Await)
-NOT_A_PATTERN(InitializeClassFieldsStatement)
+NOT_A_PATTERN(InitializeClassMembersStatement)
#undef NOT_A_PATTERN
} // namespace internal
diff --git a/deps/v8/src/parsing/preparse-data-impl.h b/deps/v8/src/parsing/preparse-data-impl.h
new file mode 100644
index 0000000000..7d1f0feed8
--- /dev/null
+++ b/deps/v8/src/parsing/preparse-data-impl.h
@@ -0,0 +1,234 @@
+// Copyright 2018 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_IMPL_H_
+#define V8_PARSING_PREPARSE_DATA_IMPL_H_
+
+#include "src/parsing/preparse-data.h"
+
+#include "src/assert-scope.h"
+
+namespace v8 {
+namespace internal {
+
+// Classes which are internal to prepared-scope-data.cc, but are exposed in
+// a header for tests.
+
+// Wraps a ZoneVector<uint8_t> to have with functions named the same as
+// PodArray<uint8_t>.
+class ZoneVectorWrapper {
+ public:
+ ZoneVectorWrapper() = default;
+ explicit ZoneVectorWrapper(ZoneVector<uint8_t>* data) : data_(data) {}
+
+ int data_length() const { return static_cast<int>(data_->size()); }
+
+ uint8_t get(int index) const { return data_->at(index); }
+
+ private:
+ ZoneVector<uint8_t>* data_ = nullptr;
+};
+
+template <class Data>
+class BaseConsumedPreparseData : public ConsumedPreparseData {
+ public:
+ class ByteData : public PreparseByteDataConstants {
+ public:
+ ByteData() {}
+
+ // Reading from the ByteData is only allowed when a ReadingScope is on the
+ // stack. This ensures that we have a DisallowHeapAllocation in place
+ // whenever ByteData holds a raw pointer into the heap.
+ class ReadingScope {
+ public:
+ ReadingScope(ByteData* consumed_data, Data data)
+ : consumed_data_(consumed_data) {
+ consumed_data->data_ = data;
+#ifdef DEBUG
+ consumed_data->has_data_ = true;
+#endif
+ }
+ explicit ReadingScope(BaseConsumedPreparseData<Data>* parent)
+ : ReadingScope(parent->scope_data_.get(), parent->GetScopeData()) {}
+ ~ReadingScope() {
+#ifdef DEBUG
+ consumed_data_->has_data_ = false;
+#endif
+ }
+
+ private:
+ ByteData* consumed_data_;
+ DISALLOW_HEAP_ALLOCATION(no_gc);
+ };
+
+ void SetPosition(int position) {
+ DCHECK_LE(position, data_.data_length());
+ index_ = position;
+ }
+
+ size_t RemainingBytes() const {
+ DCHECK(has_data_);
+ DCHECK_LE(index_, data_.data_length());
+ return data_.data_length() - index_;
+ }
+
+ bool HasRemainingBytes(size_t bytes) const {
+ DCHECK(has_data_);
+ return index_ <= data_.data_length() && bytes <= RemainingBytes();
+ }
+
+ int32_t ReadUint32() {
+ DCHECK(has_data_);
+ DCHECK(HasRemainingBytes(kUint32Size));
+ // Check that there indeed is an integer following.
+ DCHECK_EQ(data_.get(index_++), kUint32Size);
+ int32_t result = data_.get(index_) + (data_.get(index_ + 1) << 8) +
+ (data_.get(index_ + 2) << 16) +
+ (data_.get(index_ + 3) << 24);
+ index_ += 4;
+ stored_quarters_ = 0;
+ return result;
+ }
+
+ int32_t ReadVarint32() {
+ DCHECK(HasRemainingBytes(kVarintMinSize));
+ DCHECK_EQ(data_.get(index_++), kVarintMinSize);
+ int32_t value = 0;
+ bool has_another_byte;
+ unsigned shift = 0;
+ do {
+ uint8_t byte = data_.get(index_++);
+ value |= static_cast<int32_t>(byte & 0x7F) << shift;
+ shift += 7;
+ has_another_byte = byte & 0x80;
+ } while (has_another_byte);
+ DCHECK_EQ(data_.get(index_++), kVarintEndMarker);
+ stored_quarters_ = 0;
+ return value;
+ }
+
+ uint8_t ReadUint8() {
+ DCHECK(has_data_);
+ DCHECK(HasRemainingBytes(kUint8Size));
+ // Check that there indeed is a byte following.
+ DCHECK_EQ(data_.get(index_++), kUint8Size);
+ stored_quarters_ = 0;
+ return data_.get(index_++);
+ }
+
+ uint8_t ReadQuarter() {
+ DCHECK(has_data_);
+ if (stored_quarters_ == 0) {
+ DCHECK(HasRemainingBytes(kUint8Size));
+ // Check that there indeed are quarters following.
+ DCHECK_EQ(data_.get(index_++), kQuarterMarker);
+ stored_byte_ = data_.get(index_++);
+ stored_quarters_ = 4;
+ }
+ // Read the first 2 bits from stored_byte_.
+ uint8_t result = (stored_byte_ >> 6) & 3;
+ DCHECK_LE(result, 3);
+ --stored_quarters_;
+ stored_byte_ <<= 2;
+ return result;
+ }
+
+ private:
+ Data data_ = {};
+ int index_ = 0;
+ uint8_t stored_quarters_ = 0;
+ uint8_t stored_byte_ = 0;
+#ifdef DEBUG
+ bool has_data_ = false;
+#endif
+ };
+
+ BaseConsumedPreparseData() : scope_data_(new ByteData()), child_index_(0) {}
+
+ virtual Data GetScopeData() = 0;
+
+ virtual ProducedPreparseData* GetChildData(Zone* zone, int child_index) = 0;
+
+ ProducedPreparseData* GetDataForSkippableFunction(
+ Zone* zone, int start_position, int* end_position, int* num_parameters,
+ int* num_inner_functions, bool* uses_super_property,
+ LanguageMode* language_mode) final;
+
+ void RestoreScopeAllocationData(DeclarationScope* scope) final;
+
+#ifdef DEBUG
+ bool VerifyDataStart();
+#endif
+
+ private:
+ void RestoreDataForScope(Scope* scope);
+ void RestoreDataForVariable(Variable* var);
+ void RestoreDataForInnerScopes(Scope* scope);
+
+ std::unique_ptr<ByteData> scope_data_;
+ // When consuming the data, these indexes point to the data we're going to
+ // consume next.
+ int child_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseConsumedPreparseData);
+};
+
+// Implementation of ConsumedPreparseData for on-heap data.
+class OnHeapConsumedPreparseData final
+ : public BaseConsumedPreparseData<PreparseData> {
+ public:
+ OnHeapConsumedPreparseData(Isolate* isolate, Handle<PreparseData> data);
+
+ PreparseData GetScopeData() final;
+ ProducedPreparseData* GetChildData(Zone* zone, int child_index) final;
+
+ private:
+ Isolate* isolate_;
+ Handle<PreparseData> data_;
+};
+
+// A serialized PreparseData in zone memory (as apposed to being on-heap).
+class ZonePreparseData : public ZoneObject {
+ public:
+ ZonePreparseData(Zone* zone, Vector<uint8_t>* byte_data, int child_length);
+
+ Handle<PreparseData> Serialize(Isolate* isolate);
+
+ int children_length() const { return static_cast<int>(children_.size()); }
+
+ ZonePreparseData* get_child(int index) { return children_[index]; }
+
+ void set_child(int index, ZonePreparseData* child) {
+ DCHECK_NOT_NULL(child);
+ children_[index] = child;
+ }
+
+ ZoneVector<uint8_t>* byte_data() { return &byte_data_; }
+
+ private:
+ ZoneVector<uint8_t> byte_data_;
+ ZoneVector<ZonePreparseData*> children_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZonePreparseData);
+};
+
+// Implementation of ConsumedPreparseData for PreparseData
+// serialized into zone memory.
+class ZoneConsumedPreparseData final
+ : public BaseConsumedPreparseData<ZoneVectorWrapper> {
+ public:
+ ZoneConsumedPreparseData(Zone* zone, ZonePreparseData* data);
+
+ ZoneVectorWrapper GetScopeData() final;
+ ProducedPreparseData* GetChildData(Zone* zone, int child_index) final;
+
+ private:
+ ZonePreparseData* data_;
+ ZoneVectorWrapper scope_data_wrapper_;
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_PARSING_PREPARSE_DATA_IMPL_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..68986e451a
--- /dev/null
+++ b/deps/v8/src/parsing/preparse-data.cc
@@ -0,0 +1,716 @@
+// Copyright 2017 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/preparse-data.h"
+
+#include <vector>
+
+#include "src/ast/scopes.h"
+#include "src/ast/variables.h"
+#include "src/handles.h"
+#include "src/objects-inl.h"
+#include "src/objects/shared-function-info.h"
+#include "src/parsing/parser.h"
+#include "src/parsing/preparse-data-impl.h"
+#include "src/parsing/preparser.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+class ScopeCallsSloppyEvalField : public BitField8<bool, 0, 1> {};
+class InnerScopeCallsEvalField
+ : public BitField8<bool, ScopeCallsSloppyEvalField::kNext, 1> {};
+
+class VariableMaybeAssignedField : public BitField8<bool, 0, 1> {};
+class VariableContextAllocatedField
+ : public BitField8<bool, VariableMaybeAssignedField::kNext, 1> {};
+
+class HasDataField : public BitField<bool, 0, 1> {};
+class NumberOfParametersField
+ : public BitField<uint16_t, HasDataField::kNext, 16> {};
+
+class LanguageField : public BitField8<LanguageMode, 0, 1> {};
+class UsesSuperField : public BitField8<bool, LanguageField::kNext, 1> {};
+STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues);
+
+} // namespace
+
+/*
+
+ Internal data format for the backing store of PreparseDataBuilder and
+ PreparseData::scope_data (on the heap):
+
+ (Skippable function data:)
+ ------------------------------------
+ | scope_data_start (debug only) |
+ ------------------------------------
+ | data for inner function n |
+ | ... |
+ ------------------------------------
+ | data for inner function 1 |
+ | ... |
+ ------------------------------------
+ (Scope allocation data:) << scope_data_start points here in debug
+ ------------------------------------
+ magic value (debug only)
+ ------------------------------------
+ scope positions (debug only)
+ ------------------------------------
+ | scope type << only in debug |
+ | eval |
+ | ---------------------- |
+ | | data for variables | |
+ | | ... | |
+ | ---------------------- |
+ ------------------------------------
+ ------------------------------------
+ | data for inner scope m | << but not for function scopes
+ | ... |
+ ------------------------------------
+ ...
+ ------------------------------------
+ | data for inner scope 1 |
+ | ... |
+ ------------------------------------
+
+ PreparseData::child_data is an array of PreparseData objects, one
+ for each skippable inner function.
+
+ ConsumedPreparseData wraps a PreparseData and reads data from it.
+
+ */
+
+PreparseDataBuilder::PreparseDataBuilder(Zone* zone,
+ PreparseDataBuilder* parent_builder)
+ : parent_(parent_builder),
+ byte_data_(),
+ children_(zone),
+ function_scope_(nullptr),
+ num_inner_functions_(0),
+ num_inner_with_data_(0),
+ bailed_out_(false),
+ has_data_(false) {}
+
+void PreparseDataBuilder::DataGatheringScope::Start(
+ DeclarationScope* function_scope) {
+ Zone* main_zone = preparser_->main_zone();
+ builder_ = new (main_zone)
+ PreparseDataBuilder(main_zone, preparser_->preparse_data_builder());
+ preparser_->set_preparse_data_builder(builder_);
+ function_scope->set_preparse_data_builder(builder_);
+}
+
+PreparseDataBuilder::DataGatheringScope::~DataGatheringScope() {
+ if (builder_ == nullptr) return;
+ // Copy over the data from the buffer into the zone-allocated byte_data_
+ PreparseDataBuilder* parent = builder_->parent_;
+ if (parent != nullptr && builder_->HasDataForParent()) {
+ parent->children_.push_back(builder_);
+ }
+ preparser_->set_preparse_data_builder(parent);
+}
+
+#ifdef DEBUG
+void PreparseDataBuilder::ByteData::WriteUint32(uint32_t data) {
+ DCHECK(!is_finalized_);
+ byte_data_->push_back(kUint32Size);
+ byte_data_->push_back(data & 0xFF);
+ byte_data_->push_back((data >> 8) & 0xFF);
+ byte_data_->push_back((data >> 16) & 0xFF);
+ byte_data_->push_back((data >> 24) & 0xFF);
+ free_quarters_in_last_byte_ = 0;
+}
+
+void PreparseDataBuilder::ByteData::SaveCurrentSizeAtFirstUint32() {
+ CHECK(!is_finalized_);
+ uint32_t data = static_cast<uint32_t>(byte_data_->size());
+ uint8_t* start = &byte_data_->front();
+ int i = 0;
+ // Check that that position already holds an item of the expected size.
+ CHECK_GE(byte_data_->size(), kUint32Size);
+ CHECK_EQ(start[i++], kUint32Size);
+ start[i++] = data & 0xFF;
+ start[i++] = (data >> 8) & 0xFF;
+ start[i++] = (data >> 16) & 0xFF;
+ start[i++] = (data >> 24) & 0xFF;
+}
+
+int PreparseDataBuilder::ByteData::length() const {
+ CHECK(!is_finalized_);
+ return static_cast<int>(byte_data_->size());
+}
+#endif
+
+void PreparseDataBuilder::ByteData::WriteVarint32(uint32_t data) {
+#ifdef DEBUG
+ // Save expected item size in debug mode.
+ byte_data_->push_back(kVarintMinSize);
+#endif
+ // See ValueSerializer::WriteVarint.
+ do {
+ uint8_t next_byte = (data & 0x7F);
+ data >>= 7;
+ // Add continue bit.
+ if (data) next_byte |= 0x80;
+ byte_data_->push_back(next_byte & 0xFF);
+ } while (data);
+#ifdef DEBUG
+ // Save a varint marker in debug mode.
+ byte_data_->push_back(kVarintEndMarker);
+#endif
+ free_quarters_in_last_byte_ = 0;
+}
+
+void PreparseDataBuilder::ByteData::WriteUint8(uint8_t data) {
+ DCHECK(!is_finalized_);
+#ifdef DEBUG
+ // Save expected item size in debug mode.
+ byte_data_->push_back(kUint8Size);
+#endif
+ byte_data_->push_back(data);
+ free_quarters_in_last_byte_ = 0;
+}
+
+void PreparseDataBuilder::ByteData::WriteQuarter(uint8_t data) {
+ DCHECK(!is_finalized_);
+ DCHECK_LE(data, 3);
+ if (free_quarters_in_last_byte_ == 0) {
+#ifdef DEBUG
+ // Save a marker in debug mode.
+ byte_data_->push_back(kQuarterMarker);
+#endif
+ byte_data_->push_back(0);
+ free_quarters_in_last_byte_ = 3;
+ } else {
+ --free_quarters_in_last_byte_;
+ }
+
+ uint8_t shift_amount = free_quarters_in_last_byte_ * 2;
+ DCHECK_EQ(byte_data_->back() & (3 << shift_amount), 0);
+ byte_data_->back() |= (data << shift_amount);
+}
+
+void PreparseDataBuilder::ByteData::Start(std::vector<uint8_t>* buffer) {
+ DCHECK(!is_finalized_);
+ byte_data_ = buffer;
+ DCHECK_EQ(byte_data_->size(), 0);
+}
+
+void PreparseDataBuilder::ByteData::Finalize(Zone* zone) {
+ int size = static_cast<int>(byte_data_->size());
+ uint8_t* raw_zone_data =
+ static_cast<uint8_t*>(ZoneAllocationPolicy(zone).New(size));
+ memcpy(raw_zone_data, &byte_data_->front(), size);
+
+ byte_data_->resize(0);
+
+ zone_byte_data_ = Vector<uint8_t>(raw_zone_data, size);
+#ifdef DEBUG
+ is_finalized_ = true;
+#endif
+}
+
+void PreparseDataBuilder::DataGatheringScope::SetSkippableFunction(
+ DeclarationScope* function_scope, int num_inner_functions) {
+ DCHECK_NULL(builder_->function_scope_);
+ builder_->function_scope_ = function_scope;
+ DCHECK_EQ(builder_->num_inner_functions_, 0);
+ builder_->num_inner_functions_ = num_inner_functions;
+ builder_->parent_->has_data_ = true;
+}
+
+bool PreparseDataBuilder::HasInnerFunctions() const {
+ return !children_.is_empty();
+}
+
+bool PreparseDataBuilder::HasData() const { return !bailed_out_ && has_data_; }
+
+bool PreparseDataBuilder::HasDataForParent() const {
+ return HasData() || function_scope_ != nullptr;
+}
+
+bool PreparseDataBuilder::ScopeNeedsData(Scope* scope) {
+ if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
+ // Default constructors don't need data (they cannot contain inner functions
+ // defined by the user). Other functions do.
+ return !IsDefaultConstructor(scope->AsDeclarationScope()->function_kind());
+ }
+ if (!scope->is_hidden()) {
+ for (Variable* var : *scope->locals()) {
+ if (IsDeclaredVariableMode(var->mode())) return true;
+ }
+ }
+ for (Scope* inner = scope->inner_scope(); inner != nullptr;
+ inner = inner->sibling()) {
+ if (ScopeNeedsData(inner)) return true;
+ }
+ return false;
+}
+
+bool PreparseDataBuilder::SaveDataForSkippableFunction(
+ PreparseDataBuilder* builder) {
+ DeclarationScope* function_scope = builder->function_scope_;
+ // Start position is used for a sanity check when consuming the data, we could
+ // remove it in the future if we're very pressed for space but it's been good
+ // at catching bugs in the wild so far.
+ byte_data_.WriteVarint32(function_scope->start_position());
+ byte_data_.WriteVarint32(function_scope->end_position());
+
+ bool has_data = builder->HasData();
+ uint32_t has_data_and_num_parameters =
+ HasDataField::encode(has_data) |
+ NumberOfParametersField::encode(function_scope->num_parameters());
+ byte_data_.WriteVarint32(has_data_and_num_parameters);
+ byte_data_.WriteVarint32(builder->num_inner_functions_);
+
+ uint8_t language_and_super =
+ LanguageField::encode(function_scope->language_mode()) |
+ UsesSuperField::encode(function_scope->NeedsHomeObject());
+ byte_data_.WriteQuarter(language_and_super);
+ return has_data;
+}
+
+void PreparseDataBuilder::SaveScopeAllocationData(DeclarationScope* scope,
+ Parser* parser) {
+ if (!has_data_) return;
+ DCHECK(HasInnerFunctions());
+
+ byte_data_.Start(parser->preparse_data_buffer());
+
+#ifdef DEBUG
+ // Reserve Uint32 for scope_data_start debug info.
+ byte_data_.WriteUint32(0);
+#endif
+
+ for (const auto& builder : children_) {
+ // Keep track of functions with inner data. {children_} contains also the
+ // builders that have no inner functions at all.
+ if (SaveDataForSkippableFunction(builder)) num_inner_with_data_++;
+ }
+
+ // Don't save imcoplete scope information when bailed out.
+ if (!bailed_out_) {
+#ifdef DEBUG
+ // function data items, kSkippableMinFunctionDataSize each.
+ CHECK_GE(byte_data_.length(), kPlaceholderSize);
+ CHECK_LE(byte_data_.length(), std::numeric_limits<uint32_t>::max());
+
+ byte_data_.SaveCurrentSizeAtFirstUint32();
+ // For a data integrity check, write a value between data about skipped inner
+ // funcs and data about variables.
+ byte_data_.WriteUint32(kMagicValue);
+ byte_data_.WriteUint32(scope->start_position());
+ byte_data_.WriteUint32(scope->end_position());
+#endif
+
+ if (ScopeNeedsData(scope)) SaveDataForScope(scope);
+ }
+ byte_data_.Finalize(parser->factory()->zone());
+}
+
+void PreparseDataBuilder::SaveDataForScope(Scope* scope) {
+ DCHECK_NE(scope->end_position(), kNoSourcePosition);
+ DCHECK(ScopeNeedsData(scope));
+
+#ifdef DEBUG
+ byte_data_.WriteUint8(scope->scope_type());
+#endif
+
+ uint8_t eval =
+ ScopeCallsSloppyEvalField::encode(
+ scope->is_declaration_scope() &&
+ scope->AsDeclarationScope()->calls_sloppy_eval()) |
+ InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval());
+ byte_data_.WriteUint8(eval);
+
+ if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
+ Variable* function = scope->AsDeclarationScope()->function_var();
+ if (function != nullptr) SaveDataForVariable(function);
+ }
+
+ for (Variable* var : *scope->locals()) {
+ if (IsDeclaredVariableMode(var->mode())) SaveDataForVariable(var);
+ }
+
+ SaveDataForInnerScopes(scope);
+}
+
+void PreparseDataBuilder::SaveDataForVariable(Variable* var) {
+#ifdef DEBUG
+ // Store the variable name in debug mode; this way we can check that we
+ // restore data to the correct variable.
+ const AstRawString* name = var->raw_name();
+ byte_data_.WriteUint8(name->is_one_byte());
+ byte_data_.WriteUint32(name->length());
+ for (int i = 0; i < name->length(); ++i) {
+ byte_data_.WriteUint8(name->raw_data()[i]);
+ }
+#endif
+
+ byte variable_data = VariableMaybeAssignedField::encode(
+ var->maybe_assigned() == kMaybeAssigned) |
+ VariableContextAllocatedField::encode(
+ var->has_forced_context_allocation());
+ byte_data_.WriteQuarter(variable_data);
+}
+
+void PreparseDataBuilder::SaveDataForInnerScopes(Scope* scope) {
+ // Inner scopes are stored in the reverse order, but we'd like to write the
+ // data in the logical order. There might be many inner scopes, so we don't
+ // want to recurse here.
+ for (Scope* inner = scope->inner_scope(); inner != nullptr;
+ inner = inner->sibling()) {
+ if (ScopeIsSkippableFunctionScope(inner)) {
+ // Don't save data about function scopes, since they'll have their own
+ // PreparseDataBuilder where their data is saved.
+ DCHECK_NOT_NULL(inner->AsDeclarationScope()->preparse_data_builder());
+ continue;
+ }
+ if (!ScopeNeedsData(inner)) continue;
+ SaveDataForScope(inner);
+ }
+}
+
+bool PreparseDataBuilder::ScopeIsSkippableFunctionScope(Scope* scope) {
+ // Lazy non-arrow function scopes are skippable. Lazy functions are exactly
+ // those Scopes which have their own PreparseDataBuilder object. This
+ // logic ensures that the scope allocation data is consistent with the
+ // skippable function data (both agree on where the lazy function boundaries
+ // are).
+ if (scope->scope_type() != ScopeType::FUNCTION_SCOPE) return false;
+ DeclarationScope* declaration_scope = scope->AsDeclarationScope();
+ return !declaration_scope->is_arrow_scope() &&
+ declaration_scope->preparse_data_builder() != nullptr;
+}
+
+Handle<PreparseData> PreparseDataBuilder::ByteData::CopyToHeap(
+ Isolate* isolate, int children_length) {
+ DCHECK(is_finalized_);
+ int data_length = zone_byte_data_.length();
+ Handle<PreparseData> data =
+ isolate->factory()->NewPreparseData(data_length, children_length);
+ data->copy_in(0, zone_byte_data_.start(), data_length);
+ return data;
+}
+
+ZonePreparseData* PreparseDataBuilder::ByteData::CopyToZone(
+ Zone* zone, int children_length) {
+ DCHECK(is_finalized_);
+ return new (zone) ZonePreparseData(zone, &zone_byte_data_, children_length);
+}
+
+Handle<PreparseData> PreparseDataBuilder::Serialize(Isolate* isolate) {
+ DCHECK(HasData());
+ DCHECK(!ThisOrParentBailedOut());
+ Handle<PreparseData> data =
+ byte_data_.CopyToHeap(isolate, num_inner_with_data_);
+ int i = 0;
+ for (const auto& builder : children_) {
+ if (!builder->HasData()) continue;
+ Handle<PreparseData> child_data = builder->Serialize(isolate);
+ data->set_child(i++, *child_data);
+ }
+ DCHECK_EQ(i, data->children_length());
+ return data;
+}
+
+ZonePreparseData* PreparseDataBuilder::Serialize(Zone* zone) {
+ DCHECK(HasData());
+ DCHECK(!ThisOrParentBailedOut());
+ ZonePreparseData* data = byte_data_.CopyToZone(zone, num_inner_with_data_);
+ int i = 0;
+ for (const auto& builder : children_) {
+ if (!builder->HasData()) continue;
+ ZonePreparseData* child = builder->Serialize(zone);
+ data->set_child(i++, child);
+ }
+ DCHECK_EQ(i, data->children_length());
+ return data;
+}
+
+class BuilderProducedPreparseData final : public ProducedPreparseData {
+ public:
+ explicit BuilderProducedPreparseData(PreparseDataBuilder* builder)
+ : builder_(builder) {
+ DCHECK(builder->HasData());
+ }
+
+ Handle<PreparseData> Serialize(Isolate* isolate) final {
+ return builder_->Serialize(isolate);
+ }
+
+ ZonePreparseData* Serialize(Zone* zone) final {
+ return builder_->Serialize(zone);
+ };
+
+ private:
+ PreparseDataBuilder* builder_;
+};
+
+class OnHeapProducedPreparseData final : public ProducedPreparseData {
+ public:
+ explicit OnHeapProducedPreparseData(Handle<PreparseData> data)
+ : data_(data) {}
+
+ Handle<PreparseData> Serialize(Isolate* isolate) final {
+ DCHECK(!data_->is_null());
+ return data_;
+ }
+
+ ZonePreparseData* Serialize(Zone* zone) final {
+ // Not required.
+ UNREACHABLE();
+ };
+
+ private:
+ Handle<PreparseData> data_;
+};
+
+class ZoneProducedPreparseData final : public ProducedPreparseData {
+ public:
+ explicit ZoneProducedPreparseData(ZonePreparseData* data) : data_(data) {}
+
+ Handle<PreparseData> Serialize(Isolate* isolate) final {
+ return data_->Serialize(isolate);
+ }
+
+ ZonePreparseData* Serialize(Zone* zone) final { return data_; };
+
+ private:
+ ZonePreparseData* data_;
+};
+
+ProducedPreparseData* ProducedPreparseData::For(PreparseDataBuilder* builder,
+ Zone* zone) {
+ return new (zone) BuilderProducedPreparseData(builder);
+}
+
+ProducedPreparseData* ProducedPreparseData::For(Handle<PreparseData> data,
+ Zone* zone) {
+ return new (zone) OnHeapProducedPreparseData(data);
+}
+
+ProducedPreparseData* ProducedPreparseData::For(ZonePreparseData* data,
+ Zone* zone) {
+ return new (zone) ZoneProducedPreparseData(data);
+}
+
+template <class Data>
+ProducedPreparseData*
+BaseConsumedPreparseData<Data>::GetDataForSkippableFunction(
+ Zone* zone, int start_position, int* end_position, int* num_parameters,
+ int* num_inner_functions, bool* uses_super_property,
+ LanguageMode* language_mode) {
+ // The skippable function *must* be the next function in the data. Use the
+ // start position as a sanity check.
+ typename ByteData::ReadingScope reading_scope(this);
+ CHECK(scope_data_->HasRemainingBytes(
+ PreparseByteDataConstants::kSkippableFunctionMinDataSize));
+ int start_position_from_data = scope_data_->ReadVarint32();
+ CHECK_EQ(start_position, start_position_from_data);
+ *end_position = scope_data_->ReadVarint32();
+ DCHECK_GT(*end_position, start_position);
+
+ uint32_t has_data_and_num_parameters = scope_data_->ReadVarint32();
+ bool has_data = HasDataField::decode(has_data_and_num_parameters);
+ *num_parameters =
+ NumberOfParametersField::decode(has_data_and_num_parameters);
+ *num_inner_functions = scope_data_->ReadVarint32();
+
+ uint8_t language_and_super = scope_data_->ReadQuarter();
+ *language_mode = LanguageMode(LanguageField::decode(language_and_super));
+ *uses_super_property = UsesSuperField::decode(language_and_super);
+
+ if (!has_data) return nullptr;
+
+ // Retrieve the corresponding PreparseData and associate it to the
+ // skipped function. If the skipped functions contains inner functions, those
+ // can be skipped when the skipped function is eagerly parsed.
+ return GetChildData(zone, child_index_++);
+}
+
+template <class Data>
+void BaseConsumedPreparseData<Data>::RestoreScopeAllocationData(
+ DeclarationScope* scope) {
+ DCHECK_EQ(scope->scope_type(), ScopeType::FUNCTION_SCOPE);
+ typename ByteData::ReadingScope reading_scope(this);
+
+#ifdef DEBUG
+ int magic_value_from_data = scope_data_->ReadUint32();
+ // Check that we've consumed all inner function data.
+ DCHECK_EQ(magic_value_from_data, ByteData::kMagicValue);
+
+ int start_position_from_data = scope_data_->ReadUint32();
+ int end_position_from_data = scope_data_->ReadUint32();
+ DCHECK_EQ(start_position_from_data, scope->start_position());
+ DCHECK_EQ(end_position_from_data, scope->end_position());
+#endif
+
+ RestoreDataForScope(scope);
+
+ // Check that we consumed all scope data.
+ DCHECK_EQ(scope_data_->RemainingBytes(), 0);
+}
+
+template <typename Data>
+void BaseConsumedPreparseData<Data>::RestoreDataForScope(Scope* scope) {
+ if (scope->is_declaration_scope() &&
+ scope->AsDeclarationScope()->is_skipped_function()) {
+ return;
+ }
+
+ // It's possible that scope is not present in the data at all (since PreParser
+ // doesn't create the corresponding scope). In this case, the Scope won't
+ // contain any variables for which we need the data.
+ if (!PreparseDataBuilder::ScopeNeedsData(scope)) return;
+
+ // scope_type is stored only in debug mode.
+ DCHECK_EQ(scope_data_->ReadUint8(), scope->scope_type());
+
+ CHECK(scope_data_->HasRemainingBytes(ByteData::kUint8Size));
+ uint32_t eval = scope_data_->ReadUint8();
+ if (ScopeCallsSloppyEvalField::decode(eval)) scope->RecordEvalCall();
+ if (InnerScopeCallsEvalField::decode(eval)) scope->RecordInnerScopeEvalCall();
+
+ if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
+ Variable* function = scope->AsDeclarationScope()->function_var();
+ if (function != nullptr) RestoreDataForVariable(function);
+ }
+
+ for (Variable* var : *scope->locals()) {
+ if (IsDeclaredVariableMode(var->mode())) RestoreDataForVariable(var);
+ }
+
+ RestoreDataForInnerScopes(scope);
+}
+
+template <typename Data>
+void BaseConsumedPreparseData<Data>::RestoreDataForVariable(Variable* var) {
+#ifdef DEBUG
+ const AstRawString* name = var->raw_name();
+ bool data_one_byte = scope_data_->ReadUint8();
+ DCHECK_IMPLIES(name->is_one_byte(), data_one_byte);
+ DCHECK_EQ(scope_data_->ReadUint32(), static_cast<uint32_t>(name->length()));
+ if (!name->is_one_byte() && data_one_byte) {
+ // It's possible that "name" is a two-byte representation of the string
+ // stored in the data.
+ for (int i = 0; i < 2 * name->length(); i += 2) {
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+ DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]);
+ DCHECK_EQ(0, name->raw_data()[i + 1]);
+#else
+ DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i + 1]);
+ DCHECK_EQ(0, name->raw_data()[i]);
+#endif // V8_TARGET_LITTLE_ENDIAN
+ }
+ } else {
+ for (int i = 0; i < name->length(); ++i) {
+ DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]);
+ }
+ }
+#endif
+ uint8_t variable_data = scope_data_->ReadQuarter();
+ if (VariableMaybeAssignedField::decode(variable_data)) {
+ var->set_maybe_assigned();
+ }
+ if (VariableContextAllocatedField::decode(variable_data)) {
+ var->set_is_used();
+ var->ForceContextAllocation();
+ }
+}
+
+template <typename Data>
+void BaseConsumedPreparseData<Data>::RestoreDataForInnerScopes(Scope* scope) {
+ for (Scope* inner = scope->inner_scope(); inner != nullptr;
+ inner = inner->sibling()) {
+ RestoreDataForScope(inner);
+ }
+}
+
+#ifdef DEBUG
+template <class Data>
+bool BaseConsumedPreparseData<Data>::VerifyDataStart() {
+ typename ByteData::ReadingScope reading_scope(this);
+ // The first uint32 contains the size of the skippable function data.
+ int scope_data_start = scope_data_->ReadUint32();
+ scope_data_->SetPosition(scope_data_start);
+ CHECK_EQ(scope_data_->ReadUint32(), ByteData::kMagicValue);
+ // The first data item is scope_data_start. Skip over it.
+ scope_data_->SetPosition(ByteData::kPlaceholderSize);
+ return true;
+}
+#endif
+
+PreparseData OnHeapConsumedPreparseData::GetScopeData() { return *data_; }
+
+ProducedPreparseData* OnHeapConsumedPreparseData::GetChildData(Zone* zone,
+ int index) {
+ DisallowHeapAllocation no_gc;
+ Handle<PreparseData> child_data_handle(data_->get_child(index), isolate_);
+ return ProducedPreparseData::For(child_data_handle, zone);
+}
+
+OnHeapConsumedPreparseData::OnHeapConsumedPreparseData(
+ Isolate* isolate, Handle<PreparseData> data)
+ : BaseConsumedPreparseData<PreparseData>(), isolate_(isolate), data_(data) {
+ DCHECK_NOT_NULL(isolate);
+ DCHECK(data->IsPreparseData());
+ DCHECK(VerifyDataStart());
+}
+
+ZonePreparseData::ZonePreparseData(Zone* zone, Vector<uint8_t>* byte_data,
+ int children_length)
+ : byte_data_(byte_data->begin(), byte_data->end(), zone),
+ children_(children_length, zone) {}
+
+Handle<PreparseData> ZonePreparseData::Serialize(Isolate* isolate) {
+ int data_size = static_cast<int>(byte_data()->size());
+ int child_data_length = children_length();
+ Handle<PreparseData> result =
+ isolate->factory()->NewPreparseData(data_size, child_data_length);
+ result->copy_in(0, byte_data()->data(), data_size);
+
+ for (int i = 0; i < child_data_length; i++) {
+ ZonePreparseData* child = get_child(i);
+ DCHECK_NOT_NULL(child);
+ Handle<PreparseData> child_data = child->Serialize(isolate);
+ result->set_child(i, *child_data);
+ }
+ return result;
+}
+
+ZoneConsumedPreparseData::ZoneConsumedPreparseData(Zone* zone,
+ ZonePreparseData* data)
+ : data_(data), scope_data_wrapper_(data_->byte_data()) {
+ DCHECK(VerifyDataStart());
+}
+
+ZoneVectorWrapper ZoneConsumedPreparseData::GetScopeData() {
+ return scope_data_wrapper_;
+}
+
+ProducedPreparseData* ZoneConsumedPreparseData::GetChildData(Zone* zone,
+ int child_index) {
+ CHECK_GT(data_->children_length(), child_index);
+ ZonePreparseData* child_data = data_->get_child(child_index);
+ if (child_data == nullptr) return nullptr;
+ return ProducedPreparseData::For(child_data, zone);
+}
+
+std::unique_ptr<ConsumedPreparseData> ConsumedPreparseData::For(
+ Isolate* isolate, Handle<PreparseData> data) {
+ DCHECK(!data.is_null());
+ return base::make_unique<OnHeapConsumedPreparseData>(isolate, data);
+}
+
+std::unique_ptr<ConsumedPreparseData> ConsumedPreparseData::For(
+ Zone* zone, ZonePreparseData* data) {
+ if (data == nullptr) return {};
+ return base::make_unique<ZoneConsumedPreparseData>(zone, data);
+}
+
+} // 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..0e08297c36
--- /dev/null
+++ b/deps/v8/src/parsing/preparse-data.h
@@ -0,0 +1,275 @@
+// Copyright 2017 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/globals.h"
+#include "src/handles.h"
+#include "src/maybe-handles.h"
+#include "src/zone/zone-chunk-list.h"
+#include "src/zone/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+
+template <typename T>
+class PodArray;
+
+class Parser;
+class PreParser;
+class PreparseData;
+class ZonePreparseData;
+
+/*
+
+ Skipping inner functions.
+
+ Consider the following code:
+ (function eager_outer() {
+ function lazy_inner() {
+ let a;
+ function skip_me() { a; }
+ }
+
+ return lazy_inner;
+ })();
+
+ ... lazy_inner(); ...
+
+ When parsing the code the first time, eager_outer is parsed and lazy_inner
+ (and everything inside it) is preparsed. When lazy_inner is called, we don't
+ want to parse or preparse skip_me again. Instead, we want to skip over it,
+ since it has already been preparsed once.
+
+ In order to be able to do this, we need to store the information needed for
+ allocating the variables in lazy_inner when we preparse it, and then later do
+ scope allocation based on that data.
+
+ We need the following data for each scope in lazy_inner's scope tree:
+ For each Variable:
+ - is_used
+ - maybe_assigned
+ - has_forced_context_allocation
+
+ For each Scope:
+ - inner_scope_calls_eval_.
+
+ ProducedPreparseData implements storing the above mentioned data and
+ ConsumedPreparseData implements restoring it (= setting the context
+ allocation status of the variables in a Scope (and its subscopes) based on the
+ data).
+
+ */
+
+struct PreparseByteDataConstants {
+#ifdef DEBUG
+ static constexpr int kMagicValue = 0xC0DE0DE;
+
+ static constexpr size_t kUint32Size = 5;
+ static constexpr size_t kVarintMinSize = 3;
+ static constexpr size_t kVarintEndMarker = 0xF1;
+ static constexpr size_t kUint8Size = 2;
+ static constexpr size_t kQuarterMarker = 0xF2;
+ static constexpr size_t kPlaceholderSize = kUint32Size;
+#else
+ static constexpr size_t kUint32Size = 4;
+ static constexpr size_t kVarintMinSize = 1;
+ static constexpr size_t kUint8Size = 1;
+ static constexpr size_t kPlaceholderSize = 0;
+#endif
+
+ static const size_t kSkippableFunctionMinDataSize =
+ 4 * kVarintMinSize + 1 * kUint8Size;
+};
+
+class PreparseDataBuilder : public ZoneObject,
+ public PreparseByteDataConstants {
+ public:
+ // Create a PreparseDataBuilder object which will collect data as we
+ // parse.
+ explicit PreparseDataBuilder(Zone* zone, PreparseDataBuilder* parent_builder);
+
+ PreparseDataBuilder* parent() const { return parent_; }
+
+ // For gathering the inner function data and splitting it up according to the
+ // laziness boundaries. Each lazy function gets its own
+ // ProducedPreparseData, and so do all lazy functions inside it.
+ class DataGatheringScope {
+ public:
+ explicit DataGatheringScope(PreParser* preparser)
+ : preparser_(preparser), builder_(nullptr) {}
+
+ void Start(DeclarationScope* function_scope);
+ void SetSkippableFunction(DeclarationScope* function_scope,
+ int num_inner_functions);
+ ~DataGatheringScope();
+
+ private:
+ PreParser* preparser_;
+ PreparseDataBuilder* builder_;
+
+ DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
+ };
+
+ class ByteData : public ZoneObject, public PreparseByteDataConstants {
+ public:
+ ByteData() : byte_data_(nullptr), free_quarters_in_last_byte_(0) {}
+
+ ~ByteData() {}
+
+ void Start(std::vector<uint8_t>* buffer);
+ void Finalize(Zone* zone);
+
+ Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length);
+ ZonePreparseData* CopyToZone(Zone* zone, int children_length);
+
+ void WriteVarint32(uint32_t data);
+ void WriteUint8(uint8_t data);
+ void WriteQuarter(uint8_t data);
+
+#ifdef DEBUG
+ void WriteUint32(uint32_t data);
+ // For overwriting previously written data at position 0.
+ void SaveCurrentSizeAtFirstUint32();
+ int length() const;
+#endif
+
+ private:
+ union {
+ // Only used during construction (is_finalized_ == false).
+ std::vector<uint8_t>* byte_data_;
+ // Once the data is finalized, it lives in a Zone, this implies
+ // is_finalized_ == true.
+ Vector<uint8_t> zone_byte_data_;
+ };
+ uint8_t free_quarters_in_last_byte_;
+
+#ifdef DEBUG
+ bool is_finalized_ = false;
+#endif
+ };
+
+ // Saves the information needed for allocating the Scope's (and its
+ // subscopes') variables.
+ void SaveScopeAllocationData(DeclarationScope* scope, Parser* parser);
+
+ // In some cases, PreParser cannot produce the same Scope structure as
+ // Parser. If it happens, we're unable to produce the data that would enable
+ // skipping the inner functions of that function.
+ void Bailout() {
+ bailed_out_ = true;
+ // We don't need to call Bailout on existing / future children: the only way
+ // to try to retrieve their data is through calling Serialize on the parent,
+ // and if the parent is bailed out, it won't call Serialize on its children.
+ }
+
+ bool bailed_out() const { return bailed_out_; }
+
+#ifdef DEBUG
+ bool ThisOrParentBailedOut() const {
+ if (bailed_out_) return true;
+ if (parent_ == nullptr) return false;
+ return parent_->ThisOrParentBailedOut();
+ }
+#endif // DEBUG
+
+ bool HasInnerFunctions() const;
+ bool HasData() const;
+ bool HasDataForParent() const;
+
+ static bool ScopeNeedsData(Scope* scope);
+ static bool ScopeIsSkippableFunctionScope(Scope* scope);
+ void AddSkippableFunction(int start_position, int end_position,
+ int num_parameters, int num_inner_functions,
+ LanguageMode language_mode, bool has_data,
+ bool uses_super_property);
+
+ private:
+ friend class BuilderProducedPreparseData;
+
+ Handle<PreparseData> Serialize(Isolate* isolate);
+ ZonePreparseData* Serialize(Zone* zone);
+
+ void SaveDataForScope(Scope* scope);
+ void SaveDataForVariable(Variable* var);
+ void SaveDataForInnerScopes(Scope* scope);
+ bool SaveDataForSkippableFunction(PreparseDataBuilder* builder);
+
+ void CopyByteData(Zone* zone);
+
+ PreparseDataBuilder* parent_;
+ ByteData byte_data_;
+ ZoneChunkList<PreparseDataBuilder*> children_;
+
+ DeclarationScope* function_scope_;
+ int num_inner_functions_;
+ int num_inner_with_data_;
+
+ // Whether we've given up producing the data for this function.
+ bool bailed_out_ : 1;
+ bool has_data_ : 1;
+
+ DISALLOW_COPY_AND_ASSIGN(PreparseDataBuilder);
+};
+
+class ProducedPreparseData : public ZoneObject {
+ public:
+ // If there is data (if the Scope contains skippable inner functions), move
+ // the data into the heap and return a Handle to it; otherwise return a null
+ // MaybeHandle.
+ virtual Handle<PreparseData> Serialize(Isolate* isolate) = 0;
+
+ // If there is data (if the Scope contains skippable inner functions), return
+ // an off-heap ZonePreparseData representing the data; otherwise
+ // return nullptr.
+ virtual ZonePreparseData* Serialize(Zone* zone) = 0;
+
+ // Create a ProducedPreparseData which is a proxy for a previous
+ // produced PreparseData in zone.
+ static ProducedPreparseData* For(PreparseDataBuilder* builder, Zone* zone);
+
+ // Create a ProducedPreparseData which is a proxy for a previous
+ // produced PreparseData on the heap.
+ static ProducedPreparseData* For(Handle<PreparseData> data, Zone* zone);
+
+ // Create a ProducedPreparseData which is a proxy for a previous
+ // produced PreparseData in zone.
+ static ProducedPreparseData* For(ZonePreparseData* data, Zone* zone);
+};
+
+class ConsumedPreparseData {
+ public:
+ // Creates a ConsumedPreparseData representing the data of an on-heap
+ // PreparseData |data|.
+ static std::unique_ptr<ConsumedPreparseData> For(Isolate* isolate,
+ Handle<PreparseData> data);
+
+ // Creates a ConsumedPreparseData representing the data of an off-heap
+ // ZonePreparseData |data|.
+ static std::unique_ptr<ConsumedPreparseData> For(Zone* zone,
+ ZonePreparseData* data);
+
+ virtual ~ConsumedPreparseData() = default;
+
+ virtual ProducedPreparseData* GetDataForSkippableFunction(
+ Zone* zone, int start_position, int* end_position, int* num_parameters,
+ int* num_inner_functions, bool* uses_super_property,
+ LanguageMode* language_mode) = 0;
+
+ // Restores the information needed for allocating the Scope's (and its
+ // subscopes') variables.
+ virtual void RestoreScopeAllocationData(DeclarationScope* scope) = 0;
+
+ protected:
+ ConsumedPreparseData() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConsumedPreparseData);
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_PARSING_PREPARSE_DATA_H_
diff --git a/deps/v8/src/parsing/preparsed-scope-data-impl.h b/deps/v8/src/parsing/preparsed-scope-data-impl.h
deleted file mode 100644
index e2d31c07d5..0000000000
--- a/deps/v8/src/parsing/preparsed-scope-data-impl.h
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2018 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_PREPARSED_SCOPE_DATA_IMPL_H_
-#define V8_PARSING_PREPARSED_SCOPE_DATA_IMPL_H_
-
-#include "src/parsing/preparsed-scope-data.h"
-
-#include "src/assert-scope.h"
-
-namespace v8 {
-namespace internal {
-
-// Classes which are internal to prepared-scope-data.cc, but are exposed in
-// a header for tests.
-
-struct PreParsedScopeByteDataConstants {
-#ifdef DEBUG
- static constexpr int kMagicValue = 0xC0DE0DE;
-
- static constexpr size_t kUint32Size = 5;
- static constexpr size_t kUint8Size = 2;
- static constexpr size_t kQuarterMarker = 0;
- static constexpr size_t kPlaceholderSize = kUint32Size;
-#else
- static constexpr size_t kUint32Size = 4;
- static constexpr size_t kUint8Size = 1;
- static constexpr size_t kPlaceholderSize = 0;
-#endif
-
- static const size_t kSkippableFunctionDataSize =
- 4 * kUint32Size + 1 * kUint8Size;
-};
-
-class PreParsedScopeDataBuilder::ByteData
- : public ZoneObject,
- public PreParsedScopeByteDataConstants {
- public:
- explicit ByteData(Zone* zone)
- : backing_store_(zone), free_quarters_in_last_byte_(0) {}
-
- void WriteUint32(uint32_t data);
- void WriteUint8(uint8_t data);
- void WriteQuarter(uint8_t data);
-
-#ifdef DEBUG
- // For overwriting previously written data at position 0.
- void OverwriteFirstUint32(uint32_t data);
-#endif
-
- Handle<PodArray<uint8_t>> Serialize(Isolate* isolate);
-
- size_t size() const { return backing_store_.size(); }
-
- ZoneChunkList<uint8_t>::iterator begin() { return backing_store_.begin(); }
-
- ZoneChunkList<uint8_t>::iterator end() { return backing_store_.end(); }
-
- private:
- ZoneChunkList<uint8_t> backing_store_;
- uint8_t free_quarters_in_last_byte_;
-};
-
-template <class Data>
-class BaseConsumedPreParsedScopeData : public ConsumedPreParsedScopeData {
- public:
- class ByteData : public PreParsedScopeByteDataConstants {
- public:
- ByteData()
- : data_(nullptr), index_(0), stored_quarters_(0), stored_byte_(0) {}
-
- // Reading from the ByteData is only allowed when a ReadingScope is on the
- // stack. This ensures that we have a DisallowHeapAllocation in place
- // whenever ByteData holds a raw pointer into the heap.
- class ReadingScope {
- public:
- ReadingScope(ByteData* consumed_data, Data* data)
- : consumed_data_(consumed_data) {
- consumed_data->data_ = data;
- }
- explicit ReadingScope(BaseConsumedPreParsedScopeData<Data>* parent)
- : ReadingScope(parent->scope_data_.get(), parent->GetScopeData()) {}
- ~ReadingScope() { consumed_data_->data_ = nullptr; }
-
- private:
- ByteData* consumed_data_;
- DisallowHeapAllocation no_gc;
- };
-
- void SetPosition(int position) { index_ = position; }
-
- size_t RemainingBytes() const {
- DCHECK_NOT_NULL(data_);
- return data_->length() - index_;
- }
-
- int32_t ReadUint32() {
- DCHECK_NOT_NULL(data_);
- DCHECK_GE(RemainingBytes(), kUint32Size);
-#ifdef DEBUG
- // Check that there indeed is an integer following.
- DCHECK_EQ(data_->get(index_++), kUint32Size);
-#endif
- int32_t result = 0;
- byte* p = reinterpret_cast<byte*>(&result);
- for (int i = 0; i < 4; ++i) {
- *p++ = data_->get(index_++);
- }
- stored_quarters_ = 0;
- return result;
- }
-
- uint8_t ReadUint8() {
- DCHECK_NOT_NULL(data_);
- DCHECK_GE(RemainingBytes(), kUint8Size);
-#ifdef DEBUG
- // Check that there indeed is a byte following.
- DCHECK_EQ(data_->get(index_++), kUint8Size);
-#endif
- stored_quarters_ = 0;
- return data_->get(index_++);
- }
-
- uint8_t ReadQuarter() {
- DCHECK_NOT_NULL(data_);
- if (stored_quarters_ == 0) {
- DCHECK_GE(RemainingBytes(), kUint8Size);
-#ifdef DEBUG
- // Check that there indeed are quarters following.
- DCHECK_EQ(data_->get(index_++), kQuarterMarker);
-#endif
- stored_byte_ = data_->get(index_++);
- stored_quarters_ = 4;
- }
- // Read the first 2 bits from stored_byte_.
- uint8_t result = (stored_byte_ >> 6) & 3;
- DCHECK_LE(result, 3);
- --stored_quarters_;
- stored_byte_ <<= 2;
- return result;
- }
-
- private:
- Data* data_;
- int index_;
- uint8_t stored_quarters_;
- uint8_t stored_byte_;
- };
-
- BaseConsumedPreParsedScopeData()
- : scope_data_(new ByteData()), child_index_(0) {}
-
- virtual Data* GetScopeData() = 0;
-
- virtual ProducedPreParsedScopeData* GetChildData(Zone* zone,
- int child_index) = 0;
-
- ProducedPreParsedScopeData* GetDataForSkippableFunction(
- Zone* zone, int start_position, int* end_position, int* num_parameters,
- int* num_inner_functions, bool* uses_super_property,
- LanguageMode* language_mode) final;
-
- void RestoreScopeAllocationData(DeclarationScope* scope) final;
-
-#ifdef DEBUG
- void VerifyDataStart();
-#endif
-
- private:
- void RestoreData(Scope* scope);
- void RestoreDataForVariable(Variable* var);
- void RestoreDataForInnerScopes(Scope* scope);
-
- std::unique_ptr<ByteData> scope_data_;
- // When consuming the data, these indexes point to the data we're going to
- // consume next.
- int child_index_;
-
- DISALLOW_COPY_AND_ASSIGN(BaseConsumedPreParsedScopeData);
-};
-
-// Implementation of ConsumedPreParsedScopeData for on-heap data.
-class OnHeapConsumedPreParsedScopeData final
- : public BaseConsumedPreParsedScopeData<PodArray<uint8_t>> {
- public:
- OnHeapConsumedPreParsedScopeData(Isolate* isolate,
- Handle<PreParsedScopeData> data);
-
- PodArray<uint8_t>* GetScopeData() final;
- ProducedPreParsedScopeData* GetChildData(Zone* zone, int child_index) final;
-
- private:
- Isolate* isolate_;
- Handle<PreParsedScopeData> data_;
-};
-
-// Wraps a ZoneVector<uint8_t> to have with functions named the same as
-// PodArray<uint8_t>.
-class ZoneVectorWrapper {
- public:
- explicit ZoneVectorWrapper(ZoneVector<uint8_t>* data) : data_(data) {}
-
- int length() const { return static_cast<int>(data_->size()); }
-
- uint8_t get(int index) const { return data_->at(index); }
-
- private:
- ZoneVector<uint8_t>* data_;
-
- DISALLOW_COPY_AND_ASSIGN(ZoneVectorWrapper);
-};
-
-// A serialized PreParsedScopeData in zone memory (as apposed to being on-heap).
-class ZonePreParsedScopeData : public ZoneObject {
- public:
- ZonePreParsedScopeData(Zone* zone,
- ZoneChunkList<uint8_t>::iterator byte_data_begin,
- ZoneChunkList<uint8_t>::iterator byte_data_end,
- int child_length);
-
- Handle<PreParsedScopeData> Serialize(Isolate* isolate);
-
- int child_length() const { return static_cast<int>(children_.size()); }
-
- ZonePreParsedScopeData* get_child(int index) { return children_[index]; }
-
- void set_child(int index, ZonePreParsedScopeData* child) {
- children_[index] = child;
- }
-
- ZoneVector<uint8_t>* byte_data() { return &byte_data_; }
-
- private:
- ZoneVector<uint8_t> byte_data_;
- ZoneVector<ZonePreParsedScopeData*> children_;
-
- DISALLOW_COPY_AND_ASSIGN(ZonePreParsedScopeData);
-};
-
-// Implementation of ConsumedPreParsedScopeData for PreParsedScopeData
-// serialized into zone memory.
-class ZoneConsumedPreParsedScopeData final
- : public BaseConsumedPreParsedScopeData<ZoneVectorWrapper> {
- public:
- ZoneConsumedPreParsedScopeData(Zone* zone, ZonePreParsedScopeData* data);
-
- ZoneVectorWrapper* GetScopeData() final;
- ProducedPreParsedScopeData* GetChildData(Zone* zone, int child_index) final;
-
- private:
- ZonePreParsedScopeData* data_;
- ZoneVectorWrapper scope_data_wrapper_;
-};
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_PARSING_PREPARSED_SCOPE_DATA_IMPL_H_
diff --git a/deps/v8/src/parsing/preparsed-scope-data.cc b/deps/v8/src/parsing/preparsed-scope-data.cc
deleted file mode 100644
index 9d61740753..0000000000
--- a/deps/v8/src/parsing/preparsed-scope-data.cc
+++ /dev/null
@@ -1,737 +0,0 @@
-// Copyright 2017 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/preparsed-scope-data.h"
-
-#include <vector>
-
-#include "src/ast/scopes.h"
-#include "src/ast/variables.h"
-#include "src/handles.h"
-#include "src/objects-inl.h"
-#include "src/objects/shared-function-info.h"
-#include "src/parsing/preparsed-scope-data-impl.h"
-#include "src/parsing/preparser.h"
-
-namespace v8 {
-namespace internal {
-
-namespace {
-
-class ScopeCallsSloppyEvalField : public BitField<bool, 0, 1> {};
-class InnerScopeCallsEvalField
- : public BitField<bool, ScopeCallsSloppyEvalField::kNext, 1> {};
-
-class VariableMaybeAssignedField : public BitField8<bool, 0, 1> {};
-class VariableContextAllocatedField
- : public BitField8<bool, VariableMaybeAssignedField::kNext, 1> {};
-
-class LanguageField : public BitField8<LanguageMode, 0, 1> {};
-class UsesSuperField : public BitField8<bool, LanguageField::kNext, 1> {};
-STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues);
-
-} // namespace
-
-/*
-
- Internal data format for the backing store of PreParsedScopeDataBuilder and
- PreParsedScopeData::scope_data (on the heap):
-
- (Skippable function data:)
- ------------------------------------
- | scope_data_start (debug only) |
- ------------------------------------
- | data for inner function 1 |
- | ... |
- ------------------------------------
- | data for inner function n |
- | ... |
- ------------------------------------
- (Scope allocation data:) << scope_data_start points here in debug
- ------------------------------------
- magic value (debug only)
- ------------------------------------
- scope positions (debug only)
- ------------------------------------
- | scope type << only in debug |
- | eval |
- | ---------------------- |
- | | data for variables | |
- | | ... | |
- | ---------------------- |
- ------------------------------------
- ------------------------------------
- | data for inner scope 1 | << but not for function scopes
- | ... |
- ------------------------------------
- ...
- ------------------------------------
- | data for inner scope m |
- | ... |
- ------------------------------------
-
- PreParsedScopeData::child_data is an array of PreParsedScopeData objects, one
- for each skippable inner function.
-
- ConsumedPreParsedScopeData wraps a PreParsedScopeData and reads data from it.
-
- */
-
-void PreParsedScopeDataBuilder::ByteData::WriteUint32(uint32_t data) {
-#ifdef DEBUG
- // Save expected item size in debug mode.
- backing_store_.push_back(kUint32Size);
-#endif
- const uint8_t* d = reinterpret_cast<uint8_t*>(&data);
- for (int i = 0; i < 4; ++i) {
- backing_store_.push_back(*d++);
- }
- free_quarters_in_last_byte_ = 0;
-}
-
-#ifdef DEBUG
-void PreParsedScopeDataBuilder::ByteData::OverwriteFirstUint32(uint32_t data) {
- auto it = backing_store_.begin();
- // Check that that position already holds an item of the expected size.
- DCHECK_GE(backing_store_.size(), kUint32Size);
- DCHECK_EQ(*it, kUint32Size);
- ++it;
- const uint8_t* d = reinterpret_cast<uint8_t*>(&data);
- for (size_t i = 0; i < 4; ++i) {
- *it++ = *d++;
- }
-}
-#endif
-
-void PreParsedScopeDataBuilder::ByteData::WriteUint8(uint8_t data) {
-#ifdef DEBUG
- // Save expected item size in debug mode.
- backing_store_.push_back(kUint8Size);
-#endif
- backing_store_.push_back(data);
- free_quarters_in_last_byte_ = 0;
-}
-
-void PreParsedScopeDataBuilder::ByteData::WriteQuarter(uint8_t data) {
- DCHECK_LE(data, 3);
- if (free_quarters_in_last_byte_ == 0) {
-#ifdef DEBUG
- // Save a marker in debug mode.
- backing_store_.push_back(kQuarterMarker);
-#endif
- backing_store_.push_back(0);
- free_quarters_in_last_byte_ = 3;
- } else {
- --free_quarters_in_last_byte_;
- }
-
- uint8_t shift_amount = free_quarters_in_last_byte_ * 2;
- DCHECK_EQ(backing_store_.back() & (3 << shift_amount), 0);
- backing_store_.back() |= (data << shift_amount);
-}
-
-Handle<PodArray<uint8_t>> PreParsedScopeDataBuilder::ByteData::Serialize(
- Isolate* isolate) {
- Handle<PodArray<uint8_t>> array = PodArray<uint8_t>::New(
- isolate, static_cast<int>(backing_store_.size()), TENURED);
-
- DisallowHeapAllocation no_gc;
- PodArray<uint8_t>* raw_array = *array;
-
- int i = 0;
- for (uint8_t item : backing_store_) {
- raw_array->set(i++, item);
- }
- return array;
-}
-
-PreParsedScopeDataBuilder::PreParsedScopeDataBuilder(
- Zone* zone, PreParsedScopeDataBuilder* parent)
- : parent_(parent),
- byte_data_(new (zone) ByteData(zone)),
- data_for_inner_functions_(zone),
- bailed_out_(false) {
- DCHECK(FLAG_preparser_scope_analysis);
- if (parent != nullptr) {
- parent->data_for_inner_functions_.push_back(this);
- }
-#ifdef DEBUG
- // Reserve space for scope_data_start, written later:
- byte_data_->WriteUint32(0);
-#endif
-}
-
-PreParsedScopeDataBuilder::DataGatheringScope::DataGatheringScope(
- DeclarationScope* function_scope, PreParser* preparser)
- : function_scope_(function_scope),
- preparser_(preparser),
- builder_(nullptr) {
- if (FLAG_preparser_scope_analysis) {
- PreParsedScopeDataBuilder* parent =
- preparser->preparsed_scope_data_builder();
- Zone* main_zone = preparser->main_zone();
- builder_ = new (main_zone) PreParsedScopeDataBuilder(main_zone, parent);
- preparser->set_preparsed_scope_data_builder(builder_);
- function_scope->set_preparsed_scope_data_builder(builder_);
- }
-}
-
-PreParsedScopeDataBuilder::DataGatheringScope::~DataGatheringScope() {
- if (builder_) {
- preparser_->set_preparsed_scope_data_builder(builder_->parent_);
- }
-}
-
-void PreParsedScopeDataBuilder::DataGatheringScope::MarkFunctionAsSkippable(
- int end_position, int num_inner_functions) {
- DCHECK_NOT_NULL(builder_);
- DCHECK_NOT_NULL(builder_->parent_);
- builder_->parent_->AddSkippableFunction(
- function_scope_->start_position(), end_position,
- function_scope_->num_parameters(), num_inner_functions,
- function_scope_->language_mode(), function_scope_->NeedsHomeObject());
-}
-
-void PreParsedScopeDataBuilder::AddSkippableFunction(int start_position,
- int end_position,
- int num_parameters,
- int num_inner_functions,
- LanguageMode language_mode,
- bool uses_super_property) {
- if (bailed_out_) {
- return;
- }
-
- // Start position is used for a sanity check when consuming the data, we could
- // remove it in the future if we're very pressed for space but it's been good
- // at catching bugs in the wild so far.
- byte_data_->WriteUint32(start_position);
- byte_data_->WriteUint32(end_position);
- byte_data_->WriteUint32(num_parameters);
- byte_data_->WriteUint32(num_inner_functions);
-
- uint8_t language_and_super = LanguageField::encode(language_mode) |
- UsesSuperField::encode(uses_super_property);
-
- byte_data_->WriteQuarter(language_and_super);
-}
-
-void PreParsedScopeDataBuilder::SaveScopeAllocationData(
- DeclarationScope* scope) {
- // The data contains a uint32 (reserved space for scope_data_start) and
- // function data items, kSkippableFunctionDataSize each.
- DCHECK_GE(byte_data_->size(), ByteData::kPlaceholderSize);
- DCHECK_LE(byte_data_->size(), std::numeric_limits<uint32_t>::max());
- DCHECK_EQ(byte_data_->size() % ByteData::kSkippableFunctionDataSize,
- ByteData::kPlaceholderSize);
-
- if (bailed_out_) {
- return;
- }
-
- uint32_t scope_data_start = static_cast<uint32_t>(byte_data_->size());
-
- // If there are no skippable inner functions, we don't need to save anything.
- if (scope_data_start == ByteData::kPlaceholderSize) {
- return;
- }
-
-#ifdef DEBUG
- byte_data_->OverwriteFirstUint32(scope_data_start);
-
- // For a data integrity check, write a value between data about skipped inner
- // funcs and data about variables.
- byte_data_->WriteUint32(ByteData::kMagicValue);
- byte_data_->WriteUint32(scope->start_position());
- byte_data_->WriteUint32(scope->end_position());
-#endif
-
- SaveDataForScope(scope);
-}
-
-bool PreParsedScopeDataBuilder::ContainsInnerFunctions() const {
- return byte_data_->size() > ByteData::kPlaceholderSize;
-}
-
-MaybeHandle<PreParsedScopeData> PreParsedScopeDataBuilder::Serialize(
- Isolate* isolate) {
- if (bailed_out_) {
- return MaybeHandle<PreParsedScopeData>();
- }
-
- DCHECK(!ThisOrParentBailedOut());
-
- if (byte_data_->size() <= ByteData::kPlaceholderSize) {
- // The data contains only the placeholder.
- return MaybeHandle<PreParsedScopeData>();
- }
-
- int child_data_length = static_cast<int>(data_for_inner_functions_.size());
- Handle<PreParsedScopeData> data =
- isolate->factory()->NewPreParsedScopeData(child_data_length);
-
- Handle<PodArray<uint8_t>> scope_data_array = byte_data_->Serialize(isolate);
- data->set_scope_data(*scope_data_array);
-
- int i = 0;
- for (const auto& item : data_for_inner_functions_) {
- Handle<PreParsedScopeData> child_data;
- if (item->Serialize(isolate).ToHandle(&child_data)) {
- data->set_child_data(i, *child_data);
- } else {
- DCHECK(data->child_data(i)->IsNull());
- }
- i++;
- }
-
- return data;
-}
-
-ZonePreParsedScopeData* PreParsedScopeDataBuilder::Serialize(Zone* zone) {
- if (bailed_out_) {
- return nullptr;
- }
-
- DCHECK(!ThisOrParentBailedOut());
-
- if (byte_data_->size() <= ByteData::kPlaceholderSize) {
- // The data contains only the placeholder.
- return nullptr;
- }
-
- int child_length = static_cast<int>(data_for_inner_functions_.size());
- ZonePreParsedScopeData* result = new (zone) ZonePreParsedScopeData(
- zone, byte_data_->begin(), byte_data_->end(), child_length);
-
- int i = 0;
- for (const auto& item : data_for_inner_functions_) {
- ZonePreParsedScopeData* child = item->Serialize(zone);
- result->set_child(i, child);
- i++;
- }
-
- return result;
-}
-
-bool PreParsedScopeDataBuilder::ScopeNeedsData(Scope* scope) {
- if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
- // Default constructors don't need data (they cannot contain inner functions
- // defined by the user). Other functions do.
- return !IsDefaultConstructor(scope->AsDeclarationScope()->function_kind());
- }
- if (!scope->is_hidden()) {
- for (Variable* var : *scope->locals()) {
- if (IsDeclaredVariableMode(var->mode())) {
- return true;
- }
- }
- }
- for (Scope* inner = scope->inner_scope(); inner != nullptr;
- inner = inner->sibling()) {
- if (ScopeNeedsData(inner)) {
- return true;
- }
- }
- return false;
-}
-
-bool PreParsedScopeDataBuilder::ScopeIsSkippableFunctionScope(Scope* scope) {
- // Lazy non-arrow function scopes are skippable. Lazy functions are exactly
- // those Scopes which have their own PreParsedScopeDataBuilder object. This
- // logic ensures that the scope allocation data is consistent with the
- // skippable function data (both agree on where the lazy function boundaries
- // are).
- if (scope->scope_type() != ScopeType::FUNCTION_SCOPE) {
- return false;
- }
- DeclarationScope* declaration_scope = scope->AsDeclarationScope();
- return !declaration_scope->is_arrow_scope() &&
- declaration_scope->preparsed_scope_data_builder() != nullptr;
-}
-
-void PreParsedScopeDataBuilder::SaveDataForScope(Scope* scope) {
- DCHECK_NE(scope->end_position(), kNoSourcePosition);
-
- if (!ScopeNeedsData(scope)) {
- return;
- }
-
-#ifdef DEBUG
- byte_data_->WriteUint8(scope->scope_type());
-#endif
-
- uint8_t eval =
- ScopeCallsSloppyEvalField::encode(
- scope->is_declaration_scope() &&
- scope->AsDeclarationScope()->calls_sloppy_eval()) |
- InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval());
- byte_data_->WriteUint8(eval);
-
- if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
- Variable* function = scope->AsDeclarationScope()->function_var();
- if (function != nullptr) {
- SaveDataForVariable(function);
- }
- }
-
- for (Variable* var : *scope->locals()) {
- if (IsDeclaredVariableMode(var->mode())) {
- SaveDataForVariable(var);
- }
- }
-
- SaveDataForInnerScopes(scope);
-}
-
-void PreParsedScopeDataBuilder::SaveDataForVariable(Variable* var) {
-#ifdef DEBUG
- // Store the variable name in debug mode; this way we can check that we
- // restore data to the correct variable.
- const AstRawString* name = var->raw_name();
- byte_data_->WriteUint8(name->is_one_byte());
- byte_data_->WriteUint32(name->length());
- for (int i = 0; i < name->length(); ++i) {
- byte_data_->WriteUint8(name->raw_data()[i]);
- }
-#endif
- byte variable_data = VariableMaybeAssignedField::encode(
- var->maybe_assigned() == kMaybeAssigned) |
- VariableContextAllocatedField::encode(
- var->has_forced_context_allocation());
- byte_data_->WriteQuarter(variable_data);
-}
-
-void PreParsedScopeDataBuilder::SaveDataForInnerScopes(Scope* scope) {
- // Inner scopes are stored in the reverse order, but we'd like to write the
- // data in the logical order. There might be many inner scopes, so we don't
- // want to recurse here.
- std::vector<Scope*> scopes;
- for (Scope* inner = scope->inner_scope(); inner != nullptr;
- inner = inner->sibling()) {
- if (ScopeIsSkippableFunctionScope(inner)) {
- // Don't save data about function scopes, since they'll have their own
- // PreParsedScopeDataBuilder where their data is saved.
- DCHECK_NOT_NULL(
- inner->AsDeclarationScope()->preparsed_scope_data_builder());
- continue;
- }
- scopes.push_back(inner);
- }
- for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) {
- SaveDataForScope(*it);
- }
-}
-
-class BuilderProducedPreParsedScopeData final
- : public ProducedPreParsedScopeData {
- public:
- explicit BuilderProducedPreParsedScopeData(PreParsedScopeDataBuilder* builder)
- : builder_(builder) {}
-
- MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) final {
- return builder_->Serialize(isolate);
- }
-
- ZonePreParsedScopeData* Serialize(Zone* zone) final {
- return builder_->Serialize(zone);
- };
-
- private:
- PreParsedScopeDataBuilder* builder_;
-};
-
-class OnHeapProducedPreParsedScopeData final
- : public ProducedPreParsedScopeData {
- public:
- explicit OnHeapProducedPreParsedScopeData(Handle<PreParsedScopeData> data)
- : data_(data) {}
-
- MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) final {
- return data_;
- }
-
- ZonePreParsedScopeData* Serialize(Zone* zone) final {
- // Not required.
- UNREACHABLE();
- };
-
- private:
- Handle<PreParsedScopeData> data_;
-};
-
-class ZoneProducedPreParsedScopeData final : public ProducedPreParsedScopeData {
- public:
- explicit ZoneProducedPreParsedScopeData(ZonePreParsedScopeData* data)
- : data_(data) {}
-
- MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) final {
- return data_->Serialize(isolate);
- }
-
- ZonePreParsedScopeData* Serialize(Zone* zone) final { return data_; };
-
- private:
- ZonePreParsedScopeData* data_;
-};
-
-ProducedPreParsedScopeData* ProducedPreParsedScopeData::For(
- PreParsedScopeDataBuilder* builder, Zone* zone) {
- return new (zone) BuilderProducedPreParsedScopeData(builder);
-}
-
-ProducedPreParsedScopeData* ProducedPreParsedScopeData::For(
- Handle<PreParsedScopeData> data, Zone* zone) {
- return new (zone) OnHeapProducedPreParsedScopeData(data);
-}
-
-ProducedPreParsedScopeData* ProducedPreParsedScopeData::For(
- ZonePreParsedScopeData* data, Zone* zone) {
- return new (zone) ZoneProducedPreParsedScopeData(data);
-}
-
-template <class Data>
-ProducedPreParsedScopeData*
-BaseConsumedPreParsedScopeData<Data>::GetDataForSkippableFunction(
- Zone* zone, int start_position, int* end_position, int* num_parameters,
- int* num_inner_functions, bool* uses_super_property,
- LanguageMode* language_mode) {
- // The skippable function *must* be the next function in the data. Use the
- // start position as a sanity check.
- typename ByteData::ReadingScope reading_scope(this);
- CHECK_GE(scope_data_->RemainingBytes(), ByteData::kSkippableFunctionDataSize);
- int start_position_from_data = scope_data_->ReadUint32();
- CHECK_EQ(start_position, start_position_from_data);
-
- *end_position = scope_data_->ReadUint32();
- DCHECK_GT(*end_position, start_position);
- *num_parameters = scope_data_->ReadUint32();
- *num_inner_functions = scope_data_->ReadUint32();
-
- uint8_t language_and_super = scope_data_->ReadQuarter();
- *language_mode = LanguageMode(LanguageField::decode(language_and_super));
- *uses_super_property = UsesSuperField::decode(language_and_super);
-
- // Retrieve the corresponding PreParsedScopeData and associate it to the
- // skipped function. If the skipped functions contains inner functions, those
- // can be skipped when the skipped function is eagerly parsed.
- return GetChildData(zone, child_index_++);
-}
-
-template <class Data>
-void BaseConsumedPreParsedScopeData<Data>::RestoreScopeAllocationData(
- DeclarationScope* scope) {
- DCHECK_EQ(scope->scope_type(), ScopeType::FUNCTION_SCOPE);
- typename ByteData::ReadingScope reading_scope(this);
-
-#ifdef DEBUG
- int magic_value_from_data = scope_data_->ReadUint32();
- // Check that we've consumed all inner function data.
- DCHECK_EQ(magic_value_from_data, ByteData::kMagicValue);
-
- int start_position_from_data = scope_data_->ReadUint32();
- int end_position_from_data = scope_data_->ReadUint32();
- DCHECK_EQ(start_position_from_data, scope->start_position());
- DCHECK_EQ(end_position_from_data, scope->end_position());
-#endif
-
- RestoreData(scope);
-
- // Check that we consumed all scope data.
- DCHECK_EQ(scope_data_->RemainingBytes(), 0);
-}
-
-template <typename Data>
-void BaseConsumedPreParsedScopeData<Data>::RestoreData(Scope* scope) {
- if (scope->is_declaration_scope() &&
- scope->AsDeclarationScope()->is_skipped_function()) {
- return;
- }
-
- // It's possible that scope is not present in the data at all (since PreParser
- // doesn't create the corresponding scope). In this case, the Scope won't
- // contain any variables for which we need the data.
- if (!PreParsedScopeDataBuilder::ScopeNeedsData(scope)) {
- return;
- }
-
- // scope_type is stored only in debug mode.
- CHECK_GE(scope_data_->RemainingBytes(), ByteData::kUint8Size);
- DCHECK_EQ(scope_data_->ReadUint8(), scope->scope_type());
-
- uint32_t eval = scope_data_->ReadUint8();
- if (ScopeCallsSloppyEvalField::decode(eval)) {
- scope->RecordEvalCall();
- }
- if (InnerScopeCallsEvalField::decode(eval)) {
- scope->RecordInnerScopeEvalCall();
- }
-
- if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
- Variable* function = scope->AsDeclarationScope()->function_var();
- if (function != nullptr) {
- RestoreDataForVariable(function);
- }
- }
-
- for (Variable* var : *scope->locals()) {
- if (IsDeclaredVariableMode(var->mode())) {
- RestoreDataForVariable(var);
- }
- }
-
- RestoreDataForInnerScopes(scope);
-}
-
-template <typename Data>
-void BaseConsumedPreParsedScopeData<Data>::RestoreDataForVariable(
- Variable* var) {
-#ifdef DEBUG
- const AstRawString* name = var->raw_name();
- bool data_one_byte = scope_data_->ReadUint8();
- DCHECK_IMPLIES(name->is_one_byte(), data_one_byte);
- DCHECK_EQ(scope_data_->ReadUint32(), static_cast<uint32_t>(name->length()));
- if (!name->is_one_byte() && data_one_byte) {
- // It's possible that "name" is a two-byte representation of the string
- // stored in the data.
- for (int i = 0; i < 2 * name->length(); i += 2) {
-#if defined(V8_TARGET_LITTLE_ENDIAN)
- DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]);
- DCHECK_EQ(0, name->raw_data()[i + 1]);
-#else
- DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i + 1]);
- DCHECK_EQ(0, name->raw_data()[i]);
-#endif // V8_TARGET_LITTLE_ENDIAN
- }
- } else {
- for (int i = 0; i < name->length(); ++i) {
- DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]);
- }
- }
-#endif
- uint8_t variable_data = scope_data_->ReadQuarter();
- if (VariableMaybeAssignedField::decode(variable_data)) {
- var->set_maybe_assigned();
- }
- if (VariableContextAllocatedField::decode(variable_data)) {
- var->set_is_used();
- var->ForceContextAllocation();
- }
-}
-
-template <typename Data>
-void BaseConsumedPreParsedScopeData<Data>::RestoreDataForInnerScopes(
- Scope* scope) {
- std::vector<Scope*> scopes;
- for (Scope* inner = scope->inner_scope(); inner != nullptr;
- inner = inner->sibling()) {
- scopes.push_back(inner);
- }
- for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) {
- RestoreData(*it);
- }
-}
-
-#ifdef DEBUG
-template <class Data>
-void BaseConsumedPreParsedScopeData<Data>::VerifyDataStart() {
- typename ByteData::ReadingScope reading_scope(this);
- int scope_data_start = scope_data_->ReadUint32();
- scope_data_->SetPosition(scope_data_start);
- DCHECK_EQ(scope_data_->ReadUint32(), ByteData::kMagicValue);
- // The first data item is scope_data_start. Skip over it.
- scope_data_->SetPosition(ByteData::kPlaceholderSize);
-}
-#endif
-
-PodArray<uint8_t>* OnHeapConsumedPreParsedScopeData::GetScopeData() {
- return data_->scope_data();
-}
-
-ProducedPreParsedScopeData* OnHeapConsumedPreParsedScopeData::GetChildData(
- Zone* zone, int child_index) {
- CHECK_GT(data_->length(), child_index);
- Object* child_data = data_->child_data(child_index);
- if (!child_data->IsPreParsedScopeData()) {
- return nullptr;
- }
- Handle<PreParsedScopeData> child_data_handle(
- PreParsedScopeData::cast(child_data), isolate_);
- return ProducedPreParsedScopeData::For(child_data_handle, zone);
-}
-
-OnHeapConsumedPreParsedScopeData::OnHeapConsumedPreParsedScopeData(
- Isolate* isolate, Handle<PreParsedScopeData> data)
- : BaseConsumedPreParsedScopeData<PodArray<uint8_t>>(),
- isolate_(isolate),
- data_(data) {
- DCHECK_NOT_NULL(isolate);
- DCHECK(data->IsPreParsedScopeData());
-#ifdef DEBUG
- VerifyDataStart();
-#endif
-}
-
-ZonePreParsedScopeData::ZonePreParsedScopeData(
- Zone* zone, ZoneChunkList<uint8_t>::iterator byte_data_begin,
- ZoneChunkList<uint8_t>::iterator byte_data_end, int child_length)
- : byte_data_(byte_data_begin, byte_data_end, zone),
- children_(child_length, zone) {}
-
-Handle<PreParsedScopeData> ZonePreParsedScopeData::Serialize(Isolate* isolate) {
- int child_data_length = child_length();
- Handle<PreParsedScopeData> result =
- isolate->factory()->NewPreParsedScopeData(child_data_length);
-
- Handle<PodArray<uint8_t>> scope_data_array = PodArray<uint8_t>::New(
- isolate, static_cast<int>(byte_data()->size()), TENURED);
- scope_data_array->copy_in(0, byte_data()->data(),
- static_cast<int>(byte_data()->size()));
- result->set_scope_data(*scope_data_array);
-
- for (int i = 0; i < child_data_length; i++) {
- ZonePreParsedScopeData* child = get_child(i);
- if (child) {
- Handle<PreParsedScopeData> child_data = child->Serialize(isolate);
- result->set_child_data(i, *child_data);
- }
- }
- return result;
-}
-
-ZoneConsumedPreParsedScopeData::ZoneConsumedPreParsedScopeData(
- Zone* zone, ZonePreParsedScopeData* data)
- : data_(data), scope_data_wrapper_(data_->byte_data()) {
-#ifdef DEBUG
- VerifyDataStart();
-#endif
-}
-
-ZoneVectorWrapper* ZoneConsumedPreParsedScopeData::GetScopeData() {
- return &scope_data_wrapper_;
-}
-
-ProducedPreParsedScopeData* ZoneConsumedPreParsedScopeData::GetChildData(
- Zone* zone, int child_index) {
- CHECK_GT(data_->child_length(), child_index);
- ZonePreParsedScopeData* child_data = data_->get_child(child_index);
- if (child_data == nullptr) {
- return nullptr;
- }
- return ProducedPreParsedScopeData::For(child_data, zone);
-}
-
-std::unique_ptr<ConsumedPreParsedScopeData> ConsumedPreParsedScopeData::For(
- Isolate* isolate, Handle<PreParsedScopeData> data) {
- DCHECK(!data.is_null());
- return base::make_unique<OnHeapConsumedPreParsedScopeData>(isolate, data);
-}
-
-std::unique_ptr<ConsumedPreParsedScopeData> ConsumedPreParsedScopeData::For(
- Zone* zone, ZonePreParsedScopeData* data) {
- if (data == nullptr) return {};
- return base::make_unique<ZoneConsumedPreParsedScopeData>(zone, data);
-}
-
-} // namespace internal
-} // namespace v8
diff --git a/deps/v8/src/parsing/preparsed-scope-data.h b/deps/v8/src/parsing/preparsed-scope-data.h
deleted file mode 100644
index 25298c4331..0000000000
--- a/deps/v8/src/parsing/preparsed-scope-data.h
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2017 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_PREPARSED_SCOPE_DATA_H_
-#define V8_PARSING_PREPARSED_SCOPE_DATA_H_
-
-#include "src/globals.h"
-#include "src/handles.h"
-#include "src/maybe-handles.h"
-#include "src/zone/zone-chunk-list.h"
-#include "src/zone/zone-containers.h"
-
-namespace v8 {
-namespace internal {
-
-template <typename T>
-class PodArray;
-
-class PreParser;
-class PreParsedScopeData;
-class ZonePreParsedScopeData;
-
-/*
-
- Skipping inner functions.
-
- Consider the following code:
- (function eager_outer() {
- function lazy_inner() {
- let a;
- function skip_me() { a; }
- }
-
- return lazy_inner;
- })();
-
- ... lazy_inner(); ...
-
- When parsing the code the first time, eager_outer is parsed and lazy_inner
- (and everything inside it) is preparsed. When lazy_inner is called, we don't
- want to parse or preparse skip_me again. Instead, we want to skip over it,
- since it has already been preparsed once.
-
- In order to be able to do this, we need to store the information needed for
- allocating the variables in lazy_inner when we preparse it, and then later do
- scope allocation based on that data.
-
- We need the following data for each scope in lazy_inner's scope tree:
- For each Variable:
- - is_used
- - maybe_assigned
- - has_forced_context_allocation
-
- For each Scope:
- - inner_scope_calls_eval_.
-
- ProducedPreParsedScopeData implements storing the above mentioned data and
- ConsumedPreParsedScopeData implements restoring it (= setting the context
- allocation status of the variables in a Scope (and its subscopes) based on the
- data).
-
- */
-
-class PreParsedScopeDataBuilder : public ZoneObject {
- public:
- class ByteData;
-
- // Create a PreParsedScopeDataBuilder object which will collect data as we
- // parse.
- PreParsedScopeDataBuilder(Zone* zone, PreParsedScopeDataBuilder* parent);
-
- PreParsedScopeDataBuilder* parent() const { return parent_; }
-
- // For gathering the inner function data and splitting it up according to the
- // laziness boundaries. Each lazy function gets its own
- // ProducedPreParsedScopeData, and so do all lazy functions inside it.
- class DataGatheringScope {
- public:
- DataGatheringScope(DeclarationScope* function_scope, PreParser* preparser);
- ~DataGatheringScope();
-
- void MarkFunctionAsSkippable(int end_position, int num_inner_functions);
-
- private:
- DeclarationScope* function_scope_;
- PreParser* preparser_;
- PreParsedScopeDataBuilder* builder_;
-
- DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
- };
-
- // Saves the information needed for allocating the Scope's (and its
- // subscopes') variables.
- void SaveScopeAllocationData(DeclarationScope* scope);
-
- // In some cases, PreParser cannot produce the same Scope structure as
- // Parser. If it happens, we're unable to produce the data that would enable
- // skipping the inner functions of that function.
- void Bailout() {
- bailed_out_ = true;
-
- // We don't need to call Bailout on existing / future children: the only way
- // to try to retrieve their data is through calling Serialize on the parent,
- // and if the parent is bailed out, it won't call Serialize on its children.
- }
-
- bool bailed_out() const { return bailed_out_; }
-
-#ifdef DEBUG
- bool ThisOrParentBailedOut() const {
- if (bailed_out_) {
- return true;
- }
- if (parent_ == nullptr) {
- return false;
- }
- return parent_->ThisOrParentBailedOut();
- }
-#endif // DEBUG
-
- bool ContainsInnerFunctions() const;
-
- static bool ScopeNeedsData(Scope* scope);
- static bool ScopeIsSkippableFunctionScope(Scope* scope);
-
- private:
- friend class BuilderProducedPreParsedScopeData;
-
- virtual MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate);
- virtual ZonePreParsedScopeData* Serialize(Zone* zone);
-
- void AddSkippableFunction(int start_position, int end_position,
- int num_parameters, int num_inner_functions,
- LanguageMode language_mode,
- bool uses_super_property);
-
- void SaveDataForScope(Scope* scope);
- void SaveDataForVariable(Variable* var);
- void SaveDataForInnerScopes(Scope* scope);
-
- PreParsedScopeDataBuilder* parent_;
-
- ByteData* byte_data_;
- ZoneChunkList<PreParsedScopeDataBuilder*> data_for_inner_functions_;
-
- // Whether we've given up producing the data for this function.
- bool bailed_out_;
-
- DISALLOW_COPY_AND_ASSIGN(PreParsedScopeDataBuilder);
-};
-
-class ProducedPreParsedScopeData : public ZoneObject {
- public:
- // If there is data (if the Scope contains skippable inner functions), move
- // the data into the heap and return a Handle to it; otherwise return a null
- // MaybeHandle.
- virtual MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) = 0;
-
- // If there is data (if the Scope contains skippable inner functions), return
- // an off-heap ZonePreParsedScopeData representing the data; otherwise
- // return nullptr.
- virtual ZonePreParsedScopeData* Serialize(Zone* zone) = 0;
-
- // Create a ProducedPreParsedScopeData which is a proxy for a previous
- // produced PreParsedScopeData in zone.
- static ProducedPreParsedScopeData* For(PreParsedScopeDataBuilder* builder,
- Zone* zone);
-
- // Create a ProducedPreParsedScopeData which is a proxy for a previous
- // produced PreParsedScopeData on the heap.
- static ProducedPreParsedScopeData* For(Handle<PreParsedScopeData> data,
- Zone* zone);
-
- // Create a ProducedPreParsedScopeData which is a proxy for a previous
- // produced PreParsedScopeData in zone.
- static ProducedPreParsedScopeData* For(ZonePreParsedScopeData* data,
- Zone* zone);
-};
-
-class ConsumedPreParsedScopeData {
- public:
- // Creates a ConsumedPreParsedScopeData representing the data of an on-heap
- // PreParsedScopeData |data|.
- static std::unique_ptr<ConsumedPreParsedScopeData> For(
- Isolate* isolate, Handle<PreParsedScopeData> data);
-
- // Creates a ConsumedPreParsedScopeData representing the data of an off-heap
- // ZonePreParsedScopeData |data|.
- static std::unique_ptr<ConsumedPreParsedScopeData> For(
- Zone* zone, ZonePreParsedScopeData* data);
-
- virtual ~ConsumedPreParsedScopeData() = default;
-
- virtual ProducedPreParsedScopeData* GetDataForSkippableFunction(
- Zone* zone, int start_position, int* end_position, int* num_parameters,
- int* num_inner_functions, bool* uses_super_property,
- LanguageMode* language_mode) = 0;
-
- // Restores the information needed for allocating the Scope's (and its
- // subscopes') variables.
- virtual void RestoreScopeAllocationData(DeclarationScope* scope) = 0;
-
- protected:
- ConsumedPreParsedScopeData() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConsumedPreParsedScopeData);
-};
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_PARSING_PREPARSED_SCOPE_DATA_H_
diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc
index 0e74014542..ee496aad10 100644
--- a/deps/v8/src/parsing/preparser.cc
+++ b/deps/v8/src/parsing/preparser.cc
@@ -9,9 +9,8 @@
#include "src/conversions-inl.h"
#include "src/conversions.h"
#include "src/globals.h"
-#include "src/parsing/duplicate-finder.h"
#include "src/parsing/parser-base.h"
-#include "src/parsing/preparsed-scope-data.h"
+#include "src/parsing/preparse-data.h"
#include "src/parsing/preparser.h"
#include "src/unicode.h"
#include "src/utils.h"
@@ -19,26 +18,11 @@
namespace v8 {
namespace internal {
-// ----------------------------------------------------------------------------
-// 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_VALUE(x) ok); \
- if (!*ok) return x; \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
-
-#define CHECK_OK CHECK_OK_VALUE(Expression::Default())
-#define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
-
namespace {
-PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
+PreParserIdentifier GetSymbolHelper(Scanner* scanner,
+ const AstRawString* string,
+ AstValueFactory* avf) {
// These symbols require slightly different treatement:
// - regular keywords (async, await, etc.; treated in 1st switch.)
// - 'contextual' keywords (and may contain escaped; treated in 2nd switch.)
@@ -53,24 +37,20 @@ PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
default:
break;
}
- switch (scanner->current_contextual_token()) {
- case Token::CONSTRUCTOR:
- return PreParserIdentifier::Constructor();
- case Token::NAME:
- return PreParserIdentifier::Name();
- default:
- break;
+ if (string == avf->constructor_string()) {
+ return PreParserIdentifier::Constructor();
+ }
+ if (string == avf->name_string()) {
+ return PreParserIdentifier::Name();
}
if (scanner->literal_contains_escapes()) {
return PreParserIdentifier::Default();
}
- switch (scanner->current_contextual_token()) {
- case Token::EVAL:
- return PreParserIdentifier::Eval();
- case Token::ARGUMENTS:
- return PreParserIdentifier::Arguments();
- default:
- break;
+ if (string == avf->eval_string()) {
+ return PreParserIdentifier::Eval();
+ }
+ if (string == avf->arguments_string()) {
+ return PreParserIdentifier::Arguments();
}
return PreParserIdentifier::Default();
}
@@ -78,12 +58,11 @@ PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
} // unnamed namespace
PreParserIdentifier PreParser::GetSymbol() const {
- PreParserIdentifier symbol = GetSymbolHelper(scanner());
- if (track_unresolved_variables_) {
- const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
- DCHECK_NOT_NULL(result);
- symbol.string_ = result;
- }
+ const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
+ PreParserIdentifier symbol =
+ GetSymbolHelper(scanner(), result, ast_value_factory());
+ DCHECK_NOT_NULL(result);
+ symbol.string_ = result;
return symbol;
}
@@ -94,6 +73,12 @@ PreParser::PreParseResult PreParser::PreParseProgram() {
scope->set_is_being_lazily_parsed(true);
#endif
+ if (FLAG_harmony_hashbang) {
+ // Note: We should only skip the hashbang in non-Eval scripts
+ // (currently, Eval is not handled by the PreParser).
+ scanner()->SkipHashBang();
+ }
+
// ModuleDeclarationInstantiation for Source Text Module Records creates a
// new Module Environment Record whose outer lexical environment record is
// the global scope.
@@ -101,26 +86,30 @@ PreParser::PreParseResult PreParser::PreParseProgram() {
FunctionState top_scope(&function_state_, &scope_, scope);
original_scope_ = scope_;
- bool ok = true;
- int start_position = scanner()->peek_location().beg_pos;
- PreParserStatementList body;
- ParseStatementList(body, Token::EOS, &ok);
+ int start_position = peek_position();
+ PreParserScopedStatementList body(pointer_buffer());
+ ParseStatementList(&body, Token::EOS);
original_scope_ = nullptr;
if (stack_overflow()) return kPreParseStackOverflow;
- if (!ok) {
- ReportUnexpectedToken(scanner()->current_token());
- } else if (is_strict(language_mode())) {
- CheckStrictOctalLiteral(start_position, scanner()->location().end_pos, &ok);
+ if (is_strict(language_mode())) {
+ CheckStrictOctalLiteral(start_position, scanner()->location().end_pos);
}
return kPreParseSuccess;
}
+void PreParserFormalParameters::ValidateDuplicate(PreParser* preparser) const {
+ if (has_duplicate_) preparser->ReportUnidentifiableError();
+}
+
+void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const {
+ if (strict_parameter_error_) preparser->ReportUnidentifiableError();
+}
+
PreParser::PreParseResult PreParser::PreParseFunction(
const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, bool is_inner_function, bool may_abort,
- int* use_counts, ProducedPreParsedScopeData** produced_preparsed_scope_data,
- int script_id) {
+ DeclarationScope* function_scope, int* use_counts,
+ ProducedPreparseData** produced_preparse_data, int script_id) {
DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
use_counts_ = use_counts;
set_script_id(script_id);
@@ -128,19 +117,7 @@ PreParser::PreParseResult PreParser::PreParseFunction(
function_scope->set_is_being_lazily_parsed(true);
#endif
- track_unresolved_variables_ =
- ShouldTrackUnresolvedVariables(is_inner_function);
-
- // Start collecting data for a new function which might contain skippable
- // functions.
- std::unique_ptr<PreParsedScopeDataBuilder::DataGatheringScope>
- preparsed_scope_data_builder_scope;
- if (FLAG_preparser_scope_analysis && !IsArrowFunction(kind)) {
- DCHECK(track_unresolved_variables_);
- preparsed_scope_data_builder_scope.reset(
- new PreParsedScopeDataBuilder::DataGatheringScope(function_scope,
- this));
- }
+ PreParserFormalParameters formals(function_scope);
// In the preparser, we use the function literal ids to count how many
// FunctionLiterals were encountered. The PreParser doesn't actually persist
@@ -153,122 +130,123 @@ PreParser::PreParseResult PreParser::PreParseFunction(
DCHECK_NULL(function_state_);
DCHECK_NULL(scope_);
FunctionState function_state(&function_state_, &scope_, function_scope);
- // This indirection is needed so that we can use the CHECK_OK macros.
- bool ok_holder = true;
- bool* ok = &ok_holder;
- PreParserFormalParameters formals(function_scope);
- DuplicateFinder duplicate_finder;
- std::unique_ptr<ExpressionClassifier> formals_classifier;
+ // Start collecting data for a new function which might contain skippable
+ // functions.
+ PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);
+
+ if (IsArrowFunction(kind)) {
+ formals.is_simple = function_scope->has_simple_parameters();
+ } else {
+ preparse_data_builder_scope.Start(function_scope);
- // Parse non-arrow function parameters. For arrow functions, the parameters
- // have already been parsed.
- if (!IsArrowFunction(kind)) {
- formals_classifier.reset(new ExpressionClassifier(this, &duplicate_finder));
+ // Parse non-arrow function parameters. For arrow functions, the parameters
+ // have already been parsed.
+ ParameterDeclarationParsingScope formals_scope(this);
// We return kPreParseSuccess in failure cases too - errors are retrieved
// separately by Parser::SkipLazyFunctionBody.
- ParseFormalParameterList(
- &formals,
- CHECK_OK_VALUE(pending_error_handler()->ErrorUnidentifiableByPreParser()
- ? kPreParseNotIdentifiableError
- : kPreParseSuccess));
- Expect(Token::RPAREN, CHECK_OK_VALUE(kPreParseSuccess));
+ ParseFormalParameterList(&formals);
+ if (formals_scope.has_duplicate()) formals.set_has_duplicate();
+ if (!formals.is_simple) {
+ BuildParameterInitializationBlock(formals);
+ }
+
+ Expect(Token::RPAREN);
int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(
- formals.arity, kind, formals.has_rest, function_scope->start_position(),
- formals_end_position, CHECK_OK_VALUE(kPreParseSuccess));
+ CheckArityRestrictions(formals.arity, kind, formals.has_rest,
+ function_scope->start_position(),
+ formals_end_position);
}
- Expect(Token::LBRACE, CHECK_OK_VALUE(kPreParseSuccess));
+ Expect(Token::LBRACE);
DeclarationScope* inner_scope = function_scope;
- LazyParsingResult result;
if (!formals.is_simple) {
inner_scope = NewVarblockScope();
- inner_scope->set_start_position(scanner()->location().beg_pos);
+ inner_scope->set_start_position(position());
}
{
BlockState block_state(&scope_, inner_scope);
- result = ParseStatementListAndLogFunction(&formals, may_abort, ok);
+ ParseStatementListAndLogFunction(&formals);
}
- if (!formals.is_simple) {
- BuildParameterInitializationBlock(formals, ok);
+ bool allow_duplicate_parameters = false;
+
+ if (formals.is_simple) {
+ if (is_sloppy(function_scope->language_mode())) {
+ function_scope->HoistSloppyBlockFunctions(nullptr);
+ }
+ allow_duplicate_parameters =
+ is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind);
+ } else {
if (is_sloppy(inner_scope->language_mode())) {
inner_scope->HoistSloppyBlockFunctions(nullptr);
}
SetLanguageMode(function_scope, inner_scope->language_mode());
inner_scope->set_end_position(scanner()->peek_location().end_pos);
- inner_scope->FinalizeBlockScope();
- } else {
- if (is_sloppy(function_scope->language_mode())) {
- function_scope->HoistSloppyBlockFunctions(nullptr);
+ if (inner_scope->FinalizeBlockScope() != nullptr) {
+ const AstRawString* conflict = inner_scope->FindVariableDeclaredIn(
+ function_scope, VariableMode::kLastLexicalVariableMode);
+ if (conflict != nullptr) ReportVarRedeclarationIn(conflict, inner_scope);
}
}
use_counts_ = nullptr;
- if (result == kLazyParsingAborted) {
- DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
- return kPreParseAbort;
- } else if (stack_overflow()) {
- DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
+ if (stack_overflow()) {
return kPreParseStackOverflow;
- } else if (pending_error_handler()->ErrorUnidentifiableByPreParser()) {
- DCHECK(!*ok);
+ } else if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
return kPreParseNotIdentifiableError;
- } else if (!*ok) {
+ } else if (has_error()) {
DCHECK(pending_error_handler()->has_pending_error());
} else {
DCHECK_EQ(Token::RBRACE, scanner()->peek());
- DCHECK(result == kLazyParsingComplete);
if (!IsArrowFunction(kind)) {
// Validate parameter names. We can do this only after parsing the
// function, since the function can declare itself strict.
- const bool allow_duplicate_parameters =
- is_sloppy(function_scope->language_mode()) && formals.is_simple &&
- !IsConciseMethod(kind);
- ValidateFormalParameters(function_scope->language_mode(),
- allow_duplicate_parameters, ok);
- if (!*ok) {
- if (pending_error_handler()->ErrorUnidentifiableByPreParser()) {
+ ValidateFormalParameters(language_mode(), formals,
+ allow_duplicate_parameters);
+ if (has_error()) {
+ if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
return kPreParseNotIdentifiableError;
} else {
return kPreParseSuccess;
}
}
- if (track_unresolved_variables_) {
- // Declare arguments after parsing the function since lexical
- // 'arguments' masks the arguments object. Declare arguments before
- // declaring the function var since the arguments object masks 'function
- // arguments'.
- function_scope->DeclareArguments(ast_value_factory());
+ // Declare arguments after parsing the function since lexical
+ // 'arguments' masks the arguments object. Declare arguments before
+ // declaring the function var since the arguments object masks 'function
+ // arguments'.
+ function_scope->DeclareArguments(ast_value_factory());
- DeclareFunctionNameVar(function_name, function_type, function_scope);
+ DeclareFunctionNameVar(function_name, function_type, function_scope);
+
+ if (preparse_data_builder_->HasData()) {
+ *produced_preparse_data =
+ ProducedPreparseData::For(preparse_data_builder_, main_zone());
}
+ }
- *produced_preparsed_scope_data = ProducedPreParsedScopeData::For(
- preparsed_scope_data_builder_, main_zone());
+ if (pending_error_handler()->has_error_unidentifiable_by_preparser()) {
+ return kPreParseNotIdentifiableError;
}
- DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
if (is_strict(function_scope->language_mode())) {
int end_pos = scanner()->location().end_pos;
- CheckStrictOctalLiteral(function_scope->start_position(), end_pos, ok);
+ CheckStrictOctalLiteral(function_scope->start_position(), end_pos);
}
}
- DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
+ DCHECK(!pending_error_handler()->has_error_unidentifiable_by_preparser());
return kPreParseSuccess;
}
-
// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
// See preparser-data.h for the data.
@@ -287,94 +265,87 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode,
- ZonePtrList<const AstRawString>* arguments_for_wrapped_function, bool* ok) {
+ ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
// Wrapped functions are not parsed in the preparser.
DCHECK_NULL(arguments_for_wrapped_function);
DCHECK_NE(FunctionLiteral::kWrapped, function_type);
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
- const RuntimeCallCounterId counters[2][2] = {
- {RuntimeCallCounterId::kPreParseBackgroundNoVariableResolution,
- RuntimeCallCounterId::kPreParseNoVariableResolution},
- {RuntimeCallCounterId::kPreParseBackgroundWithVariableResolution,
- RuntimeCallCounterId::kPreParseWithVariableResolution}};
- RuntimeCallTimerScope runtime_timer(
- runtime_call_stats_,
- counters[track_unresolved_variables_][parsing_on_main_thread_]);
+ const RuntimeCallCounterId counters[2] = {
+ RuntimeCallCounterId::kPreParseBackgroundWithVariableResolution,
+ RuntimeCallCounterId::kPreParseWithVariableResolution};
+ RuntimeCallTimerScope runtime_timer(runtime_call_stats_,
+ counters[parsing_on_main_thread_]);
base::ElapsedTimer timer;
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
DeclarationScope* function_scope = NewFunctionScope(kind);
function_scope->SetLanguageMode(language_mode);
+ int func_id = GetNextFunctionLiteralId();
+ bool skippable_function = false;
// Start collecting data for a new function which might contain skippable
// functions.
- std::unique_ptr<PreParsedScopeDataBuilder::DataGatheringScope>
- preparsed_scope_data_builder_scope;
- if (!function_state_->next_function_is_likely_called() &&
- preparsed_scope_data_builder_ != nullptr) {
- DCHECK(FLAG_preparser_scope_analysis);
- DCHECK(track_unresolved_variables_);
- preparsed_scope_data_builder_scope.reset(
- new PreParsedScopeDataBuilder::DataGatheringScope(function_scope,
- this));
- }
+ {
+ PreparseDataBuilder::DataGatheringScope preparse_data_builder_scope(this);
+ skippable_function = !function_state_->next_function_is_likely_called() &&
+ preparse_data_builder_ != nullptr;
+ if (skippable_function) {
+ preparse_data_builder_scope.Start(function_scope);
+ }
- FunctionState function_state(&function_state_, &scope_, function_scope);
- DuplicateFinder duplicate_finder;
- ExpressionClassifier formals_classifier(this, &duplicate_finder);
- int func_id = GetNextFunctionLiteralId();
+ FunctionState function_state(&function_state_, &scope_, function_scope);
- 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, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
- int formals_end_position = scanner()->location().end_pos;
+ Expect(Token::LPAREN);
+ int start_position = position();
+ function_scope->set_start_position(start_position);
+ PreParserFormalParameters formals(function_scope);
+ {
+ ParameterDeclarationParsingScope formals_scope(this);
+ ParseFormalParameterList(&formals);
+ if (formals_scope.has_duplicate()) formals.set_has_duplicate();
+ }
+ Expect(Token::RPAREN);
+ int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position,
- formals_end_position, CHECK_OK);
+ CheckArityRestrictions(formals.arity, kind, formals.has_rest,
+ start_position, formals_end_position);
- Expect(Token::LBRACE, CHECK_OK);
+ Expect(Token::LBRACE);
- // Parse function body.
- PreParserStatementList body;
- int pos = function_token_pos == kNoSourcePosition ? peek_position()
- : function_token_pos;
- ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
- FunctionBodyType::kBlock, true, CHECK_OK);
+ // Parse function body.
+ PreParserScopedStatementList body(pointer_buffer());
+ int pos = function_token_pos == kNoSourcePosition ? peek_position()
+ : function_token_pos;
+ AcceptINScope scope(this, true);
+ ParseFunctionBody(&body, function_name, pos, formals, kind, function_type,
+ FunctionBodyType::kBlock);
- // Parsing the body may change the language mode in our scope.
- language_mode = function_scope->language_mode();
+ // Parsing the body may change the language mode in our scope.
+ language_mode = function_scope->language_mode();
- if (is_sloppy(language_mode)) {
- function_scope->HoistSloppyBlockFunctions(nullptr);
- }
+ if (is_sloppy(language_mode)) {
+ function_scope->HoistSloppyBlockFunctions(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(language_mode, allow_duplicate_parameters, CHECK_OK);
-
- int end_position = scanner()->location().end_pos;
- if (is_strict(language_mode)) {
- CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
- }
+ // 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);
- if (preparsed_scope_data_builder_scope) {
- preparsed_scope_data_builder_scope->MarkFunctionAsSkippable(
- end_position, GetLastFunctionLiteralId() - func_id);
+ if (is_strict(language_mode)) {
+ CheckStrictOctalLiteral(start_position, end_position());
+ }
+ if (skippable_function) {
+ preparse_data_builder_scope.SetSkippableFunction(
+ function_scope, GetLastFunctionLiteralId() - func_id);
+ }
}
+
if (V8_UNLIKELY(FLAG_log_function_events)) {
double ms = timer.Elapsed().InMillisecondsF();
- const char* event_name = track_unresolved_variables_
- ? "preparse-resolution"
- : "preparse-no-resolution";
+ const char* event_name = "preparse-resolution";
// We might not always get a function name here. However, it can be easily
// reconstructed from the script id and the byte range in the log processor.
const char* name = "";
@@ -392,87 +363,47 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
return Expression::Default();
}
-PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction(
- PreParserFormalParameters* formals, bool may_abort, bool* ok) {
- PreParserStatementList body;
- LazyParsingResult result = ParseStatementList(
- body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
- if (result == kLazyParsingAborted) return result;
+void PreParser::ParseStatementListAndLogFunction(
+ PreParserFormalParameters* formals) {
+ PreParserScopedStatementList body(pointer_buffer());
+ ParseStatementList(&body, Token::RBRACE);
// Position right after terminal '}'.
- DCHECK_EQ(Token::RBRACE, scanner()->peek());
+ DCHECK_IMPLIES(!has_error(), scanner()->peek() == Token::RBRACE);
int body_end = scanner()->peek_location().end_pos;
DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple);
log_.LogFunction(body_end, formals->num_parameters(),
GetLastFunctionLiteralId());
- return kLazyParsingComplete;
}
-PreParserStatement PreParser::BuildParameterInitializationBlock(
- const PreParserFormalParameters& parameters, bool* ok) {
+PreParserBlock PreParser::BuildParameterInitializationBlock(
+ const PreParserFormalParameters& parameters) {
DCHECK(!parameters.is_simple);
DCHECK(scope()->is_function_scope());
- if (FLAG_preparser_scope_analysis &&
- scope()->AsDeclarationScope()->calls_sloppy_eval() &&
- preparsed_scope_data_builder_ != nullptr) {
+ if (scope()->AsDeclarationScope()->calls_sloppy_eval() &&
+ preparse_data_builder_ != nullptr) {
// We cannot replicate the Scope structure constructed by the Parser,
// because we've lost information whether each individual parameter was
// simple or not. Give up trying to produce data to skip inner functions.
- if (preparsed_scope_data_builder_->parent() != nullptr) {
+ if (preparse_data_builder_->parent() != nullptr) {
// Lazy parsing started before the current function; the function which
// cannot contain skippable functions is the parent function. (Its inner
// functions cannot either; they are implicitly bailed out.)
- preparsed_scope_data_builder_->parent()->Bailout();
+ preparse_data_builder_->parent()->Bailout();
} else {
// Lazy parsing started at the current function; it cannot contain
// skippable functions.
- preparsed_scope_data_builder_->Bailout();
+ preparse_data_builder_->Bailout();
}
}
- return PreParserStatement::Default();
-}
-
-PreParserExpression PreParser::ExpressionFromIdentifier(
- const PreParserIdentifier& name, int start_position, InferName infer) {
- VariableProxy* proxy = nullptr;
- if (track_unresolved_variables_) {
- DCHECK_NOT_NULL(name.string_);
- proxy = scope()->NewUnresolved(factory()->ast_node_factory(), name.string_,
- start_position, NORMAL_VARIABLE);
- }
- return PreParserExpression::FromIdentifier(name, proxy, zone());
+ return PreParserBlock::Default();
}
-void PreParser::DeclareAndInitializeVariables(
- PreParserStatement block,
- const DeclarationDescriptor* declaration_descriptor,
- const DeclarationParsingResult::Declaration* declaration,
- ZonePtrList<const AstRawString>* names, bool* ok) {
- if (declaration->pattern.variables_ != nullptr) {
- DCHECK(FLAG_lazy_inner_functions);
- DCHECK(track_unresolved_variables_);
- for (auto variable : *(declaration->pattern.variables_)) {
- declaration_descriptor->scope->RemoveUnresolved(variable);
- Variable* var = scope()->DeclareVariableName(
- variable->raw_name(), declaration_descriptor->mode);
- if (FLAG_preparser_scope_analysis) {
- MarkLoopVariableAsAssigned(declaration_descriptor->scope, var,
- declaration_descriptor->declaration_kind);
- // This is only necessary if there is an initializer, but we don't have
- // that information here. Consequently, the preparser sometimes says
- // maybe-assigned where the parser (correctly) says never-assigned.
- }
- if (names) {
- names->Add(variable->raw_name(), zone());
- }
- }
- }
+bool PreParser::IdentifierEquals(const PreParserIdentifier& identifier,
+ const AstRawString* other) {
+ return identifier.string_ == other;
}
-#undef CHECK_OK
-#undef CHECK_OK_CUSTOM
-
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h
index 65509a2029..d403854743 100644
--- a/deps/v8/src/parsing/preparser.h
+++ b/deps/v8/src/parsing/preparser.h
@@ -22,7 +22,7 @@ namespace internal {
// interface as AstNodeFactory, so ParserBase doesn't need to care which one is
// used.
-class PreParsedScopeDataBuilder;
+class PreparseDataBuilder;
class PreParserIdentifier {
public:
@@ -56,8 +56,12 @@ class PreParserIdentifier {
}
bool IsNull() const { return type_ == kNullIdentifier; }
bool IsEval() const { return type_ == kEvalIdentifier; }
+ bool IsAsync() const { return type_ == kAsyncIdentifier; }
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
- bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
+ bool IsEvalOrArguments() const {
+ STATIC_ASSERT(kEvalIdentifier + 1 == kArgumentsIdentifier);
+ return IsInRange(type_, kEvalIdentifier, kArgumentsIdentifier);
+ }
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
bool IsAwait() const { return type_ == kAwaitIdentifier; }
bool IsName() const { return type_ == kNameIdentifier; }
@@ -77,7 +81,6 @@ class PreParserIdentifier {
};
explicit PreParserIdentifier(Type type) : string_(nullptr), type_(type) {}
- // Only non-nullptr when PreParser.track_unresolved_variables_ is true.
const AstRawString* string_;
Type type_;
@@ -88,89 +91,54 @@ class PreParserIdentifier {
class PreParserExpression {
public:
- using VariableZoneThreadedListType =
- ZoneThreadedList<VariableProxy, VariableProxy::PreParserNext>;
-
- PreParserExpression()
- : code_(TypeField::encode(kNull)), variables_(nullptr) {}
+ PreParserExpression() : code_(TypeField::encode(kNull)) {}
static PreParserExpression Null() { return PreParserExpression(); }
+ static PreParserExpression Failure() {
+ return PreParserExpression(TypeField::encode(kFailure));
+ }
- static PreParserExpression Default(
- VariableZoneThreadedListType* variables = nullptr) {
- return PreParserExpression(TypeField::encode(kExpression), variables);
+ static PreParserExpression Default() {
+ return PreParserExpression(TypeField::encode(kExpression));
}
static PreParserExpression Spread(const PreParserExpression& expression) {
- return PreParserExpression(TypeField::encode(kSpreadExpression),
- expression.variables_);
+ return PreParserExpression(TypeField::encode(kSpreadExpression));
}
- static PreParserExpression FromIdentifier(const PreParserIdentifier& id,
- VariableProxy* variable,
- Zone* zone) {
- PreParserExpression expression(TypeField::encode(kIdentifierExpression) |
- IdentifierTypeField::encode(id.type_));
- expression.AddVariable(variable, zone);
- return expression;
+ static PreParserExpression FromIdentifier(const PreParserIdentifier& id) {
+ return PreParserExpression(TypeField::encode(kIdentifierExpression) |
+ IdentifierTypeField::encode(id.type_));
}
static PreParserExpression BinaryOperation(const PreParserExpression& left,
Token::Value op,
const PreParserExpression& right,
Zone* zone) {
- if (op == Token::COMMA) {
- // Possibly an arrow function parameter list.
- if (left.variables_ == nullptr) {
- return PreParserExpression(TypeField::encode(kExpression),
- right.variables_);
- }
- if (right.variables_ != nullptr) {
- left.variables_->Append(std::move(*right.variables_));
- }
- return PreParserExpression(TypeField::encode(kExpression),
- left.variables_);
- }
return PreParserExpression(TypeField::encode(kExpression));
}
- static PreParserExpression Assignment(
- VariableZoneThreadedListType* variables) {
+ static PreParserExpression Assignment() {
return PreParserExpression(TypeField::encode(kExpression) |
- ExpressionTypeField::encode(kAssignment),
- variables);
+ ExpressionTypeField::encode(kAssignment));
}
static PreParserExpression NewTargetExpression() {
return PreParserExpression::Default();
}
- static PreParserExpression ObjectLiteral(
- VariableZoneThreadedListType* variables) {
- return PreParserExpression(TypeField::encode(kObjectLiteralExpression),
- variables);
+ static PreParserExpression ObjectLiteral() {
+ return PreParserExpression(TypeField::encode(kObjectLiteralExpression));
}
- static PreParserExpression ArrayLiteral(
- VariableZoneThreadedListType* variables) {
- return PreParserExpression(TypeField::encode(kArrayLiteralExpression),
- variables);
+ 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 UseAsmStringLiteral() {
- return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
- IsUseAsmField::encode(true));
- }
-
static PreParserExpression This() {
return PreParserExpression(TypeField::encode(kExpression) |
ExpressionTypeField::encode(kThisExpression));
@@ -229,6 +197,9 @@ class PreParserExpression {
}
bool IsNull() const { return TypeField::decode(code_) == kNull; }
+ bool IsFailureExpression() const {
+ return TypeField::decode(code_) == kFailure;
+ }
bool IsIdentifier() const {
return TypeField::decode(code_) == kIdentifierExpression;
@@ -252,18 +223,14 @@ class PreParserExpression {
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 IsPattern() const {
+ STATIC_ASSERT(kObjectLiteralExpression + 1 == kArrayLiteralExpression);
+ return IsInRange(TypeField::decode(code_), kObjectLiteralExpression,
+ kArrayLiteralExpression);
}
- bool IsUseAsmLiteral() const {
- return TypeField::decode(code_) == kStringLiteralExpression &&
- IsUseAsmField::decode(code_);
+ bool IsStringLiteral() const {
+ return TypeField::decode(code_) == kStringLiteralExpression;
}
bool IsThis() const {
@@ -325,24 +292,25 @@ class PreParserExpression {
return TypeField::decode(code_) == kSpreadExpression;
}
+ bool is_parenthesized() const { return IsParenthesizedField::decode(code_); }
+
+ void mark_parenthesized() {
+ code_ = IsParenthesizedField::update(code_, true);
+ }
+
+ void clear_parenthesized() {
+ code_ = IsParenthesizedField::update(code_, false);
+ }
+
PreParserExpression AsFunctionLiteral() { return *this; }
// Dummy implementation for making expression->somefunc() work in both Parser
// and PreParser.
PreParserExpression* operator->() { return this; }
- void set_is_private_field() {
- if (variables_ != nullptr) {
- DCHECK(IsIdentifier());
- DCHECK(AsIdentifier().IsPrivateName());
- DCHECK_EQ(1, variables_->LengthForTest());
- variables_->first()->set_is_private_field();
- }
- }
-
// More dummy implementations of things PreParser doesn't need to track:
void SetShouldEagerCompile() {}
- void mark_as_iife() {}
+ void mark_as_oneshot_iife() {}
int position() const { return kNoSourcePosition; }
void set_function_token_position(int position) {}
@@ -352,6 +320,7 @@ class PreParserExpression {
private:
enum Type {
kNull,
+ kFailure,
kExpression,
kIdentifierExpression,
kStringLiteralExpression,
@@ -373,20 +342,8 @@ class PreParserExpression {
kAssignment
};
- explicit PreParserExpression(
- uint32_t expression_code,
- VariableZoneThreadedListType* variables = nullptr)
- : code_(expression_code), variables_(variables) {}
-
- void AddVariable(VariableProxy* variable, Zone* zone) {
- if (variable == nullptr) {
- return;
- }
- if (variables_ == nullptr) {
- variables_ = new (zone) VariableZoneThreadedListType();
- }
- variables_->Add(variable);
- }
+ explicit PreParserExpression(uint32_t expression_code)
+ : code_(expression_code) {}
// The first three bits are for the Type.
typedef BitField<Type, 0, 3> TypeField;
@@ -396,80 +353,66 @@ class PreParserExpression {
// 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;
+ typedef BitField<bool, TypeField::kNext, 1> IsParenthesizedField;
// 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, 4> ExpressionTypeField;
- typedef BitField<bool, TypeField::kNext, 1> IsUseStrictField;
- typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseAsmField;
- typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 8>
+ typedef BitField<ExpressionType, IsParenthesizedField::kNext, 4>
+ ExpressionTypeField;
+ typedef BitField<PreParserIdentifier::Type, IsParenthesizedField::kNext, 8>
IdentifierTypeField;
- typedef BitField<bool, TypeField::kNext, 1> HasCoverInitializedNameField;
+ typedef BitField<bool, IsParenthesizedField::kNext, 1>
+ HasCoverInitializedNameField;
uint32_t code_;
- // If the PreParser is used in the variable tracking mode, PreParserExpression
- // accumulates variables in that expression.
- VariableZoneThreadedListType* variables_;
-
friend class PreParser;
friend class PreParserFactory;
friend class PreParserExpressionList;
};
+class PreParserStatement;
+class PreParserStatementList {
+ public:
+ PreParserStatementList() : PreParserStatementList(false) {}
+ PreParserStatementList* operator->() { return this; }
+ void Add(const PreParserStatement& element, Zone* zone) {}
+ static PreParserStatementList Null() { return PreParserStatementList(true); }
+ bool IsNull() const { return is_null_; }
+
+ private:
+ explicit PreParserStatementList(bool is_null) : is_null_(is_null) {}
+ bool is_null_;
+};
+
+class PreParserScopedStatementList {
+ public:
+ explicit PreParserScopedStatementList(std::vector<void*>* buffer) {}
+ void Rewind() {}
+ void MergeInto(const PreParserScopedStatementList* other) {}
+ void Add(const PreParserStatement& element) {}
+ int length() { return 0; }
+};
// The pre-parser doesn't need to build lists of expressions, identifiers, or
// the like. If the PreParser is used in variable tracking mode, it needs to
// build lists of variables though.
class PreParserExpressionList {
- using VariableZoneThreadedListType =
- ZoneThreadedList<VariableProxy, VariableProxy::PreParserNext>;
-
public:
- // These functions make list->Add(some_expression) work (and do nothing).
- PreParserExpressionList() : PreParserExpressionList(0) {}
- PreParserExpressionList* operator->() { return this; }
- void Add(const PreParserExpression& expression, Zone* zone) {
- if (expression.variables_ != nullptr) {
- DCHECK(FLAG_lazy_inner_functions);
- DCHECK_NOT_NULL(zone);
- if (variables_ == nullptr) {
- variables_ = new (zone) VariableZoneThreadedListType();
- }
- variables_->Append(std::move(*expression.variables_));
- }
+ explicit PreParserExpressionList(std::vector<void*>* buffer) : length_(0) {}
+
+ int length() const { return length_; }
+
+ void Add(const PreParserExpression& expression) {
++length_;
}
- int length() const { return length_; }
- static PreParserExpressionList Null() { return PreParserExpressionList(-1); }
- bool IsNull() const { return length_ == -1; }
- void Set(int index, const PreParserExpression& element) {}
private:
- explicit PreParserExpressionList(int n) : length_(n), variables_(nullptr) {}
int length_;
- VariableZoneThreadedListType* variables_;
-
friend class PreParser;
friend class PreParserFactory;
};
-class PreParserStatement;
-
-class PreParserStatementList {
- public:
- PreParserStatementList() : PreParserStatementList(false) {}
- PreParserStatementList* operator->() { return this; }
- void Add(const PreParserStatement& element, Zone* zone) {}
- static PreParserStatementList Null() { return PreParserStatementList(true); }
- bool IsNull() const { return is_null_; }
-
- private:
- explicit PreParserStatementList(bool is_null) : is_null_(is_null) {}
- bool is_null_;
-};
-
class PreParserStatement {
public:
static PreParserStatement Default() {
@@ -488,33 +431,21 @@ class PreParserStatement {
return PreParserStatement(kJumpStatement);
}
+ void InitializeStatements(const PreParserScopedStatementList& statements,
+ Zone* zone) {}
+
// Creates expression statement from expression.
// Preserves being an unparenthesized string literal, possibly
// "use strict".
static PreParserStatement ExpressionStatement(
const PreParserExpression& expression) {
- if (expression.IsUseStrictLiteral()) {
- return PreParserStatement(kUseStrictExpressionStatement);
- }
- if (expression.IsUseAsmLiteral()) {
- return PreParserStatement(kUseAsmExpressionStatement);
- }
if (expression.IsStringLiteral()) {
return PreParserStatement(kStringLiteralExpressionStatement);
}
return Default();
}
- bool IsStringLiteral() {
- return code_ == kStringLiteralExpressionStatement || IsUseStrictLiteral() ||
- IsUseAsmLiteral();
- }
-
- bool IsUseStrictLiteral() {
- return code_ == kUseStrictExpressionStatement;
- }
-
- bool IsUseAsmLiteral() { return code_ == kUseAsmExpressionStatement; }
+ bool IsStringLiteral() { return code_ == kStringLiteralExpressionStatement; }
bool IsJumpStatement() {
return code_ == kJumpStatement;
@@ -540,22 +471,46 @@ class PreParserStatement {
void Initialize(PreParserStatement init, const PreParserExpression& cond,
PreParserStatement next, PreParserStatement body,
const SourceRange& body_range = {}) {}
+ void Initialize(PreParserExpression each, const PreParserExpression& subject,
+ PreParserStatement body, const SourceRange& body_range = {}) {
+ }
- private:
+ protected:
enum Type {
kNullStatement,
kEmptyStatement,
kUnknownStatement,
kJumpStatement,
kStringLiteralExpressionStatement,
- kUseStrictExpressionStatement,
- kUseAsmExpressionStatement,
};
explicit PreParserStatement(Type code) : code_(code) {}
+
+ private:
Type code_;
};
+// A PreParserBlock extends statement with a place to store the scope.
+// The scope is dropped as the block is returned as a statement.
+class PreParserBlock : public PreParserStatement {
+ public:
+ void set_scope(Scope* scope) { scope_ = scope; }
+ Scope* scope() const { return scope_; }
+ static PreParserBlock Default() {
+ return PreParserBlock(PreParserStatement::kUnknownStatement);
+ }
+ static PreParserBlock Null() {
+ return PreParserBlock(PreParserStatement::kNullStatement);
+ }
+ // Dummy implementation for making block->somefunc() work in both Parser and
+ // PreParser.
+ PreParserBlock* operator->() { return this; }
+
+ private:
+ explicit PreParserBlock(PreParserStatement::Type type)
+ : PreParserStatement(type), scope_(nullptr) {}
+ Scope* scope_;
+};
class PreParserFactory {
public:
@@ -566,16 +521,7 @@ class PreParserFactory {
PreParserExpression NewStringLiteral(const PreParserIdentifier& identifier,
int pos) {
- // This is needed for object literal property names. Property names are
- // normalized to string literals during object literal parsing.
- PreParserExpression expression = PreParserExpression::Default();
- if (identifier.string_ != nullptr) {
- DCHECK(FLAG_lazy_inner_functions);
- VariableProxy* variable = ast_node_factory_.NewVariableProxy(
- identifier.string_, NORMAL_VARIABLE);
- expression.AddVariable(variable, zone_);
- }
- return expression;
+ return PreParserExpression::Default();
}
PreParserExpression NewNumberLiteral(double number,
int pos) {
@@ -593,30 +539,31 @@ class PreParserFactory {
}
PreParserExpression NewArrayLiteral(const PreParserExpressionList& values,
int first_spread_index, int pos) {
- return PreParserExpression::ArrayLiteral(values.variables_);
+ return PreParserExpression::ArrayLiteral();
}
PreParserExpression NewClassLiteralProperty(const PreParserExpression& key,
const PreParserExpression& value,
ClassLiteralProperty::Kind kind,
bool is_static,
- bool is_computed_name) {
+ bool is_computed_name,
+ bool is_private) {
return PreParserExpression::Default();
}
PreParserExpression NewObjectLiteralProperty(const PreParserExpression& key,
const PreParserExpression& value,
ObjectLiteralProperty::Kind kind,
bool is_computed_name) {
- return PreParserExpression::Default(value.variables_);
+ return PreParserExpression::Default();
}
PreParserExpression NewObjectLiteralProperty(const PreParserExpression& key,
const PreParserExpression& value,
bool is_computed_name) {
- return PreParserExpression::Default(value.variables_);
+ return PreParserExpression::Default();
}
PreParserExpression NewObjectLiteral(
const PreParserExpressionList& properties, int boilerplate_properties,
int pos, bool has_rest_property) {
- return PreParserExpression::ObjectLiteral(properties.variables_);
+ return PreParserExpression::ObjectLiteral();
}
PreParserExpression NewVariableProxy(void* variable) {
return PreParserExpression::Default();
@@ -653,16 +600,12 @@ class PreParserFactory {
int pos) {
return PreParserExpression::Default();
}
- PreParserExpression NewRewritableExpression(
- const PreParserExpression& expression, Scope* scope) {
- return expression;
- }
PreParserExpression NewAssignment(Token::Value op,
const PreParserExpression& left,
const PreParserExpression& right, int pos) {
// Identifiers need to be tracked since this might be a parameter with a
// default value inside an arrow function parameter list.
- return PreParserExpression::Assignment(left.variables_);
+ return PreParserExpression::Assignment();
}
PreParserExpression NewYield(const PreParserExpression& expression, int pos,
Suspend::OnAbruptResume on_abrupt_resume) {
@@ -717,14 +660,14 @@ class PreParserFactory {
}
PreParserExpression NewFunctionLiteral(
const PreParserIdentifier& name, Scope* scope,
- PreParserStatementList body, int expected_property_count,
+ const PreParserScopedStatementList& body, int expected_property_count,
int parameter_count, int function_length,
FunctionLiteral::ParameterFlag has_duplicate_parameters,
FunctionLiteral::FunctionType function_type,
FunctionLiteral::EagerCompileHint eager_compile_hint, int position,
bool has_braces, int function_literal_id,
- ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr) {
- DCHECK_NULL(produced_preparsed_scope_data);
+ ProducedPreparseData* produced_preparse_data = nullptr) {
+ DCHECK_NULL(produced_preparse_data);
return PreParserExpression::Default();
}
@@ -734,17 +677,25 @@ class PreParserFactory {
}
PreParserExpression NewEmptyParentheses(int pos) {
- return PreParserExpression::Default();
+ PreParserExpression result = PreParserExpression::Default();
+ result.mark_parenthesized();
+ return result;
}
- PreParserStatement NewEmptyStatement(int pos) {
- return PreParserStatement::Default();
+ PreParserStatement EmptyStatement() { return PreParserStatement::Default(); }
+
+ PreParserBlock NewBlock(int capacity, bool ignore_completion_value) {
+ return PreParserBlock::Default();
}
- PreParserStatement NewBlock(
- int capacity, bool ignore_completion_value,
- ZonePtrList<const AstRawString>* labels = nullptr) {
- return PreParserStatement::Default();
+ PreParserBlock NewBlock(bool ignore_completion_value,
+ ZonePtrList<const AstRawString>* labels) {
+ return PreParserBlock::Default();
+ }
+
+ PreParserBlock NewBlock(bool ignore_completion_value,
+ const PreParserScopedStatementList& list) {
+ return PreParserBlock::Default();
}
PreParserStatement NewDebuggerStatement(int pos) {
@@ -801,8 +752,9 @@ class PreParserFactory {
return PreParserStatement::Default();
}
- PreParserStatement NewCaseClause(const PreParserExpression& label,
- PreParserStatementList statements) {
+ PreParserStatement NewCaseClause(
+ const PreParserExpression& label,
+ const PreParserScopedStatementList& statements) {
return PreParserStatement::Default();
}
@@ -821,7 +773,7 @@ class PreParserFactory {
PreParserStatement NewForOfStatement(
ZonePtrList<const AstRawString>* labels,
- ZonePtrList<const AstRawString>* own_labels, int pos) {
+ ZonePtrList<const AstRawString>* own_labels, int pos, IteratorType type) {
return PreParserStatement::Default();
}
@@ -837,35 +789,32 @@ class PreParserFactory {
}
private:
- // For creating VariableProxy objects (if
- // PreParser::track_unresolved_variables_ is used).
+ // For creating VariableProxy objects to track unresolved variables.
AstNodeFactory ast_node_factory_;
Zone* zone_;
};
+class PreParser;
-struct PreParserFormalParameters : FormalParametersBase {
- struct Parameter : public ZoneObject {
- using VariableZoneThreadedListType =
- ZoneThreadedList<VariableProxy, VariableProxy::PreParserNext>;
-
- Parameter(VariableZoneThreadedListType* variables, bool is_rest)
- : variables_(variables), is_rest(is_rest) {}
- Parameter** next() { return &next_parameter; }
- Parameter* const* next() const { return &next_parameter; }
-
- VariableZoneThreadedListType* variables_;
- Parameter* next_parameter = nullptr;
- bool is_rest : 1;
- };
+class PreParserFormalParameters : public FormalParametersBase {
+ public:
explicit PreParserFormalParameters(DeclarationScope* scope)
: FormalParametersBase(scope) {}
- base::ThreadedList<Parameter> params;
-};
+ void set_has_duplicate() { has_duplicate_ = true; }
+ bool has_duplicate() { return has_duplicate_; }
+ void ValidateDuplicate(PreParser* preparser) const;
+ void set_strict_parameter_error(const Scanner::Location& loc,
+ MessageTemplate message) {
+ strict_parameter_error_ = loc.IsValid();
+ }
+ void ValidateStrictMode(PreParser* preparser) const;
-class PreParser;
+ private:
+ bool has_duplicate_ = false;
+ bool strict_parameter_error_ = false;
+};
class PreParserTarget {
public:
@@ -880,7 +829,7 @@ class PreParserTargetScope {
class PreParserFuncNameInferrer {
public:
- PreParserFuncNameInferrer(AstValueFactory* avf, Zone* zone) {}
+ explicit PreParserFuncNameInferrer(AstValueFactory* avf) {}
void RemoveAsyncKeywordFromEnd() const {}
void Infer() const {}
void RemoveLastFunction() const {}
@@ -920,39 +869,40 @@ class PreParserSourceRangeScope {
DISALLOW_IMPLICIT_CONSTRUCTORS(PreParserSourceRangeScope);
};
+class PreParserPropertyList {};
+
template <>
struct ParserTypes<PreParser> {
typedef ParserBase<PreParser> Base;
typedef PreParser Impl;
// Return types for traversing functions.
- typedef PreParserIdentifier Identifier;
+ typedef PreParserExpression ClassLiteralProperty;
typedef PreParserExpression Expression;
typedef PreParserExpression FunctionLiteral;
typedef PreParserExpression ObjectLiteralProperty;
- typedef PreParserExpression ClassLiteralProperty;
typedef PreParserExpression Suspend;
- typedef PreParserExpression RewritableExpression;
typedef PreParserExpressionList ExpressionList;
typedef PreParserExpressionList ObjectPropertyList;
- typedef PreParserExpressionList ClassPropertyList;
typedef PreParserFormalParameters FormalParameters;
- typedef PreParserStatement Statement;
- typedef PreParserStatementList StatementList;
- typedef PreParserStatement Block;
+ typedef PreParserIdentifier Identifier;
+ typedef PreParserPropertyList ClassPropertyList;
+ typedef PreParserScopedStatementList StatementList;
+ typedef PreParserBlock Block;
typedef PreParserStatement BreakableStatement;
- typedef PreParserStatement IterationStatement;
typedef PreParserStatement ForStatement;
+ typedef PreParserStatement IterationStatement;
+ typedef PreParserStatement Statement;
// For constructing objects returned by the traversing functions.
typedef PreParserFactory Factory;
- typedef PreParserTarget Target;
- typedef PreParserTargetScope TargetScope;
+ // Other implementation-specific tasks.
typedef PreParserFuncNameInferrer FuncNameInferrer;
typedef PreParserSourceRange SourceRange;
typedef PreParserSourceRangeScope SourceRangeScope;
- static constexpr bool ExpressionClassifierReportErrors = false;
+ typedef PreParserTarget Target;
+ typedef PreParserTargetScope TargetScope;
};
@@ -970,7 +920,6 @@ struct ParserTypes<PreParser> {
// it is used) are generally omitted.
class PreParser : public ParserBase<PreParser> {
friend class ParserBase<PreParser>;
- friend class v8::internal::ExpressionClassifier<ParserTypes<PreParser>>;
public:
typedef PreParserIdentifier Identifier;
@@ -979,7 +928,6 @@ class PreParser : public ParserBase<PreParser> {
enum PreParseResult {
kPreParseStackOverflow,
- kPreParseAbort,
kPreParseNotIdentifiableError,
kPreParseSuccess
};
@@ -995,8 +943,7 @@ class PreParser : public ParserBase<PreParser> {
runtime_call_stats, logger, script_id,
parsing_module, parsing_on_main_thread),
use_counts_(nullptr),
- track_unresolved_variables_(false),
- preparsed_scope_data_builder_(nullptr) {}
+ preparse_data_builder_(nullptr) {}
static bool IsPreParser() { return true; }
@@ -1019,25 +966,23 @@ class PreParser : public ParserBase<PreParser> {
PreParseResult PreParseFunction(
const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, bool track_unresolved_variables,
- bool may_abort, int* use_counts,
- ProducedPreParsedScopeData** produced_preparser_scope_data,
- int script_id);
-
- V8_INLINE static bool ShouldTrackUnresolvedVariables(bool is_inner_function) {
- return FLAG_preparser_scope_analysis || is_inner_function;
- }
+ DeclarationScope* function_scope, int* use_counts,
+ ProducedPreparseData** produced_preparser_scope_data, int script_id);
- PreParsedScopeDataBuilder* preparsed_scope_data_builder() const {
- return preparsed_scope_data_builder_;
+ PreparseDataBuilder* preparse_data_builder() const {
+ return preparse_data_builder_;
}
- void set_preparsed_scope_data_builder(
- PreParsedScopeDataBuilder* preparsed_scope_data_builder) {
- preparsed_scope_data_builder_ = preparsed_scope_data_builder;
+ void set_preparse_data_builder(PreparseDataBuilder* preparse_data_builder) {
+ preparse_data_builder_ = preparse_data_builder;
}
private:
+ friend class i::ExpressionScope<ParserTypes<PreParser>>;
+ friend class i::VariableDeclarationParsingScope<ParserTypes<PreParser>>;
+ friend class i::ParameterDeclarationParsingScope<ParserTypes<PreParser>>;
+ friend class i::ArrowHeadParsingScope<ParserTypes<PreParser>>;
+ friend class PreParserFormalParameters;
// 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
@@ -1057,13 +1002,11 @@ class PreParser : public ParserBase<PreParser> {
return pending_error_handler_;
}
- V8_INLINE bool SkipFunction(
- const AstRawString* name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, int* num_parameters,
- ProducedPreParsedScopeData** produced_preparsed_scope_data,
- bool is_inner_function, bool may_abort,
- FunctionLiteral::EagerCompileHint* hint, bool* ok) {
+ V8_INLINE bool SkipFunction(const AstRawString* name, FunctionKind kind,
+ FunctionLiteral::FunctionType function_type,
+ DeclarationScope* function_scope,
+ int* num_parameters,
+ ProducedPreparseData** produced_preparse_data) {
UNREACHABLE();
}
@@ -1072,15 +1015,13 @@ class PreParser : public ParserBase<PreParser> {
FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_pos, FunctionLiteral::FunctionType function_type,
LanguageMode language_mode,
- ZonePtrList<const AstRawString>* arguments_for_wrapped_function,
- bool* ok);
+ ZonePtrList<const AstRawString>* arguments_for_wrapped_function);
PreParserExpression InitializeObjectLiteral(PreParserExpression literal) {
return literal;
}
- LazyParsingResult ParseStatementListAndLogFunction(
- PreParserFormalParameters* formals, bool maybe_abort, bool* ok);
+ void ParseStatementListAndLogFunction(PreParserFormalParameters* formals);
struct TemplateLiteralState {};
@@ -1099,7 +1040,7 @@ class PreParser : public ParserBase<PreParser> {
const PreParserExpression& expression) {
return expression.IsPropertyWithPrivateFieldKey();
}
- V8_INLINE void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
+ V8_INLINE void CheckConflictingVarDeclarations(Scope* scope) {}
V8_INLINE void SetLanguageMode(Scope* scope, LanguageMode mode) {
scope->SetLanguageMode(mode);
@@ -1114,22 +1055,14 @@ class PreParser : public ParserBase<PreParser> {
SpreadCallNew(const PreParserExpression& function,
const PreParserExpressionList& args, int pos);
- V8_INLINE void RewriteDestructuringAssignments() {}
-
V8_INLINE void PrepareGeneratorVariables() {}
V8_INLINE void RewriteAsyncFunctionBody(
- PreParserStatementList body, PreParserStatement block,
- const PreParserExpression& return_value, bool* ok) {}
-
- void DeclareAndInitializeVariables(
- PreParserStatement block,
- const DeclarationDescriptor* declaration_descriptor,
- const DeclarationParsingResult::Declaration* declaration,
- ZonePtrList<const AstRawString>* names, bool* ok);
+ const PreParserScopedStatementList* body, PreParserStatement block,
+ const PreParserExpression& return_value) {}
V8_INLINE void DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>** own_labels,
- const PreParserExpression& expr, bool* ok) {
+ const PreParserExpression& expr) {
DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait());
DCHECK(IsIdentifier(expr));
}
@@ -1149,24 +1082,29 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default();
}
- V8_INLINE void RewriteCatchPattern(CatchInfo* catch_info, bool* ok) {
- if (track_unresolved_variables_) {
- const AstRawString* catch_name = catch_info->name.string_;
- if (catch_name == nullptr) {
- catch_name = ast_value_factory()->dot_catch_string();
- }
- catch_info->scope->DeclareCatchVariableName(catch_name);
+ void DeclareVariable(VariableProxy* proxy, VariableKind kind,
+ VariableMode mode, InitializationFlag init, Scope* scope,
+ bool* was_added, int position) {
+ DeclareVariableName(proxy->raw_name(), mode, scope, was_added, kind);
+ }
- if (catch_info->pattern.variables_ != nullptr) {
- for (auto variable : *catch_info->pattern.variables_) {
- scope()->DeclareVariableName(variable->raw_name(),
- VariableMode::kLet);
- }
- }
+ void DeclareVariableName(const AstRawString* name, VariableMode mode,
+ Scope* scope, bool* was_added,
+ VariableKind kind = NORMAL_VARIABLE) {
+ if (scope->DeclareVariableName(name, mode, was_added, kind) == nullptr) {
+ ReportUnidentifiableError();
}
}
- V8_INLINE void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok) {}
+ V8_INLINE PreParserBlock RewriteCatchPattern(CatchInfo* catch_info) {
+ return PreParserBlock::Default();
+ }
+
+ V8_INLINE void ReportVarRedeclarationIn(const AstRawString* name,
+ Scope* scope) {
+ ReportUnidentifiableError();
+ }
+
V8_INLINE PreParserStatement RewriteTryStatement(
PreParserStatement try_block, PreParserStatement catch_block,
const SourceRange& catch_range, PreParserStatement finally_block,
@@ -1174,20 +1112,24 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default();
}
+ V8_INLINE void ReportUnexpectedTokenAt(
+ Scanner::Location location, Token::Value token,
+ MessageTemplate message = MessageTemplate::kUnexpectedToken) {
+ ReportUnidentifiableError();
+ }
V8_INLINE void ParseAndRewriteGeneratorFunctionBody(
- int pos, FunctionKind kind, PreParserStatementList body, bool* ok) {
- ParseStatementList(body, Token::RBRACE, ok);
+ int pos, FunctionKind kind, PreParserScopedStatementList* body) {
+ ParseStatementList(body, Token::RBRACE);
}
V8_INLINE void ParseAndRewriteAsyncGeneratorFunctionBody(
- int pos, FunctionKind kind, PreParserStatementList body, bool* ok) {
- ParseStatementList(body, Token::RBRACE, ok);
+ int pos, FunctionKind kind, PreParserScopedStatementList* body) {
+ ParseStatementList(body, Token::RBRACE);
}
V8_INLINE void DeclareFunctionNameVar(
const AstRawString* function_name,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope) {
- if (track_unresolved_variables_ &&
- function_type == FunctionLiteral::kNamedExpression &&
+ if (function_type == FunctionLiteral::kNamedExpression &&
function_scope->LookupLocal(function_name) == nullptr) {
DCHECK_EQ(function_scope, scope());
function_scope->DeclareFunctionVar(function_name);
@@ -1202,31 +1144,33 @@ class PreParser : public ParserBase<PreParser> {
function_scope);
}
- V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body,
- int pos, bool* ok) {
- return PreParserExpression::Default();
- }
+ bool IdentifierEquals(const PreParserIdentifier& identifier,
+ const AstRawString* other);
// TODO(nikolaos): The preparser currently does not keep track of labels
// and targets.
V8_INLINE PreParserStatement
- LookupBreakTarget(const PreParserIdentifier& label, bool* ok) {
+ LookupBreakTarget(const PreParserIdentifier& label) {
return PreParserStatement::Default();
}
V8_INLINE PreParserStatement
- LookupContinueTarget(const PreParserIdentifier& label, bool* ok) {
+ LookupContinueTarget(const PreParserIdentifier& label) {
return PreParserStatement::Default();
}
V8_INLINE PreParserStatement
DeclareFunction(const PreParserIdentifier& variable_name,
const PreParserExpression& function, VariableMode mode,
- int pos, bool is_sloppy_block_function,
- ZonePtrList<const AstRawString>* names, bool* ok) {
+ int beg_pos, int end_pos, bool is_sloppy_block_function,
+ ZonePtrList<const AstRawString>* names) {
DCHECK_NULL(names);
if (variable_name.string_ != nullptr) {
- DCHECK(track_unresolved_variables_);
- scope()->DeclareVariableName(variable_name.string_, mode);
+ bool was_added;
+ if (is_strict(language_mode())) {
+ DeclareVariableName(variable_name.string_, mode, scope(), &was_added);
+ } else {
+ scope()->DeclareVariableName(variable_name.string_, mode, &was_added);
+ }
if (is_sloppy_block_function) {
GetDeclarationScope()->DeclareSloppyBlockFunction(variable_name.string_,
scope());
@@ -1238,47 +1182,51 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE PreParserStatement DeclareClass(
const PreParserIdentifier& variable_name,
const PreParserExpression& value, ZonePtrList<const AstRawString>* names,
- int class_token_pos, int end_pos, bool* ok) {
+ int class_token_pos, int end_pos) {
// Preparser shouldn't be used in contexts where we need to track the names.
DCHECK_NULL(names);
if (variable_name.string_ != nullptr) {
- DCHECK(track_unresolved_variables_);
- scope()->DeclareVariableName(variable_name.string_, VariableMode::kLet);
+ bool was_added;
+ DeclareVariableName(variable_name.string_, VariableMode::kLet, scope(),
+ &was_added);
}
return PreParserStatement::Default();
}
V8_INLINE void DeclareClassVariable(const PreParserIdentifier& name,
ClassInfo* class_info,
- int class_token_pos, bool* ok) {
+ int class_token_pos) {
if (name.string_ != nullptr) {
- DCHECK(track_unresolved_variables_);
- scope()->DeclareVariableName(name.string_, VariableMode::kConst);
+ bool was_added;
+ DeclareVariableName(name.string_, VariableMode::kConst, scope(),
+ &was_added);
}
}
V8_INLINE void DeclareClassProperty(const PreParserIdentifier& class_name,
const PreParserExpression& property,
- const PreParserIdentifier& property_name,
- ClassLiteralProperty::Kind kind,
- bool is_static, bool is_constructor,
- bool is_computed_name,
- ClassInfo* class_info, bool* ok) {
- if (kind == ClassLiteralProperty::PUBLIC_FIELD && is_computed_name) {
- scope()->DeclareVariableName(
+ bool is_constructor,
+ ClassInfo* class_info) {}
+
+ V8_INLINE void DeclareClassField(const PreParserExpression& property,
+ const PreParserIdentifier& property_name,
+ bool is_static, bool is_computed_name,
+ bool is_private, ClassInfo* class_info) {
+ DCHECK_IMPLIES(is_computed_name, !is_private);
+ if (is_computed_name) {
+ bool was_added;
+ DeclareVariableName(
ClassFieldVariableName(ast_value_factory(),
class_info->computed_field_count),
- VariableMode::kConst);
- }
-
- if (kind == ClassLiteralProperty::PRIVATE_FIELD &&
- property_name.string_ != nullptr) {
- DCHECK(track_unresolved_variables_);
- scope()->DeclareVariableName(property_name.string_, VariableMode::kConst);
+ VariableMode::kConst, scope(), &was_added);
+ } else if (is_private && property_name.string_ != nullptr) {
+ bool was_added;
+ DeclareVariableName(property_name.string_, VariableMode::kConst, scope(),
+ &was_added);
}
}
V8_INLINE PreParserExpression
RewriteClassLiteral(Scope* scope, const PreParserIdentifier& name,
- ClassInfo* class_info, int pos, int end_pos, bool* ok) {
+ ClassInfo* class_info, int pos, int end_pos) {
bool has_default_constructor = !class_info->has_seen_constructor;
// Account for the default constructor.
if (has_default_constructor) {
@@ -1300,14 +1248,14 @@ class PreParser : public ParserBase<PreParser> {
if (class_info->has_static_class_fields) {
GetNextFunctionLiteralId();
}
- if (class_info->has_instance_class_fields) {
+ if (class_info->has_instance_members) {
GetNextFunctionLiteralId();
}
return PreParserExpression::Default();
}
V8_INLINE PreParserStatement DeclareNative(const PreParserIdentifier& name,
- int pos, bool* ok) {
+ int pos) {
return PreParserStatement::Default();
}
@@ -1319,6 +1267,10 @@ class PreParser : public ParserBase<PreParser> {
return identifier.IsEval();
}
+ V8_INLINE bool IsAsync(const PreParserIdentifier& identifier) const {
+ return identifier.IsAsync();
+ }
+
V8_INLINE bool IsArguments(const PreParserIdentifier& identifier) const {
return identifier.IsArguments();
}
@@ -1378,14 +1330,6 @@ class PreParser : public ParserBase<PreParser> {
return false;
}
- V8_INLINE bool IsUseStrictDirective(PreParserStatement statement) const {
- return statement.IsUseStrictLiteral();
- }
-
- V8_INLINE bool IsUseAsmDirective(PreParserStatement statement) const {
- return statement.IsUseAsmLiteral();
- }
-
V8_INLINE bool IsStringLiteral(PreParserStatement statement) const {
return statement.IsStringLiteral();
}
@@ -1407,19 +1351,6 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE static void CheckAssigningFunctionLiteralToProperty(
const PreParserExpression& left, const PreParserExpression& right) {}
- V8_INLINE void MarkExpressionAsAssigned(
- const 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.
- if (expression.variables_ != nullptr) {
- DCHECK(FLAG_lazy_inner_functions);
- DCHECK(track_unresolved_variables_);
- for (auto variable : *expression.variables_) {
- variable->set_is_assigned();
- }
- }
- }
-
V8_INLINE bool ShortcutNumericLiteralBinaryExpression(
PreParserExpression* x, const PreParserExpression& y, Token::Value op,
int pos) {
@@ -1430,6 +1361,7 @@ class PreParser : public ParserBase<PreParser> {
PreParserExpression y,
Token::Value op, int pos,
const SourceRange& range) {
+ x->clear_parenthesized();
return nullptr;
}
@@ -1439,64 +1371,27 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE PreParserStatement
- BuildInitializationBlock(DeclarationParsingResult* parsing_result,
- ZonePtrList<const AstRawString>* names, bool* ok) {
- for (auto declaration : parsing_result->declarations) {
- DeclareAndInitializeVariables(PreParserStatement::Default(),
- &(parsing_result->descriptor), &declaration,
- names, ok);
- }
+ BuildInitializationBlock(DeclarationParsingResult* parsing_result) {
return PreParserStatement::Default();
}
- V8_INLINE PreParserStatement InitializeForEachStatement(
- PreParserStatement stmt, const PreParserExpression& each,
- const PreParserExpression& subject, PreParserStatement body) {
- MarkExpressionAsAssigned(each);
- return stmt;
- }
-
- V8_INLINE PreParserStatement InitializeForOfStatement(
- PreParserStatement stmt, const PreParserExpression& each,
- const PreParserExpression& iterable, PreParserStatement body,
- bool finalize, IteratorType type,
- int next_result_pos = kNoSourcePosition) {
- MarkExpressionAsAssigned(each);
- return stmt;
- }
-
- V8_INLINE PreParserStatement RewriteForVarInLegacy(const ForInfo& for_info) {
- return PreParserStatement::Null();
+ V8_INLINE PreParserBlock RewriteForVarInLegacy(const ForInfo& for_info) {
+ return PreParserBlock::Null();
}
V8_INLINE void DesugarBindingInForEachStatement(
ForInfo* for_info, PreParserStatement* body_block,
- PreParserExpression* each_variable, bool* ok) {
- if (track_unresolved_variables_) {
- DCHECK_EQ(1, for_info->parsing_result.declarations.size());
- bool is_for_var_of =
- for_info->mode == ForEachStatement::ITERATE &&
- for_info->parsing_result.descriptor.mode == VariableMode::kVar;
- bool collect_names =
- IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) ||
- is_for_var_of;
-
- DeclareAndInitializeVariables(
- PreParserStatement::Default(), &for_info->parsing_result.descriptor,
- &for_info->parsing_result.declarations[0],
- collect_names ? &for_info->bound_names : nullptr, ok);
- }
+ PreParserExpression* each_variable) {
}
- V8_INLINE PreParserStatement CreateForEachStatementTDZ(
- PreParserStatement init_block, const ForInfo& for_info, bool* ok) {
- if (track_unresolved_variables_) {
- if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) {
- for (auto name : for_info.bound_names) {
- scope()->DeclareVariableName(name, VariableMode::kLet);
- }
- return PreParserStatement::Default();
+ V8_INLINE PreParserBlock CreateForEachStatementTDZ(PreParserBlock init_block,
+ const ForInfo& for_info) {
+ if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) {
+ for (auto name : for_info.bound_names) {
+ bool was_added;
+ DeclareVariableName(name, VariableMode::kLet, scope(), &was_added);
}
+ return PreParserBlock::Default();
}
return init_block;
}
@@ -1504,24 +1399,22 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE StatementT DesugarLexicalBindingsInForStatement(
PreParserStatement loop, PreParserStatement init,
const PreParserExpression& cond, PreParserStatement next,
- PreParserStatement body, Scope* inner_scope, const ForInfo& for_info,
- bool* ok) {
+ PreParserStatement body, Scope* inner_scope, const ForInfo& for_info) {
// See Parser::DesugarLexicalBindingsInForStatement.
- if (track_unresolved_variables_) {
- for (auto name : for_info.bound_names) {
- inner_scope->DeclareVariableName(
- name, for_info.parsing_result.descriptor.mode);
- }
+ for (auto name : for_info.bound_names) {
+ bool was_added;
+ DeclareVariableName(name, for_info.parsing_result.descriptor.mode,
+ inner_scope, &was_added);
}
return loop;
}
- PreParserStatement BuildParameterInitializationBlock(
- const PreParserFormalParameters& parameters, bool* ok);
+ PreParserBlock BuildParameterInitializationBlock(
+ const PreParserFormalParameters& parameters);
- V8_INLINE PreParserStatement
+ V8_INLINE PreParserBlock
BuildRejectPromiseOnException(PreParserStatement init_block) {
- return PreParserStatement::Default();
+ return PreParserBlock::Default();
}
V8_INLINE void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) {
@@ -1531,44 +1424,52 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void InsertShadowingVarBindingInitializers(
PreParserStatement block) {}
- V8_INLINE PreParserExpression
- NewThrowReferenceError(MessageTemplate::Template message, int pos) {
+ V8_INLINE PreParserExpression NewThrowReferenceError(MessageTemplate message,
+ int pos) {
return PreParserExpression::Default();
}
- V8_INLINE PreParserExpression
- NewThrowSyntaxError(MessageTemplate::Template message,
- const PreParserIdentifier& arg, int pos) {
+ V8_INLINE PreParserExpression NewThrowSyntaxError(
+ MessageTemplate message, const PreParserIdentifier& arg, int pos) {
return PreParserExpression::Default();
}
- V8_INLINE PreParserExpression
- NewThrowTypeError(MessageTemplate::Template message,
- const PreParserIdentifier& arg, int pos) {
+ V8_INLINE PreParserExpression NewThrowTypeError(
+ MessageTemplate message, const PreParserIdentifier& arg, int pos) {
return PreParserExpression::Default();
}
// Reporting errors.
void ReportMessageAt(Scanner::Location source_location,
- MessageTemplate::Template message,
- const char* arg = nullptr,
+ MessageTemplate message, const char* arg = nullptr,
ParseErrorType error_type = kSyntaxError) {
pending_error_handler()->ReportMessageAt(source_location.beg_pos,
source_location.end_pos, message,
arg, error_type);
+ scanner()->set_parser_error();
}
V8_INLINE void ReportUnidentifiableError() {
- pending_error_handler()->SetUnidentifiableError();
+ pending_error_handler()->set_unidentifiable_error();
+ scanner()->set_parser_error();
}
V8_INLINE void ReportMessageAt(Scanner::Location source_location,
- MessageTemplate::Template message,
+ MessageTemplate message,
const PreParserIdentifier& arg,
ParseErrorType error_type = kSyntaxError) {
UNREACHABLE();
}
+ void ReportMessageAt(Scanner::Location source_location,
+ MessageTemplate message, const AstRawString* arg,
+ ParseErrorType error_type = kSyntaxError) {
+ pending_error_handler()->ReportMessageAt(source_location.beg_pos,
+ source_location.end_pos, message,
+ arg, error_type);
+ scanner()->set_parser_error();
+ }
+
// "null" return type creators.
V8_INLINE static PreParserIdentifier NullIdentifier() {
return PreParserIdentifier::Null();
@@ -1576,19 +1477,19 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE static PreParserExpression NullExpression() {
return PreParserExpression::Null();
}
+ V8_INLINE static PreParserExpression FailureExpression() {
+ return PreParserExpression::Failure();
+ }
V8_INLINE static PreParserExpression NullLiteralProperty() {
return PreParserExpression::Null();
}
- V8_INLINE static PreParserExpressionList NullExpressionList() {
- return PreParserExpressionList::Null();
- }
-
V8_INLINE static PreParserStatementList NullStatementList() {
return PreParserStatementList::Null();
}
V8_INLINE static PreParserStatement NullStatement() {
return PreParserStatement::Null();
}
+ V8_INLINE static PreParserBlock NullBlock() { return PreParserBlock::Null(); }
template <typename T>
V8_INLINE static bool IsNull(T subject) {
@@ -1611,38 +1512,32 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE PreParserExpression ThisExpression(int pos = kNoSourcePosition) {
- if (track_unresolved_variables_) {
- scope()->NewUnresolved(factory()->ast_node_factory(),
- ast_value_factory()->this_string(), pos,
- THIS_VARIABLE);
- }
+ scope()->NewUnresolved(factory()->ast_node_factory(),
+ ast_value_factory()->this_string(), pos,
+ THIS_VARIABLE);
return PreParserExpression::This();
}
V8_INLINE PreParserExpression NewSuperPropertyReference(int pos) {
- if (track_unresolved_variables_) {
- scope()->NewUnresolved(factory()->ast_node_factory(),
- ast_value_factory()->this_function_string(), pos,
- NORMAL_VARIABLE);
- scope()->NewUnresolved(factory()->ast_node_factory(),
- ast_value_factory()->this_string(), pos,
- THIS_VARIABLE);
- }
+ scope()->NewUnresolved(factory()->ast_node_factory(),
+ ast_value_factory()->this_function_string(), pos,
+ NORMAL_VARIABLE);
+ scope()->NewUnresolved(factory()->ast_node_factory(),
+ ast_value_factory()->this_string(), pos,
+ THIS_VARIABLE);
return PreParserExpression::Default();
}
V8_INLINE PreParserExpression NewSuperCallReference(int pos) {
- if (track_unresolved_variables_) {
- scope()->NewUnresolved(factory()->ast_node_factory(),
- ast_value_factory()->this_function_string(), pos,
- NORMAL_VARIABLE);
- scope()->NewUnresolved(factory()->ast_node_factory(),
- ast_value_factory()->new_target_string(), pos,
- NORMAL_VARIABLE);
- scope()->NewUnresolved(factory()->ast_node_factory(),
- ast_value_factory()->this_string(), pos,
- THIS_VARIABLE);
- }
+ scope()->NewUnresolved(factory()->ast_node_factory(),
+ ast_value_factory()->this_function_string(), pos,
+ NORMAL_VARIABLE);
+ scope()->NewUnresolved(factory()->ast_node_factory(),
+ ast_value_factory()->new_target_string(), pos,
+ NORMAL_VARIABLE);
+ scope()->NewUnresolved(factory()->ast_node_factory(),
+ ast_value_factory()->this_string(), pos,
+ THIS_VARIABLE);
return PreParserExpression::SuperCallReference();
}
@@ -1656,30 +1551,26 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE PreParserExpression ExpressionFromLiteral(Token::Value token,
int pos) {
- return PreParserExpression::Default();
+ if (token != Token::STRING) return PreParserExpression::Default();
+ return PreParserExpression::StringLiteral();
}
PreParserExpression ExpressionFromIdentifier(
const PreParserIdentifier& name, int start_position,
- InferName infer = InferName::kYes);
-
- V8_INLINE PreParserExpression ExpressionFromString(int pos) {
- if (scanner()->IsUseStrict()) {
- return PreParserExpression::UseStrictStringLiteral();
+ InferName infer = InferName::kYes) {
+ if (name.string_ != nullptr) {
+ expression_scope()->NewVariable(name.string_, start_position);
}
- return PreParserExpression::StringLiteral();
- }
-
- V8_INLINE PreParserExpressionList NewExpressionList(int size) const {
- return PreParserExpressionList();
+ return PreParserExpression::FromIdentifier(name);
}
- V8_INLINE PreParserExpressionList NewObjectPropertyList(int size) const {
- return PreParserExpressionList();
+ V8_INLINE Variable* DeclareCatchVariableName(
+ Scope* scope, const PreParserIdentifier& identifier) {
+ return scope->DeclareCatchVariableName(identifier.string_);
}
- V8_INLINE PreParserExpressionList NewClassPropertyList(int size) const {
- return PreParserExpressionList();
+ V8_INLINE PreParserPropertyList NewClassPropertyList(int size) const {
+ return PreParserPropertyList();
}
V8_INLINE PreParserStatementList NewStatementList(int size) const {
@@ -1688,7 +1579,7 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE PreParserExpression
NewV8Intrinsic(const PreParserIdentifier& name,
- const PreParserExpressionList& arguments, int pos, bool* ok) {
+ const PreParserExpressionList& arguments, int pos) {
return PreParserExpression::Default();
}
@@ -1698,74 +1589,28 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE void AddFormalParameter(PreParserFormalParameters* parameters,
- const PreParserExpression& pattern,
+ PreParserExpression& pattern,
const PreParserExpression& initializer,
int initializer_end_position,
bool is_rest) {
- if (track_unresolved_variables_) {
- DCHECK(FLAG_lazy_inner_functions);
- parameters->params.Add(new (zone()) PreParserFormalParameters::Parameter(
- pattern.variables_, is_rest));
- }
+ DeclarationScope* scope = parameters->scope;
+ scope->RecordParameter(is_rest);
parameters->UpdateArityAndFunctionLength(!initializer.IsNull(), is_rest);
}
V8_INLINE void DeclareFormalParameters(
- DeclarationScope* scope,
- const base::ThreadedList<PreParserFormalParameters::Parameter>&
- parameters,
- bool is_simple) {
- if (!is_simple) scope->SetHasNonSimpleParameters();
- if (track_unresolved_variables_) {
- DCHECK(FLAG_lazy_inner_functions);
- for (auto parameter : parameters) {
- DCHECK_IMPLIES(is_simple, parameter->variables_ != nullptr);
- DCHECK_IMPLIES(is_simple, parameter->variables_->LengthForTest() == 1);
- // Make sure each parameter is added only once even if it's a
- // destructuring parameter which contains multiple names.
- bool add_parameter = true;
- if (parameter->variables_ != nullptr) {
- for (auto variable : (*parameter->variables_)) {
- // We declare the parameter name for all names, but only create a
- // parameter entry for the first one.
- scope->DeclareParameterName(variable->raw_name(),
- parameter->is_rest, ast_value_factory(),
- true, add_parameter);
- add_parameter = false;
- }
- }
- if (add_parameter) {
- // No names were declared; declare a dummy one here to up the
- // parameter count.
- DCHECK(!is_simple);
- scope->DeclareParameterName(ast_value_factory()->empty_string(),
- parameter->is_rest, ast_value_factory(),
- false, add_parameter);
- }
- }
- }
+ const PreParserFormalParameters* parameters) {
+ if (!parameters->is_simple) parameters->scope->SetHasNonSimpleParameters();
}
V8_INLINE void DeclareArrowFunctionFormalParameters(
PreParserFormalParameters* parameters, const 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.
- if (track_unresolved_variables_) {
- DCHECK(FLAG_lazy_inner_functions);
- if (params.variables_ != nullptr) {
- for (auto variable : *params.variables_) {
- parameters->scope->DeclareVariableName(variable->raw_name(),
- VariableMode::kVar);
- }
- }
- }
+ const Scanner::Location& params_loc) {
}
V8_INLINE PreParserExpression
ExpressionListToExpression(const PreParserExpressionList& args) {
- return PreParserExpression::Default(args.variables_);
+ return PreParserExpression::Default();
}
V8_INLINE void SetFunctionNameFromPropertyName(
@@ -1775,11 +1620,6 @@ class PreParser : public ParserBase<PreParser> {
const PreParserExpression& value, const PreParserExpression& identifier) {
}
- V8_INLINE ZoneList<typename ExpressionClassifier::Error>*
- GetReportedErrorList() const {
- return function_state_->GetReportedErrorList();
- }
-
V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) {
if (use_counts_ != nullptr) ++use_counts_[feature];
}
@@ -1797,10 +1637,9 @@ class PreParser : public ParserBase<PreParser> {
// Preparser's private field members.
int* use_counts_;
- bool track_unresolved_variables_;
PreParserLogger log_;
- PreParsedScopeDataBuilder* preparsed_scope_data_builder_;
+ PreparseDataBuilder* preparse_data_builder_;
};
PreParserExpression PreParser::SpreadCall(const PreParserExpression& function,
diff --git a/deps/v8/src/parsing/rewriter.cc b/deps/v8/src/parsing/rewriter.cc
index 151244f692..5ba7b3ba51 100644
--- a/deps/v8/src/parsing/rewriter.cc
+++ b/deps/v8/src/parsing/rewriter.cc
@@ -18,13 +18,13 @@ class Processor final : public AstVisitor<Processor> {
Processor(uintptr_t stack_limit, DeclarationScope* closure_scope,
Variable* result, AstValueFactory* ast_value_factory)
: result_(result),
- result_assigned_(false),
replacement_(nullptr),
- is_set_(false),
- breakable_(false),
zone_(ast_value_factory->zone()),
closure_scope_(closure_scope),
- factory_(ast_value_factory, ast_value_factory->zone()) {
+ factory_(ast_value_factory, ast_value_factory->zone()),
+ result_assigned_(false),
+ is_set_(false),
+ breakable_(false) {
DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
InitializeAstVisitor(stack_limit);
}
@@ -32,13 +32,13 @@ class Processor final : public AstVisitor<Processor> {
Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result,
AstValueFactory* ast_value_factory)
: result_(result),
- result_assigned_(false),
replacement_(nullptr),
- is_set_(false),
- breakable_(false),
zone_(ast_value_factory->zone()),
closure_scope_(closure_scope),
- factory_(ast_value_factory, zone_) {
+ factory_(ast_value_factory, zone_),
+ result_assigned_(false),
+ is_set_(false),
+ breakable_(false) {
DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
InitializeAstVisitor(parser->stack_limit());
}
@@ -64,24 +64,10 @@ class Processor final : public AstVisitor<Processor> {
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_;
-
- bool breakable_;
-
class BreakableScope final {
public:
explicit BreakableScope(Processor* processor, bool breakable = true)
@@ -108,6 +94,20 @@ class Processor final : public AstVisitor<Processor> {
void VisitIterationStatement(IterationStatement* stmt);
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+
+ // 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_;
+
+ // 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_;
+
+ bool breakable_;
};
@@ -337,8 +337,8 @@ void Processor::VisitDebuggerStatement(DebuggerStatement* node) {
replacement_ = node;
}
-void Processor::VisitInitializeClassFieldsStatement(
- InitializeClassFieldsStatement* node) {
+void Processor::VisitInitializeClassMembersStatement(
+ InitializeClassMembersStatement* node) {
replacement_ = node;
}
@@ -405,36 +405,5 @@ bool Rewriter::Rewrite(ParseInfo* info) {
return true;
}
-bool Rewriter::Rewrite(Parser* parser, DeclarationScope* closure_scope,
- DoExpression* expr, AstValueFactory* factory) {
- DisallowHeapAllocation no_allocation;
- DisallowHandleAllocation no_handles;
- DisallowHandleDereference no_deref;
-
- Block* block = expr->block();
- DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
- DCHECK(block->scope() == nullptr ||
- block->scope()->GetClosureScope() == closure_scope);
- ZonePtrList<Statement>* body = block->statements();
- VariableProxy* result = expr->result();
- Variable* result_var = result->var();
-
- if (!body->is_empty()) {
- Processor processor(parser, closure_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(kNoSourcePosition);
- 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
index d0b1191a9f..62873b2980 100644
--- a/deps/v8/src/parsing/rewriter.h
+++ b/deps/v8/src/parsing/rewriter.h
@@ -9,7 +9,6 @@ namespace v8 {
namespace internal {
class AstValueFactory;
-class DoExpression;
class Isolate;
class ParseInfo;
class Parser;
@@ -25,15 +24,6 @@ class Rewriter {
// 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. The temporary is added
- // to the closure scope of the do-expression, which matches the closure scope
- // of the outer scope (the do-expression itself runs in a block scope, not a
- // closure scope). This closure scope needs to be passed in since the
- // do-expression could have dropped its own block scope.
- static bool Rewrite(Parser* parser, DeclarationScope* closure_scope,
- DoExpression* expr, AstValueFactory* factory);
};
diff --git a/deps/v8/src/parsing/scanner-character-streams.cc b/deps/v8/src/parsing/scanner-character-streams.cc
index 8472e9f4fc..32dcaacbf5 100644
--- a/deps/v8/src/parsing/scanner-character-streams.cc
+++ b/deps/v8/src/parsing/scanner-character-streams.cc
@@ -20,8 +20,8 @@ namespace internal {
class ScopedExternalStringLock {
public:
- explicit ScopedExternalStringLock(ExternalString* string) {
- DCHECK(string);
+ explicit ScopedExternalStringLock(ExternalString string) {
+ DCHECK(!string.is_null());
if (string->IsExternalOneByteString()) {
resource_ = ExternalOneByteString::cast(string)->resource();
} else {
@@ -33,7 +33,7 @@ class ScopedExternalStringLock {
}
// Copying a lock increases the locking depth.
- ScopedExternalStringLock(const ScopedExternalStringLock& other)
+ ScopedExternalStringLock(const ScopedExternalStringLock& other) V8_NOEXCEPT
: resource_(other.resource_) {
resource_->Lock();
}
@@ -84,13 +84,16 @@ class OnHeapStream {
OnHeapStream(Handle<String> string, size_t start_offset, size_t end)
: string_(string), start_offset_(start_offset), length_(end) {}
- OnHeapStream(const OnHeapStream& other) : start_offset_(0), length_(0) {
+ OnHeapStream(const OnHeapStream&) V8_NOEXCEPT : start_offset_(0), length_(0) {
UNREACHABLE();
}
- Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
- return {&string_->GetChars()[start_offset_ + Min(length_, pos)],
- &string_->GetChars()[start_offset_ + length_]};
+ // The no_gc argument is only here because of the templated way this class
+ // is used along with other implementations that require V8 heap access.
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats,
+ DisallowHeapAllocation* no_gc) {
+ return {&string_->GetChars(*no_gc)[start_offset_ + Min(length_, pos)],
+ &string_->GetChars(*no_gc)[start_offset_ + length_]};
}
static const bool kCanBeCloned = false;
@@ -109,16 +112,21 @@ class ExternalStringStream {
typedef typename CharTraits<Char>::ExternalString ExternalString;
public:
- ExternalStringStream(ExternalString* string, size_t start_offset,
+ ExternalStringStream(ExternalString string, size_t start_offset,
size_t length)
: lock_(string),
data_(string->GetChars() + start_offset),
length_(length) {}
- ExternalStringStream(const ExternalStringStream& other)
- : lock_(other.lock_), data_(other.data_), length_(other.length_) {}
+ ExternalStringStream(const ExternalStringStream& other) V8_NOEXCEPT
+ : lock_(other.lock_),
+ data_(other.data_),
+ length_(other.length_) {}
- Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
+ // The no_gc argument is only here because of the templated way this class
+ // is used along with other implementations that require V8 heap access.
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats,
+ DisallowHeapAllocation* no_gc = nullptr) {
return {&data_[Min(length_, pos)], &data_[length_]};
}
@@ -137,7 +145,10 @@ class TestingStream {
public:
TestingStream(const Char* data, size_t length)
: data_(data), length_(length) {}
- Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
+ // The no_gc argument is only here because of the templated way this class
+ // is used along with other implementations that require V8 heap access.
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats,
+ DisallowHeapAllocation* no_gc = nullptr) {
return {&data_[Min(length_, pos)], &data_[length_]};
}
@@ -156,12 +167,15 @@ class ChunkedStream {
explicit ChunkedStream(ScriptCompiler::ExternalSourceStream* source)
: source_(source) {}
- ChunkedStream(const ChunkedStream& other) {
+ ChunkedStream(const ChunkedStream&) V8_NOEXCEPT {
// TODO(rmcilroy): Implement cloning for chunked streams.
UNREACHABLE();
}
- Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
+ // The no_gc argument is only here because of the templated way this class
+ // is used along with other implementations that require V8 heap access.
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats,
+ DisallowHeapAllocation* no_gc = nullptr) {
Chunk chunk = FindChunk(pos, stats);
size_t buffer_end = chunk.length;
size_t buffer_pos = Min(buffer_end, pos - chunk.position);
@@ -257,8 +271,9 @@ class BufferedCharacterStream : public Utf16CharacterStream {
buffer_start_ = &buffer_[0];
buffer_cursor_ = buffer_start_;
+ DisallowHeapAllocation no_gc;
Range<uint8_t> range =
- byte_stream_.GetDataAt(position, runtime_call_stats());
+ byte_stream_.GetDataAt(position, runtime_call_stats(), &no_gc);
if (range.length() == 0) {
buffer_end_ = buffer_start_;
return false;
@@ -310,8 +325,9 @@ class UnbufferedCharacterStream : public Utf16CharacterStream {
bool ReadBlock() final {
size_t position = pos();
buffer_pos_ = position;
+ DisallowHeapAllocation no_gc;
Range<uint16_t> range =
- byte_stream_.GetDataAt(position, runtime_call_stats());
+ byte_stream_.GetDataAt(position, runtime_call_stats(), &no_gc);
buffer_start_ = range.start;
buffer_end_ = range.end;
buffer_cursor_ = buffer_start_;
@@ -356,7 +372,9 @@ class RelocatingCharacterStream
}
void UpdateBufferPointers() {
- Range<uint16_t> range = byte_stream_.GetDataAt(0, runtime_call_stats());
+ DisallowHeapAllocation no_gc;
+ Range<uint16_t> range =
+ byte_stream_.GetDataAt(0, runtime_call_stats(), &no_gc);
if (range.start != buffer_start_) {
buffer_cursor_ = (buffer_cursor_ - buffer_start_) + range.start;
buffer_start_ = range.start;
@@ -707,9 +725,9 @@ Utf16CharacterStream* ScannerStream::For(Isolate* isolate, Handle<String> data,
DCHECK_LE(end_pos, data->length());
size_t start_offset = 0;
if (data->IsSlicedString()) {
- SlicedString* string = SlicedString::cast(*data);
+ SlicedString string = SlicedString::cast(*data);
start_offset = string->offset();
- String* parent = string->parent();
+ String parent = string->parent();
if (parent->IsThinString()) parent = ThinString::cast(parent)->actual();
data = handle(parent, isolate);
} else {
diff --git a/deps/v8/src/parsing/scanner-inl.h b/deps/v8/src/parsing/scanner-inl.h
index 9647957062..1e2cf9e447 100644
--- a/deps/v8/src/parsing/scanner-inl.h
+++ b/deps/v8/src/parsing/scanner-inl.h
@@ -6,159 +6,19 @@
#define V8_PARSING_SCANNER_INL_H_
#include "src/char-predicates-inl.h"
+#include "src/parsing/keywords-gen.h"
#include "src/parsing/scanner.h"
-#include "src/unicode-cache-inl.h"
namespace v8 {
namespace internal {
-// Make sure tokens are stored as a single byte.
-STATIC_ASSERT(sizeof(Token::Value) == 1);
-
-// Table of one-character tokens, by character (0x00..0x7F only).
-// clang-format off
-static const Token::Value 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
-};
-// clang-format on
-
// ----------------------------------------------------------------------------
// Keyword Matcher
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
KEYWORD_GROUP('a') \
- KEYWORD("arguments", Token::ARGUMENTS) \
- KEYWORD("as", Token::AS) \
KEYWORD("async", Token::ASYNC) \
KEYWORD("await", Token::AWAIT) \
- KEYWORD("anonymous", Token::ANONYMOUS) \
KEYWORD_GROUP('b') \
KEYWORD("break", Token::BREAK) \
KEYWORD_GROUP('c') \
@@ -166,7 +26,6 @@ static const Token::Value one_char_tokens[] = {
KEYWORD("catch", Token::CATCH) \
KEYWORD("class", Token::CLASS) \
KEYWORD("const", Token::CONST) \
- KEYWORD("constructor", Token::CONSTRUCTOR) \
KEYWORD("continue", Token::CONTINUE) \
KEYWORD_GROUP('d') \
KEYWORD("debugger", Token::DEBUGGER) \
@@ -176,17 +35,13 @@ static const Token::Value one_char_tokens[] = {
KEYWORD_GROUP('e') \
KEYWORD("else", Token::ELSE) \
KEYWORD("enum", Token::ENUM) \
- KEYWORD("eval", Token::EVAL) \
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("from", Token::FROM) \
KEYWORD("function", Token::FUNCTION) \
- KEYWORD_GROUP('g') \
- KEYWORD("get", Token::GET) \
KEYWORD_GROUP('i') \
KEYWORD("if", Token::IF) \
KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
@@ -196,36 +51,26 @@ static const Token::Value one_char_tokens[] = {
KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('l') \
KEYWORD("let", Token::LET) \
- KEYWORD_GROUP('m') \
- KEYWORD("meta", Token::META) \
KEYWORD_GROUP('n') \
- KEYWORD("name", Token::NAME) \
KEYWORD("new", Token::NEW) \
KEYWORD("null", Token::NULL_LITERAL) \
- KEYWORD_GROUP('o') \
- KEYWORD("of", Token::OF) \
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("prototype", Token::PROTOTYPE) \
KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('r') \
KEYWORD("return", Token::RETURN) \
KEYWORD_GROUP('s') \
- KEYWORD("set", Token::SET) \
KEYWORD("static", Token::STATIC) \
KEYWORD("super", Token::SUPER) \
KEYWORD("switch", Token::SWITCH) \
KEYWORD_GROUP('t') \
- KEYWORD("target", Token::TARGET) \
KEYWORD("this", Token::THIS) \
KEYWORD("throw", Token::THROW) \
KEYWORD("true", Token::TRUE_LITERAL) \
KEYWORD("try", Token::TRY) \
KEYWORD("typeof", Token::TYPEOF) \
- KEYWORD_GROUP('u') \
- KEYWORD("undefined", Token::UNDEFINED) \
KEYWORD_GROUP('v') \
KEYWORD("var", Token::VAR) \
KEYWORD("void", Token::VOID) \
@@ -233,124 +78,235 @@ static const Token::Value one_char_tokens[] = {
KEYWORD("while", Token::WHILE) \
KEYWORD("with", Token::WITH) \
KEYWORD_GROUP('y') \
- KEYWORD("yield", Token::YIELD) \
- KEYWORD_GROUP('_') \
- KEYWORD("__proto__", Token::PROTO_UNDERSCORED) \
- KEYWORD_GROUP('#') \
- KEYWORD("#constructor", Token::PRIVATE_CONSTRUCTOR)
+ KEYWORD("yield", Token::YIELD)
+
+constexpr bool IsKeywordStart(char c) {
+#define KEYWORD_GROUP_CHECK(ch) c == ch ||
+#define KEYWORD_CHECK(keyword, token)
+ return KEYWORDS(KEYWORD_GROUP_CHECK, KEYWORD_CHECK) /* || */ false;
+#undef KEYWORD_GROUP_CHECK
+#undef KEYWORD_CHECK
+}
V8_INLINE Token::Value KeywordOrIdentifierToken(const uint8_t* input,
int input_length) {
DCHECK_GE(input_length, 1);
- const int kMinLength = 2;
- const int kMaxLength = 12;
- 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); \
- DCHECK_EQ(input[0], keyword[0]); \
- DCHECK(token == Token::FUTURE_STRICT_RESERVED_WORD || \
- 0 == strncmp(keyword, Token::String(token), sizeof(keyword))); \
- 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]) && \
- (keyword_length <= 10 || input[10] == keyword[10])) { \
- return token; \
- } \
- }
+ return PerfectKeywordHash::GetToken(reinterpret_cast<const char*>(input),
+ input_length);
+}
+
+// Recursive constexpr template magic to check if a character is in a given
+// string.
+template <int N>
+constexpr bool IsInString(const char (&s)[N], char c, size_t i = 0) {
+ return i >= N ? false : s[i] == c ? true : IsInString(s, c, i + 1);
+}
+
+inline constexpr bool CanBeKeywordCharacter(char c) {
+ return IsInString(
+#define KEYWORD_GROUP_CASE(ch) // Nothing
+#define KEYWORD(keyword, token) keyword
+ // Use C string literal concatenation ("a" "b" becomes "ab") to build one
+ // giant string containing all the keywords.
KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
- }
- return Token::IDENTIFIER;
-#undef KEYWORDS
#undef KEYWORD
#undef KEYWORD_GROUP_CASE
+ ,
+ c);
+}
+
+// Make sure tokens are stored as a single byte.
+STATIC_ASSERT(sizeof(Token::Value) == 1);
+
+// Get the shortest token that this character starts, the token may change
+// depending on subsequent characters.
+constexpr Token::Value GetOneCharToken(char c) {
+ // clang-format off
+ return
+ c == '(' ? Token::LPAREN :
+ c == ')' ? Token::RPAREN :
+ c == '{' ? Token::LBRACE :
+ c == '}' ? Token::RBRACE :
+ c == '[' ? Token::LBRACK :
+ c == ']' ? Token::RBRACK :
+ c == '?' ? Token::CONDITIONAL :
+ c == ':' ? Token::COLON :
+ c == ';' ? Token::SEMICOLON :
+ c == ',' ? Token::COMMA :
+ c == '.' ? Token::PERIOD :
+ c == '|' ? Token::BIT_OR :
+ c == '&' ? Token::BIT_AND :
+ c == '^' ? Token::BIT_XOR :
+ c == '~' ? Token::BIT_NOT :
+ c == '!' ? Token::NOT :
+ c == '<' ? Token::LT :
+ c == '>' ? Token::GT :
+ c == '%' ? Token::MOD :
+ c == '=' ? Token::ASSIGN :
+ c == '+' ? Token::ADD :
+ c == '-' ? Token::SUB :
+ c == '*' ? Token::MUL :
+ c == '/' ? Token::DIV :
+ c == '#' ? Token::PRIVATE_NAME :
+ c == '"' ? Token::STRING :
+ c == '\'' ? Token::STRING :
+ c == '`' ? Token::TEMPLATE_SPAN :
+ c == '\\' ? Token::IDENTIFIER :
+ // Whitespace or line terminator
+ c == ' ' ? Token::WHITESPACE :
+ c == '\t' ? Token::WHITESPACE :
+ c == '\v' ? Token::WHITESPACE :
+ c == '\f' ? Token::WHITESPACE :
+ c == '\r' ? Token::WHITESPACE :
+ c == '\n' ? Token::WHITESPACE :
+ // IsDecimalDigit must be tested before IsAsciiIdentifier
+ IsDecimalDigit(c) ? Token::NUMBER :
+ IsAsciiIdentifier(c) ? Token::IDENTIFIER :
+ Token::ILLEGAL;
+ // clang-format on
}
+// Table of one-character tokens, by character (0x00..0x7F only).
+static const constexpr Token::Value one_char_tokens[128] = {
+#define CALL_GET_SCAN_FLAGS(N) GetOneCharToken(N),
+ INT_0_TO_127_LIST(CALL_GET_SCAN_FLAGS)
+#undef CALL_GET_SCAN_FLAGS
+};
+
+#undef KEYWORDS
+
V8_INLINE Token::Value Scanner::ScanIdentifierOrKeyword() {
- LiteralScope literal(this);
- return ScanIdentifierOrKeywordInner(&literal);
+ next().literal_chars.Start();
+ return ScanIdentifierOrKeywordInner();
+}
+
+// Character flags for the fast path of scanning a keyword or identifier token.
+enum class ScanFlags : uint8_t {
+ kTerminatesLiteral = 1 << 0,
+ // "Cannot" rather than "can" so that this flag can be ORed together across
+ // multiple characters.
+ kCannotBeKeyword = 1 << 1,
+ kCannotBeKeywordStart = 1 << 2,
+ kStringTerminator = 1 << 3,
+ kNeedsSlowPath = 1 << 4,
+};
+constexpr uint8_t GetScanFlags(char c) {
+ return
+ // Keywords are all lowercase and only contain letters.
+ // Note that non-identifier characters do not set this flag, so
+ // that it plays well with kTerminatesLiteral.
+ (IsAsciiIdentifier(c) && !CanBeKeywordCharacter(c)
+ ? static_cast<uint8_t>(ScanFlags::kCannotBeKeyword)
+ : 0) |
+ (IsKeywordStart(c)
+ ? 0
+ : static_cast<uint8_t>(ScanFlags::kCannotBeKeywordStart)) |
+ // Anything that isn't an identifier character will terminate the
+ // literal, or at least terminates the literal fast path processing
+ // (like an escape).
+ (!IsAsciiIdentifier(c)
+ ? static_cast<uint8_t>(ScanFlags::kTerminatesLiteral)
+ : 0) |
+ // Possible string termination characters.
+ ((c == '\'' || c == '"' || c == '\n' || c == '\r' || c == '\\')
+ ? static_cast<uint8_t>(ScanFlags::kStringTerminator)
+ : 0) |
+ // Escapes are processed on the slow path.
+ (c == '\\' ? static_cast<uint8_t>(ScanFlags::kNeedsSlowPath) : 0);
+}
+inline bool TerminatesLiteral(uint8_t scan_flags) {
+ return (scan_flags & static_cast<uint8_t>(ScanFlags::kTerminatesLiteral));
+}
+inline bool CanBeKeyword(uint8_t scan_flags) {
+ return !(scan_flags & static_cast<uint8_t>(ScanFlags::kCannotBeKeyword));
}
+inline bool NeedsSlowPath(uint8_t scan_flags) {
+ return (scan_flags & static_cast<uint8_t>(ScanFlags::kNeedsSlowPath));
+}
+inline bool MayTerminateString(uint8_t scan_flags) {
+ return (scan_flags & static_cast<uint8_t>(ScanFlags::kStringTerminator));
+}
+// Table of precomputed scan flags for the 128 ASCII characters, for branchless
+// flag calculation during the scan.
+static constexpr const uint8_t character_scan_flags[128] = {
+#define CALL_GET_SCAN_FLAGS(N) GetScanFlags(N),
+ INT_0_TO_127_LIST(CALL_GET_SCAN_FLAGS)
+#undef CALL_GET_SCAN_FLAGS
+};
-V8_INLINE Token::Value Scanner::ScanIdentifierOrKeywordInner(
- LiteralScope* literal) {
- DCHECK(unicode_cache_->IsIdentifierStart(c0_));
+inline bool CharCanBeKeyword(uc32 c) {
+ return static_cast<uint32_t>(c) < arraysize(character_scan_flags) &&
+ CanBeKeyword(character_scan_flags[c]);
+}
+
+V8_INLINE Token::Value Scanner::ScanIdentifierOrKeywordInner() {
+ DCHECK(IsIdentifierStart(c0_));
bool escaped = false;
- if (IsInRange(c0_, 'a', 'z') || c0_ == '_') {
- do {
+ bool can_be_keyword = true;
+
+ STATIC_ASSERT(arraysize(character_scan_flags) == kMaxAscii + 1);
+ if (V8_LIKELY(static_cast<uint32_t>(c0_) <= kMaxAscii)) {
+ if (V8_LIKELY(c0_ != '\\')) {
+ uint8_t scan_flags = character_scan_flags[c0_];
+ DCHECK(!TerminatesLiteral(scan_flags));
+ STATIC_ASSERT(static_cast<uint8_t>(ScanFlags::kCannotBeKeywordStart) ==
+ static_cast<uint8_t>(ScanFlags::kCannotBeKeyword) << 1);
+ scan_flags >>= 1;
+ // Make sure the shifting above doesn't set NeedsSlowPath. Otherwise we'll
+ // fall into the slow path after scanning the identifier.
+ DCHECK(!NeedsSlowPath(scan_flags));
AddLiteralChar(static_cast<char>(c0_));
- Advance();
- } while (IsInRange(c0_, 'a', 'z') || c0_ == '_');
-
- if (IsDecimalDigit(c0_) || IsInRange(c0_, 'A', 'Z') || c0_ == '$') {
- // Identifier starting with lowercase or _.
- do {
- AddLiteralChar(static_cast<char>(c0_));
- Advance();
- } while (IsAsciiIdentifier(c0_));
-
- if (c0_ <= kMaxAscii && c0_ != '\\') {
- literal->Complete();
- return Token::IDENTIFIER;
+ AdvanceUntil([this, &scan_flags](uc32 c0) {
+ if (V8_UNLIKELY(static_cast<uint32_t>(c0) > kMaxAscii)) {
+ // A non-ascii character means we need to drop through to the slow
+ // path.
+ // TODO(leszeks): This would be most efficient as a goto to the slow
+ // path, check codegen and maybe use a bool instead.
+ scan_flags |= static_cast<uint8_t>(ScanFlags::kNeedsSlowPath);
+ return true;
+ }
+ uint8_t char_flags = character_scan_flags[c0];
+ scan_flags |= char_flags;
+ if (TerminatesLiteral(char_flags)) {
+ return true;
+ } else {
+ AddLiteralChar(static_cast<char>(c0));
+ return false;
+ }
+ });
+
+ if (V8_LIKELY(!NeedsSlowPath(scan_flags))) {
+ if (!CanBeKeyword(scan_flags)) return Token::IDENTIFIER;
+ // Could be a keyword or identifier.
+ Vector<const uint8_t> chars = next().literal_chars.one_byte_literal();
+ return KeywordOrIdentifierToken(chars.start(), chars.length());
}
- } else if (c0_ <= kMaxAscii && c0_ != '\\') {
- // Only a-z+ or _: could be a keyword or identifier.
- Vector<const uint8_t> chars = next().literal_chars.one_byte_literal();
- Token::Value token =
- KeywordOrIdentifierToken(chars.start(), chars.length());
- if (token == Token::IDENTIFIER ||
- token == Token::FUTURE_STRICT_RESERVED_WORD ||
- Token::IsContextualKeyword(token))
- literal->Complete();
- return token;
- }
- } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '$') {
- do {
- AddLiteralChar(static_cast<char>(c0_));
- Advance();
- } while (IsAsciiIdentifier(c0_));
- if (c0_ <= kMaxAscii && c0_ != '\\') {
- literal->Complete();
- return Token::IDENTIFIER;
- }
- } else if (c0_ == '\\') {
- escaped = true;
- uc32 c = ScanIdentifierUnicodeEscape();
- DCHECK(!unicode_cache_->IsIdentifierStart(-1));
- if (c == '\\' || !unicode_cache_->IsIdentifierStart(c)) {
- return Token::ILLEGAL;
+ can_be_keyword = CanBeKeyword(scan_flags);
+ } else {
+ // Special case for escapes at the start of an identifier.
+ escaped = true;
+ uc32 c = ScanIdentifierUnicodeEscape();
+ DCHECK(!IsIdentifierStart(-1));
+ if (c == '\\' || !IsIdentifierStart(c)) {
+ return Token::ILLEGAL;
+ }
+ AddLiteralChar(c);
+ can_be_keyword = CharCanBeKeyword(c);
}
- AddLiteralChar(c);
}
- return ScanIdentifierOrKeywordInnerSlow(literal, escaped);
+ return ScanIdentifierOrKeywordInnerSlow(escaped, can_be_keyword);
}
V8_INLINE Token::Value Scanner::SkipWhiteSpace() {
int start_position = source_pos();
// We won't skip behind the end of input.
- DCHECK(!unicode_cache_->IsWhiteSpaceOrLineTerminator(kEndOfInput));
+ DCHECK(!IsWhiteSpaceOrLineTerminator(kEndOfInput));
// Advance as long as character is a WhiteSpace or LineTerminator.
- while (unicode_cache_->IsWhiteSpaceOrLineTerminator(c0_)) {
+ while (IsWhiteSpaceOrLineTerminator(c0_)) {
if (!next().after_line_terminator && unibrow::IsLineTerminator(c0_)) {
next().after_line_terminator = true;
}
@@ -371,178 +327,194 @@ V8_INLINE Token::Value Scanner::ScanSingleToken() {
do {
next().location.beg_pos = source_pos();
- if (static_cast<unsigned>(c0_) <= 0x7F) {
- Token::Value token = one_char_tokens[c0_];
- if (token != Token::ILLEGAL) {
- Advance();
- return token;
- }
- }
-
- switch (c0_) {
- case '"':
- case '\'':
- return ScanString();
-
- case '<':
- // < <= << <<= <!--
- Advance();
- if (c0_ == '=') return Select(Token::LTE);
- if (c0_ == '<') return Select('=', Token::ASSIGN_SHL, Token::SHL);
- if (c0_ == '!') {
- token = ScanHtmlComment();
- continue;
- }
- return Token::LT;
-
- case '>':
- // > >= >> >>= >>> >>>=
- Advance();
- if (c0_ == '=') return Select(Token::GTE);
- if (c0_ == '>') {
- // >> >>= >>> >>>=
+ if (V8_LIKELY(static_cast<unsigned>(c0_) <= kMaxAscii)) {
+ token = one_char_tokens[c0_];
+
+ switch (token) {
+ case Token::LPAREN:
+ case Token::RPAREN:
+ case Token::LBRACE:
+ case Token::RBRACE:
+ case Token::LBRACK:
+ case Token::RBRACK:
+ case Token::CONDITIONAL:
+ case Token::COLON:
+ case Token::SEMICOLON:
+ case Token::COMMA:
+ case Token::BIT_NOT:
+ case Token::ILLEGAL:
+ // One character tokens.
+ return Select(token);
+
+ case Token::STRING:
+ return ScanString();
+
+ case Token::LT:
+ // < <= << <<= <!--
Advance();
- if (c0_ == '=') return Select(Token::ASSIGN_SAR);
- if (c0_ == '>') return Select('=', Token::ASSIGN_SHR, Token::SHR);
- return Token::SAR;
- }
- return Token::GT;
-
- case '=':
- // = == === =>
- Advance();
- if (c0_ == '=') return Select('=', Token::EQ_STRICT, Token::EQ);
- if (c0_ == '>') return Select(Token::ARROW);
- return Token::ASSIGN;
-
- case '!':
- // ! != !==
- Advance();
- if (c0_ == '=') return Select('=', Token::NE_STRICT, Token::NE);
- return Token::NOT;
-
- case '+':
- // + ++ +=
- Advance();
- if (c0_ == '+') return Select(Token::INC);
- if (c0_ == '=') return Select(Token::ASSIGN_ADD);
- return Token::ADD;
-
- case '-':
- // - -- --> -=
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '>' && next().after_line_terminator) {
- // For compatibility with SpiderMonkey, we skip lines that
- // start with an HTML comment end '-->'.
- token = SkipSingleHTMLComment();
+ if (c0_ == '=') return Select(Token::LTE);
+ if (c0_ == '<') return Select('=', Token::ASSIGN_SHL, Token::SHL);
+ if (c0_ == '!') {
+ token = ScanHtmlComment();
continue;
}
- return Token::DEC;
- }
- if (c0_ == '=') return Select(Token::ASSIGN_SUB);
- return Token::SUB;
-
- case '*':
- // * *=
- Advance();
- if (c0_ == '*') return Select('=', Token::ASSIGN_EXP, Token::EXP);
- if (c0_ == '=') return Select(Token::ASSIGN_MUL);
- return Token::MUL;
-
- case '%':
- // % %=
- return Select('=', Token::ASSIGN_MOD, Token::MOD);
-
- case '/':
- // / // /* /=
- Advance();
- if (c0_ == '/') {
- uc32 c = Peek();
- if (c == '#' || c == '@') {
+ return Token::LT;
+
+ case Token::GT:
+ // > >= >> >>= >>> >>>=
+ Advance();
+ if (c0_ == '=') return Select(Token::GTE);
+ if (c0_ == '>') {
+ // >> >>= >>> >>>=
Advance();
+ if (c0_ == '=') return Select(Token::ASSIGN_SAR);
+ if (c0_ == '>') return Select('=', Token::ASSIGN_SHR, Token::SHR);
+ return Token::SAR;
+ }
+ return Token::GT;
+
+ case Token::ASSIGN:
+ // = == === =>
+ Advance();
+ if (c0_ == '=') return Select('=', Token::EQ_STRICT, Token::EQ);
+ if (c0_ == '>') return Select(Token::ARROW);
+ return Token::ASSIGN;
+
+ case Token::NOT:
+ // ! != !==
+ Advance();
+ if (c0_ == '=') return Select('=', Token::NE_STRICT, Token::NE);
+ return Token::NOT;
+
+ case Token::ADD:
+ // + ++ +=
+ Advance();
+ if (c0_ == '+') return Select(Token::INC);
+ if (c0_ == '=') return Select(Token::ASSIGN_ADD);
+ return Token::ADD;
+
+ case Token::SUB:
+ // - -- --> -=
+ Advance();
+ if (c0_ == '-') {
Advance();
- token = SkipSourceURLComment();
+ if (c0_ == '>' && next().after_line_terminator) {
+ // For compatibility with SpiderMonkey, we skip lines that
+ // start with an HTML comment end '-->'.
+ token = SkipSingleHTMLComment();
+ continue;
+ }
+ return Token::DEC;
+ }
+ if (c0_ == '=') return Select(Token::ASSIGN_SUB);
+ return Token::SUB;
+
+ case Token::MUL:
+ // * *=
+ Advance();
+ if (c0_ == '*') return Select('=', Token::ASSIGN_EXP, Token::EXP);
+ if (c0_ == '=') return Select(Token::ASSIGN_MUL);
+ return Token::MUL;
+
+ case Token::MOD:
+ // % %=
+ return Select('=', Token::ASSIGN_MOD, Token::MOD);
+
+ case Token::DIV:
+ // / // /* /=
+ Advance();
+ if (c0_ == '/') {
+ uc32 c = Peek();
+ if (c == '#' || c == '@') {
+ Advance();
+ Advance();
+ token = SkipSourceURLComment();
+ continue;
+ }
+ token = SkipSingleLineComment();
continue;
}
- token = SkipSingleLineComment();
- continue;
- }
- if (c0_ == '*') {
- token = SkipMultiLineComment();
- continue;
- }
- if (c0_ == '=') return Select(Token::ASSIGN_DIV);
- return Token::DIV;
-
- case '&':
- // & && &=
- Advance();
- if (c0_ == '&') return Select(Token::AND);
- if (c0_ == '=') return Select(Token::ASSIGN_BIT_AND);
- return Token::BIT_AND;
-
- case '|':
- // | || |=
- Advance();
- if (c0_ == '|') return Select(Token::OR);
- if (c0_ == '=') return Select(Token::ASSIGN_BIT_OR);
- return Token::BIT_OR;
-
- case '^':
- // ^ ^=
- return Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
-
- case '.':
- // . Number
- Advance();
- if (IsDecimalDigit(c0_)) return ScanNumber(true);
- if (c0_ == '.') {
- if (Peek() == '.') {
- Advance();
- Advance();
- return Token::ELLIPSIS;
+ if (c0_ == '*') {
+ token = SkipMultiLineComment();
+ continue;
}
- }
- return Token::PERIOD;
+ if (c0_ == '=') return Select(Token::ASSIGN_DIV);
+ return Token::DIV;
+
+ case Token::BIT_AND:
+ // & && &=
+ Advance();
+ if (c0_ == '&') return Select(Token::AND);
+ if (c0_ == '=') return Select(Token::ASSIGN_BIT_AND);
+ return Token::BIT_AND;
- case '`':
- Advance();
- return ScanTemplateSpan();
+ case Token::BIT_OR:
+ // | || |=
+ Advance();
+ if (c0_ == '|') return Select(Token::OR);
+ if (c0_ == '=') return Select(Token::ASSIGN_BIT_OR);
+ return Token::BIT_OR;
+
+ case Token::BIT_XOR:
+ // ^ ^=
+ return Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
- case '#':
- return ScanPrivateName();
+ case Token::PERIOD:
+ // . Number
+ Advance();
+ if (IsDecimalDigit(c0_)) return ScanNumber(true);
+ if (c0_ == '.') {
+ if (Peek() == '.') {
+ Advance();
+ Advance();
+ return Token::ELLIPSIS;
+ }
+ }
+ return Token::PERIOD;
- default:
- if (unicode_cache_->IsIdentifierStart(c0_) ||
- (CombineSurrogatePair() &&
- unicode_cache_->IsIdentifierStart(c0_))) {
- Token::Value token = ScanIdentifierOrKeyword();
- if (!Token::IsContextualKeyword(token)) return token;
+ case Token::TEMPLATE_SPAN:
+ Advance();
+ return ScanTemplateSpan();
- next().contextual_token = token;
- return Token::IDENTIFIER;
- }
- if (IsDecimalDigit(c0_)) return ScanNumber(false);
- if (c0_ == kEndOfInput) return Token::EOS;
- token = SkipWhiteSpace();
- continue;
+ case Token::PRIVATE_NAME:
+ return ScanPrivateName();
+
+ case Token::WHITESPACE:
+ token = SkipWhiteSpace();
+ continue;
+
+ case Token::NUMBER:
+ return ScanNumber(false);
+
+ case Token::IDENTIFIER:
+ return ScanIdentifierOrKeyword();
+
+ default:
+ UNREACHABLE();
+ }
}
+
+ if (IsIdentifierStart(c0_) ||
+ (CombineSurrogatePair() && IsIdentifierStart(c0_))) {
+ return ScanIdentifierOrKeyword();
+ }
+ if (c0_ == kEndOfInput) {
+ return source_->has_parser_error() ? Token::ILLEGAL : Token::EOS;
+ }
+ token = SkipWhiteSpace();
+
// Continue scanning for tokens as long as we're just skipping whitespace.
} while (token == Token::WHITESPACE);
return token;
}
-void Scanner::Scan() {
- next().literal_chars.Drop();
- next().raw_literal_chars.Drop();
- next().contextual_token = Token::UNINITIALIZED;
- next().invalid_template_escape_message = MessageTemplate::kNone;
+void Scanner::Scan(TokenDesc* next_desc) {
+ DCHECK_EQ(next_desc, &next());
- next().token = ScanSingleToken();
- next().location.end_pos = source_pos();
+ next_desc->token = ScanSingleToken();
+ DCHECK_IMPLIES(has_parser_error(), next_desc->token == Token::ILLEGAL);
+ next_desc->location.end_pos = source_pos();
#ifdef DEBUG
SanityCheckTokenDesc(current());
@@ -551,6 +523,8 @@ void Scanner::Scan() {
#endif
}
+void Scanner::Scan() { Scan(next_); }
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc
index 525b1bc681..43fc589e88 100644
--- a/deps/v8/src/parsing/scanner.cc
+++ b/deps/v8/src/parsing/scanner.cc
@@ -13,16 +13,15 @@
#include "src/ast/ast-value-factory.h"
#include "src/conversions-inl.h"
#include "src/objects/bigint.h"
-#include "src/parsing/duplicate-finder.h" // For Scanner::FindSymbol
#include "src/parsing/scanner-inl.h"
+#include "src/zone/zone.h"
namespace v8 {
namespace internal {
class Scanner::ErrorState {
public:
- ErrorState(MessageTemplate::Template* message_stack,
- Scanner::Location* location_stack)
+ ErrorState(MessageTemplate* message_stack, Scanner::Location* location_stack)
: message_stack_(message_stack),
old_message_(*message_stack),
location_stack_(location_stack),
@@ -49,8 +48,8 @@ class Scanner::ErrorState {
}
private:
- MessageTemplate::Template* const message_stack_;
- MessageTemplate::Template const old_message_;
+ MessageTemplate* const message_stack_;
+ MessageTemplate const old_message_;
Scanner::Location* const location_stack_;
Scanner::Location const old_location_;
};
@@ -59,7 +58,6 @@ class Scanner::ErrorState {
// Scanner::LiteralBuffer
Handle<String> Scanner::LiteralBuffer::Internalize(Isolate* isolate) const {
- DCHECK(is_used_);
if (is_one_byte()) {
return isolate->factory()->InternalizeOneByteString(one_byte_literal());
}
@@ -67,20 +65,21 @@ Handle<String> Scanner::LiteralBuffer::Internalize(Isolate* isolate) const {
}
int Scanner::LiteralBuffer::NewCapacity(int min_capacity) {
- int capacity = Max(min_capacity, backing_store_.length());
- int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
- return new_capacity;
+ return min_capacity < (kMaxGrowth / (kGrowthFactor - 1))
+ ? min_capacity * kGrowthFactor
+ : min_capacity + kMaxGrowth;
}
void Scanner::LiteralBuffer::ExpandBuffer() {
- Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
+ int min_capacity = Max(kInitialCapacity, backing_store_.length());
+ Vector<byte> new_store = Vector<byte>::New(NewCapacity(min_capacity));
MemCopy(new_store.start(), backing_store_.start(), position_);
backing_store_.Dispose();
backing_store_ = new_store;
}
void Scanner::LiteralBuffer::ConvertToTwoByte() {
- DCHECK(is_one_byte_);
+ DCHECK(is_one_byte());
Vector<byte> new_store;
int new_content_size = position_ * kUC16Size;
if (new_content_size >= backing_store_.length()) {
@@ -104,7 +103,7 @@ void Scanner::LiteralBuffer::ConvertToTwoByte() {
}
void Scanner::LiteralBuffer::AddTwoByteChar(uc32 code_unit) {
- DCHECK(!is_one_byte_);
+ DCHECK(!is_one_byte());
if (position_ >= backing_store_.length()) ExpandBuffer();
if (code_unit <=
static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
@@ -124,36 +123,23 @@ void Scanner::LiteralBuffer::AddTwoByteChar(uc32 code_unit) {
// ----------------------------------------------------------------------------
// Scanner::BookmarkScope
-const size_t Scanner::BookmarkScope::kBookmarkAtFirstPos =
- std::numeric_limits<size_t>::max() - 2;
const size_t Scanner::BookmarkScope::kNoBookmark =
std::numeric_limits<size_t>::max() - 1;
const size_t Scanner::BookmarkScope::kBookmarkWasApplied =
std::numeric_limits<size_t>::max();
-void Scanner::BookmarkScope::Set() {
+void Scanner::BookmarkScope::Set(size_t position) {
DCHECK_EQ(bookmark_, kNoBookmark);
-
- // The first token is a bit special, since current_ will still be
- // uninitialized. In this case, store kBookmarkAtFirstPos and special-case it
- // when
- // applying the bookmark.
- DCHECK_IMPLIES(scanner_->current().token == Token::UNINITIALIZED,
- scanner_->current().location.beg_pos ==
- scanner_->next().location.beg_pos);
- bookmark_ = (scanner_->current().token == Token::UNINITIALIZED)
- ? kBookmarkAtFirstPos
- : scanner_->location().beg_pos;
+ bookmark_ = position;
}
void Scanner::BookmarkScope::Apply() {
DCHECK(HasBeenSet()); // Caller hasn't called SetBookmark.
- if (bookmark_ == kBookmarkAtFirstPos) {
- scanner_->SeekNext(0);
+ if (had_parser_error_) {
+ scanner_->set_parser_error();
} else {
+ scanner_->reset_parser_error_flag();
scanner_->SeekNext(bookmark_);
- scanner_->Next();
- DCHECK_EQ(scanner_->location().beg_pos, static_cast<int>(bookmark_));
}
bookmark_ = kBookmarkWasApplied;
}
@@ -169,10 +155,8 @@ bool Scanner::BookmarkScope::HasBeenApplied() const {
// ----------------------------------------------------------------------------
// Scanner
-Scanner::Scanner(UnicodeCache* unicode_cache, Utf16CharacterStream* source,
- bool is_module)
- : unicode_cache_(unicode_cache),
- source_(source),
+Scanner::Scanner(Utf16CharacterStream* source, bool is_module)
+ : source_(source),
found_html_comment_(false),
allow_harmony_numeric_separator_(false),
is_module_(is_module),
@@ -241,13 +225,14 @@ Token::Value Scanner::Next() {
// current_ as next_ and scan into it, leaving next_next_ uninitialized.
if (V8_LIKELY(next_next().token == Token::UNINITIALIZED)) {
next_ = previous;
- next().after_line_terminator = false;
- Scan();
+ // User 'previous' instead of 'next_' because for some reason the compiler
+ // thinks 'next_' could be modified before the entry into Scan.
+ previous->after_line_terminator = false;
+ Scan(previous);
} else {
next_ = next_next_;
next_next_ = previous;
previous->token = Token::UNINITIALIZED;
- previous->contextual_token = Token::UNINITIALIZED;
DCHECK_NE(Token::UNINITIALIZED, current().token);
}
return current().token;
@@ -300,42 +285,41 @@ Token::Value Scanner::SkipSourceURLComment() {
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.
- DCHECK(!unicode_cache_->IsWhiteSpaceOrLineTerminator(kEndOfInput));
- if (!unicode_cache_->IsWhiteSpace(c0_)) return;
+ DCHECK(!IsWhiteSpaceOrLineTerminator(kEndOfInput));
+ if (!IsWhiteSpace(c0_)) return;
Advance();
LiteralBuffer name;
name.Start();
- while (c0_ != kEndOfInput &&
- !unicode_cache_->IsWhiteSpaceOrLineTerminator(c0_) && c0_ != '=') {
+ while (c0_ != kEndOfInput && !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")) {
+ if (name_literal == StaticCharVector("sourceURL")) {
value = &source_url_;
- } else if (name_literal == STATIC_CHAR_VECTOR("sourceMappingURL")) {
+ } else if (name_literal == StaticCharVector("sourceMappingURL")) {
value = &source_mapping_url_;
} else {
return;
}
if (c0_ != '=')
return;
- value->Drop();
value->Start();
Advance();
- while (unicode_cache_->IsWhiteSpace(c0_)) {
+ while (IsWhiteSpace(c0_)) {
Advance();
}
while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) {
// Disallowed characters.
if (c0_ == '"' || c0_ == '\'') {
- value->Drop();
+ value->Start();
return;
}
- if (unicode_cache_->IsWhiteSpace(c0_)) {
+ if (IsWhiteSpace(c0_)) {
break;
}
value->AddChar(c0_);
@@ -343,8 +327,8 @@ void Scanner::TryToParseSourceURLComment() {
}
// Allow whitespace at the end.
while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) {
- if (!unicode_cache_->IsWhiteSpace(c0_)) {
- value->Drop();
+ if (!IsWhiteSpace(c0_)) {
+ value->Start();
break;
}
Advance();
@@ -377,6 +361,13 @@ Token::Value Scanner::SkipMultiLineComment() {
return Token::ILLEGAL;
}
+void Scanner::SkipHashBang() {
+ if (c0_ == '#' && Peek() == '!' && source_pos() == 0) {
+ SkipSingleLineComment();
+ Scan();
+ }
+}
+
Token::Value Scanner::ScanHtmlComment() {
// Check for <!-- comments.
DCHECK_EQ(c0_, '!');
@@ -393,51 +384,20 @@ Token::Value Scanner::ScanHtmlComment() {
#ifdef DEBUG
void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const {
- // Most tokens should not have literal_chars or even raw_literal chars.
- // The rules are:
- // - UNINITIALIZED: we don't care.
- // - TEMPLATE_*: need both literal + raw literal chars.
- // - IDENTIFIERS, STRINGS, etc.: need a literal, but no raw literal.
- // - all others: should have neither.
- // Furthermore, only TEMPLATE_* tokens can have a
- // invalid_template_escape_message.
+ // Only TEMPLATE_* tokens can have a invalid_template_escape_message.
+ // ILLEGAL and UNINITIALIZED can have garbage for the field.
switch (token.token) {
case Token::UNINITIALIZED:
+ case Token::ILLEGAL:
// token.literal_chars & other members might be garbage. That's ok.
- break;
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL:
- DCHECK(token.raw_literal_chars.is_used());
- DCHECK(token.literal_chars.is_used());
- break;
- case Token::ESCAPED_KEYWORD:
- case Token::ESCAPED_STRICT_RESERVED_WORD:
- case Token::FUTURE_STRICT_RESERVED_WORD:
- case Token::IDENTIFIER:
- case Token::NUMBER:
- case Token::BIGINT:
- case Token::REGEXP_LITERAL:
- case Token::SMI:
- case Token::STRING:
- case Token::PRIVATE_NAME:
- DCHECK(token.literal_chars.is_used());
- DCHECK(!token.raw_literal_chars.is_used());
- DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone);
break;
default:
- DCHECK(!token.literal_chars.is_used());
- DCHECK(!token.raw_literal_chars.is_used());
DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone);
break;
}
-
- DCHECK_IMPLIES(token.token != Token::IDENTIFIER,
- token.contextual_token == Token::UNINITIALIZED);
- DCHECK_IMPLIES(token.contextual_token != Token::UNINITIALIZED,
- token.token == Token::IDENTIFIER &&
- Token::IsContextualKeyword(token.contextual_token));
- DCHECK(!Token::IsContextualKeyword(token.token));
}
#endif // DEBUG
@@ -541,24 +501,45 @@ Token::Value Scanner::ScanString() {
uc32 quote = c0_;
Advance(); // consume quote
- LiteralScope literal(this);
+ next().literal_chars.Start();
while (true) {
+ if (V8_UNLIKELY(c0_ == kEndOfInput)) return Token::ILLEGAL;
+ if ((V8_UNLIKELY(static_cast<uint32_t>(c0_) >= kMaxAscii) &&
+ !unibrow::IsStringLiteralLineTerminator(c0_)) ||
+ !MayTerminateString(character_scan_flags[c0_])) {
+ AddLiteralChar(c0_);
+ AdvanceUntil([this](uc32 c0) {
+ if (V8_UNLIKELY(static_cast<uint32_t>(c0) > kMaxAscii)) {
+ if (V8_UNLIKELY(unibrow::IsStringLiteralLineTerminator(c0))) {
+ return true;
+ }
+ AddLiteralChar(c0);
+ return false;
+ }
+ uint8_t char_flags = character_scan_flags[c0];
+ if (MayTerminateString(char_flags)) return true;
+ AddLiteralChar(c0);
+ return false;
+ });
+ }
if (c0_ == quote) {
- literal.Complete();
Advance();
return Token::STRING;
}
- if (c0_ == kEndOfInput || unibrow::IsStringLiteralLineTerminator(c0_)) {
- return Token::ILLEGAL;
- }
if (c0_ == '\\') {
Advance();
// TODO(verwaest): Check whether we can remove the additional check.
- if (c0_ == kEndOfInput || !ScanEscape<false>()) {
+ if (V8_UNLIKELY(c0_ == kEndOfInput || !ScanEscape<false>())) {
return Token::ILLEGAL;
}
continue;
}
+ if (V8_UNLIKELY(c0_ == kEndOfInput ||
+ unibrow::IsStringLiteralLineTerminator(c0_))) {
+ return Token::ILLEGAL;
+ }
+ DCHECK_NE(quote, c0_);
+ DCHECK((c0_ == '\'' || c0_ == '"'));
AddLiteralCharAdvance();
}
}
@@ -570,17 +551,17 @@ Token::Value Scanner::ScanPrivateName() {
return Token::ILLEGAL;
}
- LiteralScope literal(this);
+ next().literal_chars.Start();
DCHECK_EQ(c0_, '#');
- DCHECK(!unicode_cache_->IsIdentifierStart(kEndOfInput));
- if (!unicode_cache_->IsIdentifierStart(Peek())) {
+ DCHECK(!IsIdentifierStart(kEndOfInput));
+ if (!IsIdentifierStart(Peek())) {
ReportScannerError(source_pos(),
MessageTemplate::kInvalidOrUnexpectedToken);
return Token::ILLEGAL;
}
AddLiteralCharAdvance();
- Token::Value token = ScanIdentifierOrKeywordInner(&literal);
+ Token::Value token = ScanIdentifierOrKeywordInner();
return token == Token::ILLEGAL ? Token::ILLEGAL : Token::PRIVATE_NAME;
}
@@ -605,7 +586,7 @@ Token::Value Scanner::ScanTemplateSpan() {
ErrorState octal_error_state(&octal_message_, &octal_pos_);
Token::Value result = Token::TEMPLATE_SPAN;
- LiteralScope literal(this);
+ next().literal_chars.Start();
next().raw_literal_chars.Start();
const bool capture_raw = true;
while (true) {
@@ -658,10 +639,8 @@ Token::Value Scanner::ScanTemplateSpan() {
AddLiteralChar(c);
}
}
- literal.Complete();
next().location.end_pos = source_pos();
next().token = result;
- next().contextual_token = Token::UNINITIALIZED;
return result;
}
@@ -669,7 +648,6 @@ Token::Value Scanner::ScanTemplateSpan() {
Handle<String> Scanner::SourceUrl(Isolate* isolate) const {
Handle<String> tmp;
if (source_url_.length() > 0) {
- DCHECK(source_url_.is_used());
tmp = source_url_.Internalize(isolate);
}
return tmp;
@@ -678,7 +656,6 @@ Handle<String> Scanner::SourceUrl(Isolate* isolate) const {
Handle<String> Scanner::SourceMappingUrl(Isolate* isolate) const {
Handle<String> tmp;
if (source_mapping_url_.length() > 0) {
- DCHECK(source_mapping_url_.is_used());
tmp = source_mapping_url_.Internalize(isolate);
}
return tmp;
@@ -847,7 +824,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
NumberKind kind = DECIMAL;
- LiteralScope literal(this);
+ next().literal_chars.Start();
bool at_start = !seen_period;
int start_pos = source_pos(); // For reporting octal positions.
if (seen_period) {
@@ -905,10 +882,8 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
}
if (next().literal_chars.one_byte_literal().length() <= 10 &&
- value <= Smi::kMaxValue && c0_ != '.' &&
- !unicode_cache_->IsIdentifierStart(c0_)) {
+ value <= Smi::kMaxValue && c0_ != '.' && !IsIdentifierStart(c0_)) {
next().smi_value_ = static_cast<uint32_t>(value);
- literal.Complete();
if (kind == DECIMAL_WITH_LEADING_ZERO) {
octal_pos_ = Location(start_pos, source_pos());
@@ -963,12 +938,10 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
// 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_) || unicode_cache_->IsIdentifierStart(c0_)) {
+ if (IsDecimalDigit(c0_) || IsIdentifierStart(c0_)) {
return Token::ILLEGAL;
}
- literal.Complete();
-
if (kind == DECIMAL_WITH_LEADING_ZERO) {
octal_pos_ = Location(start_pos, source_pos());
octal_message_ = MessageTemplate::kStrictDecimalWithLeadingZero;
@@ -1004,54 +977,49 @@ uc32 Scanner::ScanUnicodeEscape() {
return ScanHexNumber<capture_raw, unicode>(4);
}
-Token::Value Scanner::ScanIdentifierOrKeywordInnerSlow(LiteralScope* literal,
- bool escaped) {
+Token::Value Scanner::ScanIdentifierOrKeywordInnerSlow(bool escaped,
+ bool can_be_keyword) {
while (true) {
if (c0_ == '\\') {
escaped = true;
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier part characters.
// TODO(verwaest): Make this true.
- // DCHECK(!unicode_cache_->IsIdentifierPart('\\'));
- DCHECK(!unicode_cache_->IsIdentifierPart(-1));
- if (c == '\\' || !unicode_cache_->IsIdentifierPart(c)) {
+ // DCHECK(!IsIdentifierPart('\'));
+ DCHECK(!IsIdentifierPart(-1));
+ if (c == '\\' || !IsIdentifierPart(c)) {
return Token::ILLEGAL;
}
+ can_be_keyword = can_be_keyword && CharCanBeKeyword(c);
AddLiteralChar(c);
- } else if (unicode_cache_->IsIdentifierPart(c0_) ||
- (CombineSurrogatePair() &&
- unicode_cache_->IsIdentifierPart(c0_))) {
+ } else if (IsIdentifierPart(c0_) ||
+ (CombineSurrogatePair() && IsIdentifierPart(c0_))) {
+ can_be_keyword = can_be_keyword && CharCanBeKeyword(c0_);
AddLiteralCharAdvance();
} else {
break;
}
}
- if (next().literal_chars.is_one_byte()) {
+ if (can_be_keyword && next().literal_chars.is_one_byte()) {
Vector<const uint8_t> chars = next().literal_chars.one_byte_literal();
Token::Value token =
KeywordOrIdentifierToken(chars.start(), chars.length());
/* TODO(adamk): YIELD should be handled specially. */
if (token == Token::FUTURE_STRICT_RESERVED_WORD) {
- literal->Complete();
if (escaped) return Token::ESCAPED_STRICT_RESERVED_WORD;
return token;
}
- if (token == Token::IDENTIFIER || Token::IsContextualKeyword(token)) {
- literal->Complete();
- return token;
- }
+ if (token == Token::IDENTIFIER) return token;
if (!escaped) return token;
- literal->Complete();
if (token == Token::LET || token == Token::STATIC) {
return Token::ESCAPED_STRICT_RESERVED_WORD;
}
return Token::ESCAPED_KEYWORD;
}
- literal->Complete();
return Token::IDENTIFIER;
}
@@ -1065,7 +1033,7 @@ bool Scanner::ScanRegExpPattern() {
// 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);
+ next().literal_chars.Start();
if (next().token == Token::ASSIGN_DIV) {
AddLiteralChar('=');
}
@@ -1098,9 +1066,7 @@ bool Scanner::ScanRegExpPattern() {
}
Advance(); // consume '/'
- literal.Complete();
next().token = Token::REGEXP_LITERAL;
- next().contextual_token = Token::UNINITIALIZED;
return true;
}
@@ -1110,7 +1076,7 @@ Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() {
// Scan regular expression flags.
int flags = 0;
- while (unicode_cache_->IsIdentifierPart(c0_)) {
+ while (IsIdentifierPart(c0_)) {
RegExp::Flags flag = RegExp::kNone;
switch (c0_) {
case 'g':
@@ -1173,7 +1139,6 @@ const AstRawString* Scanner::CurrentRawSymbol(
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);
}
@@ -1188,14 +1153,6 @@ const char* Scanner::CurrentLiteralAsCString(Zone* zone) const {
return buffer;
}
-bool Scanner::IsDuplicateSymbol(DuplicateFinder* duplicate_finder,
- AstValueFactory* ast_value_factory) const {
- DCHECK_NOT_NULL(duplicate_finder);
- DCHECK_NOT_NULL(ast_value_factory);
- const AstRawString* string = CurrentSymbol(ast_value_factory);
- return !duplicate_finder->known_symbols_.insert(string).second;
-}
-
void Scanner::SeekNext(size_t position) {
// Use with care: This cleanly resets most, but not all scanner state.
// TODO(vogelheim): Fix this, or at least DCHECK the relevant conditions.
@@ -1206,7 +1163,7 @@ void Scanner::SeekNext(size_t position) {
// current_ will remain unchanged, so overwrite it fully.)
for (TokenDesc& token : token_storage_) {
token.token = Token::UNINITIALIZED;
- token.contextual_token = Token::UNINITIALIZED;
+ token.invalid_template_escape_message = MessageTemplate::kNone;
}
// 2, reset the source to the desired position,
source_->Seek(position);
diff --git a/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h
index 83002b53c8..383159557b 100644
--- a/deps/v8/src/parsing/scanner.h
+++ b/deps/v8/src/parsing/scanner.h
@@ -13,8 +13,9 @@
#include "src/base/logging.h"
#include "src/char-predicates.h"
#include "src/globals.h"
-#include "src/messages.h"
+#include "src/message-template.h"
#include "src/parsing/token.h"
+#include "src/pointer-with-payload.h"
#include "src/unicode-decoder.h"
#include "src/unicode.h"
@@ -23,12 +24,11 @@ namespace internal {
class AstRawString;
class AstValueFactory;
-class DuplicateFinder;
class ExternalOneByteString;
class ExternalTwoByteString;
class ParserRecorder;
class RuntimeCallStats;
-class UnicodeCache;
+class Zone;
// ---------------------------------------------------------------------
// Buffered stream of UTF-16 code units, using an internal UTF-16 buffer.
@@ -40,6 +40,13 @@ class Utf16CharacterStream {
virtual ~Utf16CharacterStream() = default;
+ V8_INLINE void set_parser_error() {
+ buffer_cursor_ = buffer_end_;
+ has_parser_error_ = true;
+ }
+ V8_INLINE void reset_parser_error_flag() { has_parser_error_ = false; }
+ V8_INLINE bool has_parser_error() const { return has_parser_error_; }
+
inline uc32 Peek() {
if (V8_LIKELY(buffer_cursor_ < buffer_end_)) {
return static_cast<uc32>(*buffer_cursor_);
@@ -109,6 +116,11 @@ class Utf16CharacterStream {
}
}
+ // Returns true if the stream could access the V8 heap after construction.
+ bool can_be_cloned_for_parallel_access() const {
+ return can_be_cloned() && !can_access_heap();
+ }
+
// Returns true if the stream can be cloned with Clone.
// TODO(rmcilroy): Remove this once ChunkedStreams can be cloned.
virtual bool can_be_cloned() const = 0;
@@ -138,7 +150,7 @@ class Utf16CharacterStream {
bool ReadBlockChecked() {
size_t position = pos();
USE(position);
- bool success = ReadBlock();
+ bool success = !has_parser_error() && ReadBlock();
// Post-conditions: 1, We should always be at the right position.
// 2, Cursor should be inside the buffer.
@@ -186,6 +198,7 @@ class Utf16CharacterStream {
const uint16_t* buffer_end_;
size_t buffer_pos_;
RuntimeCallStats* runtime_call_stats_;
+ bool has_parser_error_ = false;
};
// ----------------------------------------------------------------------------
@@ -197,12 +210,14 @@ class Scanner {
class BookmarkScope {
public:
explicit BookmarkScope(Scanner* scanner)
- : scanner_(scanner), bookmark_(kNoBookmark) {
+ : scanner_(scanner),
+ bookmark_(kNoBookmark),
+ had_parser_error_(scanner->has_parser_error()) {
DCHECK_NOT_NULL(scanner_);
}
~BookmarkScope() = default;
- void Set();
+ void Set(size_t bookmark);
void Apply();
bool HasBeenSet() const;
bool HasBeenApplied() const;
@@ -210,24 +225,39 @@ class Scanner {
private:
static const size_t kNoBookmark;
static const size_t kBookmarkWasApplied;
- static const size_t kBookmarkAtFirstPos;
Scanner* scanner_;
size_t bookmark_;
+ bool had_parser_error_;
DISALLOW_COPY_AND_ASSIGN(BookmarkScope);
};
+ // Sets the Scanner into an error state to stop further scanning and terminate
+ // the parsing by only returning ILLEGAL tokens after that.
+ V8_INLINE void set_parser_error() {
+ if (!has_parser_error()) {
+ c0_ = kEndOfInput;
+ source_->set_parser_error();
+ for (TokenDesc& desc : token_storage_) desc.token = Token::ILLEGAL;
+ }
+ }
+ V8_INLINE void reset_parser_error_flag() {
+ source_->reset_parser_error_flag();
+ }
+ V8_INLINE bool has_parser_error() const {
+ return source_->has_parser_error();
+ }
+
// 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;
- }
+ int length() const { return end_pos - beg_pos; }
+ bool IsValid() const { return IsInRange(beg_pos, 0, end_pos); }
- static Location invalid() { return Location(-1, -1); }
+ static Location invalid() { return Location(-1, 0); }
int beg_pos;
int end_pos;
@@ -237,8 +267,7 @@ class Scanner {
static const int kNoOctalLocation = -1;
static const uc32 kEndOfInput = Utf16CharacterStream::kEndOfInput;
- explicit Scanner(UnicodeCache* scanner_contants, Utf16CharacterStream* source,
- bool is_module);
+ explicit Scanner(Utf16CharacterStream* source, bool is_module);
void Initialize();
@@ -249,27 +278,28 @@ class Scanner {
// Returns the current token again.
Token::Value current_token() const { return current().token; }
- Token::Value current_contextual_token() const {
- return current().contextual_token;
- }
- Token::Value next_contextual_token() const { return next().contextual_token; }
-
// Returns the location information for the current token
// (the token last returned by Next()).
const Location& location() const { return current().location; }
// This error is specifically an invalid hex or unicode escape sequence.
bool has_error() const { return scanner_error_ != MessageTemplate::kNone; }
- MessageTemplate::Template error() const { return scanner_error_; }
+ MessageTemplate error() const { return scanner_error_; }
const Location& error_location() const { return scanner_error_location_; }
bool has_invalid_template_escape() const {
return current().invalid_template_escape_message != MessageTemplate::kNone;
}
- MessageTemplate::Template invalid_template_escape_message() const {
+ MessageTemplate invalid_template_escape_message() const {
DCHECK(has_invalid_template_escape());
return current().invalid_template_escape_message;
}
+
+ void clear_invalid_template_escape_message() {
+ DCHECK(has_invalid_template_escape());
+ current_->invalid_template_escape_message = MessageTemplate::kNone;
+ }
+
Location invalid_template_escape_location() const {
DCHECK(has_invalid_template_escape());
return current().invalid_template_escape_location;
@@ -301,55 +331,27 @@ class Scanner {
return current().token == token;
}
- inline bool CurrentMatchesContextual(Token::Value token) const {
- DCHECK(Token::IsContextualKeyword(token));
- return current_contextual_token() == token;
- }
-
- // Match the token against the contextual keyword or literal buffer.
- inline bool CurrentMatchesContextualEscaped(Token::Value token) const {
- DCHECK(Token::IsContextualKeyword(token) || token == Token::LET);
- // Escaped keywords are not matched as tokens. So if we require escape
- // and/or string processing we need to look at the literal content
- // (which was escape-processed already).
- // Conveniently, !current().literal_chars.is_used() for all proper
- // keywords, so this second condition should exit early in common cases.
- return (current_contextual_token() == token) ||
- (current().literal_chars.is_used() &&
- current().literal_chars.Equals(Vector<const char>(
- Token::String(token), Token::StringLength(token))));
- }
+ template <size_t N>
+ bool NextLiteralEquals(const char (&s)[N]) {
+ DCHECK_EQ(Token::STRING, peek());
+ // The length of the token is used to make sure the literal equals without
+ // taking escape sequences (e.g., "use \x73trict") or line continuations
+ // (e.g., "use \(newline) strict") into account.
+ if (!is_next_literal_one_byte()) return false;
+ if (peek_location().length() != N + 1) return false;
- bool IsUseStrict() const {
- return current().token == Token::STRING &&
- current().literal_chars.Equals(
- Vector<const char>("use strict", strlen("use strict")));
+ Vector<const uint8_t> next = next_literal_one_byte_string();
+ const char* chars = reinterpret_cast<const char*>(next.start());
+ return next.length() == N - 1 && strncmp(s, chars, N - 1) == 0;
}
- bool IsGet() { return CurrentMatchesContextual(Token::GET); }
-
- bool IsSet() { return CurrentMatchesContextual(Token::SET); }
-
- bool IsLet() const {
- return CurrentMatches(Token::LET) ||
- CurrentMatchesContextualEscaped(Token::LET);
- }
-
- // Check whether the CurrentSymbol() has already been seen.
- // The DuplicateFinder holds the data, so different instances can be used
- // for different sets of duplicates to check for.
- bool IsDuplicateSymbol(DuplicateFinder* duplicate_finder,
- AstValueFactory* ast_value_factory) const;
-
- UnicodeCache* unicode_cache() const { 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();
octal_message_ = MessageTemplate::kNone;
}
- MessageTemplate::Template octal_message() const { return octal_message_; }
+ MessageTemplate octal_message() const { return octal_message_; }
// Returns the value of the last smi that was scanned.
uint32_t smi_value() const { return current().smi_value_; }
@@ -405,6 +407,9 @@ class Scanner {
const Utf16CharacterStream* stream() const { return source_; }
+ // If the next characters in the stream are "#!", the line is skipped.
+ void SkipHashBang();
+
private:
// Scoped helper for saving & restoring scanner error state.
// This is used for tagged template literals, in which normally forbidden
@@ -414,20 +419,17 @@ class Scanner {
// LiteralBuffer - Collector of chars of literals.
class LiteralBuffer {
public:
- LiteralBuffer()
- : backing_store_(), position_(0), is_one_byte_(true), is_used_(false) {}
+ LiteralBuffer() : backing_store_(), position_(0), is_one_byte_(true) {}
~LiteralBuffer() { backing_store_.Dispose(); }
V8_INLINE void AddChar(char code_unit) {
- DCHECK(is_used_);
DCHECK(IsValidAscii(code_unit));
AddOneByteChar(static_cast<byte>(code_unit));
}
V8_INLINE void AddChar(uc32 code_unit) {
- DCHECK(is_used_);
- if (is_one_byte_) {
+ if (is_one_byte()) {
if (code_unit <= static_cast<uc32>(unibrow::Latin1::kMaxChar)) {
AddOneByteChar(static_cast<byte>(code_unit));
return;
@@ -440,14 +442,12 @@ class Scanner {
bool is_one_byte() const { return is_one_byte_; }
bool Equals(Vector<const char> keyword) const {
- DCHECK(is_used_);
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(is_used_);
+ DCHECK(!is_one_byte());
DCHECK_EQ(position_ & 0x1, 0);
return Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(backing_store_.start()),
@@ -455,24 +455,14 @@ class Scanner {
}
Vector<const uint8_t> one_byte_literal() const {
- DCHECK(is_one_byte_);
- DCHECK(is_used_);
+ 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); }
+ int length() const { return is_one_byte() ? position_ : (position_ >> 1); }
void Start() {
- DCHECK(!is_used_);
- DCHECK_EQ(0, position_);
- is_used_ = true;
- }
-
- bool is_used() const { return is_used_; }
-
- void Drop() {
- is_used_ = false;
position_ = 0;
is_one_byte_ = true;
}
@@ -481,8 +471,7 @@ class Scanner {
private:
static const int kInitialCapacity = 16;
- static const int kGrowthFactory = 4;
- static const int kMinConversionSlack = 256;
+ static const int kGrowthFactor = 4;
static const int kMaxGrowth = 1 * MB;
inline bool IsValidAscii(char code_unit) {
@@ -494,7 +483,7 @@ class Scanner {
}
V8_INLINE void AddOneByteChar(byte one_byte_char) {
- DCHECK(is_one_byte_);
+ DCHECK(is_one_byte());
if (position_ >= backing_store_.length()) ExpandBuffer();
backing_store_[position_] = one_byte_char;
position_ += kOneByteSize;
@@ -507,42 +496,37 @@ class Scanner {
Vector<byte> backing_store_;
int position_;
+
bool is_one_byte_;
- bool is_used_;
DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
};
- // Scoped helper for literal recording. Automatically drops the literal
- // if aborting the scanning before it's complete.
- class LiteralScope {
- public:
- explicit LiteralScope(Scanner* scanner)
- : buffer_(&scanner->next().literal_chars), complete_(false) {
- buffer_->Start();
- }
- ~LiteralScope() {
- if (!complete_) buffer_->Drop();
- }
- void Complete() { complete_ = true; }
-
- private:
- LiteralBuffer* buffer_;
- bool complete_;
- };
-
// The current and look-ahead token.
struct TokenDesc {
Location location = {0, 0};
LiteralBuffer literal_chars;
LiteralBuffer raw_literal_chars;
Token::Value token = Token::UNINITIALIZED;
- MessageTemplate::Template invalid_template_escape_message =
- MessageTemplate::kNone;
+ MessageTemplate invalid_template_escape_message = MessageTemplate::kNone;
Location invalid_template_escape_location;
- Token::Value contextual_token = Token::UNINITIALIZED;
uint32_t smi_value_ = 0;
bool after_line_terminator = false;
+
+#ifdef DEBUG
+ bool CanAccessLiteral() const {
+ return token == Token::PRIVATE_NAME || token == Token::ILLEGAL ||
+ token == Token::UNINITIALIZED || token == Token::REGEXP_LITERAL ||
+ token == Token::ESCAPED_KEYWORD ||
+ IsInRange(token, Token::NUMBER, Token::STRING) ||
+ (Token::IsAnyIdentifier(token) && !Token::IsKeyword(token)) ||
+ IsInRange(token, Token::TEMPLATE_SPAN, Token::TEMPLATE_TAIL);
+ }
+ bool CanAccessRawLiteral() const {
+ return token == Token::ILLEGAL || token == Token::UNINITIALIZED ||
+ IsInRange(token, Token::TEMPLATE_SPAN, Token::TEMPLATE_TAIL);
+ }
+#endif // DEBUG
};
enum NumberKind {
@@ -575,14 +559,13 @@ class Scanner {
scanner_error_ = MessageTemplate::kNone;
}
- void ReportScannerError(const Location& location,
- MessageTemplate::Template error) {
+ void ReportScannerError(const Location& location, MessageTemplate error) {
if (has_error()) return;
scanner_error_ = error;
scanner_error_location_ = location;
}
- void ReportScannerError(int pos, MessageTemplate::Template error) {
+ void ReportScannerError(int pos, MessageTemplate error) {
if (has_error()) return;
scanner_error_ = error;
scanner_error_location_ = Location(pos, pos + 1);
@@ -668,45 +651,41 @@ class Scanner {
// token as a one-byte literal. E.g. Token::FUNCTION pretends to have a
// literal "function".
Vector<const uint8_t> literal_one_byte_string() const {
- if (current().literal_chars.is_used())
- return current().literal_chars.one_byte_literal();
- const char* str = Token::String(current().token);
- const uint8_t* str_as_uint8 = reinterpret_cast<const uint8_t*>(str);
- return Vector<const uint8_t>(str_as_uint8,
- Token::StringLength(current().token));
+ DCHECK(current().CanAccessLiteral() || Token::IsKeyword(current().token));
+ return current().literal_chars.one_byte_literal();
}
Vector<const uint16_t> literal_two_byte_string() const {
- DCHECK(current().literal_chars.is_used());
+ DCHECK(current().CanAccessLiteral() || Token::IsKeyword(current().token));
return current().literal_chars.two_byte_literal();
}
bool is_literal_one_byte() const {
- return !current().literal_chars.is_used() ||
- current().literal_chars.is_one_byte();
+ DCHECK(current().CanAccessLiteral() || Token::IsKeyword(current().token));
+ return current().literal_chars.is_one_byte();
}
// 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() const {
- DCHECK(next().literal_chars.is_used());
+ DCHECK(next().CanAccessLiteral());
return next().literal_chars.one_byte_literal();
}
Vector<const uint16_t> next_literal_two_byte_string() const {
- DCHECK(next().literal_chars.is_used());
+ DCHECK(next().CanAccessLiteral());
return next().literal_chars.two_byte_literal();
}
bool is_next_literal_one_byte() const {
- DCHECK(next().literal_chars.is_used());
+ DCHECK(next().CanAccessLiteral());
return next().literal_chars.is_one_byte();
}
Vector<const uint8_t> raw_literal_one_byte_string() const {
- DCHECK(current().raw_literal_chars.is_used());
+ DCHECK(current().CanAccessRawLiteral());
return current().raw_literal_chars.one_byte_literal();
}
Vector<const uint16_t> raw_literal_two_byte_string() const {
- DCHECK(current().raw_literal_chars.is_used());
+ DCHECK(current().CanAccessRawLiteral());
return current().raw_literal_chars.two_byte_literal();
}
bool is_raw_literal_one_byte() const {
- DCHECK(current().raw_literal_chars.is_used());
+ DCHECK(current().CanAccessRawLiteral());
return current().raw_literal_chars.is_one_byte();
}
@@ -721,6 +700,11 @@ class Scanner {
// Scans a single JavaScript token.
V8_INLINE Token::Value ScanSingleToken();
V8_INLINE void Scan();
+ // Performance hack: pass through a pre-calculated "next()" value to avoid
+ // having to re-calculate it in Scan. You'd think the compiler would be able
+ // to hoist the next() calculation out of the inlined Scan method, but seems
+ // that pointer aliasing analysis fails show that this is safe.
+ V8_INLINE void Scan(TokenDesc* next_desc);
V8_INLINE Token::Value SkipWhiteSpace();
Token::Value SkipSingleHTMLComment();
@@ -745,9 +729,9 @@ class Scanner {
Token::Value ScanNumber(bool seen_period);
V8_INLINE Token::Value ScanIdentifierOrKeyword();
- V8_INLINE Token::Value ScanIdentifierOrKeywordInner(LiteralScope* literal);
- Token::Value ScanIdentifierOrKeywordInnerSlow(LiteralScope* literal,
- bool escaped);
+ V8_INLINE Token::Value ScanIdentifierOrKeywordInner();
+ Token::Value ScanIdentifierOrKeywordInnerSlow(bool escaped,
+ bool can_be_keyword);
Token::Value ScanString();
Token::Value ScanPrivateName();
@@ -779,16 +763,13 @@ class Scanner {
// Subtract delimiters.
source_length -= 2;
}
- return token.literal_chars.is_used() &&
- (token.literal_chars.length() != source_length);
+ return token.literal_chars.length() != source_length;
}
#ifdef DEBUG
void SanityCheckTokenDesc(const TokenDesc&) const;
#endif
- UnicodeCache* const unicode_cache_;
-
TokenDesc& next() { return *next_; }
const TokenDesc& current() const { return *current_; }
@@ -822,9 +803,9 @@ class Scanner {
// Last-seen positions of potentially problematic tokens.
Location octal_pos_;
- MessageTemplate::Template octal_message_;
+ MessageTemplate octal_message_;
- MessageTemplate::Template scanner_error_;
+ MessageTemplate scanner_error_;
Location scanner_error_location_;
};
diff --git a/deps/v8/src/parsing/token.cc b/deps/v8/src/parsing/token.cc
index 4cbf244a2b..ec4b623775 100644
--- a/deps/v8/src/parsing/token.cc
+++ b/deps/v8/src/parsing/token.cc
@@ -10,32 +10,37 @@ namespace v8 {
namespace internal {
#define T(name, string, precedence) #name,
-const char* const Token::name_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
+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, T)};
+const char* const Token::string_[NUM_TOKENS] = {TOKEN_LIST(T, T)};
#undef T
constexpr uint8_t length(const char* str) {
return str ? static_cast<uint8_t>(strlen(str)) : 0;
}
#define T(name, string, precedence) length(string),
-const uint8_t Token::string_length_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
+const uint8_t Token::string_length_[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, T)};
-#undef T
-
-#define KT(a, b, c) 'T',
-#define KK(a, b, c) 'K',
-#define KC(a, b, c) 'C',
-const char Token::token_type[] = {TOKEN_LIST(KT, KK, KC)};
+#define T1(name, string, precedence) \
+ ((Token::name == Token::IN) ? 0 : precedence),
+#define T2(name, string, precedence) precedence,
+// precedence_[0] for accept_IN == false, precedence_[1] for accept_IN = true.
+const int8_t Token::precedence_[2][NUM_TOKENS] = {{TOKEN_LIST(T1, T1)},
+ {TOKEN_LIST(T2, T2)}};
+#undef T2
+#undef T1
+
+#define KT(a, b, c) \
+ IsPropertyNameBits::encode(Token::IsAnyIdentifier(a) || a == ESCAPED_KEYWORD),
+#define KK(a, b, c) \
+ IsKeywordBits::encode(true) | IsPropertyNameBits::encode(true),
+const uint8_t Token::token_flags[] = {TOKEN_LIST(KT, KK)};
#undef KT
#undef KK
-#undef KC
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/token.h b/deps/v8/src/parsing/token.h
index e1c6239e36..c457d39e92 100644
--- a/deps/v8/src/parsing/token.h
+++ b/deps/v8/src/parsing/token.h
@@ -20,12 +20,6 @@ namespace internal {
//
// T: Non-keyword tokens
// K: Keyword tokens
-// C: Contextual keyword token
-//
-// Contextual keyword tokens are tokens that are scanned as Token::IDENTIFIER,
-// but that in some contexts are treated as keywords. This mostly happens
-// when ECMAScript introduces new keywords, but for backwards compatibility
-// allows them to still be used as indentifiers in most contexts.
// IGNORE_TOKEN is a convenience macro that can be supplied as
// an argument (at any position) for a TOKEN_LIST call. It does
@@ -33,7 +27,8 @@ namespace internal {
#define IGNORE_TOKEN(name, string, precedence)
-/* Binary operators sorted by precedence */
+/* Binary operators */
+/* ADD and SUB are at the end since they are UnaryOp */
#define BINARY_OP_TOKEN_LIST(T, E) \
E(T, BIT_OR, "|", 6) \
E(T, BIT_XOR, "^", 7) \
@@ -41,12 +36,12 @@ namespace internal {
E(T, SHL, "<<", 11) \
E(T, SAR, ">>", 11) \
E(T, SHR, ">>>", 11) \
- E(T, ADD, "+", 12) \
- E(T, SUB, "-", 12) \
E(T, MUL, "*", 13) \
E(T, DIV, "/", 13) \
E(T, MOD, "%", 13) \
- E(T, EXP, "**", 14)
+ E(T, EXP, "**", 14) \
+ E(T, ADD, "+", 12) \
+ E(T, SUB, "-", 12)
#define EXPAND_BINOP_ASSIGN_TOKEN(T, name, string, precedence) \
T(ASSIGN_##name, string "=", 2)
@@ -54,32 +49,47 @@ namespace internal {
#define EXPAND_BINOP_TOKEN(T, name, string, precedence) \
T(name, string, precedence)
-#define TOKEN_LIST(T, K, C) \
- /* End of source indicator. */ \
- T(EOS, "EOS", 0) \
+#define TOKEN_LIST(T, K) \
+ \
+ /* BEGIN PropertyOrCall */ \
+ /* BEGIN Member */ \
+ /* BEGIN Template */ \
+ /* ES6 Template Literals */ \
+ T(TEMPLATE_SPAN, nullptr, 0) \
+ T(TEMPLATE_TAIL, nullptr, 0) \
+ /* END Template */ \
\
/* Punctuators (ECMA-262, section 7.7, page 15). */ \
+ /* BEGIN Property */ \
+ T(PERIOD, ".", 0) \
+ T(LBRACK, "[", 0) \
+ /* END Property */ \
+ /* END Member */ \
T(LPAREN, "(", 0) \
+ /* END PropertyOrCall */ \
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) \
+ /* BEGIN AutoSemicolon */ \
+ T(SEMICOLON, ";", 0) \
+ T(RBRACE, "}", 0) \
+ /* End of source indicator. */ \
+ T(EOS, "EOS", 0) \
+ /* END AutoSemicolon */ \
\
- /* Assignment operators. */ \
+ /* BEGIN ArrowOrAssignmentOp */ \
+ T(ARROW, "=>", 0) \
+ /* BEGIN AssignmentOp */ \
/* IsAssignmentOp() 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) \
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN) \
+ /* END AssignmentOp */ \
+ /* END ArrowOrAssignmentOp */ \
\
/* Binary operators sorted by precedence. */ \
/* IsBinaryOp() relies on this block of enum values */ \
@@ -87,8 +97,24 @@ namespace internal {
T(COMMA, ",", 1) \
T(OR, "||", 4) \
T(AND, "&&", 5) \
+ \
+ /* Unary operators, starting at ADD in BINARY_OP_TOKEN_LIST */ \
+ /* IsUnaryOp() relies on this block of enum values */ \
+ /* being contiguous and sorted in the same order! */ \
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_TOKEN) \
\
+ T(NOT, "!", 0) \
+ T(BIT_NOT, "~", 0) \
+ K(DELETE, "delete", 0) \
+ K(TYPEOF, "typeof", 0) \
+ K(VOID, "void", 0) \
+ \
+ /* BEGIN IsCountOp */ \
+ T(INC, "++", 0) \
+ T(DEC, "--", 0) \
+ /* END IsCountOp */ \
+ /* END IsUnaryOrCountOp */ \
+ \
/* Compare operators sorted by precedence. */ \
/* IsCompareOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \
@@ -103,15 +129,6 @@ namespace internal {
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) \
@@ -149,6 +166,8 @@ namespace internal {
T(BIGINT, nullptr, 0) \
T(STRING, nullptr, 0) \
\
+ /* BEGIN Callable */ \
+ K(SUPER, "super", 0) \
/* BEGIN AnyIdentifier */ \
/* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, nullptr, 0) \
@@ -161,14 +180,14 @@ namespace internal {
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
- K(ENUM, "enum", 0) \
/* END AnyIdentifier */ \
+ /* END Callable */ \
+ K(ENUM, "enum", 0) \
K(CLASS, "class", 0) \
K(CONST, "const", 0) \
K(EXPORT, "export", 0) \
K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \
- K(SUPER, "super", 0) \
T(PRIVATE_NAME, nullptr, 0) \
\
/* Illegal token - not able to scan. */ \
@@ -178,35 +197,13 @@ namespace internal {
/* Scanner-internal use only. */ \
T(WHITESPACE, nullptr, 0) \
T(UNINITIALIZED, nullptr, 0) \
- T(REGEXP_LITERAL, nullptr, 0) \
- \
- /* ES6 Template Literals */ \
- T(TEMPLATE_SPAN, nullptr, 0) \
- T(TEMPLATE_TAIL, nullptr, 0) \
- \
- /* Contextual keyword tokens */ \
- C(GET, "get", 0) \
- C(SET, "set", 0) \
- C(OF, "of", 0) \
- C(TARGET, "target", 0) \
- C(META, "meta", 0) \
- C(AS, "as", 0) \
- C(FROM, "from", 0) \
- C(NAME, "name", 0) \
- C(PROTO_UNDERSCORED, "__proto__", 0) \
- C(CONSTRUCTOR, "constructor", 0) \
- C(PRIVATE_CONSTRUCTOR, "#constructor", 0) \
- C(PROTOTYPE, "prototype", 0) \
- C(EVAL, "eval", 0) \
- C(ARGUMENTS, "arguments", 0) \
- C(UNDEFINED, "undefined", 0) \
- C(ANONYMOUS, "anonymous", 0)
+ T(REGEXP_LITERAL, nullptr, 0)
class Token {
public:
// All token values.
#define T(name, string, precedence) name,
- enum Value : uint8_t { TOKEN_LIST(T, T, T) NUM_TOKENS };
+ enum Value : uint8_t { TOKEN_LIST(T, T) NUM_TOKENS };
#undef T
// Returns a string corresponding to the C++ token name
@@ -216,43 +213,73 @@ class Token {
return name_[token];
}
- static char TypeForTesting(Value token) { return token_type[token]; }
+ class IsKeywordBits : public BitField8<bool, 0, 1> {};
+ class IsPropertyNameBits : public BitField8<bool, IsKeywordBits::kNext, 1> {};
// Predicates
- static bool IsKeyword(Value token) { return token_type[token] == 'K'; }
- static bool IsContextualKeyword(Value token) {
- return IsInRange(token, GET, ANONYMOUS);
+ static bool IsKeyword(Value token) {
+ return IsKeywordBits::decode(token_flags[token]);
+ }
+
+ static bool IsPropertyName(Value token) {
+ return IsPropertyNameBits::decode(token_flags[token]);
}
- static bool IsIdentifier(Value token, LanguageMode language_mode,
- bool is_generator, bool disallow_await) {
- if (IsInRange(token, IDENTIFIER, ASYNC)) return true;
- if (IsInRange(token, LET, ESCAPED_STRICT_RESERVED_WORD)) {
- return is_sloppy(language_mode);
- }
+ V8_INLINE static bool IsValidIdentifier(Value token,
+ LanguageMode language_mode,
+ bool is_generator,
+ bool disallow_await) {
+ if (V8_LIKELY(IsInRange(token, IDENTIFIER, ASYNC))) return true;
if (token == AWAIT) return !disallow_await;
if (token == YIELD) return !is_generator && is_sloppy(language_mode);
- return false;
+ return IsStrictReservedWord(token) && is_sloppy(language_mode);
+ }
+
+ static bool IsCallable(Value token) {
+ return IsInRange(token, SUPER, ESCAPED_STRICT_RESERVED_WORD);
+ }
+
+ static bool IsAutoSemicolon(Value token) {
+ return IsInRange(token, SEMICOLON, EOS);
}
static bool IsAnyIdentifier(Value token) {
- return IsInRange(token, IDENTIFIER, ENUM);
+ return IsInRange(token, IDENTIFIER, ESCAPED_STRICT_RESERVED_WORD);
}
static bool IsStrictReservedWord(Value token) {
- return IsInRange(token, LET, ESCAPED_STRICT_RESERVED_WORD);
+ return IsInRange(token, YIELD, ESCAPED_STRICT_RESERVED_WORD);
}
static bool IsLiteral(Value token) {
return IsInRange(token, NULL_LITERAL, STRING);
}
+ static bool IsTemplate(Value token) {
+ return IsInRange(token, TEMPLATE_SPAN, TEMPLATE_TAIL);
+ }
+
+ static bool IsMember(Value token) {
+ return IsInRange(token, TEMPLATE_SPAN, LBRACK);
+ }
+
+ static bool IsProperty(Value token) {
+ return IsInRange(token, PERIOD, LBRACK);
+ }
+
+ static bool IsPropertyOrCall(Value token) {
+ return IsInRange(token, TEMPLATE_SPAN, LPAREN);
+ }
+
+ static bool IsArrowOrAssignmentOp(Value token) {
+ return IsInRange(token, ARROW, ASSIGN_SUB);
+ }
+
static bool IsAssignmentOp(Value token) {
- return IsInRange(token, INIT, ASSIGN_EXP);
+ return IsInRange(token, INIT, ASSIGN_SUB);
}
- static bool IsGetOrSet(Value op) { return IsInRange(op, GET, SET); }
- static bool IsBinaryOp(Value op) { return IsInRange(op, COMMA, EXP); }
+ static bool IsBinaryOp(Value op) { return IsInRange(op, COMMA, SUB); }
static bool IsCompareOp(Value op) { return IsInRange(op, EQ, IN); }
@@ -263,7 +290,7 @@ class Token {
static bool IsEqualityOp(Value op) { return IsInRange(op, EQ, EQ_STRICT); }
static Value BinaryOpForAssignment(Value op) {
- DCHECK(IsInRange(op, ASSIGN_BIT_OR, ASSIGN_EXP));
+ DCHECK(IsInRange(op, ASSIGN_BIT_OR, ASSIGN_SUB));
Value result = static_cast<Value>(op - ASSIGN_BIT_OR + BIT_OR);
DCHECK(IsBinaryOp(result));
return result;
@@ -273,18 +300,11 @@ class Token {
return IsInRange(op, BIT_OR, SHR) || op == BIT_NOT;
}
- static bool IsUnaryOp(Value op) {
- return IsInRange(op, NOT, VOID) || IsInRange(op, ADD, SUB);
- }
-
+ static bool IsUnaryOp(Value op) { return IsInRange(op, ADD, VOID); }
static bool IsCountOp(Value op) { return IsInRange(op, INC, DEC); }
-
+ static bool IsUnaryOrCountOp(Value op) { return IsInRange(op, ADD, DEC); }
static bool IsShiftOp(Value op) { return IsInRange(op, SHL, SHR); }
- static bool IsTrivialExpressionToken(Value op) {
- return IsInRange(op, THIS, IDENTIFIER);
- }
-
// Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or nullptr if the token doesn't
// have a (unique) string (e.g. an IDENTIFIER).
@@ -300,17 +320,17 @@ class Token {
// Returns the precedence > 0 for binary and compare
// operators; returns 0 otherwise.
- static int Precedence(Value token) {
+ static int Precedence(Value token, bool accept_IN) {
DCHECK_GT(NUM_TOKENS, token); // token is unsigned
- return precedence_[token];
+ return precedence_[accept_IN][token];
}
private:
static const char* const name_[NUM_TOKENS];
static const char* const string_[NUM_TOKENS];
static const uint8_t string_length_[NUM_TOKENS];
- static const int8_t precedence_[NUM_TOKENS];
- static const char token_type[NUM_TOKENS];
+ static const int8_t precedence_[2][NUM_TOKENS];
+ static const uint8_t token_flags[NUM_TOKENS];
};
} // namespace internal