summaryrefslogtreecommitdiff
path: root/deps/v8/src/parsing/parser-base.h
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2016-12-23 16:30:57 +0100
committerMichaël Zasso <targos@protonmail.com>2017-01-26 22:46:17 +0100
commit2739185b790e040c3b044c577327f5d44bffad4a (patch)
tree29a466999212f4c85958379d9d400eec8a185ba5 /deps/v8/src/parsing/parser-base.h
parenta67a04d7654faaa04c8da00e42981ebc9fd0911c (diff)
downloadandroid-node-v8-2739185b790e040c3b044c577327f5d44bffad4a.tar.gz
android-node-v8-2739185b790e040c3b044c577327f5d44bffad4a.tar.bz2
android-node-v8-2739185b790e040c3b044c577327f5d44bffad4a.zip
deps: update V8 to 5.5.372.40
PR-URL: https://github.com/nodejs/node/pull/9618 Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/parsing/parser-base.h')
-rw-r--r--deps/v8/src/parsing/parser-base.h3974
1 files changed, 2849 insertions, 1125 deletions
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h
index b8703d0691..1ebbee4959 100644
--- a/deps/v8/src/parsing/parser-base.h
+++ b/deps/v8/src/parsing/parser-base.h
@@ -5,6 +5,7 @@
#ifndef V8_PARSING_PARSER_BASE_H
#define V8_PARSING_PARSER_BASE_H
+#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/bailout-reason.h"
#include "src/base/hashmap.h"
@@ -56,59 +57,6 @@ static inline bool operator&(ParseFunctionFlags bitfield,
return static_cast<T>(bitfield) & static_cast<T>(mask);
}
-enum class MethodKind {
- kNormal = 0,
- kStatic = 1 << 0,
- kGenerator = 1 << 1,
- kStaticGenerator = kStatic | kGenerator,
- kAsync = 1 << 2,
- kStaticAsync = kStatic | kAsync,
-
- /* Any non-ordinary method kinds */
- kSpecialMask = kGenerator | kAsync
-};
-
-inline bool IsValidMethodKind(MethodKind kind) {
- return kind == MethodKind::kNormal || kind == MethodKind::kStatic ||
- kind == MethodKind::kGenerator ||
- kind == MethodKind::kStaticGenerator || kind == MethodKind::kAsync ||
- kind == MethodKind::kStaticAsync;
-}
-
-static inline MethodKind operator|(MethodKind lhs, MethodKind rhs) {
- typedef unsigned char T;
- return static_cast<MethodKind>(static_cast<T>(lhs) | static_cast<T>(rhs));
-}
-
-static inline MethodKind& operator|=(MethodKind& lhs, const MethodKind& rhs) {
- lhs = lhs | rhs;
- DCHECK(IsValidMethodKind(lhs));
- return lhs;
-}
-
-static inline bool operator&(MethodKind bitfield, MethodKind mask) {
- typedef unsigned char T;
- return static_cast<T>(bitfield) & static_cast<T>(mask);
-}
-
-inline bool IsNormalMethod(MethodKind kind) {
- return kind == MethodKind::kNormal;
-}
-
-inline bool IsSpecialMethod(MethodKind kind) {
- return kind & MethodKind::kSpecialMask;
-}
-
-inline bool IsStaticMethod(MethodKind kind) {
- return kind & MethodKind::kStatic;
-}
-
-inline bool IsGeneratorMethod(MethodKind kind) {
- return kind & MethodKind::kGenerator;
-}
-
-inline bool IsAsyncMethod(MethodKind kind) { return kind & MethodKind::kAsync; }
-
struct FormalParametersBase {
explicit FormalParametersBase(DeclarationScope* scope) : scope(scope) {}
DeclarationScope* scope;
@@ -126,8 +74,8 @@ struct FormalParametersBase {
// 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 this->x(); \
+#define CHECK_OK_CUSTOM(x, ...) ok); \
+ if (!*ok) return impl()->x(__VA_ARGS__); \
((void)0
#define DUMMY ) // to make indentation work
#undef DUMMY
@@ -140,93 +88,86 @@ struct FormalParametersBase {
// following the Curiously Recurring Template Pattern (CRTP).
// The structure of the parser objects is roughly the following:
//
-// // Common denominator, needed to avoid cyclic dependency.
-// // Instances of this template will end up with very minimal
-// // definitions, ideally containing just typedefs.
+// // A structure template containing type definitions, needed to
+// // avoid a cyclic dependency.
// template <typename Impl>
-// class ParserBaseTraits;
-
+// struct ParserTypes;
+//
// // The parser base object, which should just implement pure
// // parser behavior. The Impl parameter is the actual derived
// // class (according to CRTP), which implements impure parser
// // behavior.
// template <typename Impl>
-// class ParserBase : public ParserBaseTraits<Impl> { ... };
+// class ParserBase { ... };
//
// // And then, for each parser variant (e.g., parser, preparser, etc):
// class Parser;
//
// template <>
-// class ParserBaseTraits<Parser> { ... };
+// class ParserTypes<Parser> { ... };
//
// class Parser : public ParserBase<Parser> { ... };
//
-// TODO(nikolaos): Currently the traits objects contain many things
-// that will be moved to the implementation objects or to the parser
-// base. The following comments will have to change, when this happens.
-
-// The traits class template encapsulates the differences between
-// parser/pre-parser implementations. In particular:
-
-// - Return types: For example, Parser functions return Expression* and
-// PreParser functions return PreParserExpression.
-
-// - Creating parse tree nodes: Parser generates an AST during the recursive
-// descent. PreParser doesn't create a tree. Instead, it passes around minimal
-// data objects (PreParserExpression, PreParserIdentifier etc.) which contain
-// just enough data for the upper layer functions. PreParserFactory is
-// responsible for creating these dummy objects. It provides a similar kind of
-// interface as AstNodeFactory, so ParserBase doesn't need to care which one is
-// used.
-
-// - Miscellaneous other tasks interleaved with the recursive descent. For
-// example, Parser keeps track of which function literals should be marked as
-// pretenured, and PreParser doesn't care.
-
-// The traits are expected to contain the following typedefs:
+// The parser base object implements pure parsing, according to the
+// language grammar. Different parser implementations may exhibit
+// different parser-driven behavior that is not considered as pure
+// parsing, e.g., early error detection and reporting, AST generation, etc.
+
+// The ParserTypes structure encapsulates the differences in the
+// types used in parsing methods. E.g., Parser methods use Expression*
+// and PreParser methods use PreParserExpression. For any given parser
+// implementation class Impl, it is expected to contain the following typedefs:
+//
// template <>
-// class ParserBaseTraits<Impl> {
-// // In particular...
-// struct Type {
-// typedef GeneratorVariable;
-// typedef AstProperties;
-// typedef ExpressionClassifier;
-// // Return types for traversing functions.
-// typedef Identifier;
-// typedef Expression;
-// typedef YieldExpression;
-// typedef FunctionLiteral;
-// typedef ClassLiteral;
-// typedef Literal;
-// typedef ObjectLiteralProperty;
-// typedef ExpressionList;
-// typedef PropertyList;
-// typedef FormalParameter;
-// typedef FormalParameters;
-// typedef StatementList;
-// // For constructing objects returned by the traversing functions.
-// typedef Factory;
-// };
-// // ...
+// struct ParserTypes<Impl> {
+// // Synonyms for ParserBase<Impl> and Impl, respectively.
+// typedef Base;
+// typedef Impl;
+// // TODO(nikolaos): this one will probably go away, as it is
+// // not related to pure parsing.
+// typedef Variable;
+// // Return types for traversing functions.
+// typedef Identifier;
+// typedef Expression;
+// typedef FunctionLiteral;
+// typedef ObjectLiteralProperty;
+// typedef ClassLiteralProperty;
+// typedef ExpressionList;
+// typedef ObjectPropertyList;
+// typedef ClassPropertyList;
+// typedef FormalParameters;
+// typedef Statement;
+// typedef StatementList;
+// typedef Block;
+// typedef BreakableStatement;
+// typedef IterationStatement;
+// // For constructing objects returned by the traversing functions.
+// typedef Factory;
+// // For other implementation-specific tasks.
+// typedef Target;
+// typedef TargetScope;
// };
template <typename Impl>
-class ParserBaseTraits;
+struct ParserTypes;
template <typename Impl>
-class ParserBase : public ParserBaseTraits<Impl> {
+class ParserBase {
public:
- // Shorten type names defined by Traits.
- typedef ParserBaseTraits<Impl> Traits;
- typedef typename Traits::Type::Expression ExpressionT;
- typedef typename Traits::Type::Identifier IdentifierT;
- typedef typename Traits::Type::FormalParameter FormalParameterT;
- typedef typename Traits::Type::FormalParameters FormalParametersT;
- typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
- typedef typename Traits::Type::Literal LiteralT;
- typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
- typedef typename Traits::Type::StatementList StatementListT;
- typedef typename Traits::Type::ExpressionClassifier ExpressionClassifier;
+ // 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 Types::ClassLiteralProperty ClassLiteralPropertyT;
+ typedef typename Types::ExpressionList ExpressionListT;
+ typedef typename Types::FormalParameters FormalParametersT;
+ typedef typename Types::Statement StatementT;
+ typedef typename Types::StatementList StatementListT;
+ typedef typename Types::Block BlockT;
+ typedef typename v8::internal::ExpressionClassifier<Types>
+ ExpressionClassifier;
// All implementation-specific methods must be called through this.
Impl* impl() { return static_cast<Impl*>(this); }
@@ -246,6 +187,7 @@ class ParserBase : public ParserBaseTraits<Impl> {
parsing_module_(false),
stack_limit_(stack_limit),
zone_(zone),
+ classifier_(nullptr),
scanner_(scanner),
stack_overflow_(false),
allow_lazy_(false),
@@ -257,7 +199,8 @@ class ParserBase : public ParserBaseTraits<Impl> {
allow_harmony_function_sent_(false),
allow_harmony_async_await_(false),
allow_harmony_restrictive_generators_(false),
- allow_harmony_trailing_commas_(false) {}
+ allow_harmony_trailing_commas_(false),
+ allow_harmony_class_fields_(false) {}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
@@ -273,6 +216,7 @@ class ParserBase : public ParserBaseTraits<Impl> {
ALLOW_ACCESSORS(harmony_async_await);
ALLOW_ACCESSORS(harmony_restrictive_generators);
ALLOW_ACCESSORS(harmony_trailing_commas);
+ ALLOW_ACCESSORS(harmony_class_fields);
#undef ALLOW_ACCESSORS
@@ -280,7 +224,12 @@ class ParserBase : public ParserBaseTraits<Impl> {
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
+ Zone* zone() const { return zone_; }
+
protected:
+ friend class v8::internal::ExpressionClassifier<ParserTypes<Impl>>;
+
+ // clang-format off
enum AllowRestrictedIdentifiers {
kAllowRestrictedIdentifiers,
kDontAllowRestrictedIdentifiers
@@ -291,14 +240,26 @@ class ParserBase : public ParserBaseTraits<Impl> {
PARSE_EAGERLY
};
+ enum LazyParsingResult {
+ kLazyParsingComplete,
+ kLazyParsingAborted
+ };
+
enum VariableDeclarationContext {
kStatementListItem,
kStatement,
kForStatement
};
+ enum class FunctionBodyType {
+ kNormal,
+ kSingleExpression
+ };
+ // clang-format on
+
class Checkpoint;
- class ObjectLiteralCheckerBase;
+ class ClassLiteralChecker;
+ class ObjectLiteralChecker;
// ---------------------------------------------------------------------------
// ScopeState and its subclasses implement the parser's scope stack.
@@ -333,8 +294,8 @@ class ParserBase : public ParserBaseTraits<Impl> {
// allocation.
// TODO(verwaest): Move to LazyBlockState class that only allocates the
// scope when needed.
- explicit BlockState(ScopeState** scope_stack)
- : ScopeState(scope_stack, NewScope(*scope_stack)) {}
+ explicit BlockState(Zone* zone, ScopeState** scope_stack)
+ : ScopeState(scope_stack, NewScope(zone, *scope_stack)) {}
void SetNonlinear() { this->scope()->SetNonlinear(); }
void set_start_position(int pos) { this->scope()->set_start_position(pos); }
@@ -348,9 +309,8 @@ class ParserBase : public ParserBaseTraits<Impl> {
}
private:
- Scope* NewScope(ScopeState* outer_state) {
+ Scope* NewScope(Zone* zone, ScopeState* outer_state) {
Scope* parent = outer_state->scope();
- Zone* zone = outer_state->zone();
return new (zone) Scope(zone, parent, BLOCK_SCOPE);
}
};
@@ -384,14 +344,6 @@ class ParserBase : public ParserBaseTraits<Impl> {
expressions_.Add(expr, zone_);
}
- void AddExplicitTailCall(ExpressionT expr, const Scanner::Location& loc) {
- if (!has_explicit_tail_calls()) {
- loc_ = loc;
- has_explicit_tail_calls_ = true;
- }
- expressions_.Add(expr, zone_);
- }
-
void Append(const TailCallExpressionList& other) {
if (!has_explicit_tail_calls()) {
loc_ = other.loc_;
@@ -425,9 +377,13 @@ class ParserBase : public ParserBaseTraits<Impl> {
class FunctionState final : public ScopeState {
public:
FunctionState(FunctionState** function_state_stack,
- ScopeState** scope_stack, Scope* scope, FunctionKind kind);
+ ScopeState** scope_stack, DeclarationScope* scope);
~FunctionState();
+ DeclarationScope* scope() const {
+ return ScopeState::scope()->AsDeclarationScope();
+ }
+
int NextMaterializedLiteralIndex() {
return next_materialized_literal_index_++;
}
@@ -442,24 +398,27 @@ class ParserBase : public ParserBaseTraits<Impl> {
void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; }
- bool is_generator() const { return IsGeneratorFunction(kind_); }
- bool is_async_function() const { return IsAsyncFunction(kind_); }
- bool is_resumable() const { return is_generator() || is_async_function(); }
-
- FunctionKind kind() const { return kind_; }
+ FunctionKind kind() const { return scope()->function_kind(); }
FunctionState* outer() const { return outer_function_state_; }
- void set_generator_object_variable(
- typename Traits::Type::GeneratorVariable* variable) {
+ void set_generator_object_variable(typename Types::Variable* variable) {
DCHECK(variable != NULL);
- DCHECK(is_resumable());
+ DCHECK(IsResumableFunction(kind()));
generator_object_variable_ = variable;
}
- typename Traits::Type::GeneratorVariable* generator_object_variable()
- const {
+ typename Types::Variable* generator_object_variable() const {
return generator_object_variable_;
}
+ void set_promise_variable(typename Types::Variable* variable) {
+ DCHECK(variable != NULL);
+ DCHECK(IsAsyncFunction(kind()));
+ promise_variable_ = variable;
+ }
+ typename Types::Variable* promise_variable() const {
+ return promise_variable_;
+ }
+
const ZoneList<DestructuringAssignment>&
destructuring_assignments_to_rewrite() const {
return destructuring_assignments_to_rewrite_;
@@ -474,14 +433,6 @@ class ParserBase : public ParserBaseTraits<Impl> {
tail_call_expressions_.AddImplicitTailCall(expression);
}
}
- void AddExplicitTailCallExpression(ExpressionT expression,
- const Scanner::Location& loc) {
- DCHECK(expression->IsCall());
- if (return_expr_context() ==
- ReturnExprContext::kInsideValidReturnStatement) {
- tail_call_expressions_.AddExplicitTailCall(expression, loc);
- }
- }
ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() {
return &reported_errors_;
@@ -530,11 +481,13 @@ class ParserBase : public ParserBaseTraits<Impl> {
// Properties count estimation.
int expected_property_count_;
- FunctionKind kind_;
// For generators, this variable may hold the generator object. It variable
// is used by yield expressions and return statements. It is not necessary
// for generator functions to have this variable set.
Variable* generator_object_variable_;
+ // For async functions, this variable holds a temporary for the Promise
+ // being created as output of the async function.
+ Variable* promise_variable_;
FunctionState** function_state_stack_;
FunctionState* outer_function_state_;
@@ -644,8 +597,97 @@ class ParserBase : public ParserBaseTraits<Impl> {
Mode old_mode_;
};
+ struct DeclarationDescriptor {
+ enum Kind { NORMAL, PARAMETER };
+ Scope* scope;
+ Scope* hoist_scope;
+ VariableMode mode;
+ int declaration_pos;
+ int initialization_pos;
+ Kind declaration_kind;
+ };
+
+ struct DeclarationParsingResult {
+ struct Declaration {
+ Declaration(ExpressionT pattern, int initializer_position,
+ ExpressionT initializer)
+ : pattern(pattern),
+ initializer_position(initializer_position),
+ initializer(initializer) {}
+
+ ExpressionT pattern;
+ int initializer_position;
+ ExpressionT initializer;
+ };
+
+ DeclarationParsingResult()
+ : declarations(4),
+ first_initializer_loc(Scanner::Location::invalid()),
+ bindings_loc(Scanner::Location::invalid()) {}
+
+ DeclarationDescriptor descriptor;
+ List<Declaration> declarations;
+ Scanner::Location first_initializer_loc;
+ Scanner::Location bindings_loc;
+ };
+
+ struct CatchInfo {
+ public:
+ explicit CatchInfo(ParserBase* parser)
+ : name(parser->impl()->EmptyIdentifier()),
+ variable(nullptr),
+ pattern(parser->impl()->EmptyExpression()),
+ scope(nullptr),
+ init_block(parser->impl()->NullBlock()),
+ inner_block(parser->impl()->NullBlock()),
+ for_promise_reject(false),
+ bound_names(1, parser->zone()),
+ tail_call_expressions(parser->zone()) {}
+ IdentifierT name;
+ Variable* variable;
+ ExpressionT pattern;
+ Scope* scope;
+ BlockT init_block;
+ BlockT inner_block;
+ bool for_promise_reject;
+ ZoneList<const AstRawString*> bound_names;
+ TailCallExpressionList tail_call_expressions;
+ };
+
+ struct ForInfo {
+ public:
+ explicit ForInfo(ParserBase* parser)
+ : bound_names(1, parser->zone()),
+ mode(ForEachStatement::ENUMERATE),
+ each_loc(),
+ parsing_result() {}
+ ZoneList<const AstRawString*> bound_names;
+ ForEachStatement::VisitMode mode;
+ Scanner::Location each_loc;
+ DeclarationParsingResult parsing_result;
+ };
+
+ struct ClassInfo {
+ public:
+ explicit ClassInfo(ParserBase* parser)
+ : proxy(nullptr),
+ extends(parser->impl()->EmptyExpression()),
+ properties(parser->impl()->NewClassPropertyList(4)),
+ instance_field_initializers(parser->impl()->NewExpressionList(0)),
+ constructor(parser->impl()->EmptyFunctionLiteral()),
+ has_seen_constructor(false),
+ static_initializer_var(nullptr) {}
+ VariableProxy* proxy;
+ ExpressionT extends;
+ typename Types::ClassPropertyList properties;
+ ExpressionListT instance_field_initializers;
+ FunctionLiteralT constructor;
+ bool has_seen_constructor;
+ Variable* static_initializer_var;
+ };
+
DeclarationScope* NewScriptScope() const {
- return new (zone()) DeclarationScope(zone());
+ return new (zone()) DeclarationScope(zone(), ast_value_factory());
}
DeclarationScope* NewVarblockScope() const {
@@ -653,7 +695,7 @@ class ParserBase : public ParserBaseTraits<Impl> {
}
ModuleScope* NewModuleScope(DeclarationScope* parent) const {
- return new (zone()) ModuleScope(zone(), parent, ast_value_factory());
+ return new (zone()) ModuleScope(parent, ast_value_factory());
}
DeclarationScope* NewEvalScope(Scope* parent) const {
@@ -683,12 +725,18 @@ class ParserBase : public ParserBaseTraits<Impl> {
new (zone()) DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind);
// TODO(verwaest): Move into the DeclarationScope constructor.
if (!IsArrowFunction(kind)) {
- result->DeclareThis(ast_value_factory());
result->DeclareDefaultFunctionVariables(ast_value_factory());
}
return result;
}
+ V8_INLINE DeclarationScope* GetDeclarationScope() const {
+ return scope()->GetDeclarationScope();
+ }
+ V8_INLINE DeclarationScope* GetClosureScope() const {
+ return scope()->GetClosureScope();
+ }
+
Scanner* scanner() const { return scanner_; }
AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
int position() const { return scanner_->location().beg_pos; }
@@ -696,7 +744,6 @@ class ParserBase : public ParserBaseTraits<Impl> {
bool stack_overflow() const { return stack_overflow_; }
void set_stack_overflow() { stack_overflow_ = true; }
Mode mode() const { return mode_; }
- Zone* zone() const { return zone_; }
INLINE(Token::Value peek()) {
if (stack_overflow_) return Token::ILLEGAL;
@@ -761,8 +808,12 @@ class ParserBase : public ParserBaseTraits<Impl> {
Expect(Token::SEMICOLON, ok);
}
- // A dummy function, just useful as an argument to CHECK_OK_CUSTOM.
+ // Dummy functions, just useful as arguments to CHECK_OK_CUSTOM.
static void Void() {}
+ template <typename T>
+ static T Return(T result) {
+ return result;
+ }
bool is_any_identifier(Token::Value token) {
return token == Token::IDENTIFIER || token == Token::ENUM ||
@@ -796,7 +847,7 @@ class ParserBase : public ParserBaseTraits<Impl> {
}
}
- bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode, bool* ok) {
+ bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode) {
if (Check(Token::IN)) {
*visit_mode = ForEachStatement::ENUMERATE;
return true;
@@ -818,21 +869,19 @@ class ParserBase : public ParserBaseTraits<Impl> {
Scanner::Location octal = scanner()->octal_position();
if (octal.IsValid() && beg_pos <= octal.beg_pos &&
octal.end_pos <= end_pos) {
- ReportMessageAt(octal, message);
+ impl()->ReportMessageAt(octal, message);
scanner()->clear_octal_position();
*ok = false;
}
}
// for now, this check just collects statistics.
- void CheckDecimalLiteralWithLeadingZero(int* use_counts, int beg_pos,
- int end_pos) {
+ void CheckDecimalLiteralWithLeadingZero(int beg_pos, int end_pos) {
Scanner::Location token_location =
scanner()->decimal_with_leading_zero_position();
if (token_location.IsValid() && beg_pos <= token_location.beg_pos &&
token_location.end_pos <= end_pos) {
scanner()->clear_decimal_with_leading_zero_position();
- if (use_counts != nullptr)
- ++use_counts[v8::Isolate::kDecimalWithLeadingZeroInStrictMode];
+ impl()->CountUsage(v8::Isolate::kDecimalWithLeadingZeroInStrictMode);
}
}
@@ -846,9 +895,7 @@ class ParserBase : public ParserBaseTraits<Impl> {
ok);
}
- void CheckDestructuringElement(ExpressionT element,
- ExpressionClassifier* classifier, int beg_pos,
- int end_pos);
+ void CheckDestructuringElement(ExpressionT element, int beg_pos, int end_pos);
// Checking the name of a function literal. This has to be done after parsing
// the function, since the function can declare itself strict.
@@ -859,14 +906,14 @@ class ParserBase : public ParserBaseTraits<Impl> {
// The function name needs to be checked in strict mode.
if (is_sloppy(language_mode)) return;
- if (this->IsEvalOrArguments(function_name)) {
- Traits::ReportMessageAt(function_name_loc,
+ if (impl()->IsEvalOrArguments(function_name)) {
+ impl()->ReportMessageAt(function_name_loc,
MessageTemplate::kStrictEvalArguments);
*ok = false;
return;
}
if (function_name_validity == kFunctionNameIsStrictReserved) {
- Traits::ReportMessageAt(function_name_loc,
+ impl()->ReportMessageAt(function_name_loc,
MessageTemplate::kUnexpectedStrictReserved);
*ok = false;
return;
@@ -880,50 +927,45 @@ class ParserBase : public ParserBaseTraits<Impl> {
return Token::Precedence(token);
}
- typename Traits::Type::Factory* factory() { return &ast_node_factory_; }
+ typename Types::Factory* factory() { return &ast_node_factory_; }
DeclarationScope* GetReceiverScope() const {
return scope()->GetReceiverScope();
}
LanguageMode language_mode() { return scope()->language_mode(); }
- bool is_generator() const { return function_state_->is_generator(); }
+ void RaiseLanguageMode(LanguageMode mode) {
+ LanguageMode old = scope()->language_mode();
+ impl()->SetLanguageMode(scope(), old > mode ? old : mode);
+ }
+ bool is_generator() const {
+ return IsGeneratorFunction(function_state_->kind());
+ }
bool is_async_function() const {
- return function_state_->is_async_function();
+ return IsAsyncFunction(function_state_->kind());
+ }
+ bool is_resumable() const {
+ return IsResumableFunction(function_state_->kind());
}
- bool is_resumable() const { return function_state_->is_resumable(); }
// Report syntax errors.
- void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
- ParseErrorType error_type = kSyntaxError) {
+ void ReportMessage(MessageTemplate::Template message) {
Scanner::Location source_location = scanner()->location();
- Traits::ReportMessageAt(source_location, message, arg, error_type);
+ impl()->ReportMessageAt(source_location, message,
+ static_cast<const char*>(nullptr), kSyntaxError);
}
- void ReportMessage(MessageTemplate::Template message, const AstRawString* arg,
+ template <typename T>
+ void ReportMessage(MessageTemplate::Template message, T arg,
ParseErrorType error_type = kSyntaxError) {
Scanner::Location source_location = scanner()->location();
- Traits::ReportMessageAt(source_location, message, arg, error_type);
- }
-
- void ReportMessageAt(Scanner::Location location,
- MessageTemplate::Template message,
- const char* arg = NULL,
- ParseErrorType error_type = kSyntaxError) {
- Traits::ReportMessageAt(location, message, arg, error_type);
- }
-
- void ReportMessageAt(Scanner::Location location,
- MessageTemplate::Template message,
- const AstRawString* arg,
- ParseErrorType error_type = kSyntaxError) {
- Traits::ReportMessageAt(location, message, arg, error_type);
+ impl()->ReportMessageAt(source_location, message, arg, error_type);
}
void ReportMessageAt(Scanner::Location location,
MessageTemplate::Template message,
ParseErrorType error_type) {
- ReportMessageAt(location, message, static_cast<const char*>(nullptr),
- error_type);
+ impl()->ReportMessageAt(location, message,
+ static_cast<const char*>(nullptr), error_type);
}
void GetUnexpectedTokenMessage(
@@ -938,59 +980,47 @@ class ParserBase : public ParserBaseTraits<Impl> {
void ReportClassifierError(
const typename ExpressionClassifier::Error& error) {
- Traits::ReportMessageAt(error.location, error.message, error.arg,
+ impl()->ReportMessageAt(error.location, error.message, error.arg,
error.type);
}
- void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) {
- if (!classifier->is_valid_expression() ||
- classifier->has_object_literal_error()) {
- const Scanner::Location& a = classifier->expression_error().location;
- const Scanner::Location& b =
- classifier->object_literal_error().location;
- if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) {
- ReportClassifierError(classifier->object_literal_error());
- } else {
- ReportClassifierError(classifier->expression_error());
- }
+ void ValidateExpression(bool* ok) {
+ if (!classifier()->is_valid_expression()) {
+ ReportClassifierError(classifier()->expression_error());
*ok = false;
}
}
- void ValidateFormalParameterInitializer(
- const ExpressionClassifier* classifier, bool* ok) {
- if (!classifier->is_valid_formal_parameter_initializer()) {
- ReportClassifierError(classifier->formal_parameter_initializer_error());
+ void ValidateFormalParameterInitializer(bool* ok) {
+ if (!classifier()->is_valid_formal_parameter_initializer()) {
+ ReportClassifierError(classifier()->formal_parameter_initializer_error());
*ok = false;
}
}
- void ValidateBindingPattern(const ExpressionClassifier* classifier,
- bool* ok) {
- if (!classifier->is_valid_binding_pattern()) {
- ReportClassifierError(classifier->binding_pattern_error());
+ void ValidateBindingPattern(bool* ok) {
+ if (!classifier()->is_valid_binding_pattern()) {
+ ReportClassifierError(classifier()->binding_pattern_error());
*ok = false;
}
}
- void ValidateAssignmentPattern(const ExpressionClassifier* classifier,
- bool* ok) {
- if (!classifier->is_valid_assignment_pattern()) {
- ReportClassifierError(classifier->assignment_pattern_error());
+ void ValidateAssignmentPattern(bool* ok) {
+ if (!classifier()->is_valid_assignment_pattern()) {
+ ReportClassifierError(classifier()->assignment_pattern_error());
*ok = false;
}
}
- void ValidateFormalParameters(const ExpressionClassifier* classifier,
- LanguageMode language_mode,
+ 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());
+ !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());
+ !classifier()->is_valid_strict_mode_formal_parameters()) {
+ ReportClassifierError(classifier()->strict_mode_formal_parameter_error());
*ok = false;
}
}
@@ -999,78 +1029,73 @@ class ParserBase : public ParserBaseTraits<Impl> {
return is_any_identifier(token) || token == Token::LPAREN;
}
- void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
- ExpressionT expr,
+ void ValidateArrowFormalParameters(ExpressionT expr,
bool parenthesized_formals, bool is_async,
bool* ok) {
- if (classifier->is_valid_binding_pattern()) {
+ if (classifier()->is_valid_binding_pattern()) {
// A simple arrow formal parameter: IDENTIFIER => BODY.
- if (!this->IsIdentifier(expr)) {
- Traits::ReportMessageAt(scanner()->location(),
+ 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()) {
+ } 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();
+ 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()) {
+ if (is_async && !classifier()->is_valid_async_arrow_formal_parameters()) {
const typename ExpressionClassifier::Error& error =
- classifier->async_arrow_formal_parameters_error();
+ classifier()->async_arrow_formal_parameters_error();
ReportClassifierError(error);
*ok = false;
}
}
- void ValidateLetPattern(const ExpressionClassifier* classifier, bool* ok) {
- if (!classifier->is_valid_let_pattern()) {
- ReportClassifierError(classifier->let_pattern_error());
- *ok = false;
- }
- }
-
- void CheckNoTailCallExpressions(const ExpressionClassifier* classifier,
- bool* ok) {
- if (FLAG_harmony_explicit_tailcalls &&
- classifier->has_tail_call_expression()) {
- ReportClassifierError(classifier->tail_call_expression_error());
+ void ValidateLetPattern(bool* ok) {
+ if (!classifier()->is_valid_let_pattern()) {
+ ReportClassifierError(classifier()->let_pattern_error());
*ok = false;
}
}
- void ExpressionUnexpectedToken(ExpressionClassifier* classifier) {
+ void ExpressionUnexpectedToken() {
MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
const char* arg;
Scanner::Location location = scanner()->peek_location();
GetUnexpectedTokenMessage(peek(), &message, &location, &arg);
- classifier->RecordExpressionError(location, message, arg);
+ classifier()->RecordExpressionError(location, message, arg);
}
- void BindingPatternUnexpectedToken(ExpressionClassifier* classifier) {
+ 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);
+ classifier()->RecordBindingPatternError(location, message, arg);
}
- void ArrowFormalParametersUnexpectedToken(ExpressionClassifier* classifier) {
+ 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);
+ classifier()->RecordArrowFormalParametersError(location, message, arg);
}
- // Recursive descent functions:
+ // 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
@@ -1078,8 +1103,7 @@ class ParserBase : public ParserBaseTraits<Impl> {
// "arguments" as identifier even in strict mode (this is needed in cases like
// "var foo = eval;").
IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok);
- IdentifierT ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
- bool* ok);
+ 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
@@ -1098,76 +1122,173 @@ class ParserBase : public ParserBaseTraits<Impl> {
ExpressionT ParseRegExpLiteral(bool* ok);
- ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
- bool* is_async, bool* ok);
- ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
- bool* ok) {
+ ExpressionT ParsePrimaryExpression(bool* is_async, bool* ok);
+ ExpressionT ParsePrimaryExpression(bool* ok) {
bool is_async;
- return ParsePrimaryExpression(classifier, &is_async, ok);
+ return ParsePrimaryExpression(&is_async, ok);
}
- ExpressionT ParseExpression(bool accept_IN, bool* ok);
- ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier,
- bool* ok);
- ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
- ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
- bool* is_computed_name,
- ExpressionClassifier* classifier, bool* ok);
- ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
- ObjectLiteralPropertyT ParsePropertyDefinition(
- ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
- MethodKind kind, bool* is_computed_name, bool* has_seen_constructor,
- ExpressionClassifier* classifier, IdentifierT* name, bool* ok);
- typename Traits::Type::ExpressionList ParseArguments(
- Scanner::Location* first_spread_pos, bool maybe_arrow,
- ExpressionClassifier* classifier, bool* ok);
- typename Traits::Type::ExpressionList ParseArguments(
- Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
- bool* ok) {
- return ParseArguments(first_spread_pos, false, classifier, ok);
- }
-
- ExpressionT ParseAssignmentExpression(bool accept_IN,
- ExpressionClassifier* classifier,
- bool* ok);
- ExpressionT ParseYieldExpression(bool accept_IN,
- ExpressionClassifier* classifier, bool* ok);
- ExpressionT ParseTailCallExpression(ExpressionClassifier* classifier,
- bool* ok);
- ExpressionT ParseConditionalExpression(bool accept_IN,
- ExpressionClassifier* classifier,
- bool* ok);
- ExpressionT ParseBinaryExpression(int prec, bool accept_IN,
- ExpressionClassifier* classifier, bool* ok);
- ExpressionT ParseUnaryExpression(ExpressionClassifier* classifier, bool* ok);
- ExpressionT ParsePostfixExpression(ExpressionClassifier* classifier,
- bool* ok);
- ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier,
- bool* ok);
- ExpressionT ParseMemberWithNewPrefixesExpression(
- ExpressionClassifier* classifier, bool* is_async, bool* ok);
- ExpressionT ParseMemberExpression(ExpressionClassifier* classifier,
- bool* is_async, bool* ok);
- ExpressionT ParseMemberExpressionContinuation(
- ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
- bool* ok);
+
+ // This method wraps the parsing of the expression inside a new expression
+ // classifier and calls RewriteNonPattern if parsing is successful.
+ // It should be used whenever we're parsing an expression that will be
+ // used as a non-pattern (i.e., in most cases).
+ V8_INLINE ExpressionT ParseExpression(bool accept_IN, 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
+ // "CoverParenthesizedExpressionAndArrowParameterList" in the ES 2017
+ // specification).
+ ExpressionT ParseExpressionCoverGrammar(bool accept_IN, bool* ok);
+
+ ExpressionT ParseArrayLiteral(bool* ok);
+
+ enum class PropertyKind {
+ kAccessorProperty,
+ kValueProperty,
+ kShorthandProperty,
+ kMethodProperty,
+ kClassField,
+ kNotSet
+ };
+
+ bool SetPropertyKindFromToken(Token::Value token, PropertyKind* kind);
+ ExpressionT ParsePropertyName(IdentifierT* name, PropertyKind* kind,
+ bool* is_generator, bool* is_get, bool* is_set,
+ bool* is_async, bool* is_computed_name,
+ bool* ok);
+ ExpressionT ParseObjectLiteral(bool* ok);
+ ClassLiteralPropertyT ParseClassPropertyDefinition(
+ ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name,
+ bool* has_seen_constructor, bool* ok);
+ FunctionLiteralT ParseClassFieldForInitializer(bool has_initializer,
+ bool* ok);
+ ObjectLiteralPropertyT ParseObjectPropertyDefinition(
+ ObjectLiteralChecker* checker, bool* is_computed_name, bool* ok);
+ ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
+ bool maybe_arrow, bool* ok);
+ ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
+ bool* ok) {
+ return ParseArguments(first_spread_pos, false, ok);
+ }
+
+ ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
+ ExpressionT ParseYieldExpression(bool accept_IN, bool* ok);
+ ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok);
+ ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
+ ExpressionT ParseUnaryExpression(bool* ok);
+ ExpressionT ParsePostfixExpression(bool* ok);
+ ExpressionT ParseLeftHandSideExpression(bool* ok);
+ ExpressionT ParseMemberWithNewPrefixesExpression(bool* is_async, bool* ok);
+ ExpressionT ParseMemberExpression(bool* is_async, bool* ok);
+ ExpressionT ParseMemberExpressionContinuation(ExpressionT expression,
+ bool* is_async, bool* ok);
ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
const FormalParametersT& parameters,
- bool is_async,
- const ExpressionClassifier& classifier,
bool* ok);
- ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
- ExpressionClassifier* classifier, bool* ok);
+ void ParseAsyncFunctionBody(Scope* scope, StatementListT body,
+ FunctionKind kind, FunctionBodyType type,
+ bool accept_IN, int pos, bool* ok);
+ ExpressionT ParseAsyncFunctionLiteral(bool* ok);
+ 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* ok);
ExpressionT ParseSuperExpression(bool is_new, bool* ok);
ExpressionT ParseNewTargetExpression(bool* ok);
- void ParseFormalParameter(FormalParametersT* parameters,
- ExpressionClassifier* classifier, bool* ok);
- void ParseFormalParameterList(FormalParametersT* parameters,
- ExpressionClassifier* classifier, bool* ok);
+ void ParseFormalParameter(FormalParametersT* parameters, bool* ok);
+ void ParseFormalParameterList(FormalParametersT* parameters, bool* ok);
void CheckArityRestrictions(int param_count, FunctionKind function_type,
bool has_rest, int formals_start_pos,
int formals_end_pos, bool* ok);
+ BlockT ParseVariableDeclarations(VariableDeclarationContext var_context,
+ DeclarationParsingResult* parsing_result,
+ ZoneList<const AstRawString*>* names,
+ bool* ok);
+ StatementT ParseAsyncFunctionDeclaration(ZoneList<const AstRawString*>* names,
+ bool default_export, bool* ok);
+ StatementT ParseFunctionDeclaration(bool* ok);
+ StatementT ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
+ bool default_export, bool* ok);
+ StatementT ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
+ ZoneList<const AstRawString*>* names,
+ bool default_export, bool* ok);
+ StatementT ParseClassDeclaration(ZoneList<const AstRawString*>* names,
+ bool default_export, bool* ok);
+ StatementT ParseNativeDeclaration(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;
+
+ // 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, int end_token,
+ bool* ok) {
+ LazyParsingResult result = ParseStatementList(body, end_token, false, ok);
+ USE(result);
+ DCHECK_EQ(result, kLazyParsingComplete);
+ }
+ LazyParsingResult ParseStatementList(StatementListT body, int end_token,
+ bool may_abort, bool* ok);
+ StatementT ParseStatementListItem(bool* ok);
+ StatementT ParseStatement(ZoneList<const AstRawString*>* labels,
+ AllowLabelledFunctionStatement allow_function,
+ bool* ok);
+ StatementT ParseStatementAsUnlabelled(ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ BlockT ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok);
+
+ // Parse a SubStatement in strict mode, or with an extra block scope in
+ // sloppy mode to handle
+ // ES#sec-functiondeclarations-in-ifstatement-statement-clauses
+ // The legacy parameter indicates whether function declarations are
+ // banned by the ES2015 specification in this location, and they are being
+ // permitted here to match previous V8 behavior.
+ StatementT ParseScopedStatement(ZoneList<const AstRawString*>* labels,
+ bool legacy, bool* ok);
+
+ StatementT ParseVariableStatement(VariableDeclarationContext var_context,
+ ZoneList<const AstRawString*>* names,
+ bool* ok);
+
+ // Magical syntax support.
+ ExpressionT ParseV8Intrinsic(bool* ok);
+
+ ExpressionT ParseDoExpression(bool* ok);
+
+ StatementT ParseDebuggerStatement(bool* ok);
+
+ StatementT ParseExpressionOrLabelledStatement(
+ ZoneList<const AstRawString*>* labels,
+ AllowLabelledFunctionStatement allow_function, bool* ok);
+ StatementT ParseIfStatement(ZoneList<const AstRawString*>* labels, bool* ok);
+ StatementT ParseContinueStatement(bool* ok);
+ StatementT ParseBreakStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ StatementT ParseReturnStatement(bool* ok);
+ StatementT ParseWithStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ StatementT ParseDoWhileStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ StatementT ParseWhileStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ StatementT ParseThrowStatement(bool* ok);
+ StatementT ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ StatementT ParseTryStatement(bool* ok);
+ StatementT ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
+
bool IsNextLetKeyword();
bool IsTrivialExpression();
@@ -1184,9 +1305,9 @@ class ParserBase : public ParserBaseTraits<Impl> {
bool IsValidReferenceExpression(ExpressionT expression);
bool IsAssignableIdentifier(ExpressionT expression) {
- if (!Traits::IsIdentifier(expression)) return false;
+ if (!impl()->IsIdentifier(expression)) return false;
if (is_strict(language_mode()) &&
- Traits::IsEvalOrArguments(Traits::AsIdentifier(expression))) {
+ impl()->IsEvalOrArguments(impl()->AsIdentifier(expression))) {
return false;
}
return true;
@@ -1201,8 +1322,8 @@ class ParserBase : public ParserBaseTraits<Impl> {
// forwards the information to scope.
Call::PossiblyEval CheckPossibleEvalCall(ExpressionT expression,
Scope* scope) {
- if (Traits::IsIdentifier(expression) &&
- Traits::IsEval(Traits::AsIdentifier(expression))) {
+ if (impl()->IsIdentifier(expression) &&
+ impl()->IsEval(impl()->AsIdentifier(expression))) {
scope->RecordEvalCall();
if (is_sloppy(scope->language_mode())) {
// For sloppy scopes we also have to record the call at function level,
@@ -1214,56 +1335,33 @@ class ParserBase : public ParserBaseTraits<Impl> {
return Call::NOT_EVAL;
}
- // Used to validate property names in object literals and class literals
- enum PropertyKind {
- kAccessorProperty,
- kValueProperty,
- kMethodProperty
- };
-
- class ObjectLiteralCheckerBase {
- public:
- explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
-
- virtual void CheckProperty(Token::Value property, PropertyKind type,
- MethodKind method_type,
- ExpressionClassifier* classifier, bool* ok) = 0;
-
- virtual ~ObjectLiteralCheckerBase() {}
-
- protected:
- ParserBase* parser() const { return parser_; }
- Scanner* scanner() const { return parser_->scanner(); }
-
- private:
- ParserBase* parser_;
- };
-
// Validation per ES6 object literals.
- class ObjectLiteralChecker : public ObjectLiteralCheckerBase {
+ class ObjectLiteralChecker {
public:
explicit ObjectLiteralChecker(ParserBase* parser)
- : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
+ : parser_(parser), has_seen_proto_(false) {}
- void CheckProperty(Token::Value property, PropertyKind type,
- MethodKind method_type, ExpressionClassifier* classifier,
- bool* ok) override;
+ void CheckDuplicateProto(Token::Value property);
private:
bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
+ ParserBase* parser() const { return parser_; }
+ Scanner* scanner() const { return parser_->scanner(); }
+
+ ParserBase* parser_;
bool has_seen_proto_;
};
// Validation per ES6 class literals.
- class ClassLiteralChecker : public ObjectLiteralCheckerBase {
+ class ClassLiteralChecker {
public:
explicit ClassLiteralChecker(ParserBase* parser)
- : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
+ : parser_(parser), has_seen_constructor_(false) {}
- void CheckProperty(Token::Value property, PropertyKind type,
- MethodKind method_type, ExpressionClassifier* classifier,
- bool* ok) override;
+ void CheckClassMethodName(Token::Value property, PropertyKind type,
+ bool is_generator, bool is_async, bool is_static,
+ bool* ok);
private:
bool IsConstructor() {
@@ -1273,6 +1371,10 @@ class ParserBase : public ParserBaseTraits<Impl> {
return this->scanner()->LiteralMatches("prototype", 9);
}
+ ParserBase* parser() const { return parser_; }
+ Scanner* scanner() const { return parser_->scanner(); }
+
+ ParserBase* parser_;
bool has_seen_constructor_;
};
@@ -1281,19 +1383,63 @@ class ParserBase : public ParserBaseTraits<Impl> {
}
Scope* scope() const { return scope_state_->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,
+ bool merge_non_patterns = true) {
+ DCHECK_NOT_NULL(classifier_);
+ ExpressionClassifier* previous = classifier_->previous();
+ DCHECK_NOT_NULL(previous);
+ previous->Accumulate(classifier_, productions, merge_non_patterns);
+ classifier_ = previous;
+ }
+
+ // Pops and discards the classifier that is on top of the stack
+ // without accumulating.
+ V8_INLINE void Discard() {
+ DCHECK_NOT_NULL(classifier_);
+ classifier_->Discard();
+ classifier_ = classifier_->previous();
+ }
+
+ // 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);
+ }
+
+ // Parser base's protected field members.
+
ScopeState* scope_state_; // Scope stack.
FunctionState* function_state_; // Function state stack.
v8::Extension* extension_;
FuncNameInferrer* fni_;
AstValueFactory* ast_value_factory_; // Not owned.
- typename Traits::Type::Factory ast_node_factory_;
+ typename Types::Factory ast_node_factory_;
ParserRecorder* log_;
Mode mode_;
bool parsing_module_;
uintptr_t stack_limit_;
+ // Parser base's private field members.
+
private:
Zone* zone_;
+ ExpressionClassifier* classifier_;
Scanner* scanner_;
bool stack_overflow_;
@@ -1308,6 +1454,7 @@ class ParserBase : public ParserBaseTraits<Impl> {
bool allow_harmony_async_await_;
bool allow_harmony_restrictive_generators_;
bool allow_harmony_trailing_commas_;
+ bool allow_harmony_class_fields_;
friend class DiscardableZoneScope;
};
@@ -1315,12 +1462,12 @@ class ParserBase : public ParserBaseTraits<Impl> {
template <typename Impl>
ParserBase<Impl>::FunctionState::FunctionState(
FunctionState** function_state_stack, ScopeState** scope_stack,
- Scope* scope, FunctionKind kind)
+ DeclarationScope* scope)
: ScopeState(scope_stack, scope),
next_materialized_literal_index_(0),
expected_property_count_(0),
- kind_(kind),
- generator_object_variable_(NULL),
+ generator_object_variable_(nullptr),
+ promise_variable_(nullptr),
function_state_stack_(function_state_stack),
outer_function_state_(*function_state_stack),
destructuring_assignments_to_rewrite_(16, scope->zone()),
@@ -1413,19 +1560,18 @@ void ParserBase<Impl>::ReportUnexpectedTokenAt(
MessageTemplate::Template message) {
const char* arg;
GetUnexpectedTokenMessage(token, &message, &source_location, &arg);
- Traits::ReportMessageAt(source_location, message, 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(&classifier, CHECK_OK_CUSTOM(EmptyIdentifier));
+ auto result = ParseAndClassifyIdentifier(CHECK_OK_CUSTOM(EmptyIdentifier));
if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) {
- ValidateAssignmentPattern(&classifier, CHECK_OK_CUSTOM(EmptyIdentifier));
- ValidateBindingPattern(&classifier, CHECK_OK_CUSTOM(EmptyIdentifier));
+ ValidateAssignmentPattern(CHECK_OK_CUSTOM(EmptyIdentifier));
+ ValidateBindingPattern(CHECK_OK_CUSTOM(EmptyIdentifier));
}
return result;
@@ -1433,33 +1579,32 @@ typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier(
template <typename Impl>
typename ParserBase<Impl>::IdentifierT
-ParserBase<Impl>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
- bool* ok) {
+ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
Token::Value next = Next();
if (next == Token::IDENTIFIER || next == Token::ASYNC ||
(next == Token::AWAIT && !parsing_module_ && !is_async_function())) {
- IdentifierT name = this->GetSymbol(scanner());
+ 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 (this->IsEvalOrArguments(name)) {
- classifier->RecordStrictModeFormalParameterError(
+ if (impl()->IsEvalOrArguments(name)) {
+ classifier()->RecordStrictModeFormalParameterError(
scanner()->location(), MessageTemplate::kStrictEvalArguments);
if (is_strict(language_mode())) {
- classifier->RecordBindingPatternError(
+ classifier()->RecordBindingPatternError(
scanner()->location(), MessageTemplate::kStrictEvalArguments);
}
} else if (next == Token::AWAIT) {
- classifier->RecordAsyncArrowFormalParametersError(
+ classifier()->RecordAsyncArrowFormalParametersError(
scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
}
- if (classifier->duplicate_finder() != nullptr &&
- scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
- classifier->RecordDuplicateFormalParameterError(scanner()->location());
+ if (classifier()->duplicate_finder() != nullptr &&
+ scanner()->FindSymbol(classifier()->duplicate_finder(), 1) != 0) {
+ classifier()->RecordDuplicateFormalParameterError(scanner()->location());
}
return name;
} else if (is_sloppy(language_mode()) &&
@@ -1467,25 +1612,25 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
next == Token::ESCAPED_STRICT_RESERVED_WORD ||
next == Token::LET || next == Token::STATIC ||
(next == Token::YIELD && !is_generator()))) {
- classifier->RecordStrictModeFormalParameterError(
+ classifier()->RecordStrictModeFormalParameterError(
scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
if (next == Token::ESCAPED_STRICT_RESERVED_WORD &&
is_strict(language_mode())) {
ReportUnexpectedToken(next);
*ok = false;
- return Traits::EmptyIdentifier();
+ return impl()->EmptyIdentifier();
}
if (next == Token::LET ||
(next == Token::ESCAPED_STRICT_RESERVED_WORD &&
scanner()->is_literal_contextual_keyword(CStrVector("let")))) {
- classifier->RecordLetPatternError(scanner()->location(),
- MessageTemplate::kLetInLexicalBinding);
+ classifier()->RecordLetPatternError(
+ scanner()->location(), MessageTemplate::kLetInLexicalBinding);
}
- return this->GetSymbol(scanner());
+ return impl()->GetSymbol();
} else {
- this->ReportUnexpectedToken(next);
+ ReportUnexpectedToken(next);
*ok = false;
- return Traits::EmptyIdentifier();
+ return impl()->EmptyIdentifier();
}
}
@@ -1505,10 +1650,10 @@ ParserBase<Impl>::ParseIdentifierOrStrictReservedWord(
} else {
ReportUnexpectedToken(next);
*ok = false;
- return Traits::EmptyIdentifier();
+ return impl()->EmptyIdentifier();
}
- return this->GetSymbol(scanner());
+ return impl()->GetSymbol();
}
template <typename Impl>
@@ -1521,12 +1666,12 @@ typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifierName(
next != Token::FUTURE_STRICT_RESERVED_WORD &&
next != Token::ESCAPED_KEYWORD &&
next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
- this->ReportUnexpectedToken(next);
+ ReportUnexpectedToken(next);
*ok = false;
- return Traits::EmptyIdentifier();
+ return impl()->EmptyIdentifier();
}
- return this->GetSymbol(scanner());
+ return impl()->GetSymbol();
}
template <typename Impl>
@@ -1537,18 +1682,18 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
Next();
ReportMessage(MessageTemplate::kUnterminatedRegExp);
*ok = false;
- return Traits::EmptyExpression();
+ return impl()->EmptyExpression();
}
int literal_index = function_state_->NextMaterializedLiteralIndex();
- IdentifierT js_pattern = this->GetNextSymbol(scanner());
+ IdentifierT js_pattern = impl()->GetNextSymbol();
Maybe<RegExp::Flags> flags = scanner()->ScanRegExpFlags();
if (flags.IsNothing()) {
Next();
ReportMessage(MessageTemplate::kMalformedRegExpFlags);
*ok = false;
- return Traits::EmptyExpression();
+ return impl()->EmptyExpression();
}
int js_flags = flags.FromJust();
Next();
@@ -1557,7 +1702,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
- ExpressionClassifier* classifier, bool* is_async, bool* ok) {
+ bool* is_async, bool* ok) {
// PrimaryExpression ::
// 'this'
// 'null'
@@ -1573,14 +1718,14 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
// '(' Expression ')'
// TemplateLiteral
// do Block
- // AsyncFunctionExpression
+ // AsyncFunctionLiteral
int beg_pos = peek_position();
switch (peek()) {
case Token::THIS: {
- BindingPatternUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
Consume(Token::THIS);
- return this->ThisExpression(beg_pos);
+ return impl()->ThisExpression(beg_pos);
}
case Token::NULL_LITERAL:
@@ -1588,15 +1733,15 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
case Token::FALSE_LITERAL:
case Token::SMI:
case Token::NUMBER:
- BindingPatternUnexpectedToken(classifier);
- return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
+ BindingPatternUnexpectedToken();
+ return impl()->ExpressionFromLiteral(Next(), beg_pos);
case Token::ASYNC:
if (allow_harmony_async_await() &&
!scanner()->HasAnyLineTerminatorAfterNext() &&
PeekAhead() == Token::FUNCTION) {
Consume(Token::ASYNC);
- return impl()->ParseAsyncFunctionExpression(CHECK_OK);
+ return ParseAsyncFunctionLiteral(CHECK_OK);
}
// CoverCallExpressionAndAsyncArrowHead
*is_async = true;
@@ -1609,28 +1754,28 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
case Token::ESCAPED_STRICT_RESERVED_WORD:
case Token::FUTURE_STRICT_RESERVED_WORD: {
// Using eval or arguments in this context is OK even in strict mode.
- IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK);
- return this->ExpressionFromIdentifier(name, beg_pos,
- scanner()->location().end_pos);
+ IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
+ return impl()->ExpressionFromIdentifier(name, beg_pos,
+ scanner()->location().end_pos);
}
case Token::STRING: {
- BindingPatternUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
Consume(Token::STRING);
- return this->ExpressionFromString(beg_pos, scanner(), factory());
+ return impl()->ExpressionFromString(beg_pos);
}
case Token::ASSIGN_DIV:
case Token::DIV:
- classifier->RecordBindingPatternError(
+ classifier()->RecordBindingPatternError(
scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp);
- return this->ParseRegExpLiteral(ok);
+ return ParseRegExpLiteral(ok);
case Token::LBRACK:
- return this->ParseArrayLiteral(classifier, ok);
+ return ParseArrayLiteral(ok);
case Token::LBRACE:
- return this->ParseObjectLiteral(classifier, ok);
+ return ParseObjectLiteral(ok);
case Token::LPAREN: {
// Arrow function formal parameters are either a single identifier or a
@@ -1638,61 +1783,34 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
// 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(classifier);
+ 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));
+ classifier()->RecordExpressionError(scanner()->location(),
+ MessageTemplate::kUnexpectedToken,
+ Token::String(Token::RPAREN));
return factory()->NewEmptyParentheses(beg_pos);
- } else if (Check(Token::ELLIPSIS)) {
- // (...x)=>x. The continuation that looks for the => is in
- // ParseAssignmentExpression.
- int ellipsis_pos = position();
- int expr_pos = peek_position();
- classifier->RecordExpressionError(scanner()->location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::ELLIPSIS));
- classifier->RecordNonSimpleParameter();
- ExpressionClassifier binding_classifier(this);
- ExpressionT expr = this->ParseAssignmentExpression(
- true, &binding_classifier, CHECK_OK);
- classifier->Accumulate(&binding_classifier,
- ExpressionClassifier::AllProductions);
- if (!this->IsIdentifier(expr) && !IsValidPattern(expr)) {
- classifier->RecordArrowFormalParametersError(
- Scanner::Location(ellipsis_pos, scanner()->location().end_pos),
- MessageTemplate::kInvalidRestParameter);
- }
- if (peek() == Token::COMMA) {
- ReportMessageAt(scanner()->peek_location(),
- MessageTemplate::kParamAfterRest);
- *ok = false;
- return this->EmptyExpression();
- }
- Expect(Token::RPAREN, CHECK_OK);
- return factory()->NewSpread(expr, ellipsis_pos, expr_pos);
}
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
function_state_->set_next_function_is_parenthesized(peek() ==
Token::FUNCTION);
- ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK);
+ ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
return expr;
}
case Token::CLASS: {
- BindingPatternUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
Consume(Token::CLASS);
- int class_token_position = position();
- IdentifierT name = this->EmptyIdentifier();
+ int class_token_pos = position();
+ IdentifierT name = impl()->EmptyIdentifier();
bool is_strict_reserved_name = false;
Scanner::Location class_name_location = Scanner::Location::invalid();
if (peek_any_identifier()) {
@@ -1700,28 +1818,26 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
CHECK_OK);
class_name_location = scanner()->location();
}
- return impl()->ParseClassLiteral(classifier, name, class_name_location,
- is_strict_reserved_name,
- class_token_position, ok);
+ return ParseClassLiteral(name, class_name_location,
+ is_strict_reserved_name, class_token_pos, ok);
}
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL:
- BindingPatternUnexpectedToken(classifier);
- return this->ParseTemplateLiteral(Traits::NoTemplateTag(), beg_pos,
- classifier, ok);
+ BindingPatternUnexpectedToken();
+ return ParseTemplateLiteral(impl()->NoTemplateTag(), beg_pos, ok);
case Token::MOD:
if (allow_natives() || extension_ != NULL) {
- BindingPatternUnexpectedToken(classifier);
- return impl()->ParseV8Intrinsic(ok);
+ BindingPatternUnexpectedToken();
+ return ParseV8Intrinsic(ok);
}
break;
case Token::DO:
if (allow_harmony_do_expressions()) {
- BindingPatternUnexpectedToken(classifier);
- return impl()->ParseDoExpression(ok);
+ BindingPatternUnexpectedToken();
+ return ParseDoExpression(ok);
}
break;
@@ -1731,78 +1847,71 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
ReportUnexpectedToken(Next());
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
bool accept_IN, bool* ok) {
ExpressionClassifier classifier(this);
- ExpressionT result = ParseExpression(accept_IN, &classifier, CHECK_OK);
- impl()->RewriteNonPattern(&classifier, CHECK_OK);
+ ExpressionT result = ParseExpressionCoverGrammar(accept_IN, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
return result;
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
- bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) {
// Expression ::
// AssignmentExpression
// Expression ',' AssignmentExpression
- ExpressionT result;
- {
+ ExpressionT result = impl()->EmptyExpression();
+ while (true) {
+ int comma_pos = position();
ExpressionClassifier binding_classifier(this);
- result = this->ParseAssignmentExpression(accept_IN, &binding_classifier,
- CHECK_OK);
- classifier->Accumulate(&binding_classifier,
- ExpressionClassifier::AllProductions);
- }
- bool is_simple_parameter_list = this->IsIdentifier(result);
- bool seen_rest = false;
- while (peek() == Token::COMMA) {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- if (seen_rest) {
- // At this point the production can't possibly be valid, but we don't know
- // which error to signal.
- classifier->RecordArrowFormalParametersError(
- scanner()->peek_location(), MessageTemplate::kParamAfterRest);
- }
- Consume(Token::COMMA);
- bool is_rest = false;
+ 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 = ParsePrimaryExpression(CHECK_OK);
+ ValidateBindingPattern(CHECK_OK);
+ 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.
+ impl()->Accumulate(ExpressionClassifier::AllProductions &
+ ~(ExpressionClassifier::BindingPatternProduction |
+ ExpressionClassifier::LetPatternProduction));
+ if (!impl()->IsIdentifier(right)) classifier()->RecordNonSimpleParameter();
+ if (impl()->IsEmptyExpression(result)) {
+ // First time through the loop.
+ result = right;
+ } else {
+ result =
+ factory()->NewBinaryOperation(Token::COMMA, result, right, comma_pos);
+ }
+
+ if (!Check(Token::COMMA)) break;
+
+ if (right->IsSpread()) {
+ classifier()->RecordArrowFormalParametersError(
+ scanner()->location(), MessageTemplate::kParamAfterRest);
+ }
+
if (allow_harmony_trailing_commas() && peek() == Token::RPAREN &&
PeekAhead() == Token::ARROW) {
// a trailing comma is allowed at the end of an arrow parameter list
break;
- } else if (peek() == Token::ELLIPSIS) {
- // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
- // as the formal parameters of'(x, y, ...z) => foo', and is not itself a
- // valid expression or binding pattern.
- ExpressionUnexpectedToken(classifier);
- BindingPatternUnexpectedToken(classifier);
- Consume(Token::ELLIPSIS);
- seen_rest = is_rest = true;
- }
- int pos = position(), expr_pos = peek_position();
- ExpressionClassifier binding_classifier(this);
- ExpressionT right = this->ParseAssignmentExpression(
- accept_IN, &binding_classifier, CHECK_OK);
- classifier->Accumulate(&binding_classifier,
- ExpressionClassifier::AllProductions);
- if (is_rest) {
- if (!this->IsIdentifier(right) && !IsValidPattern(right)) {
- classifier->RecordArrowFormalParametersError(
- Scanner::Location(pos, scanner()->location().end_pos),
- MessageTemplate::kInvalidRestParameter);
- }
- right = factory()->NewSpread(right, pos, expr_pos);
}
- is_simple_parameter_list =
- is_simple_parameter_list && this->IsIdentifier(right);
- result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
- }
- if (!is_simple_parameter_list || seen_rest) {
- classifier->RecordNonSimpleParameter();
}
return result;
@@ -1810,26 +1919,23 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
- ExpressionClassifier* classifier, bool* ok) {
+ bool* ok) {
// ArrayLiteral ::
// '[' Expression? (',' Expression?)* ']'
int pos = peek_position();
- typename Traits::Type::ExpressionList values =
- this->NewExpressionList(4, zone_);
+ ExpressionListT values = impl()->NewExpressionList(4);
int first_spread_index = -1;
Expect(Token::LBRACK, CHECK_OK);
while (peek() != Token::RBRACK) {
ExpressionT elem;
if (peek() == Token::COMMA) {
- elem = this->GetLiteralTheHole(peek_position(), factory());
+ elem = impl()->GetLiteralTheHole(peek_position());
} else if (peek() == Token::ELLIPSIS) {
int start_pos = peek_position();
Consume(Token::ELLIPSIS);
int expr_pos = peek_position();
- ExpressionT argument =
- this->ParseAssignmentExpression(true, classifier, CHECK_OK);
- CheckNoTailCallExpressions(classifier, CHECK_OK);
+ ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK);
elem = factory()->NewSpread(argument, start_pos, expr_pos);
if (first_spread_index < 0) {
@@ -1837,25 +1943,23 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
}
if (argument->IsAssignment()) {
- classifier->RecordPatternError(
+ classifier()->RecordPatternError(
Scanner::Location(start_pos, scanner()->location().end_pos),
MessageTemplate::kInvalidDestructuringTarget);
} else {
- CheckDestructuringElement(argument, classifier, start_pos,
+ CheckDestructuringElement(argument, start_pos,
scanner()->location().end_pos);
}
if (peek() == Token::COMMA) {
- classifier->RecordPatternError(
+ classifier()->RecordPatternError(
Scanner::Location(start_pos, scanner()->location().end_pos),
MessageTemplate::kElementAfterRest);
}
} else {
int beg_pos = peek_position();
- elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- CheckDestructuringElement(elem, classifier, beg_pos,
- scanner()->location().end_pos);
+ elem = ParseAssignmentExpression(true, CHECK_OK);
+ CheckDestructuringElement(elem, beg_pos, scanner()->location().end_pos);
}
values->Add(elem, zone_);
if (peek() != Token::RBRACK) {
@@ -1878,19 +1982,87 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
// to change. Also, this error message will never appear while pre-
// parsing (this is OK, as it is an implementation limitation).
ReportMessage(MessageTemplate::kTooManySpreads);
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
}
return result;
}
template <class Impl>
+bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token,
+ PropertyKind* 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 = PropertyKind::kValueProperty;
+ return true;
+ case Token::COMMA:
+ case Token::RBRACE:
+ case Token::ASSIGN:
+ *kind = PropertyKind::kShorthandProperty;
+ return true;
+ case Token::LPAREN:
+ *kind = PropertyKind::kMethodProperty;
+ return true;
+ case Token::MUL:
+ case Token::SEMICOLON:
+ *kind = PropertyKind::kClassField;
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+template <class Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
- IdentifierT* name, bool* is_get, bool* is_set, bool* is_computed_name,
- ExpressionClassifier* classifier, bool* ok) {
+ IdentifierT* name, PropertyKind* kind, bool* is_generator, bool* is_get,
+ bool* is_set, bool* is_async, bool* is_computed_name, bool* ok) {
+ DCHECK(*kind == PropertyKind::kNotSet);
+ DCHECK(!*is_generator);
+ DCHECK(!*is_get);
+ DCHECK(!*is_set);
+ DCHECK(!*is_async);
+ DCHECK(!*is_computed_name);
+
+ *is_generator = Check(Token::MUL);
+ if (*is_generator) {
+ *kind = PropertyKind::kMethodProperty;
+ }
+
Token::Value token = peek();
int pos = peek_position();
+ if (allow_harmony_async_await() && !*is_generator && token == Token::ASYNC &&
+ !scanner()->HasAnyLineTerminatorAfterNext()) {
+ Consume(Token::ASYNC);
+ token = peek();
+ if (SetPropertyKindFromToken(token, kind)) {
+ *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'async'
+ impl()->PushLiteralName(*name);
+ return factory()->NewStringLiteral(*name, pos);
+ }
+ *kind = PropertyKind::kMethodProperty;
+ *is_async = true;
+ pos = peek_position();
+ }
+
+ if (token == Token::IDENTIFIER && !*is_generator && !*is_async) {
+ // This is checking for 'get' and 'set' in particular.
+ Consume(Token::IDENTIFIER);
+ token = peek();
+ if (SetPropertyKindFromToken(token, kind) ||
+ !scanner()->IsGetOrSet(is_get, is_set)) {
+ *name = impl()->GetSymbol();
+ impl()->PushLiteralName(*name);
+ return factory()->NewStringLiteral(*name, pos);
+ }
+ *kind = PropertyKind::kAccessorProperty;
+ pos = peek_position();
+ }
+
// For non computed property names we normalize the name a bit:
//
// "12" -> 12
@@ -1900,274 +2072,417 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
//
// This is important because we use the property name as a key in a hash
// table when we compute constant properties.
+ ExpressionT expression = impl()->EmptyExpression();
switch (token) {
case Token::STRING:
Consume(Token::STRING);
- *name = this->GetSymbol(scanner());
+ *name = impl()->GetSymbol();
break;
case Token::SMI:
Consume(Token::SMI);
- *name = this->GetNumberAsSymbol(scanner());
+ *name = impl()->GetNumberAsSymbol();
break;
case Token::NUMBER:
Consume(Token::NUMBER);
- *name = this->GetNumberAsSymbol(scanner());
+ *name = impl()->GetNumberAsSymbol();
break;
case Token::LBRACK: {
+ *name = impl()->EmptyIdentifier();
*is_computed_name = true;
Consume(Token::LBRACK);
ExpressionClassifier computed_name_classifier(this);
- ExpressionT expression =
- ParseAssignmentExpression(true, &computed_name_classifier, CHECK_OK);
- impl()->RewriteNonPattern(&computed_name_classifier, CHECK_OK);
- classifier->Accumulate(&computed_name_classifier,
- ExpressionClassifier::ExpressionProductions);
+ expression = ParseAssignmentExpression(true, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ impl()->AccumulateFormalParameterContainmentErrors();
Expect(Token::RBRACK, CHECK_OK);
- return expression;
+ break;
}
default:
*name = ParseIdentifierName(CHECK_OK);
- scanner()->IsGetOrSet(is_get, is_set);
break;
}
+ if (*kind == PropertyKind::kNotSet) {
+ SetPropertyKindFromToken(peek(), kind);
+ }
+
+ if (*is_computed_name) {
+ return expression;
+ }
+
+ impl()->PushLiteralName(*name);
+
uint32_t index;
- return this->IsArrayIndex(*name, &index)
+ return impl()->IsArrayIndex(*name, &index)
? factory()->NewNumberLiteral(index, pos)
: factory()->NewStringLiteral(*name, pos);
}
template <typename Impl>
-typename ParserBase<Impl>::ObjectLiteralPropertyT
-ParserBase<Impl>::ParsePropertyDefinition(
- ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
- MethodKind method_kind, bool* is_computed_name, bool* has_seen_constructor,
- ExpressionClassifier* classifier, IdentifierT* name, bool* ok) {
- DCHECK(!in_class || IsStaticMethod(method_kind) ||
- has_seen_constructor != nullptr);
+typename ParserBase<Impl>::ClassLiteralPropertyT
+ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
+ bool has_extends,
+ bool* is_computed_name,
+ bool* has_seen_constructor,
+ bool* ok) {
+ DCHECK(has_seen_constructor != nullptr);
bool is_get = false;
bool is_set = false;
- bool is_generator = Check(Token::MUL);
+ bool is_generator = false;
bool is_async = false;
- const bool is_static = IsStaticMethod(method_kind);
+ bool is_static = false;
+ PropertyKind kind = PropertyKind::kNotSet;
Token::Value name_token = peek();
- if (is_generator) {
- method_kind |= MethodKind::kGenerator;
- } else if (allow_harmony_async_await() && name_token == Token::ASYNC &&
- !scanner()->HasAnyLineTerminatorAfterNext() &&
- PeekAhead() != Token::LPAREN && PeekAhead()) {
- is_async = true;
+ IdentifierT name = impl()->EmptyIdentifier();
+ ExpressionT name_expression;
+ if (name_token == Token::STATIC) {
+ Consume(Token::STATIC);
+ if (peek() == Token::LPAREN) {
+ kind = PropertyKind::kMethodProperty;
+ name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
+ name_expression = factory()->NewStringLiteral(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 {
+ is_static = true;
+ name_expression = ParsePropertyName(
+ &name, &kind, &is_generator, &is_get, &is_set, &is_async,
+ is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ }
+ } else {
+ name_expression = ParsePropertyName(
+ &name, &kind, &is_generator, &is_get, &is_set, &is_async,
+ is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ }
+
+ switch (kind) {
+ case PropertyKind::kClassField:
+ case PropertyKind::kNotSet: // This case is a name followed by a name or
+ // other property. Here we have to assume
+ // that's an uninitialized field followed by a
+ // linebreak followed by a property, with ASI
+ // adding the semicolon. If not, there will be
+ // a syntax error after parsing the first name
+ // as an uninitialized field.
+ case PropertyKind::kShorthandProperty:
+ case PropertyKind::kValueProperty:
+ if (allow_harmony_class_fields()) {
+ bool has_initializer = Check(Token::ASSIGN);
+ ExpressionT function_literal = ParseClassFieldForInitializer(
+ has_initializer, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ ExpectSemicolon(CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ return factory()->NewClassLiteralProperty(
+ name_expression, function_literal, ClassLiteralProperty::FIELD,
+ is_static, *is_computed_name);
+ } else {
+ ReportUnexpectedToken(Next());
+ *ok = false;
+ return impl()->EmptyClassLiteralProperty();
+ }
+
+ case PropertyKind::kMethodProperty: {
+ DCHECK(!is_get && !is_set);
+
+ // MethodDefinition
+ // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
+ // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
+
+ if (!*is_computed_name) {
+ checker->CheckClassMethodName(
+ name_token, PropertyKind::kMethodProperty, is_generator, is_async,
+ is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ }
+
+ FunctionKind kind = is_generator
+ ? FunctionKind::kConciseGeneratorMethod
+ : is_async ? FunctionKind::kAsyncConciseMethod
+ : FunctionKind::kConciseMethod;
+
+ if (!is_static && impl()->IsConstructor(name)) {
+ *has_seen_constructor = true;
+ kind = has_extends ? FunctionKind::kSubclassConstructor
+ : FunctionKind::kBaseConstructor;
+ }
+
+ ExpressionT value = impl()->ParseFunctionLiteral(
+ name, scanner()->location(), kSkipFunctionNameCheck, kind,
+ kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
+ language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+
+ return factory()->NewClassLiteralProperty(name_expression, value,
+ ClassLiteralProperty::METHOD,
+ is_static, *is_computed_name);
+ }
+
+ case PropertyKind::kAccessorProperty: {
+ DCHECK((is_get || is_set) && !is_generator && !is_async);
+
+ if (!*is_computed_name) {
+ checker->CheckClassMethodName(
+ name_token, PropertyKind::kAccessorProperty, false, false,
+ is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ // 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());
+ }
+
+ FunctionKind kind = is_get ? FunctionKind::kGetterFunction
+ : FunctionKind::kSetterFunction;
+
+ FunctionLiteralT value = impl()->ParseFunctionLiteral(
+ name, scanner()->location(), kSkipFunctionNameCheck, kind,
+ kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
+ language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+
+ if (!*is_computed_name) {
+ impl()->AddAccessorPrefixToFunctionName(is_get, value, name);
+ }
+
+ return factory()->NewClassLiteralProperty(
+ name_expression, value,
+ is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER,
+ is_static, *is_computed_name);
+ }
}
+ UNREACHABLE();
+ return impl()->EmptyClassLiteralProperty();
+}
+template <typename Impl>
+typename ParserBase<Impl>::FunctionLiteralT
+ParserBase<Impl>::ParseClassFieldForInitializer(bool has_initializer,
+ bool* ok) {
+ // Makes a concise method which evaluates and returns the initialized value
+ // (or undefined if absent).
+ FunctionKind kind = FunctionKind::kConciseMethod;
+ DeclarationScope* initializer_scope = NewFunctionScope(kind);
+ initializer_scope->set_start_position(scanner()->location().end_pos);
+ FunctionState initializer_state(&function_state_, &scope_state_,
+ initializer_scope);
+ DCHECK(scope() == initializer_scope);
+ scope()->SetLanguageMode(STRICT);
+ ExpressionClassifier expression_classifier(this);
+ ExpressionT value;
+ if (has_initializer) {
+ value = this->ParseAssignmentExpression(
+ true, CHECK_OK_CUSTOM(EmptyFunctionLiteral));
+ impl()->RewriteNonPattern(CHECK_OK_CUSTOM(EmptyFunctionLiteral));
+ } else {
+ value = factory()->NewUndefinedLiteral(kNoSourcePosition);
+ }
+ initializer_scope->set_end_position(scanner()->location().end_pos);
+ typename Types::StatementList body = impl()->NewStatementList(1);
+ body->Add(factory()->NewReturnStatement(value, kNoSourcePosition), zone());
+ FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
+ impl()->EmptyIdentifierString(), initializer_scope, body,
+ initializer_state.materialized_literal_count(),
+ initializer_state.expected_property_count(), 0,
+ FunctionLiteral::kNoDuplicateParameters,
+ FunctionLiteral::kAnonymousExpression,
+ FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position());
+ function_literal->set_is_class_field_initializer(true);
+ return function_literal;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ObjectLiteralPropertyT
+ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
+ bool* is_computed_name,
+ bool* ok) {
+ bool is_get = false;
+ bool is_set = false;
+ bool is_generator = false;
+ bool is_async = false;
+ PropertyKind kind = PropertyKind::kNotSet;
+
+ IdentifierT name = impl()->EmptyIdentifier();
+ Token::Value name_token = peek();
int next_beg_pos = scanner()->peek_location().beg_pos;
int next_end_pos = scanner()->peek_location().end_pos;
- ExpressionT name_expression =
- ParsePropertyName(name, &is_get, &is_set, is_computed_name, classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- if (fni_ != nullptr && !*is_computed_name) {
- this->PushLiteralName(fni_, *name);
- }
+ ExpressionT name_expression = ParsePropertyName(
+ &name, &kind, &is_generator, &is_get, &is_set, &is_async,
+ is_computed_name, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
+ switch (kind) {
+ case PropertyKind::kValueProperty: {
+ DCHECK(!is_get && !is_set && !is_generator && !is_async);
- if (!in_class && !is_generator) {
- DCHECK(!IsStaticMethod(method_kind));
- if (peek() == Token::COLON) {
- // PropertyDefinition
- // PropertyName ':' AssignmentExpression
if (!*is_computed_name) {
- checker->CheckProperty(name_token, kValueProperty, MethodKind::kNormal,
- classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ checker->CheckDuplicateProto(name_token);
}
Consume(Token::COLON);
int beg_pos = peek_position();
- ExpressionT value = this->ParseAssignmentExpression(
- true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- CheckDestructuringElement(value, classifier, beg_pos,
- scanner()->location().end_pos);
+ ExpressionT value = ParseAssignmentExpression(
+ true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ CheckDestructuringElement(value, beg_pos, scanner()->location().end_pos);
+
+ ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
+ name_expression, value, *is_computed_name);
+
+ if (!*is_computed_name) {
+ impl()->SetFunctionNameFromPropertyName(result, name);
+ }
- return factory()->NewObjectLiteralProperty(name_expression, value,
- is_static, *is_computed_name);
+ return result;
}
- if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(),
- parsing_module_ || is_async_function()) &&
- (peek() == Token::COMMA || peek() == Token::RBRACE ||
- peek() == Token::ASSIGN)) {
+ case PropertyKind::kShorthandProperty: {
// PropertyDefinition
// IdentifierReference
// CoverInitializedName
//
// CoverInitializedName
// IdentifierReference Initializer?
- if (classifier->duplicate_finder() != nullptr &&
- scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
- classifier->RecordDuplicateFormalParameterError(scanner()->location());
+ DCHECK(!is_get && !is_set && !is_generator && !is_async);
+
+ if (!Token::IsIdentifier(name_token, language_mode(),
+ this->is_generator(),
+ parsing_module_ || is_async_function())) {
+ ReportUnexpectedToken(Next());
+ *ok = false;
+ return impl()->EmptyObjectLiteralProperty();
}
- if (this->IsEvalOrArguments(*name) && is_strict(language_mode())) {
- classifier->RecordBindingPatternError(
+ DCHECK(!*is_computed_name);
+
+ if (classifier()->duplicate_finder() != nullptr &&
+ scanner()->FindSymbol(classifier()->duplicate_finder(), 1) != 0) {
+ classifier()->RecordDuplicateFormalParameterError(
+ scanner()->location());
+ }
+
+ if (impl()->IsEvalOrArguments(name) && is_strict(language_mode())) {
+ classifier()->RecordBindingPatternError(
scanner()->location(), MessageTemplate::kStrictEvalArguments);
}
if (name_token == Token::LET) {
- classifier->RecordLetPatternError(
+ classifier()->RecordLetPatternError(
scanner()->location(), MessageTemplate::kLetInLexicalBinding);
}
if (name_token == Token::AWAIT) {
DCHECK(!is_async_function());
- classifier->RecordAsyncArrowFormalParametersError(
+ classifier()->RecordAsyncArrowFormalParametersError(
Scanner::Location(next_beg_pos, next_end_pos),
MessageTemplate::kAwaitBindingIdentifier);
}
ExpressionT lhs =
- this->ExpressionFromIdentifier(*name, next_beg_pos, next_end_pos);
- CheckDestructuringElement(lhs, classifier, next_beg_pos, next_end_pos);
+ impl()->ExpressionFromIdentifier(name, next_beg_pos, next_end_pos);
+ CheckDestructuringElement(lhs, next_beg_pos, next_end_pos);
ExpressionT value;
if (peek() == Token::ASSIGN) {
Consume(Token::ASSIGN);
ExpressionClassifier rhs_classifier(this);
- ExpressionT rhs = this->ParseAssignmentExpression(
- true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- impl()->RewriteNonPattern(&rhs_classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- classifier->Accumulate(&rhs_classifier,
- ExpressionClassifier::ExpressionProductions);
+ ExpressionT rhs = ParseAssignmentExpression(
+ true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ impl()->RewriteNonPattern(CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ impl()->AccumulateFormalParameterContainmentErrors();
value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
kNoSourcePosition);
- classifier->RecordObjectLiteralError(
+ classifier()->RecordExpressionError(
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
MessageTemplate::kInvalidCoverInitializedName);
- Traits::SetFunctionNameFromIdentifierRef(rhs, lhs);
+ impl()->SetFunctionNameFromIdentifierRef(rhs, lhs);
} else {
value = lhs;
}
return factory()->NewObjectLiteralProperty(
- name_expression, value, ObjectLiteralProperty::COMPUTED, is_static,
- false);
+ name_expression, value, ObjectLiteralProperty::COMPUTED, false);
}
- }
- // Method definitions are never valid in patterns.
- classifier->RecordPatternError(
- Scanner::Location(next_beg_pos, scanner()->location().end_pos),
- MessageTemplate::kInvalidDestructuringTarget);
+ case PropertyKind::kMethodProperty: {
+ DCHECK(!is_get && !is_set);
- if (is_async && !IsSpecialMethod(method_kind)) {
- DCHECK(!is_get);
- DCHECK(!is_set);
- bool dont_care;
- name_expression = ParsePropertyName(
- name, &dont_care, &dont_care, is_computed_name, classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- method_kind |= MethodKind::kAsync;
- }
-
- if (is_generator || peek() == Token::LPAREN) {
- // MethodDefinition
- // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
- // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
- if (!*is_computed_name) {
- checker->CheckProperty(name_token, kMethodProperty, method_kind,
- classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- }
-
- FunctionKind kind = is_generator
- ? FunctionKind::kConciseGeneratorMethod
- : is_async ? FunctionKind::kAsyncConciseMethod
- : FunctionKind::kConciseMethod;
-
- if (in_class && !IsStaticMethod(method_kind) &&
- this->IsConstructor(*name)) {
- *has_seen_constructor = true;
- kind = has_extends ? FunctionKind::kSubclassConstructor
- : FunctionKind::kBaseConstructor;
- }
-
- ExpressionT value = impl()->ParseFunctionLiteral(
- *name, scanner()->location(), kSkipFunctionNameCheck, kind,
- kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(),
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
-
- return factory()->NewObjectLiteralProperty(name_expression, value,
- ObjectLiteralProperty::COMPUTED,
- is_static, *is_computed_name);
- }
-
- if (in_class && name_token == Token::STATIC && IsNormalMethod(method_kind)) {
- // ClassElement (static)
- // 'static' MethodDefinition
- *name = this->EmptyIdentifier();
- ObjectLiteralPropertyT property = ParsePropertyDefinition(
- checker, true, has_extends, MethodKind::kStatic, is_computed_name,
- nullptr, classifier, name, ok);
- impl()->RewriteNonPattern(classifier, ok);
- return property;
- }
-
- if (is_get || is_set) {
- // MethodDefinition (Accessors)
- // get PropertyName '(' ')' '{' FunctionBody '}'
- // set PropertyName '(' PropertySetParameterList ')' '{' FunctionBody '}'
- *name = this->EmptyIdentifier();
- bool dont_care = false;
- name_token = peek();
+ // MethodDefinition
+ // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
+ // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
- name_expression = ParsePropertyName(
- name, &dont_care, &dont_care, is_computed_name, classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ classifier()->RecordPatternError(
+ Scanner::Location(next_beg_pos, scanner()->location().end_pos),
+ MessageTemplate::kInvalidDestructuringTarget);
+
+ FunctionKind kind = is_generator
+ ? FunctionKind::kConciseGeneratorMethod
+ : is_async ? FunctionKind::kAsyncConciseMethod
+ : FunctionKind::kConciseMethod;
+
+ ExpressionT value = impl()->ParseFunctionLiteral(
+ name, scanner()->location(), kSkipFunctionNameCheck, kind,
+ kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
+ language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- if (!*is_computed_name) {
- checker->CheckProperty(name_token, kAccessorProperty, method_kind,
- classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ return factory()->NewObjectLiteralProperty(
+ name_expression, value, ObjectLiteralProperty::COMPUTED,
+ *is_computed_name);
}
- typename Traits::Type::FunctionLiteral value = impl()->ParseFunctionLiteral(
- *name, scanner()->location(), kSkipFunctionNameCheck,
- is_get ? FunctionKind::kGetterFunction : FunctionKind::kSetterFunction,
- kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(),
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ case PropertyKind::kAccessorProperty: {
+ DCHECK((is_get || is_set) && !(is_set && is_get) && !is_generator &&
+ !is_async);
+
+ classifier()->RecordPatternError(
+ Scanner::Location(next_beg_pos, scanner()->location().end_pos),
+ MessageTemplate::kInvalidDestructuringTarget);
+
+ if (!*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.
+ name_expression =
+ factory()->NewStringLiteral(name, name_expression->position());
+ }
+
+ FunctionKind kind = is_get ? FunctionKind::kGetterFunction
+ : FunctionKind::kSetterFunction;
- // Make sure the name expression is a string since we need a Name for
- // Runtime_DefineAccessorPropertyUnchecked and since we can determine this
- // statically we can skip the extra runtime check.
- if (!*is_computed_name) {
- name_expression =
- factory()->NewStringLiteral(*name, name_expression->position());
+ FunctionLiteralT value = impl()->ParseFunctionLiteral(
+ name, scanner()->location(), kSkipFunctionNameCheck, kind,
+ kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
+ language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
+ if (!*is_computed_name) {
+ impl()->AddAccessorPrefixToFunctionName(is_get, value, name);
+ }
+
+ return factory()->NewObjectLiteralProperty(
+ name_expression, value, is_get ? ObjectLiteralProperty::GETTER
+ : ObjectLiteralProperty::SETTER,
+ *is_computed_name);
}
- return factory()->NewObjectLiteralProperty(
- name_expression, value,
- is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER,
- is_static, *is_computed_name);
+ case PropertyKind::kClassField:
+ case PropertyKind::kNotSet:
+ ReportUnexpectedToken(Next());
+ *ok = false;
+ return impl()->EmptyObjectLiteralProperty();
}
-
- Token::Value next = Next();
- ReportUnexpectedToken(next);
- *ok = false;
- return this->EmptyObjectLiteralProperty();
+ UNREACHABLE();
+ return impl()->EmptyObjectLiteralProperty();
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
- ExpressionClassifier* classifier, bool* ok) {
+ bool* ok) {
// ObjectLiteral ::
// '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
int pos = peek_position();
- typename Traits::Type::PropertyList properties =
- this->NewPropertyList(4, zone_);
+ typename Types::ObjectPropertyList properties =
+ impl()->NewObjectPropertyList(4);
int number_of_boilerplate_properties = 0;
bool has_computed_names = false;
ObjectLiteralChecker checker(this);
@@ -2177,20 +2492,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
while (peek() != Token::RBRACE) {
FuncNameInferrer::State fni_state(fni_);
- const bool in_class = false;
- const bool has_extends = false;
bool is_computed_name = false;
- IdentifierT name = this->EmptyIdentifier();
- ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
- &checker, in_class, has_extends, MethodKind::kNormal, &is_computed_name,
- NULL, classifier, &name, CHECK_OK);
+ ObjectLiteralPropertyT property =
+ ParseObjectPropertyDefinition(&checker, &is_computed_name, CHECK_OK);
if (is_computed_name) {
has_computed_names = true;
}
// Count CONSTANT or COMPUTED properties to maintain the enumeration order.
- if (!has_computed_names && this->IsBoilerplateProperty(property)) {
+ if (!has_computed_names && impl()->IsBoilerplateProperty(property)) {
number_of_boilerplate_properties++;
}
properties->Add(property, zone());
@@ -2201,8 +2512,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
}
if (fni_ != nullptr) fni_->Infer();
-
- Traits::SetFunctionNameFromPropertyName(property, name);
}
Expect(Token::RBRACE, CHECK_OK);
@@ -2216,16 +2525,13 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
}
template <typename Impl>
-typename ParserBase<Impl>::Traits::Type::ExpressionList
-ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc,
- bool maybe_arrow,
- ExpressionClassifier* classifier, bool* ok) {
+typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
+ Scanner::Location* first_spread_arg_loc, bool maybe_arrow, bool* ok) {
// Arguments ::
// '(' (AssignmentExpression)*[','] ')'
Scanner::Location spread_arg = Scanner::Location::invalid();
- typename Traits::Type::ExpressionList result =
- this->NewExpressionList(4, zone_);
+ ExpressionListT result = impl()->NewExpressionList(4);
Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList));
bool done = (peek() == Token::RPAREN);
bool was_unspread = false;
@@ -2235,12 +2541,10 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc,
bool is_spread = Check(Token::ELLIPSIS);
int expr_pos = peek_position();
- ExpressionT argument = this->ParseAssignmentExpression(
- true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
- CheckNoTailCallExpressions(classifier, CHECK_OK_CUSTOM(NullExpressionList));
+ ExpressionT argument =
+ ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpressionList));
if (!maybe_arrow) {
- impl()->RewriteNonPattern(classifier,
- CHECK_OK_CUSTOM(NullExpressionList));
+ impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList));
}
if (is_spread) {
if (!spread_arg.IsValid()) {
@@ -2263,7 +2567,7 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc,
if (result->length() > Code::kMaxArguments) {
ReportMessage(MessageTemplate::kTooManyArguments);
*ok = false;
- return this->NullExpressionList();
+ return impl()->NullExpressionList();
}
done = (peek() != Token::COMMA);
if (!done) {
@@ -2276,22 +2580,21 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc,
}
Scanner::Location location = scanner_->location();
if (Token::RPAREN != Next()) {
- ReportMessageAt(location, MessageTemplate::kUnterminatedArgList);
+ impl()->ReportMessageAt(location, MessageTemplate::kUnterminatedArgList);
*ok = false;
- return this->NullExpressionList();
+ return impl()->NullExpressionList();
}
*first_spread_arg_loc = spread_arg;
if (!maybe_arrow || peek() != Token::ARROW) {
if (maybe_arrow) {
- impl()->RewriteNonPattern(classifier,
- CHECK_OK_CUSTOM(NullExpressionList));
+ impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList));
}
if (spread_arg.IsValid()) {
// Unspread parameter sequences are translated into array literals in the
// parser. Ensure that the number of materialized literals matches between
// the parser and preparser
- Traits::MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
+ impl()->MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
}
}
@@ -2301,9 +2604,7 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc,
// Precedence = 2
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
- ExpressionClassifier* classifier,
- bool* ok) {
+ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
// AssignmentExpression ::
// ConditionalExpression
// ArrowFunction
@@ -2312,13 +2613,13 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
int lhs_beg_pos = peek_position();
if (peek() == Token::YIELD && is_generator()) {
- return this->ParseYieldExpression(accept_IN, classifier, ok);
+ return ParseYieldExpression(accept_IN, ok);
}
FuncNameInferrer::State fni_state(fni_);
Checkpoint checkpoint(this);
- ExpressionClassifier arrow_formals_classifier(this,
- classifier->duplicate_finder());
+ ExpressionClassifier arrow_formals_classifier(
+ this, classifier()->duplicate_finder());
Scope::Snapshot scope_snapshot(scope());
@@ -2328,26 +2629,23 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
bool parenthesized_formals = peek() == Token::LPAREN;
if (!is_async && !parenthesized_formals) {
- ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
+ 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 = this->ParsePrimaryExpression(&arrow_formals_classifier,
- &is_async, CHECK_OK);
+ expression = ParsePrimaryExpression(&is_async, CHECK_OK);
} else {
- expression = this->ParseConditionalExpression(
- accept_IN, &arrow_formals_classifier, CHECK_OK);
+ expression = ParseConditionalExpression(accept_IN, CHECK_OK);
}
- if (is_async && this->IsIdentifier(expression) && peek_any_identifier() &&
+ if (is_async && impl()->IsIdentifier(expression) && peek_any_identifier() &&
PeekAhead() == Token::ARROW) {
// async Identifier => AsyncConciseBody
- IdentifierT name =
- ParseAndClassifyIdentifier(&arrow_formals_classifier, CHECK_OK);
- expression = this->ExpressionFromIdentifier(
+ IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
+ expression = impl()->ExpressionFromIdentifier(
name, position(), scanner()->location().end_pos, InferName::kNo);
if (fni_) {
// Remove `async` keyword from inferred name stack.
@@ -2357,26 +2655,29 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
if (peek() == Token::ARROW) {
Scanner::Location arrow_loc = scanner()->peek_location();
- ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
- parenthesized_formals, is_async, CHECK_OK);
+ 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(&arrow_formals_classifier, ok);
+ ValidateFormalParameterInitializer(ok);
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
DeclarationScope* scope =
- this->NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction
- : FunctionKind::kArrowFunction);
+ NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction
+ : FunctionKind::kArrowFunction);
// Because the arrow's parameters were parsed in the outer scope, any
// usage flags that might have been triggered there need to be copied
// to the arrow scope.
this->scope()->PropagateUsageFlagsToScope(scope);
+
+ scope_snapshot.Reparent(scope);
+
FormalParametersT parameters(scope);
- if (!arrow_formals_classifier.is_simple_parameter_list()) {
+ if (!classifier()->is_simple_parameter_list()) {
scope->SetHasNonSimpleParameters();
parameters.is_simple = false;
}
@@ -2385,18 +2686,16 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
scope->set_start_position(lhs_beg_pos);
Scanner::Location duplicate_loc = Scanner::Location::invalid();
- this->ParseArrowFunctionFormalParameterList(
- &parameters, expression, loc, &duplicate_loc, scope_snapshot, CHECK_OK);
+ impl()->DeclareArrowFunctionFormalParameters(&parameters, expression, loc,
+ &duplicate_loc, CHECK_OK);
if (duplicate_loc.IsValid()) {
- arrow_formals_classifier.RecordDuplicateFormalParameterError(
- duplicate_loc);
+ classifier()->RecordDuplicateFormalParameterError(duplicate_loc);
}
- expression = this->ParseArrowFunctionLiteral(
- accept_IN, parameters, is_async, arrow_formals_classifier, CHECK_OK);
- arrow_formals_classifier.Discard();
- classifier->RecordPatternError(arrow_loc,
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::ARROW));
+ expression = ParseArrowFunctionLiteral(accept_IN, parameters, CHECK_OK);
+ impl()->Discard();
+ classifier()->RecordPatternError(arrow_loc,
+ MessageTemplate::kUnexpectedToken,
+ Token::String(Token::ARROW));
if (fni_ != nullptr) fni_->Infer();
@@ -2407,87 +2706,70 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
// form part of one. Propagate speculative formal parameter error locations
// (including those for binding patterns, since formal parameters can
// themselves contain binding patterns).
- // Do not merge pending non-pattern expressions yet!
- unsigned productions =
- ExpressionClassifier::FormalParametersProductions |
- ExpressionClassifier::AsyncArrowFormalParametersProduction |
- ExpressionClassifier::FormalParameterInitializerProduction;
+ unsigned productions = ExpressionClassifier::AllProductions &
+ ~ExpressionClassifier::ArrowFormalParametersProduction;
// Parenthesized identifiers and property references are allowed as part
- // of a larger binding pattern, even though parenthesized patterns
+ // 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 (this->IsValidReferenceExpression(expression)) {
- productions |= ExpressionClassifier::PatternProductions &
- ~ExpressionClassifier::AssignmentPatternProduction;
- } else {
- productions |= ExpressionClassifier::PatternProductions;
+ if (IsValidReferenceExpression(expression)) {
+ productions &= ~ExpressionClassifier::AssignmentPatternProduction;
}
const bool is_destructuring_assignment =
IsValidPattern(expression) && peek() == Token::ASSIGN;
- if (!is_destructuring_assignment) {
- // This may be an expression or a pattern, so we must continue to
- // accumulate expression-related errors.
- productions |= ExpressionClassifier::ExpressionProduction |
- ExpressionClassifier::TailCallExpressionProduction |
- ExpressionClassifier::ObjectLiteralProduction;
+ if (is_destructuring_assignment) {
+ // This is definitely not an expression so don't accumulate
+ // expression-related errors.
+ productions &= ~(ExpressionClassifier::ExpressionProduction |
+ ExpressionClassifier::TailCallExpressionProduction);
}
- classifier->Accumulate(&arrow_formals_classifier, productions, false);
-
if (!Token::IsAssignmentOp(peek())) {
// Parsed conditional expression only (no assignment).
- // Now pending non-pattern expressions must be merged.
- classifier->MergeNonPatterns(&arrow_formals_classifier);
+ // Pending non-pattern expressions must be merged.
+ impl()->Accumulate(productions);
return expression;
+ } else {
+ // Pending non-pattern expressions must be discarded.
+ impl()->Accumulate(productions, false);
}
- // Now pending non-pattern expressions must be discarded.
- arrow_formals_classifier.Discard();
-
- CheckNoTailCallExpressions(classifier, CHECK_OK);
-
if (is_destructuring_assignment) {
- ValidateAssignmentPattern(classifier, CHECK_OK);
+ ValidateAssignmentPattern(CHECK_OK);
} else {
- expression = this->CheckAndRewriteReferenceExpression(
+ expression = CheckAndRewriteReferenceExpression(
expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
}
- expression = this->MarkExpressionAsAssigned(expression);
+ expression = impl()->MarkExpressionAsAssigned(expression);
Token::Value op = Next(); // Get assignment operator.
if (op != Token::ASSIGN) {
- classifier->RecordPatternError(scanner()->location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(op));
+ classifier()->RecordPatternError(scanner()->location(),
+ MessageTemplate::kUnexpectedToken,
+ Token::String(op));
}
int pos = position();
ExpressionClassifier rhs_classifier(this);
- ExpressionT right =
- this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK);
- CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK);
- impl()->RewriteNonPattern(&rhs_classifier, CHECK_OK);
- classifier->Accumulate(
- &rhs_classifier,
- ExpressionClassifier::ExpressionProductions |
- ExpressionClassifier::ObjectLiteralProduction |
- ExpressionClassifier::AsyncArrowFormalParametersProduction);
+ ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ impl()->AccumulateFormalParameterContainmentErrors();
// TODO(1231235): We try to estimate the set of properties set by
// constructors. We define a new property whenever there is an
// assignment to a property of 'this'. We should probably only add
// properties if we haven't seen them before. Otherwise we'll
// probably overestimate the number of properties.
- if (op == Token::ASSIGN && this->IsThisProperty(expression)) {
+ if (op == Token::ASSIGN && impl()->IsThisProperty(expression)) {
function_state_->AddProperty();
}
- this->CheckAssigningFunctionLiteralToProperty(expression, right);
+ impl()->CheckAssigningFunctionLiteralToProperty(expression, right);
if (fni_ != NULL) {
// Check if the right hand side is a call to avoid inferring a
@@ -2502,7 +2784,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
}
if (op == Token::ASSIGN) {
- Traits::SetFunctionNameFromIdentifierRef(right, expression);
+ impl()->SetFunctionNameFromIdentifierRef(right, expression);
}
if (op == Token::ASSIGN_EXP) {
@@ -2522,19 +2804,19 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN,
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
- bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
+ bool accept_IN, bool* ok) {
// YieldExpression ::
// 'yield' ([no line terminator] '*'? AssignmentExpression)?
int pos = peek_position();
- classifier->RecordPatternError(scanner()->peek_location(),
- MessageTemplate::kInvalidDestructuringTarget);
- classifier->RecordFormalParameterInitializerError(
+ classifier()->RecordPatternError(
+ scanner()->peek_location(), MessageTemplate::kInvalidDestructuringTarget);
+ classifier()->RecordFormalParameterInitializerError(
scanner()->peek_location(), MessageTemplate::kYieldInParameter);
Expect(Token::YIELD, CHECK_OK);
ExpressionT generator_object =
factory()->NewVariableProxy(function_state_->generator_object_variable());
// The following initialization is necessary.
- ExpressionT expression = Traits::EmptyExpression();
+ ExpressionT expression = impl()->EmptyExpression();
bool delegating = false; // yield*
if (!scanner()->HasAnyLineTerminatorBeforeNext()) {
if (Check(Token::MUL)) delegating = true;
@@ -2553,8 +2835,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
if (!delegating) break;
// Delegating yields require an RHS; fall through.
default:
- expression = ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ expression = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
break;
}
}
@@ -2563,87 +2845,18 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
return impl()->RewriteYieldStar(generator_object, expression, pos);
}
- expression = Traits::BuildIteratorResult(expression, false);
+ expression = impl()->BuildIteratorResult(expression, false);
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
- typename Traits::Type::YieldExpression yield = factory()->NewYield(
- generator_object, expression, pos, Yield::kOnExceptionThrow);
+ ExpressionT yield = factory()->NewYield(generator_object, expression, pos,
+ Yield::kOnExceptionThrow);
return yield;
}
-template <typename Impl>
-typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseTailCallExpression(ExpressionClassifier* classifier,
- bool* ok) {
- // TailCallExpression::
- // 'continue' MemberExpression Arguments
- // 'continue' CallExpression Arguments
- // 'continue' MemberExpression TemplateLiteral
- // 'continue' CallExpression TemplateLiteral
- Expect(Token::CONTINUE, CHECK_OK);
- int pos = position();
- int sub_expression_pos = peek_position();
- ExpressionT expression =
- this->ParseLeftHandSideExpression(classifier, CHECK_OK);
- CheckNoTailCallExpressions(classifier, CHECK_OK);
-
- Scanner::Location loc(pos, scanner()->location().end_pos);
- if (!expression->IsCall()) {
- Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
- ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedInsideTailCall);
- *ok = false;
- return Traits::EmptyExpression();
- }
- if (Traits::IsDirectEvalCall(expression)) {
- Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
- ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCallOfEval);
- *ok = false;
- return Traits::EmptyExpression();
- }
- if (!is_strict(language_mode())) {
- ReportMessageAt(loc, MessageTemplate::kUnexpectedSloppyTailCall);
- *ok = false;
- return Traits::EmptyExpression();
- }
- if (is_resumable()) {
- Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
- ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCall);
- *ok = false;
- return Traits::EmptyExpression();
- }
- ReturnExprContext return_expr_context =
- function_state_->return_expr_context();
- if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) {
- MessageTemplate::Template msg = MessageTemplate::kNone;
- switch (return_expr_context) {
- case ReturnExprContext::kInsideValidReturnStatement:
- UNREACHABLE();
- return Traits::EmptyExpression();
- case ReturnExprContext::kInsideValidBlock:
- msg = MessageTemplate::kUnexpectedTailCall;
- break;
- case ReturnExprContext::kInsideTryBlock:
- msg = MessageTemplate::kUnexpectedTailCallInTryBlock;
- break;
- case ReturnExprContext::kInsideForInOfBody:
- msg = MessageTemplate::kUnexpectedTailCallInForInOf;
- break;
- }
- ReportMessageAt(loc, msg);
- *ok = false;
- return Traits::EmptyExpression();
- }
- classifier->RecordTailCallExpressionError(
- loc, MessageTemplate::kUnexpectedTailCall);
- function_state_->AddExplicitTailCallExpression(expression, loc);
- return expression;
-}
-
// Precedence = 3
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
- ExpressionClassifier* classifier,
bool* ok) {
// ConditionalExpression ::
// LogicalOrExpression
@@ -2651,23 +2864,20 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
int pos = peek_position();
// We start using the binary expression parser for prec >= 4 only!
- ExpressionT expression =
- this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
+ ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
if (peek() != Token::CONDITIONAL) return expression;
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
Consume(Token::CONDITIONAL);
// In parsing the first assignment expression in conditional
// expressions we always accept the 'in' keyword; see ECMA-262,
// section 11.12, page 58.
- ExpressionT left = ParseAssignmentExpression(true, classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ ExpressionT left = ParseAssignmentExpression(true, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
Expect(Token::COLON, CHECK_OK);
- ExpressionT right =
- ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
return factory()->NewConditional(expression, left, right, pos);
}
@@ -2675,30 +2885,24 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
// Precedence >= 4
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
- int prec, bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
+ int prec, bool accept_IN, bool* ok) {
DCHECK(prec >= 4);
- ExpressionT x = this->ParseUnaryExpression(classifier, CHECK_OK);
+ ExpressionT x = ParseUnaryExpression(CHECK_OK);
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
// prec1 >= 4
while (Precedence(peek(), accept_IN) == prec1) {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
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, classifier, CHECK_OK);
- if (op != Token::OR && op != Token::AND) {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- }
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
- if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos,
- factory())) {
+ if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) {
continue;
}
@@ -2731,7 +2935,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
- ExpressionClassifier* classifier, bool* ok) {
+ bool* ok) {
// UnaryExpression ::
// PostfixExpression
// 'delete' UnaryExpression
@@ -2747,44 +2951,42 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
Token::Value op = peek();
if (Token::IsUnaryOp(op)) {
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
op = Next();
int pos = position();
- ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK);
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ ExpressionT expression = ParseUnaryExpression(CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
if (op == Token::DELETE && is_strict(language_mode())) {
- if (this->IsIdentifier(expression)) {
+ if (impl()->IsIdentifier(expression)) {
// "delete identifier" is a syntax error in strict mode.
ReportMessage(MessageTemplate::kStrictDelete);
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
}
if (peek() == Token::EXP) {
ReportUnexpectedToken(Next());
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
- // Allow Traits do rewrite the expression.
- return this->BuildUnaryExpression(expression, op, pos, factory());
+ // Allow the parser's implementation to rewrite the expression.
+ return impl()->BuildUnaryExpression(expression, op, pos);
} else if (Token::IsCountOp(op)) {
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
op = Next();
int beg_pos = peek_position();
- ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- expression = this->CheckAndRewriteReferenceExpression(
+ ExpressionT expression = ParseUnaryExpression(CHECK_OK);
+ expression = CheckAndRewriteReferenceExpression(
expression, beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
- this->MarkExpressionAsAssigned(expression);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ expression = impl()->MarkExpressionAsAssigned(expression);
+ impl()->RewriteNonPattern(CHECK_OK);
return factory()->NewCountOperation(op,
true /* prefix */,
@@ -2792,41 +2994,39 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
position());
} else if (is_async_function() && peek() == Token::AWAIT) {
- classifier->RecordFormalParameterInitializerError(
+ classifier()->RecordFormalParameterInitializerError(
scanner()->peek_location(),
MessageTemplate::kAwaitExpressionFormalParameter);
int await_pos = peek_position();
Consume(Token::AWAIT);
- ExpressionT value = ParseUnaryExpression(classifier, CHECK_OK);
+ ExpressionT value = ParseUnaryExpression(CHECK_OK);
return impl()->RewriteAwaitExpression(value, await_pos);
} else {
- return this->ParsePostfixExpression(classifier, ok);
+ return ParsePostfixExpression(ok);
}
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
- ExpressionClassifier* classifier, bool* ok) {
+ bool* ok) {
// PostfixExpression ::
// LeftHandSideExpression ('++' | '--')?
int lhs_beg_pos = peek_position();
- ExpressionT expression =
- this->ParseLeftHandSideExpression(classifier, CHECK_OK);
+ ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
- expression = this->CheckAndRewriteReferenceExpression(
+ expression = CheckAndRewriteReferenceExpression(
expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
- expression = this->MarkExpressionAsAssigned(expression);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ expression = impl()->MarkExpressionAsAssigned(expression);
+ impl()->RewriteNonPattern(CHECK_OK);
Token::Value next = Next();
expression =
@@ -2840,40 +3040,33 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier,
- bool* ok) {
+ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
// LeftHandSideExpression ::
// (NewExpression | MemberExpression) ...
- if (FLAG_harmony_explicit_tailcalls && peek() == Token::CONTINUE) {
- return this->ParseTailCallExpression(classifier, ok);
- }
-
bool is_async = false;
- ExpressionT result = this->ParseMemberWithNewPrefixesExpression(
- classifier, &is_async, CHECK_OK);
+ ExpressionT result =
+ ParseMemberWithNewPrefixesExpression(&is_async, CHECK_OK);
while (true) {
switch (peek()) {
case Token::LBRACK: {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
Consume(Token::LBRACK);
int pos = position();
- ExpressionT index = ParseExpression(true, classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
result = factory()->NewProperty(result, index, pos);
Expect(Token::RBRACK, CHECK_OK);
break;
}
case Token::LPAREN: {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
int pos;
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
if (scanner()->current_token() == Token::IDENTIFIER ||
scanner()->current_token() == Token::SUPER ||
scanner()->current_token() == Token::ASYNC) {
@@ -2895,36 +3088,36 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier,
}
}
Scanner::Location spread_pos;
- typename Traits::Type::ExpressionList args;
- if (V8_UNLIKELY(is_async && this->IsIdentifier(result))) {
+ ExpressionListT args;
+ if (V8_UNLIKELY(is_async && impl()->IsIdentifier(result))) {
ExpressionClassifier async_classifier(this);
- args = ParseArguments(&spread_pos, true, &async_classifier, CHECK_OK);
+ args = ParseArguments(&spread_pos, true, CHECK_OK);
if (peek() == Token::ARROW) {
if (fni_) {
fni_->RemoveAsyncKeywordFromEnd();
}
- ValidateBindingPattern(&async_classifier, CHECK_OK);
- if (!async_classifier.is_valid_async_arrow_formal_parameters()) {
+ ValidateBindingPattern(CHECK_OK);
+ ValidateFormalParameterInitializer(CHECK_OK);
+ if (!classifier()->is_valid_async_arrow_formal_parameters()) {
ReportClassifierError(
- async_classifier.async_arrow_formal_parameters_error());
+ classifier()->async_arrow_formal_parameters_error());
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
if (args->length()) {
// async ( Arguments ) => ...
- return Traits::ExpressionListToExpression(args);
+ return impl()->ExpressionListToExpression(args);
}
// async () => ...
return factory()->NewEmptyParentheses(pos);
} else {
- classifier->Accumulate(&async_classifier,
- ExpressionClassifier::AllProductions);
+ impl()->AccumulateFormalParameterContainmentErrors();
}
} else {
- args = ParseArguments(&spread_pos, false, classifier, CHECK_OK);
+ args = ParseArguments(&spread_pos, false, CHECK_OK);
}
- ArrowFormalParametersUnexpectedToken(classifier);
+ ArrowFormalParametersUnexpectedToken();
// Keep track of eval() calls since they disable all local variable
// optimizations.
@@ -2947,7 +3140,8 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier,
// Explicit calls to the super constructor using super() perform an
// implicit binding assignment to the 'this' variable.
if (is_super_call) {
- ExpressionT this_expr = this->ThisExpression(pos);
+ result = impl()->RewriteSuperCall(result);
+ ExpressionT this_expr = impl()->ThisExpression(pos);
result =
factory()->NewAssignment(Token::INIT, this_expr, result, pos);
}
@@ -2957,26 +3151,24 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier,
}
case Token::PERIOD: {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
Consume(Token::PERIOD);
int pos = position();
IdentifierT name = ParseIdentifierName(CHECK_OK);
result = factory()->NewProperty(
result, factory()->NewStringLiteral(name, pos), pos);
- if (fni_ != NULL) this->PushLiteralName(fni_, name);
+ impl()->PushLiteralName(name);
break;
}
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
- result = ParseTemplateLiteral(result, position(), classifier, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
+ result = ParseTemplateLiteral(result, position(), CHECK_OK);
break;
}
@@ -2988,8 +3180,8 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier,
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(
- ExpressionClassifier* classifier, bool* is_async, bool* ok) {
+ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
+ bool* ok) {
// NewExpression ::
// ('new')+ MemberExpression
//
@@ -3011,8 +3203,8 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(
// new new foo().bar().baz means (new (new foo()).bar()).baz
if (peek() == Token::NEW) {
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
Consume(Token::NEW);
int new_pos = position();
ExpressionT result;
@@ -3022,15 +3214,13 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(
} else if (peek() == Token::PERIOD) {
return ParseNewTargetExpression(CHECK_OK);
} else {
- result = this->ParseMemberWithNewPrefixesExpression(classifier, is_async,
- CHECK_OK);
+ result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK);
}
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
if (peek() == Token::LPAREN) {
// NewExpression with arguments.
Scanner::Location spread_pos;
- typename Traits::Type::ExpressionList args =
- this->ParseArguments(&spread_pos, classifier, CHECK_OK);
+ ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK);
if (spread_pos.IsValid()) {
args = impl()->PrepareSpreadArguments(args);
@@ -3039,21 +3229,19 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(
result = factory()->NewCallNew(result, args, new_pos);
}
// The expression can still continue with . or [ after the arguments.
- result = this->ParseMemberExpressionContinuation(result, is_async,
- classifier, CHECK_OK);
+ result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK);
return result;
}
// NewExpression without arguments.
- return factory()->NewCallNew(result, this->NewExpressionList(0, zone_),
- new_pos);
+ return factory()->NewCallNew(result, impl()->NewExpressionList(0), new_pos);
}
// No 'new' or 'super' keyword.
- return this->ParseMemberExpression(classifier, is_async, ok);
+ return ParseMemberExpression(is_async, ok);
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
- ExpressionClassifier* classifier, bool* is_async, bool* ok) {
+ bool* is_async, bool* ok) {
// MemberExpression ::
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
@@ -3065,8 +3253,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
// Parse the initial primary or function expression.
ExpressionT result;
if (peek() == Token::FUNCTION) {
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
Consume(Token::FUNCTION);
int function_token_position = position();
@@ -3078,19 +3266,19 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
if (!is_generator()) {
// TODO(neis): allow escaping into closures?
- ReportMessageAt(scanner()->location(),
- MessageTemplate::kUnexpectedFunctionSent);
+ impl()->ReportMessageAt(scanner()->location(),
+ MessageTemplate::kUnexpectedFunctionSent);
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
- return this->FunctionSentExpression(factory(), pos);
+ return impl()->FunctionSentExpression(pos);
}
FunctionKind function_kind = Check(Token::MUL)
? FunctionKind::kGeneratorFunction
: FunctionKind::kNormalFunction;
- IdentifierT name = this->EmptyIdentifier();
+ IdentifierT name = impl()->EmptyIdentifier();
bool is_strict_reserved_name = false;
Scanner::Location function_name_location = Scanner::Location::invalid();
FunctionLiteral::FunctionType function_type =
@@ -3111,11 +3299,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
const bool is_new = false;
result = ParseSuperExpression(is_new, CHECK_OK);
} else {
- result = ParsePrimaryExpression(classifier, is_async, CHECK_OK);
+ result = ParsePrimaryExpression(is_async, CHECK_OK);
}
- result =
- ParseMemberExpressionContinuation(result, is_async, classifier, CHECK_OK);
+ result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK);
return result;
}
@@ -3131,20 +3318,21 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
IsClassConstructor(kind)) {
if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
scope->RecordSuperPropertyUsage();
- return this->NewSuperPropertyReference(factory(), pos);
+ return impl()->NewSuperPropertyReference(pos);
}
// new super() is never allowed.
// super() is only allowed in derived constructor
if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) {
// TODO(rossberg): This might not be the correct FunctionState for the
// method here.
- return this->NewSuperCallReference(factory(), pos);
+ return impl()->NewSuperCallReference(pos);
}
}
- ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedSuper);
+ impl()->ReportMessageAt(scanner()->location(),
+ MessageTemplate::kUnexpectedSuper);
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
template <typename Impl>
@@ -3154,7 +3342,7 @@ void ParserBase<Impl>::ExpectMetaProperty(Vector<const char> property_name,
Consume(Token::PERIOD);
ExpectContextualKeyword(property_name, CHECK_OK_CUSTOM(Void));
if (scanner()->literal_contains_escapes()) {
- Traits::ReportMessageAt(
+ impl()->ReportMessageAt(
Scanner::Location(pos, scanner()->location().end_pos),
MessageTemplate::kInvalidEscapedMetaProperty, full_name);
*ok = false;
@@ -3168,63 +3356,58 @@ ParserBase<Impl>::ParseNewTargetExpression(bool* ok) {
ExpectMetaProperty(CStrVector("target"), "new.target", pos, CHECK_OK);
if (!GetReceiverScope()->is_function_scope()) {
- ReportMessageAt(scanner()->location(),
- MessageTemplate::kUnexpectedNewTarget);
+ impl()->ReportMessageAt(scanner()->location(),
+ MessageTemplate::kUnexpectedNewTarget);
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
- return this->NewTargetExpression(pos);
+ return impl()->NewTargetExpression(pos);
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseMemberExpressionContinuation(
- ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
- bool* ok) {
+ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
+ bool* is_async, bool* ok) {
// Parses this part of MemberExpression:
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
while (true) {
switch (peek()) {
case Token::LBRACK: {
*is_async = false;
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
Consume(Token::LBRACK);
int pos = position();
- ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
expression = factory()->NewProperty(expression, index, pos);
- if (fni_ != NULL) {
- this->PushPropertyName(fni_, index);
- }
+ impl()->PushPropertyName(index);
Expect(Token::RBRACK, CHECK_OK);
break;
}
case Token::PERIOD: {
*is_async = false;
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
Consume(Token::PERIOD);
int pos = position();
IdentifierT name = ParseIdentifierName(CHECK_OK);
expression = factory()->NewProperty(
expression, factory()->NewStringLiteral(name, pos), pos);
- if (fni_ != NULL) {
- this->PushLiteralName(fni_, name);
- }
+ impl()->PushLiteralName(name);
break;
}
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
*is_async = false;
- impl()->RewriteNonPattern(classifier, CHECK_OK);
- BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
+ impl()->RewriteNonPattern(CHECK_OK);
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
int pos;
if (scanner()->current_token() == Token::IDENTIFIER) {
pos = position();
@@ -3236,62 +3419,58 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(
expression->AsFunctionLiteral()->set_should_eager_compile();
}
}
- expression =
- ParseTemplateLiteral(expression, pos, classifier, CHECK_OK);
+ expression = ParseTemplateLiteral(expression, pos, CHECK_OK);
break;
}
case Token::ILLEGAL: {
ReportUnexpectedTokenAt(scanner()->peek_location(), Token::ILLEGAL);
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
default:
return expression;
}
}
DCHECK(false);
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
template <typename Impl>
void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters,
- ExpressionClassifier* classifier,
bool* ok) {
// FormalParameter[Yield,GeneratorParameter] :
// BindingElement[?Yield, ?GeneratorParameter]
bool is_rest = parameters->has_rest;
- ExpressionT pattern =
- ParsePrimaryExpression(classifier, CHECK_OK_CUSTOM(Void));
- ValidateBindingPattern(classifier, CHECK_OK_CUSTOM(Void));
+ ExpressionT pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(Void));
+ ValidateBindingPattern(CHECK_OK_CUSTOM(Void));
- if (!Traits::IsIdentifier(pattern)) {
+ if (!impl()->IsIdentifier(pattern)) {
parameters->is_simple = false;
- ValidateFormalParameterInitializer(classifier, CHECK_OK_CUSTOM(Void));
- classifier->RecordNonSimpleParameter();
+ ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void));
+ classifier()->RecordNonSimpleParameter();
}
- ExpressionT initializer = Traits::EmptyExpression();
+ ExpressionT initializer = impl()->EmptyExpression();
if (!is_rest && Check(Token::ASSIGN)) {
ExpressionClassifier init_classifier(this);
- initializer = ParseAssignmentExpression(true, &init_classifier,
- CHECK_OK_CUSTOM(Void));
- impl()->RewriteNonPattern(&init_classifier, CHECK_OK_CUSTOM(Void));
- ValidateFormalParameterInitializer(&init_classifier, CHECK_OK_CUSTOM(Void));
+ initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void));
+ impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void));
+ ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void));
parameters->is_simple = false;
- init_classifier.Discard();
- classifier->RecordNonSimpleParameter();
+ impl()->Discard();
+ classifier()->RecordNonSimpleParameter();
- Traits::SetFunctionNameFromIdentifierRef(initializer, pattern);
+ impl()->SetFunctionNameFromIdentifierRef(initializer, pattern);
}
- Traits::AddFormalParameter(parameters, pattern, initializer,
+ impl()->AddFormalParameter(parameters, pattern, initializer,
scanner()->location().end_pos, is_rest);
}
template <typename Impl>
-void ParserBase<Impl>::ParseFormalParameterList(
- FormalParametersT* parameters, ExpressionClassifier* classifier, bool* ok) {
+void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters,
+ bool* ok) {
// FormalParameters[Yield] :
// [empty]
// FunctionRestParameter[?Yield]
@@ -3313,14 +3492,14 @@ void ParserBase<Impl>::ParseFormalParameterList(
return;
}
parameters->has_rest = Check(Token::ELLIPSIS);
- ParseFormalParameter(parameters, classifier, CHECK_OK_CUSTOM(Void));
+ ParseFormalParameter(parameters, CHECK_OK_CUSTOM(Void));
if (parameters->has_rest) {
parameters->is_simple = false;
- classifier->RecordNonSimpleParameter();
+ classifier()->RecordNonSimpleParameter();
if (peek() == Token::COMMA) {
- ReportMessageAt(scanner()->peek_location(),
- MessageTemplate::kParamAfterRest);
+ impl()->ReportMessageAt(scanner()->peek_location(),
+ MessageTemplate::kParamAfterRest);
*ok = false;
return;
}
@@ -3336,8 +3515,318 @@ void ParserBase<Impl>::ParseFormalParameterList(
for (int i = 0; i < parameters->Arity(); ++i) {
auto parameter = parameters->at(i);
- Traits::DeclareFormalParameter(parameters->scope, parameter, classifier);
+ impl()->DeclareFormalParameter(parameters->scope, parameter);
+ }
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
+ VariableDeclarationContext var_context,
+ DeclarationParsingResult* parsing_result,
+ ZoneList<const AstRawString*>* names, bool* ok) {
+ // VariableDeclarations ::
+ // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
+ //
+ // ES6:
+ // FIXME(marja, nikolaos): Add an up-to-date comment about ES6 variable
+ // declaration syntax.
+
+ DCHECK_NOT_NULL(parsing_result);
+ parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
+ parsing_result->descriptor.declaration_pos = peek_position();
+ parsing_result->descriptor.initialization_pos = peek_position();
+
+ BlockT init_block = impl()->NullBlock();
+ if (var_context != kForStatement) {
+ init_block = factory()->NewBlock(
+ nullptr, 1, true, parsing_result->descriptor.declaration_pos);
+ }
+
+ switch (peek()) {
+ case Token::VAR:
+ parsing_result->descriptor.mode = VAR;
+ Consume(Token::VAR);
+ break;
+ case Token::CONST:
+ Consume(Token::CONST);
+ DCHECK(var_context != kStatement);
+ parsing_result->descriptor.mode = CONST;
+ break;
+ case Token::LET:
+ Consume(Token::LET);
+ DCHECK(var_context != kStatement);
+ parsing_result->descriptor.mode = LET;
+ break;
+ default:
+ UNREACHABLE(); // by current callers
+ break;
+ }
+
+ parsing_result->descriptor.scope = scope();
+ parsing_result->descriptor.hoist_scope = nullptr;
+
+ // The scope of a var/const declared variable anywhere inside a function
+ // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope
+ // of a let declared variable is the scope of the immediately enclosing
+ // block.
+ int bindings_start = peek_position();
+ do {
+ // Parse binding pattern.
+ FuncNameInferrer::State fni_state(fni_);
+
+ ExpressionT pattern = impl()->EmptyExpression();
+ int decl_pos = peek_position();
+ {
+ ExpressionClassifier pattern_classifier(this);
+ pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(NullBlock));
+
+ ValidateBindingPattern(CHECK_OK_CUSTOM(NullBlock));
+ if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
+ ValidateLetPattern(CHECK_OK_CUSTOM(NullBlock));
+ }
+ }
+
+ Scanner::Location variable_loc = scanner()->location();
+ bool single_name = impl()->IsIdentifier(pattern);
+
+ if (single_name) {
+ impl()->PushVariableName(impl()->AsIdentifier(pattern));
+ }
+
+ ExpressionT value = impl()->EmptyExpression();
+ int initializer_position = kNoSourcePosition;
+ if (Check(Token::ASSIGN)) {
+ ExpressionClassifier classifier(this);
+ value = ParseAssignmentExpression(var_context != kForStatement,
+ CHECK_OK_CUSTOM(NullBlock));
+ impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullBlock));
+ variable_loc.end_pos = scanner()->location().end_pos;
+
+ if (!parsing_result->first_initializer_loc.IsValid()) {
+ parsing_result->first_initializer_loc = variable_loc;
+ }
+
+ // Don't infer if it is "a = function(){...}();"-like expression.
+ if (single_name && fni_ != nullptr) {
+ if (!value->IsCall() && !value->IsCallNew()) {
+ fni_->Infer();
+ } else {
+ fni_->RemoveLastFunction();
+ }
+ }
+
+ impl()->SetFunctionNameFromIdentifierRef(value, pattern);
+
+ // End position of the initializer is after the assignment expression.
+ initializer_position = scanner()->location().end_pos;
+ } else {
+ if (var_context != kForStatement || !PeekInOrOf()) {
+ // ES6 'const' and binding patterns require initializers.
+ if (parsing_result->descriptor.mode == CONST ||
+ !impl()->IsIdentifier(pattern)) {
+ impl()->ReportMessageAt(
+ Scanner::Location(decl_pos, scanner()->location().end_pos),
+ MessageTemplate::kDeclarationMissingInitializer,
+ !impl()->IsIdentifier(pattern) ? "destructuring" : "const");
+ *ok = false;
+ return impl()->NullBlock();
+ }
+ // 'let x' initializes 'x' to undefined.
+ if (parsing_result->descriptor.mode == LET) {
+ value = impl()->GetLiteralUndefined(position());
+ }
+ }
+
+ // End position of the initializer is after the variable.
+ initializer_position = position();
+ }
+
+ typename DeclarationParsingResult::Declaration decl(
+ pattern, initializer_position, value);
+ if (var_context == kForStatement) {
+ // Save the declaration for further handling in ParseForStatement.
+ parsing_result->declarations.Add(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(NullBlock));
+ }
+ } while (Check(Token::COMMA));
+
+ parsing_result->bindings_loc =
+ Scanner::Location(bindings_start, scanner()->location().end_pos);
+
+ DCHECK(*ok);
+ return init_block;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseFunctionDeclaration(bool* ok) {
+ Consume(Token::FUNCTION);
+ int pos = position();
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ if (Check(Token::MUL)) {
+ flags |= ParseFunctionFlags::kIsGenerator;
+ if (allow_harmony_restrictive_declarations()) {
+ impl()->ReportMessageAt(scanner()->location(),
+ MessageTemplate::kGeneratorInLegacyContext);
+ *ok = false;
+ return impl()->NullStatement();
+ }
+ }
+ return ParseHoistableDeclaration(pos, flags, nullptr, false, ok);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseHoistableDeclaration(
+ ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
+ Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
+ int pos = position();
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ if (Check(Token::MUL)) {
+ flags |= ParseFunctionFlags::kIsGenerator;
+ }
+ return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseHoistableDeclaration(
+ int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
+ bool default_export, bool* ok) {
+ // FunctionDeclaration ::
+ // 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ // 'function' '(' FormalParameters ')' '{' FunctionBody '}'
+ // GeneratorDeclaration ::
+ // 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ // 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
+ //
+ // The anonymous forms are allowed iff [default_export] is true.
+ //
+ // 'function' and '*' (if present) have been consumed by the caller.
+
+ const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
+ const bool is_async = flags & ParseFunctionFlags::kIsAsync;
+ DCHECK(!is_generator || !is_async);
+
+ IdentifierT name;
+ FunctionNameValidity name_validity;
+ IdentifierT variable_name;
+ if (default_export && peek() == Token::LPAREN) {
+ impl()->GetDefaultStrings(&name, &variable_name);
+ name_validity = kSkipFunctionNameCheck;
+ } else {
+ bool is_strict_reserved;
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
+ CHECK_OK_CUSTOM(NullStatement));
+ name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved
+ : kFunctionNameValidityUnknown;
+ variable_name = name;
+ }
+
+ FuncNameInferrer::State fni_state(fni_);
+ impl()->PushEnclosingName(name);
+ FunctionLiteralT function = impl()->ParseFunctionLiteral(
+ name, scanner()->location(), name_validity,
+ is_generator ? FunctionKind::kGeneratorFunction
+ : is_async ? FunctionKind::kAsyncFunction
+ : FunctionKind::kNormalFunction,
+ pos, FunctionLiteral::kDeclaration, language_mode(),
+ CHECK_OK_CUSTOM(NullStatement));
+
+ return impl()->DeclareFunction(variable_name, function, pos, is_generator,
+ is_async, names, ok);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration(
+ ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
+ // ClassDeclaration ::
+ // 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
+ // 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
+ //
+ // The anonymous form is allowed iff [default_export] is true.
+ //
+ // 'class' is expected to be consumed by the caller.
+ //
+ // A ClassDeclaration
+ //
+ // class C { ... }
+ //
+ // has the same semantics as:
+ //
+ // let C = class C { ... };
+ //
+ // so rewrite it as such.
+
+ int class_token_pos = position();
+ IdentifierT name = impl()->EmptyIdentifier();
+ bool is_strict_reserved = false;
+ IdentifierT variable_name = impl()->EmptyIdentifier();
+ if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) {
+ impl()->GetDefaultStrings(&name, &variable_name);
+ } else {
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
+ CHECK_OK_CUSTOM(NullStatement));
+ variable_name = name;
+ }
+
+ ExpressionClassifier no_classifier(this);
+ ExpressionT value =
+ ParseClassLiteral(name, scanner()->location(), is_strict_reserved,
+ class_token_pos, CHECK_OK_CUSTOM(NullStatement));
+ int end_pos = position();
+ return impl()->DeclareClass(variable_name, value, names, class_token_pos,
+ end_pos, ok);
+}
+
+// Language extension which is only enabled for source files loaded
+// through the API's extension mechanism. A native function
+// declaration is resolved by looking up the function through a
+// callback provided by the extension.
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseNativeDeclaration(
+ bool* ok) {
+ int pos = peek_position();
+ Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
+ // Allow "eval" or "arguments" for backward compatibility.
+ IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers,
+ CHECK_OK_CUSTOM(NullStatement));
+ Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullStatement));
+ if (peek() != Token::RPAREN) {
+ do {
+ ParseIdentifier(kAllowRestrictedIdentifiers,
+ CHECK_OK_CUSTOM(NullStatement));
+ } while (Check(Token::COMMA));
+ }
+ Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullStatement));
+ Expect(Token::SEMICOLON, CHECK_OK_CUSTOM(NullStatement));
+ return impl()->DeclareNative(name, pos, ok);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseAsyncFunctionDeclaration(
+ ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
+ // AsyncFunctionDeclaration ::
+ // async [no LineTerminator here] function BindingIdentifier[Await]
+ // ( FormalParameters[Await] ) { AsyncFunctionBody }
+ DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
+ int pos = position();
+ if (scanner()->HasAnyLineTerminatorBeforeNext()) {
+ *ok = false;
+ impl()->ReportUnexpectedToken(scanner()->current_token());
+ return impl()->NullStatement();
}
+ Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
+ return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
template <typename Impl>
@@ -3348,19 +3837,22 @@ void ParserBase<Impl>::CheckArityRestrictions(int param_count,
int formals_end_pos, bool* ok) {
if (IsGetterFunction(function_kind)) {
if (param_count != 0) {
- ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
- MessageTemplate::kBadGetterArity);
+ impl()->ReportMessageAt(
+ Scanner::Location(formals_start_pos, formals_end_pos),
+ MessageTemplate::kBadGetterArity);
*ok = false;
}
} else if (IsSetterFunction(function_kind)) {
if (param_count != 1) {
- ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
- MessageTemplate::kBadSetterArity);
+ impl()->ReportMessageAt(
+ Scanner::Location(formals_start_pos, formals_end_pos),
+ MessageTemplate::kBadSetterArity);
*ok = false;
}
if (has_rest) {
- ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
- MessageTemplate::kBadSetterRestParameter);
+ impl()->ReportMessageAt(
+ Scanner::Location(formals_start_pos, formals_end_pos),
+ MessageTemplate::kBadSetterRestParameter);
*ok = false;
}
}
@@ -3412,31 +3904,33 @@ bool ParserBase<Impl>::IsTrivialExpression() {
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseArrowFunctionLiteral(
- bool accept_IN, const FormalParametersT& formal_parameters, bool is_async,
- const ExpressionClassifier& formals_classifier, bool* ok) {
+ bool accept_IN, const FormalParametersT& formal_parameters, bool* ok) {
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
// ASI inserts `;` after arrow parameters if a line terminator is found.
// `=> ...` is never a valid expression, so report as syntax error.
// If next token is not `=>`, it's a syntax error anyways.
ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW);
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
- typename Traits::Type::StatementList body;
+ StatementListT body = impl()->NullStatementList();
int num_parameters = formal_parameters.scope->num_parameters();
int materialized_literal_count = -1;
int expected_property_count = -1;
- FunctionKind arrow_kind = is_async ? kAsyncArrowFunction : kArrowFunction;
+ FunctionKind kind = formal_parameters.scope->function_kind();
+ FunctionLiteral::EagerCompileHint eager_compile_hint =
+ FunctionLiteral::kShouldLazyCompile;
+ bool should_be_used_once_hint = false;
{
FunctionState function_state(&function_state_, &scope_state_,
- formal_parameters.scope, arrow_kind);
+ formal_parameters.scope);
function_state.SkipMaterializedLiterals(
formal_parameters.materialized_literals_count);
- this->ReindexLiterals(formal_parameters);
+ impl()->ReindexLiterals(formal_parameters);
Expect(Token::ARROW, CHECK_OK);
@@ -3444,20 +3938,42 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// Multiple statement body
Consume(Token::LBRACE);
DCHECK_EQ(scope(), formal_parameters.scope);
- bool is_lazily_parsed = (mode() == PARSE_LAZILY &&
- formal_parameters.scope->AllowsLazyParsing());
+ bool is_lazily_parsed =
+ (mode() == PARSE_LAZILY &&
+ formal_parameters.scope
+ ->AllowsLazyParsingWithoutUnresolvedVariables());
+ // TODO(marja): consider lazy-parsing inner arrow functions too. is_this
+ // handling in Scope::ResolveVariable needs to change.
if (is_lazily_parsed) {
- body = this->NewStatementList(0, zone());
- impl()->SkipLazyFunctionBody(&materialized_literal_count,
- &expected_property_count, CHECK_OK);
+ Scanner::BookmarkScope bookmark(scanner());
+ bookmark.Set();
+ LazyParsingResult result = impl()->SkipLazyFunctionBody(
+ &materialized_literal_count, &expected_property_count, false, true,
+ CHECK_OK);
+ formal_parameters.scope->ResetAfterPreparsing(
+ ast_value_factory_, result == kLazyParsingAborted);
+
if (formal_parameters.materialized_literals_count > 0) {
materialized_literal_count +=
formal_parameters.materialized_literals_count;
}
- } else {
+
+ if (result == kLazyParsingAborted) {
+ bookmark.Apply();
+ // Trigger eager (re-)parsing, just below this block.
+ is_lazily_parsed = false;
+
+ // This is probably an initialization function. Inform the compiler it
+ // should also eager-compile this function, and that we expect it to
+ // be used once.
+ eager_compile_hint = FunctionLiteral::kShouldEagerCompile;
+ should_be_used_once_hint = true;
+ }
+ }
+ if (!is_lazily_parsed) {
body = impl()->ParseEagerFunctionBody(
- this->EmptyIdentifier(), kNoSourcePosition, formal_parameters,
- arrow_kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
+ impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters,
+ kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
materialized_literal_count =
function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
@@ -3469,18 +3985,18 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
function_state_->return_expr_context());
ReturnExprScope allow_tail_calls(
function_state_, ReturnExprContext::kInsideValidReturnStatement);
- body = this->NewStatementList(1, zone());
- this->AddParameterInitializationBlock(formal_parameters, body, is_async,
- CHECK_OK);
+ body = impl()->NewStatementList(1);
+ impl()->AddParameterInitializationBlock(
+ formal_parameters, body, kind == kAsyncArrowFunction, CHECK_OK);
ExpressionClassifier classifier(this);
- if (is_async) {
- impl()->ParseAsyncArrowSingleExpressionBody(body, accept_IN,
- &classifier, pos, CHECK_OK);
- impl()->RewriteNonPattern(&classifier, CHECK_OK);
+ if (kind == kAsyncArrowFunction) {
+ ParseAsyncFunctionBody(scope(), body, kAsyncArrowFunction,
+ FunctionBodyType::kSingleExpression, accept_IN,
+ pos, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
} else {
- ExpressionT expression =
- ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
- impl()->RewriteNonPattern(&classifier, CHECK_OK);
+ ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
body->Add(factory()->NewReturnStatement(expression, pos), zone());
if (allow_tailcalls() && !is_sloppy(language_mode())) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
@@ -3499,8 +4015,8 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// that duplicates are not allowed. Of course, the arrow function may
// itself be strict as well.
const bool allow_duplicate_parameters = false;
- this->ValidateFormalParameters(&formals_classifier, language_mode(),
- allow_duplicate_parameters, CHECK_OK);
+ ValidateFormalParameters(language_mode(), allow_duplicate_parameters,
+ CHECK_OK);
// Validate strict mode.
if (is_strict(language_mode())) {
@@ -3513,24 +4029,141 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
}
FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
- this->EmptyIdentifierString(), formal_parameters.scope, body,
+ impl()->EmptyIdentifierString(), formal_parameters.scope, body,
materialized_literal_count, expected_property_count, num_parameters,
FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kAnonymousExpression,
- FunctionLiteral::kShouldLazyCompile, arrow_kind,
+ FunctionLiteral::kAnonymousExpression, eager_compile_hint,
formal_parameters.scope->start_position());
function_literal->set_function_token_position(
formal_parameters.scope->start_position());
+ if (should_be_used_once_hint) {
+ function_literal->set_should_be_used_once_hint();
+ }
- if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
+ impl()->AddFunctionForNameInference(function_literal);
return function_literal;
}
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) {
+ // All parts of a ClassDeclaration and ClassExpression are strict code.
+ if (name_is_strict_reserved) {
+ impl()->ReportMessageAt(class_name_location,
+ MessageTemplate::kUnexpectedStrictReserved);
+ *ok = false;
+ return impl()->EmptyExpression();
+ }
+ if (impl()->IsEvalOrArguments(name)) {
+ impl()->ReportMessageAt(class_name_location,
+ MessageTemplate::kStrictEvalArguments);
+ *ok = false;
+ return impl()->EmptyExpression();
+ }
+
+ BlockState block_state(zone(), &scope_state_);
+ RaiseLanguageMode(STRICT);
+
+ ClassInfo class_info(this);
+ impl()->DeclareClassVariable(name, block_state.scope(), &class_info,
+ class_token_pos, CHECK_OK);
+
+ if (Check(Token::EXTENDS)) {
+ block_state.set_start_position(scanner()->location().end_pos);
+ ExpressionClassifier extends_classifier(this);
+ class_info.extends = ParseLeftHandSideExpression(CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ impl()->AccumulateFormalParameterContainmentErrors();
+ } else {
+ block_state.set_start_position(scanner()->location().end_pos);
+ }
+
+ ClassLiteralChecker checker(this);
+
+ Expect(Token::LBRACE, CHECK_OK);
+
+ const bool has_extends = !impl()->IsEmptyExpression(class_info.extends);
+ while (peek() != Token::RBRACE) {
+ if (Check(Token::SEMICOLON)) continue;
+ FuncNameInferrer::State fni_state(fni_);
+ bool is_computed_name = false; // Classes do not care about computed
+ // property names here.
+ ExpressionClassifier property_classifier(this);
+ ClassLiteralPropertyT property = ParseClassPropertyDefinition(
+ &checker, has_extends, &is_computed_name,
+ &class_info.has_seen_constructor, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ impl()->AccumulateFormalParameterContainmentErrors();
+
+ impl()->DeclareClassProperty(name, property, &class_info, CHECK_OK);
+ impl()->InferFunctionName();
+ }
+
+ Expect(Token::RBRACE, CHECK_OK);
+ return impl()->RewriteClassLiteral(name, &class_info, class_token_pos, ok);
+}
+
+template <typename Impl>
+void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body,
+ FunctionKind kind,
+ FunctionBodyType body_type,
+ bool accept_IN, int pos,
+ bool* ok) {
+ scope->ForceContextAllocation();
+
+ impl()->PrepareAsyncFunctionBody(body, kind, pos);
+
+ BlockT block = factory()->NewBlock(nullptr, 8, true, kNoSourcePosition);
+
+ ExpressionT return_value = impl()->EmptyExpression();
+ if (body_type == FunctionBodyType::kNormal) {
+ ParseStatementList(block->statements(), Token::RBRACE,
+ CHECK_OK_CUSTOM(Void));
+ return_value = factory()->NewUndefinedLiteral(kNoSourcePosition);
+ } else {
+ return_value = ParseAssignmentExpression(accept_IN, CHECK_OK_CUSTOM(Void));
+ impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void));
+ }
+
+ impl()->RewriteAsyncFunctionBody(body, block, return_value,
+ CHECK_OK_CUSTOM(Void));
+ scope->set_end_position(scanner()->location().end_pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
+ // AsyncFunctionLiteral ::
+ // async [no LineTerminator here] function ( FormalParameters[Await] )
+ // { AsyncFunctionBody }
+ //
+ // async [no LineTerminator here] function BindingIdentifier[Await]
+ // ( FormalParameters[Await] ) { AsyncFunctionBody }
+ DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
+ int pos = position();
+ Expect(Token::FUNCTION, CHECK_OK);
+ bool is_strict_reserved = false;
+ IdentifierT name = impl()->EmptyIdentifier();
+ FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
+
+ if (peek_any_identifier()) {
+ type = FunctionLiteral::kNamedExpression;
+ name = ParseIdentifierOrStrictReservedWord(FunctionKind::kAsyncFunction,
+ &is_strict_reserved, CHECK_OK);
+ }
+ return impl()->ParseFunctionLiteral(
+ name, scanner()->location(),
+ is_strict_reserved ? kFunctionNameIsStrictReserved
+ : kFunctionNameValidityUnknown,
+ FunctionKind::kAsyncFunction, pos, type, language_mode(), CHECK_OK);
+}
+
+template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
- ExpressionT tag, int start, ExpressionClassifier* classifier, bool* ok) {
+ ExpressionT tag, int start, bool* ok) {
// A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal
// text followed by a substitution expression), finalized by a single
// TEMPLATE_TAIL.
@@ -3569,29 +4202,28 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
next = peek();
if (next == Token::EOS) {
- ReportMessageAt(Scanner::Location(start, peek_position()),
- MessageTemplate::kUnterminatedTemplate);
+ impl()->ReportMessageAt(Scanner::Location(start, peek_position()),
+ MessageTemplate::kUnterminatedTemplate);
*ok = false;
- return Traits::EmptyExpression();
+ return impl()->EmptyExpression();
} else if (next == Token::ILLEGAL) {
- Traits::ReportMessageAt(
+ impl()->ReportMessageAt(
Scanner::Location(position() + 1, peek_position()),
MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
*ok = false;
- return Traits::EmptyExpression();
+ return impl()->EmptyExpression();
}
int expr_pos = peek_position();
- ExpressionT expression = this->ParseExpression(true, classifier, CHECK_OK);
- CheckNoTailCallExpressions(classifier, CHECK_OK);
- impl()->RewriteNonPattern(classifier, CHECK_OK);
+ ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
impl()->AddTemplateExpression(&ts, expression);
if (peek() != Token::RBRACE) {
- ReportMessageAt(Scanner::Location(expr_pos, peek_position()),
- MessageTemplate::kUnterminatedTemplateExpr);
+ impl()->ReportMessageAt(Scanner::Location(expr_pos, peek_position()),
+ MessageTemplate::kUnterminatedTemplateExpr);
*ok = false;
- return Traits::EmptyExpression();
+ return impl()->EmptyExpression();
}
// If we didn't die parsing that expression, our next token should be a
@@ -3601,16 +4233,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
pos = position();
if (next == Token::EOS) {
- ReportMessageAt(Scanner::Location(start, pos),
- MessageTemplate::kUnterminatedTemplate);
+ impl()->ReportMessageAt(Scanner::Location(start, pos),
+ MessageTemplate::kUnterminatedTemplate);
*ok = false;
- return Traits::EmptyExpression();
+ return impl()->EmptyExpression();
} else if (next == Token::ILLEGAL) {
- Traits::ReportMessageAt(
+ impl()->ReportMessageAt(
Scanner::Location(position() + 1, peek_position()),
MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
*ok = false;
- return Traits::EmptyExpression();
+ return impl()->EmptyExpression();
}
impl()->AddTemplateSpan(&ts, next == Token::TEMPLATE_TAIL);
@@ -3627,8 +4259,8 @@ typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::CheckAndRewriteReferenceExpression(
ExpressionT expression, int beg_pos, int end_pos,
MessageTemplate::Template message, bool* ok) {
- return this->CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos,
- message, kReferenceError, ok);
+ return CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos,
+ message, kReferenceError, ok);
}
template <typename Impl>
@@ -3636,12 +4268,12 @@ typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::CheckAndRewriteReferenceExpression(
ExpressionT expression, int beg_pos, int end_pos,
MessageTemplate::Template message, ParseErrorType type, bool* ok) {
- if (this->IsIdentifier(expression) && is_strict(language_mode()) &&
- this->IsEvalOrArguments(this->AsIdentifier(expression))) {
+ 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 this->EmptyExpression();
+ return impl()->EmptyExpression();
}
if (expression->IsValidReferenceExpression()) {
return expression;
@@ -3649,47 +4281,1140 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression(
if (expression->IsCall()) {
// If it is a call, make it a runtime error for legacy web compatibility.
// Rewrite `expr' to `expr[throw ReferenceError]'.
- ExpressionT error = this->NewThrowReferenceError(message, beg_pos);
+ ExpressionT error = impl()->NewThrowReferenceError(message, beg_pos);
return factory()->NewProperty(expression, error, beg_pos);
}
ReportMessageAt(Scanner::Location(beg_pos, end_pos), message, type);
*ok = false;
- return this->EmptyExpression();
+ return impl()->EmptyExpression();
}
template <typename Impl>
bool ParserBase<Impl>::IsValidReferenceExpression(ExpressionT expression) {
- return this->IsAssignableIdentifier(expression) || expression->IsProperty();
+ return IsAssignableIdentifier(expression) || expression->IsProperty();
}
template <typename Impl>
-void ParserBase<Impl>::CheckDestructuringElement(
- ExpressionT expression, ExpressionClassifier* classifier, int begin,
- int end) {
+void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression,
+ int begin, int end) {
if (!IsValidPattern(expression) && !expression->IsAssignment() &&
!IsValidReferenceExpression(expression)) {
- classifier->RecordAssignmentPatternError(
+ classifier()->RecordAssignmentPatternError(
Scanner::Location(begin, end),
MessageTemplate::kInvalidDestructuringTarget);
}
}
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic(
+ bool* ok) {
+ // CallRuntime ::
+ // '%' Identifier Arguments
+
+ int pos = peek_position();
+ Expect(Token::MOD, CHECK_OK);
+ // 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);
+
+ DCHECK(!spread_pos.IsValid());
+
+ return impl()->NewV8Intrinsic(name, args, pos, ok);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseDoExpression(
+ bool* ok) {
+ // AssignmentExpression ::
+ // do '{' StatementList '}'
+
+ int pos = peek_position();
+ Expect(Token::DO, CHECK_OK);
+ BlockT block = ParseBlock(nullptr, CHECK_OK);
+ return impl()->RewriteDoExpression(block, pos, ok);
+}
+// Redefinition of CHECK_OK for parsing statements.
#undef CHECK_OK
-#undef CHECK_OK_CUSTOM
+#define CHECK_OK CHECK_OK_CUSTOM(NullStatement)
+
+template <typename Impl>
+typename ParserBase<Impl>::LazyParsingResult
+ParserBase<Impl>::ParseStatementList(StatementListT body, int end_token,
+ bool may_abort, bool* ok) {
+ // StatementList ::
+ // (StatementListItem)* <end_token>
+
+ // Allocate a target stack to use for this set of source
+ // elements. This way, all scripts and functions get their own
+ // target stack thus avoiding illegal breaks and continues across
+ // functions.
+ typename Types::TargetScope target_scope(this);
+ int count_statements = 0;
+
+ DCHECK(!impl()->IsNullStatementList(body));
+ bool directive_prologue = true; // Parsing directive prologue.
+
+ while (peek() != end_token) {
+ if (directive_prologue && peek() != Token::STRING) {
+ directive_prologue = false;
+ }
+
+ bool starts_with_identifier = peek() == Token::IDENTIFIER;
+ Scanner::Location token_loc = scanner()->peek_location();
+ StatementT stat =
+ ParseStatementListItem(CHECK_OK_CUSTOM(Return, kLazyParsingComplete));
+
+ if (impl()->IsNullStatement(stat) || impl()->IsEmptyStatement(stat)) {
+ 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(STRICT);
+ 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;
+ }
+ // Because declarations in strict eval code don't leak into the scope
+ // of the eval call, it is likely that functions declared in strict
+ // eval code will be used within the eval code, so lazy parsing is
+ // probably not a win.
+ if (scope()->is_eval_scope()) mode_ = PARSE_EAGERLY;
+ } else if (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(SLOPPY);
+ } else {
+ // End of the directive prologue.
+ directive_prologue = false;
+ RaiseLanguageMode(SLOPPY);
+ }
+ } else {
+ RaiseLanguageMode(SLOPPY);
+ }
+
+ // 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());
+ }
+ return kLazyParsingComplete;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem(
+ bool* ok) {
+ // ECMA 262 6th Edition
+ // StatementListItem[Yield, Return] :
+ // Statement[?Yield, ?Return]
+ // Declaration[?Yield]
+ //
+ // Declaration[Yield] :
+ // HoistableDeclaration[?Yield]
+ // ClassDeclaration[?Yield]
+ // LexicalDeclaration[In, ?Yield]
+ //
+ // HoistableDeclaration[Yield, Default] :
+ // FunctionDeclaration[?Yield, ?Default]
+ // GeneratorDeclaration[?Yield, ?Default]
+ //
+ // LexicalDeclaration[In, Yield] :
+ // LetOrConst BindingList[?In, ?Yield] ;
+
+ switch (peek()) {
+ case Token::FUNCTION:
+ return ParseHoistableDeclaration(nullptr, false, ok);
+ case Token::CLASS:
+ Consume(Token::CLASS);
+ return ParseClassDeclaration(nullptr, false, ok);
+ case Token::VAR:
+ case Token::CONST:
+ return ParseVariableStatement(kStatementListItem, nullptr, ok);
+ case Token::LET:
+ if (IsNextLetKeyword()) {
+ return ParseVariableStatement(kStatementListItem, nullptr, ok);
+ }
+ break;
+ case Token::ASYNC:
+ if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
+ !scanner()->HasAnyLineTerminatorAfterNext()) {
+ Consume(Token::ASYNC);
+ return ParseAsyncFunctionDeclaration(nullptr, false, ok);
+ }
+ /* falls through */
+ default:
+ break;
+ }
+ return ParseStatement(nullptr, kAllowLabelledFunctionStatement, ok);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
+ ZoneList<const AstRawString*>* labels,
+ AllowLabelledFunctionStatement allow_function, bool* ok) {
+ // Statement ::
+ // Block
+ // VariableStatement
+ // EmptyStatement
+ // ExpressionStatement
+ // IfStatement
+ // IterationStatement
+ // ContinueStatement
+ // BreakStatement
+ // ReturnStatement
+ // WithStatement
+ // LabelledStatement
+ // SwitchStatement
+ // ThrowStatement
+ // TryStatement
+ // DebuggerStatement
+
+ // Note: Since labels can only be used by 'break' and 'continue'
+ // statements, which themselves are only valid within blocks,
+ // iterations or 'switch' statements (i.e., BreakableStatements),
+ // labels can be simply ignored in all other cases; except for
+ // trivial labeled break statements 'label: break label' which is
+ // parsed into an empty statement.
+ switch (peek()) {
+ case Token::LBRACE:
+ return ParseBlock(labels, ok);
+ case Token::SEMICOLON:
+ Next();
+ return factory()->NewEmptyStatement(kNoSourcePosition);
+ case Token::IF:
+ return ParseIfStatement(labels, ok);
+ case Token::DO:
+ return ParseDoWhileStatement(labels, ok);
+ case Token::WHILE:
+ return ParseWhileStatement(labels, ok);
+ case Token::FOR:
+ return ParseForStatement(labels, ok);
+ case Token::CONTINUE:
+ case Token::BREAK:
+ case Token::RETURN:
+ case Token::THROW:
+ case Token::TRY: {
+ // These statements must have their labels preserved in an enclosing
+ // block, as the corresponding AST nodes do not currently store their
+ // labels.
+ // TODO(nikolaos, marja): Consider adding the labels to the AST nodes.
+ if (labels == nullptr) {
+ return ParseStatementAsUnlabelled(labels, ok);
+ } else {
+ BlockT result =
+ factory()->NewBlock(labels, 1, false, kNoSourcePosition);
+ typename Types::Target target(this, result);
+ StatementT statement = ParseStatementAsUnlabelled(labels, CHECK_OK);
+ result->statements()->Add(statement, zone());
+ return result;
+ }
+ }
+ case Token::WITH:
+ return ParseWithStatement(labels, ok);
+ case Token::SWITCH:
+ return ParseSwitchStatement(labels, ok);
+ case Token::FUNCTION:
+ // FunctionDeclaration only allowed as a StatementListItem, not in
+ // an arbitrary Statement position. Exceptions such as
+ // ES#sec-functiondeclarations-in-ifstatement-statement-clauses
+ // are handled by calling ParseScopedStatement rather than
+ // ParseStatement directly.
+ impl()->ReportMessageAt(scanner()->peek_location(),
+ is_strict(language_mode())
+ ? MessageTemplate::kStrictFunction
+ : MessageTemplate::kSloppyFunction);
+ *ok = false;
+ return impl()->NullStatement();
+ case Token::DEBUGGER:
+ return ParseDebuggerStatement(ok);
+ case Token::VAR:
+ return ParseVariableStatement(kStatement, nullptr, ok);
+ default:
+ return ParseExpressionOrLabelledStatement(labels, allow_function, ok);
+ }
+}
+
+// This method parses a subset of statements (break, continue, return, throw,
+// try) which are to be grouped because they all require their labeles to be
+// preserved in an enclosing block.
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseStatementAsUnlabelled(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ switch (peek()) {
+ case Token::CONTINUE:
+ return ParseContinueStatement(ok);
+ case Token::BREAK:
+ return ParseBreakStatement(labels, ok);
+ case Token::RETURN:
+ return ParseReturnStatement(ok);
+ case Token::THROW:
+ return ParseThrowStatement(ok);
+ case Token::TRY:
+ return ParseTryStatement(ok);
+ default:
+ UNREACHABLE();
+ return impl()->NullStatement();
+ }
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // Block ::
+ // '{' StatementList '}'
+
+ // Construct block expecting 16 statements.
+ BlockT body = factory()->NewBlock(labels, 16, false, kNoSourcePosition);
+
+ // Parse the statements and collect escaping labels.
+ Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullBlock));
+ {
+ BlockState block_state(zone(), &scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
+ typename Types::Target target(this, body);
+
+ while (peek() != Token::RBRACE) {
+ StatementT stat = ParseStatementListItem(CHECK_OK_CUSTOM(NullBlock));
+ if (!impl()->IsNullStatement(stat) && !impl()->IsEmptyStatement(stat)) {
+ body->statements()->Add(stat, zone());
+ }
+ }
+
+ Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullBlock));
+ block_state.set_end_position(scanner()->location().end_pos);
+ body->set_scope(block_state.FinalizedBlockScope());
+ }
+ return body;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement(
+ ZoneList<const AstRawString*>* labels, bool legacy, bool* ok) {
+ if (is_strict(language_mode()) || peek() != Token::FUNCTION ||
+ (legacy && allow_harmony_restrictive_declarations())) {
+ return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
+ } else {
+ if (legacy) {
+ impl()->CountUsage(v8::Isolate::kLegacyFunctionDeclaration);
+ }
+ // Make a block around the statement for a lexical binding
+ // is introduced by a FunctionDeclaration.
+ BlockState block_state(zone(), &scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
+ BlockT block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition);
+ StatementT body = ParseFunctionDeclaration(CHECK_OK);
+ block->statements()->Add(body, zone());
+ block_state.set_end_position(scanner()->location().end_pos);
+ block->set_scope(block_state.FinalizedBlockScope());
+ return block;
+ }
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement(
+ VariableDeclarationContext var_context,
+ ZoneList<const AstRawString*>* names, bool* ok) {
+ // VariableStatement ::
+ // VariableDeclarations ';'
+
+ // The scope of a var declared variable anywhere inside a function
+ // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
+ // transform a source-level var declaration into a (Function) Scope
+ // declaration, and rewrite the source-level initialization into an assignment
+ // statement. We use a block to collect multiple assignments.
+ //
+ // We mark the block as initializer block because we don't want the
+ // rewriter to add a '.result' assignment to such a block (to get compliant
+ // behavior for code such as print(eval('var x = 7')), and for cosmetic
+ // reasons when pretty-printing. Also, unless an assignment (initialization)
+ // is inside an initializer block, it is ignored.
+
+ DeclarationParsingResult parsing_result;
+ StatementT result =
+ ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return result;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDebuggerStatement(
+ bool* ok) {
+ // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
+ // contexts this is used as a statement which invokes the debugger as i a
+ // break point is present.
+ // DebuggerStatement ::
+ // 'debugger' ';'
+
+ int pos = peek_position();
+ Expect(Token::DEBUGGER, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return factory()->NewDebuggerStatement(pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseExpressionOrLabelledStatement(
+ ZoneList<const AstRawString*>* labels,
+ AllowLabelledFunctionStatement allow_function, bool* ok) {
+ // ExpressionStatement | LabelledStatement ::
+ // Expression ';'
+ // Identifier ':' Statement
+ //
+ // ExpressionStatement[Yield] :
+ // [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ;
+
+ int pos = peek_position();
+
+ switch (peek()) {
+ case Token::FUNCTION:
+ case Token::LBRACE:
+ UNREACHABLE(); // Always handled by the callers.
+ case Token::CLASS:
+ ReportUnexpectedToken(Next());
+ *ok = false;
+ return impl()->NullStatement();
+ default:
+ break;
+ }
+
+ bool starts_with_identifier = peek_any_identifier();
+ ExpressionT expr = ParseExpression(true, CHECK_OK);
+ 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.
+ labels = impl()->DeclareLabel(labels, impl()->AsIdentifierExpression(expr),
+ CHECK_OK);
+ Consume(Token::COLON);
+ // ES#sec-labelled-function-declarations Labelled Function Declarations
+ if (peek() == Token::FUNCTION && is_sloppy(language_mode())) {
+ if (allow_function == kAllowLabelledFunctionStatement) {
+ return ParseFunctionDeclaration(ok);
+ } else {
+ return ParseScopedStatement(labels, true, ok);
+ }
+ }
+ return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
+ }
+
+ // If we have an extension, we allow a native function declaration.
+ // A native function declaration starts with "native function" with
+ // no line-terminator between the two words.
+ if (extension_ != nullptr && peek() == Token::FUNCTION &&
+ !scanner()->HasAnyLineTerminatorBeforeNext() && impl()->IsNative(expr) &&
+ !scanner()->literal_contains_escapes()) {
+ return ParseNativeDeclaration(ok);
+ }
+
+ // Parsed expression statement, followed by semicolon.
+ ExpectSemicolon(CHECK_OK);
+ return factory()->NewExpressionStatement(expr, pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // IfStatement ::
+ // 'if' '(' Expression ')' Statement ('else' Statement)?
+
+ int pos = peek_position();
+ Expect(Token::IF, CHECK_OK);
+ Expect(Token::LPAREN, CHECK_OK);
+ ExpressionT condition = ParseExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+ StatementT then_statement = ParseScopedStatement(labels, false, CHECK_OK);
+ StatementT else_statement = impl()->NullStatement();
+ if (Check(Token::ELSE)) {
+ else_statement = ParseScopedStatement(labels, false, CHECK_OK);
+ } else {
+ else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
+ }
+ return factory()->NewIfStatement(condition, then_statement, else_statement,
+ pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement(
+ bool* ok) {
+ // ContinueStatement ::
+ // 'continue' Identifier? ';'
+
+ int pos = peek_position();
+ Expect(Token::CONTINUE, CHECK_OK);
+ IdentifierT label = impl()->EmptyIdentifier();
+ Token::Value tok = peek();
+ if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON &&
+ tok != Token::RBRACE && tok != Token::EOS) {
+ // ECMA allows "eval" or "arguments" as labels even in strict mode.
+ label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+ }
+ typename Types::IterationStatement target =
+ impl()->LookupContinueTarget(label, CHECK_OK);
+ if (impl()->IsNullStatement(target)) {
+ // Illegal continue statement.
+ MessageTemplate::Template message = MessageTemplate::kIllegalContinue;
+ if (!impl()->IsEmptyIdentifier(label)) {
+ message = MessageTemplate::kUnknownLabel;
+ }
+ ReportMessage(message, label);
+ *ok = false;
+ return impl()->NullStatement();
+ }
+ ExpectSemicolon(CHECK_OK);
+ return factory()->NewContinueStatement(target, pos);
+}
template <typename Impl>
-void ParserBase<Impl>::ObjectLiteralChecker::CheckProperty(
- Token::Value property, PropertyKind type, MethodKind method_type,
- ExpressionClassifier* classifier, bool* ok) {
- DCHECK(!IsStaticMethod(method_type));
- DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty);
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // BreakStatement ::
+ // 'break' Identifier? ';'
+ int pos = peek_position();
+ Expect(Token::BREAK, CHECK_OK);
+ IdentifierT label = impl()->EmptyIdentifier();
+ Token::Value tok = peek();
+ if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON &&
+ tok != Token::RBRACE && tok != Token::EOS) {
+ // ECMA allows "eval" or "arguments" as labels even in strict mode.
+ label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
+ }
+ // Parse labeled break statements that target themselves into
+ // empty statements, e.g. 'l1: l2: l3: break l2;'
+ if (!impl()->IsEmptyIdentifier(label) &&
+ impl()->ContainsLabel(labels, label)) {
+ ExpectSemicolon(CHECK_OK);
+ return factory()->NewEmptyStatement(pos);
+ }
+ typename Types::BreakableStatement target =
+ impl()->LookupBreakTarget(label, CHECK_OK);
+ if (impl()->IsNullStatement(target)) {
+ // Illegal break statement.
+ MessageTemplate::Template message = MessageTemplate::kIllegalBreak;
+ if (!impl()->IsEmptyIdentifier(label)) {
+ message = MessageTemplate::kUnknownLabel;
+ }
+ ReportMessage(message, label);
+ *ok = false;
+ return impl()->NullStatement();
+ }
+ ExpectSemicolon(CHECK_OK);
+ return factory()->NewBreakStatement(target, pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
+ bool* ok) {
+ // 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);
+ Scanner::Location loc = scanner()->location();
+
+ switch (GetDeclarationScope()->scope_type()) {
+ case SCRIPT_SCOPE:
+ case EVAL_SCOPE:
+ case MODULE_SCOPE:
+ impl()->ReportMessageAt(loc, MessageTemplate::kIllegalReturn);
+ *ok = false;
+ return impl()->NullStatement();
+ default:
+ break;
+ }
+
+ Token::Value tok = peek();
+ ExpressionT return_value = impl()->EmptyExpression();
+ if (scanner()->HasAnyLineTerminatorBeforeNext() || tok == Token::SEMICOLON ||
+ tok == Token::RBRACE || tok == Token::EOS) {
+ if (IsSubclassConstructor(function_state_->kind())) {
+ return_value = impl()->ThisExpression(loc.beg_pos);
+ } else {
+ return_value = impl()->GetLiteralUndefined(position());
+ }
+ } else {
+ if (IsSubclassConstructor(function_state_->kind())) {
+ // Because of the return code rewriting that happens in case of a subclass
+ // constructor we don't want to accept tail calls, therefore we don't set
+ // ReturnExprScope to kInsideValidReturnStatement here.
+ return_value = ParseExpression(true, CHECK_OK);
+ } else {
+ ReturnExprScope maybe_allow_tail_calls(
+ function_state_, ReturnExprContext::kInsideValidReturnStatement);
+ return_value = ParseExpression(true, CHECK_OK);
+
+ if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) {
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ function_state_->AddImplicitTailCallExpression(return_value);
+ }
+ }
+ }
+ ExpectSemicolon(CHECK_OK);
+ return_value = impl()->RewriteReturn(return_value, loc.beg_pos);
+ return factory()->NewReturnStatement(return_value, loc.beg_pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // WithStatement ::
+ // 'with' '(' Expression ')' Statement
+
+ Expect(Token::WITH, CHECK_OK);
+ int pos = position();
+
+ if (is_strict(language_mode())) {
+ ReportMessage(MessageTemplate::kStrictWith);
+ *ok = false;
+ return impl()->NullStatement();
+ }
+
+ Expect(Token::LPAREN, CHECK_OK);
+ ExpressionT expr = ParseExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+
+ Scope* with_scope = NewScope(WITH_SCOPE);
+ StatementT body = impl()->NullStatement();
+ {
+ BlockState block_state(&scope_state_, with_scope);
+ with_scope->set_start_position(scanner()->peek_location().beg_pos);
+ body = ParseScopedStatement(labels, true, CHECK_OK);
+ with_scope->set_end_position(scanner()->location().end_pos);
+ }
+ return factory()->NewWithStatement(with_scope, expr, body, pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // DoStatement ::
+ // 'do' Statement 'while' '(' Expression ')' ';'
+
+ auto loop = factory()->NewDoWhileStatement(labels, peek_position());
+ typename Types::Target target(this, loop);
+
+ Expect(Token::DO, CHECK_OK);
+ StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
+ Expect(Token::WHILE, CHECK_OK);
+ Expect(Token::LPAREN, CHECK_OK);
+
+ ExpressionT cond = ParseExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+
+ // Allow do-statements to be terminated with and without
+ // semi-colons. This allows code such as 'do;while(0)return' to
+ // parse, which would not be the case if we had used the
+ // ExpectSemicolon() functionality here.
+ Check(Token::SEMICOLON);
+
+ loop->Initialize(cond, body);
+ return loop;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // WhileStatement ::
+ // 'while' '(' Expression ')' Statement
+
+ auto loop = factory()->NewWhileStatement(labels, peek_position());
+ typename Types::Target target(this, loop);
+
+ Expect(Token::WHILE, CHECK_OK);
+ Expect(Token::LPAREN, CHECK_OK);
+ ExpressionT cond = ParseExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+ StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
+
+ loop->Initialize(cond, body);
+ return loop;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement(
+ bool* ok) {
+ // ThrowStatement ::
+ // 'throw' Expression ';'
+
+ Expect(Token::THROW, CHECK_OK);
+ int pos = position();
+ if (scanner()->HasAnyLineTerminatorBeforeNext()) {
+ ReportMessage(MessageTemplate::kNewlineAfterThrow);
+ *ok = false;
+ return impl()->NullStatement();
+ }
+ ExpressionT exception = ParseExpression(true, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+
+ return impl()->NewThrowStatement(exception, pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // SwitchStatement ::
+ // 'switch' '(' Expression ')' '{' CaseClause* '}'
+ // CaseClause ::
+ // 'case' Expression ':' StatementList
+ // 'default' ':' StatementList
+
+ int switch_pos = peek_position();
+
+ Expect(Token::SWITCH, CHECK_OK);
+ Expect(Token::LPAREN, CHECK_OK);
+ ExpressionT tag = ParseExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+
+ auto switch_statement = factory()->NewSwitchStatement(labels, switch_pos);
+
+ {
+ BlockState cases_block_state(zone(), &scope_state_);
+ cases_block_state.set_start_position(scanner()->location().beg_pos);
+ cases_block_state.SetNonlinear();
+ typename Types::Target target(this, switch_statement);
+
+ bool default_seen = false;
+ auto cases = impl()->NewCaseClauseList(4);
+ Expect(Token::LBRACE, CHECK_OK);
+ while (peek() != Token::RBRACE) {
+ // An empty label indicates the default case.
+ ExpressionT label = impl()->EmptyExpression();
+ if (Check(Token::CASE)) {
+ label = ParseExpression(true, CHECK_OK);
+ } else {
+ Expect(Token::DEFAULT, CHECK_OK);
+ if (default_seen) {
+ ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch);
+ *ok = false;
+ return impl()->NullStatement();
+ }
+ default_seen = true;
+ }
+ Expect(Token::COLON, CHECK_OK);
+ int clause_pos = position();
+ 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, clause_pos);
+ cases->Add(clause, zone());
+ }
+ Expect(Token::RBRACE, CHECK_OK);
+
+ cases_block_state.set_end_position(scanner()->location().end_pos);
+ return impl()->RewriteSwitchStatement(
+ tag, switch_statement, cases, cases_block_state.FinalizedBlockScope());
+ }
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
+ bool* ok) {
+ // TryStatement ::
+ // 'try' Block Catch
+ // 'try' Block Finally
+ // 'try' Block Catch Finally
+ //
+ // Catch ::
+ // 'catch' '(' Identifier ')' Block
+ //
+ // Finally ::
+ // 'finally' Block
+
+ Expect(Token::TRY, CHECK_OK);
+ int pos = position();
+
+ BlockT try_block = impl()->NullBlock();
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideTryBlock);
+ try_block = ParseBlock(nullptr, CHECK_OK);
+ }
+
+ CatchInfo catch_info(this);
+ catch_info.for_promise_reject = allow_natives() && Check(Token::MOD);
+
+ if (peek() != Token::CATCH && peek() != Token::FINALLY) {
+ ReportMessage(MessageTemplate::kNoCatchOrFinally);
+ *ok = false;
+ return impl()->NullStatement();
+ }
+
+ BlockT catch_block = impl()->NullBlock();
+ if (Check(Token::CATCH)) {
+ Expect(Token::LPAREN, CHECK_OK);
+ catch_info.scope = NewScope(CATCH_SCOPE);
+ catch_info.scope->set_start_position(scanner()->location().beg_pos);
+
+ {
+ CollectExpressionsInTailPositionToListScope
+ collect_tail_call_expressions_scope(
+ function_state_, &catch_info.tail_call_expressions);
+ BlockState catch_block_state(&scope_state_, catch_info.scope);
+
+ catch_block = factory()->NewBlock(nullptr, 16, false, kNoSourcePosition);
+
+ // Create a block scope to hold any lexical declarations created
+ // as part of destructuring the catch parameter.
+ {
+ BlockState catch_variable_block_state(zone(), &scope_state_);
+ catch_variable_block_state.set_start_position(
+ scanner()->location().beg_pos);
+ typename Types::Target target(this, catch_block);
+
+ // 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);
+ } else {
+ ExpressionClassifier pattern_classifier(this);
+ catch_info.pattern = ParsePrimaryExpression(CHECK_OK);
+ ValidateBindingPattern(CHECK_OK);
+ }
+
+ Expect(Token::RPAREN, CHECK_OK);
+ impl()->RewriteCatchPattern(&catch_info, CHECK_OK);
+ if (!impl()->IsNullStatement(catch_info.init_block)) {
+ catch_block->statements()->Add(catch_info.init_block, zone());
+ }
+
+ catch_info.inner_block = ParseBlock(nullptr, CHECK_OK);
+ catch_block->statements()->Add(catch_info.inner_block, zone());
+ impl()->ValidateCatchBlock(catch_info, CHECK_OK);
+ catch_variable_block_state.set_end_position(
+ scanner()->location().end_pos);
+ catch_block->set_scope(
+ catch_variable_block_state.FinalizedBlockScope());
+ }
+ }
+
+ catch_info.scope->set_end_position(scanner()->location().end_pos);
+ }
+
+ BlockT finally_block = impl()->NullBlock();
+ DCHECK(peek() == Token::FINALLY || !impl()->IsNullStatement(catch_block));
+ if (Check(Token::FINALLY)) {
+ finally_block = ParseBlock(nullptr, CHECK_OK);
+ }
+
+ return impl()->RewriteTryStatement(try_block, catch_block, finally_block,
+ catch_info, pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ int stmt_pos = peek_position();
+ ForInfo for_info(this);
+ bool bound_names_are_lexical = false;
+
+ // Create an in-between scope for let-bound iteration variables.
+ BlockState for_state(zone(), &scope_state_);
+ Expect(Token::FOR, CHECK_OK);
+ Expect(Token::LPAREN, CHECK_OK);
+ for_state.set_start_position(scanner()->location().beg_pos);
+ for_state.set_is_hidden();
+
+ StatementT init = impl()->NullStatement();
+ if (peek() != Token::SEMICOLON) {
+ // An initializer is present.
+ if (peek() == Token::VAR || peek() == Token::CONST ||
+ (peek() == Token::LET && IsNextLetKeyword())) {
+ // The initializer contains declarations.
+ ParseVariableDeclarations(kForStatement, &for_info.parsing_result,
+ nullptr, CHECK_OK);
+ bound_names_are_lexical =
+ IsLexicalVariableMode(for_info.parsing_result.descriptor.mode);
+ for_info.each_loc = scanner()->location();
+
+ if (CheckInOrOf(&for_info.mode)) {
+ // Just one declaration followed by in/of.
+ if (for_info.parsing_result.declarations.length() != 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() &&
+ (is_strict(language_mode()) ||
+ for_info.mode == ForEachStatement::ITERATE ||
+ bound_names_are_lexical ||
+ !impl()->IsIdentifier(
+ for_info.parsing_result.declarations[0].pattern) ||
+ allow_harmony_for_in())) {
+ // Only increment the use count if we would have let this through
+ // without the flag.
+ if (allow_harmony_for_in()) {
+ impl()->CountUsage(v8::Isolate::kForInInitializer);
+ }
+ impl()->ReportMessageAt(
+ for_info.parsing_result.first_initializer_loc,
+ MessageTemplate::kForInOfLoopInitializer,
+ ForEachStatement::VisitModeString(for_info.mode));
+ *ok = false;
+ return impl()->NullStatement();
+ }
+
+ BlockT init_block = impl()->RewriteForVarInLegacy(for_info);
+
+ auto loop =
+ factory()->NewForEachStatement(for_info.mode, labels, stmt_pos);
+ typename Types::Target target(this, loop);
+
+ int each_keyword_pos = scanner()->location().beg_pos;
+
+ ExpressionT enumerable = impl()->EmptyExpression();
+ if (for_info.mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ enumerable = ParseAssignmentExpression(true, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ } else {
+ enumerable = ParseExpression(true, CHECK_OK);
+ }
+
+ Expect(Token::RPAREN, CHECK_OK);
+
+ StatementT final_loop = impl()->NullStatement();
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
+ BlockState block_state(zone(), &scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
+
+ StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
+
+ BlockT body_block = impl()->NullBlock();
+ ExpressionT each_variable = impl()->EmptyExpression();
+ impl()->DesugarBindingInForEachStatement(&for_info, &body_block,
+ &each_variable, CHECK_OK);
+ body_block->statements()->Add(body, zone());
+ final_loop = impl()->InitializeForEachStatement(
+ loop, each_variable, enumerable, body_block, each_keyword_pos);
+
+ block_state.set_end_position(scanner()->location().end_pos);
+ body_block->set_scope(block_state.FinalizedBlockScope());
+ }
+
+ init_block =
+ impl()->CreateForEachStatementTDZ(init_block, for_info, ok);
+
+ for_state.set_end_position(scanner()->location().end_pos);
+ Scope* for_scope = for_state.FinalizedBlockScope();
+ // Parsed for-in loop w/ variable declarations.
+ if (!impl()->IsNullStatement(init_block)) {
+ init_block->statements()->Add(final_loop, zone());
+ init_block->set_scope(for_scope);
+ return init_block;
+ } else {
+ DCHECK_NULL(for_scope);
+ return final_loop;
+ }
+ } else {
+ // One or more declaration not followed by in/of.
+ init = impl()->BuildInitializationBlock(
+ &for_info.parsing_result,
+ bound_names_are_lexical ? &for_info.bound_names : nullptr,
+ CHECK_OK);
+ }
+ } else {
+ // 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 = scanner()->location().end_pos;
+
+ 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 {
+ impl()->RewriteNonPattern(CHECK_OK);
+ }
+
+ if (is_for_each) {
+ // Initializer is reference followed by in/of.
+ if (!is_destructuring) {
+ expression = impl()->CheckAndRewriteReferenceExpression(
+ expression, lhs_beg_pos, lhs_end_pos,
+ MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK);
+ }
+
+ auto loop =
+ factory()->NewForEachStatement(for_info.mode, labels, stmt_pos);
+ typename Types::Target target(this, loop);
+
+ int each_keyword_pos = scanner()->location().beg_pos;
+
+ ExpressionT enumerable = impl()->EmptyExpression();
+ if (for_info.mode == ForEachStatement::ITERATE) {
+ ExpressionClassifier classifier(this);
+ enumerable = ParseAssignmentExpression(true, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ } else {
+ enumerable = ParseExpression(true, CHECK_OK);
+ }
+
+ Expect(Token::RPAREN, CHECK_OK);
+
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
+ BlockState block_state(zone(), &scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
+
+ // For legacy compat reasons, give for loops similar treatment to
+ // if statements in allowing a function declaration for a body
+ StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
+ block_state.set_end_position(scanner()->location().end_pos);
+ StatementT final_loop = impl()->InitializeForEachStatement(
+ loop, expression, enumerable, body, each_keyword_pos);
+
+ Scope* for_scope = for_state.FinalizedBlockScope();
+ DCHECK_NULL(for_scope);
+ USE(for_scope);
+ Scope* block_scope = block_state.FinalizedBlockScope();
+ DCHECK_NULL(block_scope);
+ USE(block_scope);
+ return final_loop;
+ }
+ } else {
+ // Initializer is just an expression.
+ init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
+ }
+ }
+ }
+
+ // Standard 'for' loop, we have parsed the initializer at this point.
+ auto loop = factory()->NewForStatement(labels, stmt_pos);
+ typename Types::Target target(this, loop);
+
+ Expect(Token::SEMICOLON, CHECK_OK);
+
+ ExpressionT cond = impl()->EmptyExpression();
+ StatementT next = impl()->NullStatement();
+ StatementT body = impl()->NullStatement();
+
+ // If there are let bindings, then condition and the next statement of the
+ // for loop must be parsed in a new scope.
+ Scope* inner_scope = scope();
+ // TODO(verwaest): Allocate this through a ScopeState as well.
+ if (bound_names_are_lexical && for_info.bound_names.length() > 0) {
+ inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
+ inner_scope->set_start_position(scanner()->location().beg_pos);
+ }
+ {
+ BlockState block_state(&scope_state_, inner_scope);
+
+ if (peek() != Token::SEMICOLON) {
+ cond = ParseExpression(true, CHECK_OK);
+ }
+ Expect(Token::SEMICOLON, CHECK_OK);
+
+ if (peek() != Token::RPAREN) {
+ ExpressionT exp = ParseExpression(true, CHECK_OK);
+ next = factory()->NewExpressionStatement(exp, exp->position());
+ }
+ Expect(Token::RPAREN, CHECK_OK);
+
+ body = ParseScopedStatement(nullptr, true, CHECK_OK);
+ }
+
+ if (bound_names_are_lexical && for_info.bound_names.length() > 0) {
+ auto result = impl()->DesugarLexicalBindingsInForStatement(
+ loop, init, cond, next, body, inner_scope, for_info, CHECK_OK);
+ for_state.set_end_position(scanner()->location().end_pos);
+ return result;
+ } else {
+ for_state.set_end_position(scanner()->location().end_pos);
+ Scope* for_scope = for_state.FinalizedBlockScope();
+ if (for_scope != nullptr) {
+ // Rewrite a for statement of the form
+ // for (const x = i; c; n) b
+ //
+ // into
+ //
+ // {
+ // const x = i;
+ // for (; c; n) b
+ // }
+ //
+ // or, desugar
+ // for (; c; n) b
+ // into
+ // {
+ // for (; c; n) b
+ // }
+ // just in case b introduces a lexical binding some other way, e.g., if b
+ // is a FunctionDeclaration.
+ BlockT block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition);
+ if (!impl()->IsNullStatement(init)) {
+ block->statements()->Add(init, zone());
+ }
+ block->statements()->Add(loop, zone());
+ block->set_scope(for_scope);
+ loop->Initialize(init, cond, next, body);
+ return block;
+ } else {
+ loop->Initialize(init, cond, next, body);
+ return loop;
+ }
+ }
+}
+
+#undef CHECK_OK
+#undef CHECK_OK_CUSTOM
+
+template <typename Impl>
+void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto(
+ Token::Value property) {
if (property == Token::SMI || property == Token::NUMBER) return;
- if (type == kValueProperty && IsProto()) {
+ if (IsProto()) {
if (has_seen_proto_) {
- classifier->RecordObjectLiteralError(
+ this->parser()->classifier()->RecordExpressionError(
this->scanner()->location(), MessageTemplate::kDuplicateProto);
return;
}
@@ -3698,23 +5423,22 @@ void ParserBase<Impl>::ObjectLiteralChecker::CheckProperty(
}
template <typename Impl>
-void ParserBase<Impl>::ClassLiteralChecker::CheckProperty(
- Token::Value property, PropertyKind type, MethodKind method_type,
- ExpressionClassifier* classifier, bool* ok) {
- DCHECK(type == kMethodProperty || type == kAccessorProperty);
+void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
+ Token::Value property, PropertyKind type, bool is_generator, bool is_async,
+ bool is_static, bool* ok) {
+ DCHECK(type == PropertyKind::kMethodProperty ||
+ type == PropertyKind::kAccessorProperty);
if (property == Token::SMI || property == Token::NUMBER) return;
- if (IsStaticMethod(method_type)) {
+ if (is_static) {
if (IsPrototype()) {
this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
*ok = false;
return;
}
} else if (IsConstructor()) {
- const bool is_generator = IsGeneratorMethod(method_type);
- const bool is_async = IsAsyncMethod(method_type);
- if (is_generator || is_async || type == kAccessorProperty) {
+ if (is_generator || is_async || type == PropertyKind::kAccessorProperty) {
MessageTemplate::Template msg =
is_generator ? MessageTemplate::kConstructorIsGenerator
: is_async ? MessageTemplate::kConstructorIsAsync