aboutsummaryrefslogtreecommitdiff
path: root/src/parsing/parser-base.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/parsing/parser-base.h')
-rw-r--r--src/parsing/parser-base.h1527
1 files changed, 975 insertions, 552 deletions
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index bb62f86e..cf56c53a 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -9,6 +9,7 @@
#include "src/ast/scopes.h"
#include "src/bailout-reason.h"
#include "src/base/hashmap.h"
+#include "src/counters.h"
#include "src/globals.h"
#include "src/messages.h"
#include "src/parsing/expression-classifier.h"
@@ -100,6 +101,12 @@ struct FormalParametersBase {
// Used in functions where the return type is ExpressionT.
#define CHECK_OK CHECK_OK_CUSTOM(EmptyExpression)
+#define CHECK_OK_VOID ok); \
+ if (!*ok) return; \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
// Common base class template shared between parser and pre-parser.
// The Impl parameter is the actual class of the parser/pre-parser,
// following the Curiously Recurring Template Pattern (CRTP).
@@ -192,14 +199,16 @@ class ParserBase {
ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
v8::Extension* extension, AstValueFactory* ast_value_factory,
- RuntimeCallStats* runtime_call_stats)
- : scope_state_(nullptr),
+ RuntimeCallStats* runtime_call_stats,
+ bool parsing_on_main_thread = true)
+ : scope_(nullptr),
function_state_(nullptr),
extension_(extension),
fni_(nullptr),
ast_value_factory_(ast_value_factory),
ast_node_factory_(ast_value_factory),
runtime_call_stats_(runtime_call_stats),
+ parsing_on_main_thread_(parsing_on_main_thread),
parsing_module_(false),
stack_limit_(stack_limit),
zone_(zone),
@@ -207,29 +216,34 @@ class ParserBase {
scanner_(scanner),
stack_overflow_(false),
default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile),
- allow_lazy_(false),
+ function_literal_id_(0),
allow_natives_(false),
allow_tailcalls_(false),
allow_harmony_do_expressions_(false),
allow_harmony_function_sent_(false),
- allow_harmony_async_await_(false),
allow_harmony_restrictive_generators_(false),
allow_harmony_trailing_commas_(false),
- allow_harmony_class_fields_(false) {}
+ allow_harmony_class_fields_(false),
+ allow_harmony_object_rest_spread_(false),
+ allow_harmony_dynamic_import_(false),
+ allow_harmony_async_iteration_(false),
+ allow_harmony_template_escapes_(false) {}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
void set_allow_##name(bool allow) { allow_##name##_ = allow; }
- ALLOW_ACCESSORS(lazy);
ALLOW_ACCESSORS(natives);
ALLOW_ACCESSORS(tailcalls);
ALLOW_ACCESSORS(harmony_do_expressions);
ALLOW_ACCESSORS(harmony_function_sent);
- ALLOW_ACCESSORS(harmony_async_await);
ALLOW_ACCESSORS(harmony_restrictive_generators);
ALLOW_ACCESSORS(harmony_trailing_commas);
ALLOW_ACCESSORS(harmony_class_fields);
+ ALLOW_ACCESSORS(harmony_object_rest_spread);
+ ALLOW_ACCESSORS(harmony_dynamic_import);
+ ALLOW_ACCESSORS(harmony_async_iteration);
+ ALLOW_ACCESSORS(harmony_template_escapes);
#undef ALLOW_ACCESSORS
@@ -246,6 +260,13 @@ class ParserBase {
return default_eager_compile_hint_;
}
+ int GetNextFunctionLiteralId() { return ++function_literal_id_; }
+ int GetLastFunctionLiteralId() const { return function_literal_id_; }
+
+ void SkipFunctionLiterals(int delta) { function_literal_id_ += delta; }
+
+ void ResetFunctionLiteralId() { function_literal_id_ = 0; }
+
Zone* zone() const { return zone_; }
protected:
@@ -271,57 +292,26 @@ class ParserBase {
class ObjectLiteralChecker;
// ---------------------------------------------------------------------------
- // ScopeState and its subclasses implement the parser's scope stack.
- // ScopeState keeps track of the current scope, and the outer ScopeState. The
- // parser's scope_state_ points to the top ScopeState. ScopeState's
- // constructor push on the scope stack and the destructors pop. BlockState and
- // FunctionState are used to hold additional per-block and per-function state.
- class ScopeState BASE_EMBEDDED {
+ // BlockState and FunctionState implement the parser's scope stack.
+ // The parser's current scope is in scope_. BlockState and FunctionState
+ // constructors push on the scope stack and the destructors pop. They are also
+ // used to hold the parser's per-funcion state.
+ class BlockState BASE_EMBEDDED {
public:
- V8_INLINE Scope* scope() const { return scope_; }
- Zone* zone() const { return scope_->zone(); }
-
- protected:
- ScopeState(ScopeState** scope_stack, Scope* scope)
- : scope_stack_(scope_stack), outer_scope_(*scope_stack), scope_(scope) {
- *scope_stack = this;
+ BlockState(Scope** scope_stack, Scope* scope)
+ : scope_stack_(scope_stack), outer_scope_(*scope_stack) {
+ *scope_stack_ = scope;
}
- ~ScopeState() { *scope_stack_ = outer_scope_; }
- private:
- ScopeState** const scope_stack_;
- ScopeState* const outer_scope_;
- Scope* const scope_;
- };
+ BlockState(Zone* zone, Scope** scope_stack)
+ : BlockState(scope_stack,
+ new (zone) Scope(zone, *scope_stack, BLOCK_SCOPE)) {}
- class BlockState final : public ScopeState {
- public:
- BlockState(ScopeState** scope_stack, Scope* scope)
- : ScopeState(scope_stack, scope) {}
-
- // BlockState(ScopeState**) automatically manages Scope(BLOCK_SCOPE)
- // allocation.
- // TODO(verwaest): Move to LazyBlockState class that only allocates the
- // scope when needed.
- 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); }
- void set_end_position(int pos) { this->scope()->set_end_position(pos); }
- void set_is_hidden() { this->scope()->set_is_hidden(); }
- Scope* FinalizedBlockScope() const {
- return this->scope()->FinalizeBlockScope();
- }
- LanguageMode language_mode() const {
- return this->scope()->language_mode();
- }
+ ~BlockState() { *scope_stack_ = outer_scope_; }
private:
- Scope* NewScope(Zone* zone, ScopeState* outer_state) {
- Scope* parent = outer_state->scope();
- return new (zone) Scope(zone, parent, BLOCK_SCOPE);
- }
+ Scope** const scope_stack_;
+ Scope* const outer_scope_;
};
struct DestructuringAssignment {
@@ -383,26 +373,13 @@ class ParserBase {
kInsideForInOfBody,
};
- class FunctionState final : public ScopeState {
+ class FunctionState final : public BlockState {
public:
- FunctionState(FunctionState** function_state_stack,
- ScopeState** scope_stack, DeclarationScope* scope);
+ FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
+ DeclarationScope* scope);
~FunctionState();
- DeclarationScope* scope() const {
- return ScopeState::scope()->AsDeclarationScope();
- }
-
- int NextMaterializedLiteralIndex() {
- return next_materialized_literal_index_++;
- }
- int materialized_literal_count() {
- return next_materialized_literal_index_;
- }
-
- void SkipMaterializedLiterals(int count) {
- next_materialized_literal_index_ += count;
- }
+ DeclarationScope* scope() const { return scope_->AsDeclarationScope(); }
void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; }
@@ -410,22 +387,23 @@ class ParserBase {
FunctionKind kind() const { return scope()->function_kind(); }
FunctionState* outer() const { return outer_function_state_; }
- void set_generator_object_variable(typename Types::Variable* variable) {
- DCHECK(variable != NULL);
- DCHECK(IsResumableFunction(kind()));
- generator_object_variable_ = variable;
- }
typename Types::Variable* generator_object_variable() const {
- return generator_object_variable_;
+ return scope()->generator_object_var();
}
- 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_;
+ return scope()->promise_var();
+ }
+
+ void RewindDestructuringAssignments(int pos) {
+ destructuring_assignments_to_rewrite_.Rewind(pos);
+ }
+
+ void SetDestructuringAssignmentsScope(int pos, Scope* scope) {
+ for (int i = pos; i < destructuring_assignments_to_rewrite_.length();
+ ++i) {
+ destructuring_assignments_to_rewrite_[i].scope = scope;
+ }
}
const ZoneList<DestructuringAssignment>&
@@ -458,25 +436,25 @@ class ParserBase {
return &non_patterns_to_rewrite_;
}
- bool next_function_is_parenthesized() const {
- return next_function_is_parenthesized_;
+ bool next_function_is_likely_called() const {
+ return next_function_is_likely_called_;
}
- void set_next_function_is_parenthesized(bool parenthesized) {
- next_function_is_parenthesized_ = parenthesized;
+ bool previous_function_was_likely_called() const {
+ return previous_function_was_likely_called_;
}
- bool this_function_is_parenthesized() const {
- return this_function_is_parenthesized_;
+ void set_next_function_is_likely_called() {
+ next_function_is_likely_called_ = true;
}
private:
void AddDestructuringAssignment(DestructuringAssignment pair) {
- destructuring_assignments_to_rewrite_.Add(pair, this->zone());
+ destructuring_assignments_to_rewrite_.Add(pair, scope_->zone());
}
void AddNonPatternForRewriting(ExpressionT expr, bool* ok) {
- non_patterns_to_rewrite_.Add(expr, this->zone());
+ non_patterns_to_rewrite_.Add(expr, scope_->zone());
if (non_patterns_to_rewrite_.length() >=
std::numeric_limits<uint16_t>::max())
*ok = false;
@@ -490,16 +468,9 @@ class ParserBase {
// Properties count estimation.
int expected_property_count_;
- // 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_;
+ DeclarationScope* scope_;
ZoneList<DestructuringAssignment> destructuring_assignments_to_rewrite_;
TailCallExpressionList tail_call_expressions_;
@@ -508,13 +479,13 @@ class ParserBase {
ZoneList<typename ExpressionClassifier::Error> reported_errors_;
- // If true, the next (and immediately following) function literal is
- // preceded by a parenthesis.
- bool next_function_is_parenthesized_;
-
- // The value of the parents' next_function_is_parenthesized_, as it applies
- // to this function. Filled in by constructor.
- bool this_function_is_parenthesized_;
+ // Record whether the next (=== immediately following) function literal is
+ // preceded by a parenthesis / exclamation mark. Also record the previous
+ // state.
+ // These are managed by the FunctionState constructor; the caller may only
+ // call set_next_function_is_likely_called.
+ bool next_function_is_likely_called_;
+ bool previous_function_was_likely_called_;
friend Impl;
friend class Checkpoint;
@@ -593,7 +564,6 @@ class ParserBase {
struct DeclarationDescriptor {
enum Kind { NORMAL, PARAMETER };
Scope* scope;
- Scope* hoist_scope;
VariableMode mode;
int declaration_pos;
int initialization_pos;
@@ -633,7 +603,6 @@ class ParserBase {
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;
@@ -642,7 +611,6 @@ class ParserBase {
Scope* scope;
BlockT init_block;
BlockT inner_block;
- bool for_promise_reject;
ZoneList<const AstRawString*> bound_names;
TailCallExpressionList tail_call_expressions;
};
@@ -666,17 +634,17 @@ class ParserBase {
: 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) {}
+ has_name_static_property(false),
+ has_static_computed_names(false) {}
VariableProxy* proxy;
ExpressionT extends;
typename Types::ClassPropertyList properties;
- ExpressionListT instance_field_initializers;
FunctionLiteralT constructor;
bool has_seen_constructor;
- Variable* static_initializer_var;
+ bool has_name_static_property;
+ bool has_static_computed_names;
};
DeclarationScope* NewScriptScope() const {
@@ -712,10 +680,15 @@ class ParserBase {
return new (zone()) Scope(zone(), parent, scope_type);
}
- DeclarationScope* NewFunctionScope(FunctionKind kind) const {
+ // Creates a function scope that always allocates in zone(). The function
+ // scope itself is either allocated in zone() or in target_zone if one is
+ // passed in.
+ DeclarationScope* NewFunctionScope(FunctionKind kind,
+ Zone* target_zone = nullptr) const {
DCHECK(ast_value_factory());
- DeclarationScope* result =
- new (zone()) DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind);
+ if (target_zone == nullptr) target_zone = zone();
+ DeclarationScope* result = new (target_zone)
+ DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind);
// TODO(verwaest): Move into the DeclarationScope constructor.
if (!IsArrowFunction(kind)) {
result->DeclareDefaultFunctionVariables(ast_value_factory());
@@ -810,6 +783,7 @@ class ParserBase {
bool is_any_identifier(Token::Value token) {
return token == Token::IDENTIFIER || token == Token::ENUM ||
token == Token::AWAIT || token == Token::ASYNC ||
+ token == Token::ESCAPED_STRICT_RESERVED_WORD ||
token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::LET ||
token == Token::STATIC || token == Token::YIELD;
}
@@ -855,36 +829,39 @@ class ParserBase {
}
// Checks whether an octal literal was last seen between beg_pos and end_pos.
- // If so, reports an error. Only called for strict mode and template strings.
- void CheckOctalLiteral(int beg_pos, int end_pos,
- MessageTemplate::Template message, bool* ok) {
+ // Only called for strict mode strings.
+ void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
Scanner::Location octal = scanner()->octal_position();
if (octal.IsValid() && beg_pos <= octal.beg_pos &&
octal.end_pos <= end_pos) {
+ MessageTemplate::Template message = scanner()->octal_message();
+ DCHECK_NE(message, MessageTemplate::kNone);
impl()->ReportMessageAt(octal, message);
scanner()->clear_octal_position();
+ if (message == MessageTemplate::kStrictDecimalWithLeadingZero) {
+ impl()->CountUsage(v8::Isolate::kDecimalWithLeadingZeroInStrictMode);
+ }
*ok = false;
}
}
- // for now, this check just collects statistics.
- 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();
- impl()->CountUsage(v8::Isolate::kDecimalWithLeadingZeroInStrictMode);
- }
- }
- inline void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
- CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kStrictOctalLiteral,
- ok);
- }
+ // Checks if an octal literal or an invalid hex or unicode escape sequence
+ // appears in a template literal. In the presence of such, either
+ // returns false or reports an error, depending on should_throw. Otherwise
+ // returns true.
+ inline bool CheckTemplateEscapes(bool should_throw, bool* ok) {
+ if (!scanner()->has_invalid_template_escape()) {
+ return true;
+ }
- inline void CheckTemplateOctalLiteral(int beg_pos, int end_pos, bool* ok) {
- CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kTemplateOctalLiteral,
- ok);
+ // Handle error case(s)
+ if (should_throw) {
+ impl()->ReportMessageAt(scanner()->invalid_template_escape_location(),
+ scanner()->invalid_template_escape_message());
+ *ok = false;
+ }
+ scanner()->clear_invalid_template_escape();
+ return false;
}
void CheckDestructuringElement(ExpressionT element, int beg_pos, int end_pos);
@@ -1058,14 +1035,6 @@ class ParserBase {
}
}
- 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);
- }
-
void BindingPatternUnexpectedToken() {
MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
const char* arg;
@@ -1143,6 +1112,7 @@ class ParserBase {
kShorthandProperty,
kMethodProperty,
kClassField,
+ kSpreadProperty,
kNotSet
};
@@ -1154,11 +1124,13 @@ class ParserBase {
ExpressionT ParseObjectLiteral(bool* ok);
ClassLiteralPropertyT ParseClassPropertyDefinition(
ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name,
- bool* has_seen_constructor, bool* ok);
+ bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind,
+ bool* is_static, bool* has_name_static_property, bool* ok);
FunctionLiteralT ParseClassFieldForInitializer(bool has_initializer,
bool* ok);
ObjectLiteralPropertyT ParseObjectPropertyDefinition(
- ObjectLiteralChecker* checker, bool* is_computed_name, bool* ok);
+ ObjectLiteralChecker* checker, bool* is_computed_name,
+ bool* is_rest_property, bool* ok);
ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
bool maybe_arrow, bool* ok);
ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
@@ -1177,9 +1149,14 @@ class ParserBase {
ExpressionT ParseMemberExpression(bool* is_async, bool* ok);
ExpressionT ParseMemberExpressionContinuation(ExpressionT expression,
bool* is_async, bool* ok);
+
+ // `rewritable_length`: length of the destructuring_assignments_to_rewrite()
+ // queue in the parent function state, prior to parsing of formal parameters.
+ // If the arrow function is lazy, any items added during formal parameter
+ // parsing are removed from the queue.
ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
const FormalParametersT& parameters,
- bool* ok);
+ int rewritable_length, bool* ok);
void ParseAsyncFunctionBody(Scope* scope, StatementListT body,
FunctionKind kind, FunctionBodyType type,
bool accept_IN, int pos, bool* ok);
@@ -1188,8 +1165,10 @@ class ParserBase {
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 ParseTemplateLiteral(ExpressionT tag, int start, bool tagged,
+ bool* ok);
ExpressionT ParseSuperExpression(bool is_new, bool* ok);
+ ExpressionT ParseDynamicImportExpression(bool* ok);
ExpressionT ParseNewTargetExpression(bool* ok);
void ParseFormalParameter(FormalParametersT* parameters, bool* ok);
@@ -1214,6 +1193,12 @@ class ParserBase {
bool default_export, bool* ok);
StatementT ParseNativeDeclaration(bool* ok);
+ // Consumes the ending }.
+ void ParseFunctionBody(StatementListT result, IdentifierT function_name,
+ int pos, const FormalParametersT& parameters,
+ FunctionKind kind,
+ FunctionLiteral::FunctionType function_type, 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:
@@ -1234,6 +1219,9 @@ class ParserBase {
LazyParsingResult ParseStatementList(StatementListT body, int end_token,
bool may_abort, bool* ok);
StatementT ParseStatementListItem(bool* ok);
+ StatementT ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok) {
+ return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
+ }
StatementT ParseStatement(ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function,
bool* ok);
@@ -1244,11 +1232,8 @@ class ParserBase {
// 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);
+ bool* ok);
StatementT ParseVariableStatement(VariableDeclarationContext var_context,
ZoneList<const AstRawString*>* names,
@@ -1280,6 +1265,21 @@ class ParserBase {
bool* ok);
StatementT ParseTryStatement(bool* ok);
StatementT ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
+ StatementT ParseForEachStatementWithDeclarations(
+ int stmt_pos, ForInfo* for_info, ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ StatementT ParseForEachStatementWithoutDeclarations(
+ int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
+ ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok);
+
+ // Parse a C-style for loop: 'for (<init>; <cond>; <step>) { ... }'
+ StatementT ParseStandardForLoop(int stmt_pos, StatementT init,
+ bool bound_names_are_lexical,
+ ForInfo* for_info, BlockState* for_state,
+ ZoneList<const AstRawString*>* labels,
+ bool* ok);
+ StatementT ParseForAwaitStatement(ZoneList<const AstRawString*>* labels,
+ bool* ok);
bool IsNextLetKeyword();
bool IsTrivialExpression();
@@ -1309,6 +1309,24 @@ class ParserBase {
return expression->IsObjectLiteral() || expression->IsArrayLiteral();
}
+ // Due to hoisting, the value of a 'var'-declared variable may actually change
+ // even if the code contains only the "initial" assignment, namely when that
+ // assignment occurs inside a loop. For example:
+ //
+ // let i = 10;
+ // do { var x = i } while (i--):
+ //
+ // As a simple and very conservative approximation of this, we explicitly mark
+ // as maybe-assigned any non-lexical variable whose initializing "declaration"
+ // does not syntactically occur in the function scope. (In the example above,
+ // it occurs in a block scope.)
+ //
+ // Note that non-lexical variables include temporaries, which may also get
+ // assigned inside a loop due to the various rewritings that the parser
+ // performs.
+ //
+ static void MarkLoopVariableAsAssigned(Scope* scope, Variable* var);
+
// Keep track of eval() calls since they disable all local variable
// optimizations. This checks if expression is an eval call, and if yes,
// forwards the information to scope.
@@ -1327,6 +1345,15 @@ class ParserBase {
return Call::NOT_EVAL;
}
+ // Convenience method which determines the type of return statement to emit
+ // depending on the current function type.
+ inline StatementT BuildReturnStatement(ExpressionT expr, int pos) {
+ if (V8_UNLIKELY(is_async_function())) {
+ return factory()->NewAsyncReturnStatement(expr, pos);
+ }
+ return factory()->NewReturnStatement(expr, pos);
+ }
+
// Validation per ES6 object literals.
class ObjectLiteralChecker {
public:
@@ -1373,7 +1400,7 @@ class ParserBase {
ModuleDescriptor* module() const {
return scope()->AsModuleScope()->module();
}
- Scope* scope() const { return scope_state_->scope(); }
+ Scope* scope() const { return scope_; }
// Stack of expression classifiers.
// The top of the stack is always pointed to by classifier().
@@ -1416,13 +1443,14 @@ class ParserBase {
// Parser base's protected field members.
- ScopeState* scope_state_; // Scope stack.
+ Scope* scope_; // Scope stack.
FunctionState* function_state_; // Function state stack.
v8::Extension* extension_;
FuncNameInferrer* fni_;
AstValueFactory* ast_value_factory_; // Not owned.
typename Types::Factory ast_node_factory_;
RuntimeCallStats* runtime_call_stats_;
+ bool parsing_on_main_thread_;
bool parsing_module_;
uintptr_t stack_limit_;
@@ -1437,42 +1465,45 @@ class ParserBase {
FunctionLiteral::EagerCompileHint default_eager_compile_hint_;
- bool allow_lazy_;
+ int function_literal_id_;
+
bool allow_natives_;
bool allow_tailcalls_;
bool allow_harmony_do_expressions_;
bool allow_harmony_function_sent_;
- bool allow_harmony_async_await_;
bool allow_harmony_restrictive_generators_;
bool allow_harmony_trailing_commas_;
bool allow_harmony_class_fields_;
+ bool allow_harmony_object_rest_spread_;
+ bool allow_harmony_dynamic_import_;
+ bool allow_harmony_async_iteration_;
+ bool allow_harmony_template_escapes_;
friend class DiscardableZoneScope;
};
template <typename Impl>
ParserBase<Impl>::FunctionState::FunctionState(
- FunctionState** function_state_stack, ScopeState** scope_stack,
+ FunctionState** function_state_stack, Scope** scope_stack,
DeclarationScope* scope)
- : ScopeState(scope_stack, scope),
+ : BlockState(scope_stack, scope),
next_materialized_literal_index_(0),
expected_property_count_(0),
- generator_object_variable_(nullptr),
- promise_variable_(nullptr),
function_state_stack_(function_state_stack),
outer_function_state_(*function_state_stack),
+ scope_(scope),
destructuring_assignments_to_rewrite_(16, scope->zone()),
tail_call_expressions_(scope->zone()),
return_expr_context_(ReturnExprContext::kInsideValidBlock),
non_patterns_to_rewrite_(0, scope->zone()),
reported_errors_(16, scope->zone()),
- next_function_is_parenthesized_(false),
- this_function_is_parenthesized_(false) {
+ next_function_is_likely_called_(false),
+ previous_function_was_likely_called_(false) {
*function_state_stack = this;
if (outer_function_state_) {
- this_function_is_parenthesized_ =
- outer_function_state_->next_function_is_parenthesized_;
- outer_function_state_->next_function_is_parenthesized_ = false;
+ outer_function_state_->previous_function_was_likely_called_ =
+ outer_function_state_->next_function_is_likely_called_;
+ outer_function_state_->next_function_is_likely_called_ = false;
}
}
@@ -1594,7 +1625,7 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
}
if (classifier()->duplicate_finder() != nullptr &&
- scanner()->FindSymbol(classifier()->duplicate_finder(), 1) != 0) {
+ scanner()->FindSymbol(classifier()->duplicate_finder())) {
classifier()->RecordDuplicateFormalParameterError(scanner()->location());
}
return name;
@@ -1634,7 +1665,8 @@ ParserBase<Impl>::ParseIdentifierOrStrictReservedWord(
!IsAsyncFunction(function_kind)) ||
next == Token::ASYNC) {
*is_strict_reserved = false;
- } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
+ } else if (next == Token::ESCAPED_STRICT_RESERVED_WORD ||
+ next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
next == Token::STATIC ||
(next == Token::YIELD && !IsGeneratorFunction(function_kind))) {
*is_strict_reserved = true;
@@ -1676,8 +1708,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
return impl()->EmptyExpression();
}
- int literal_index = function_state_->NextMaterializedLiteralIndex();
-
IdentifierT js_pattern = impl()->GetNextSymbol();
Maybe<RegExp::Flags> flags = scanner()->ScanRegExpFlags();
if (flags.IsNothing()) {
@@ -1688,7 +1718,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
}
int js_flags = flags.FromJust();
Next();
- return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index, pos);
+ return factory()->NewRegExpLiteral(js_pattern, js_flags, pos);
}
template <typename Impl>
@@ -1728,8 +1758,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
return impl()->ExpressionFromLiteral(Next(), beg_pos);
case Token::ASYNC:
- if (allow_harmony_async_await() &&
- !scanner()->HasAnyLineTerminatorAfterNext() &&
+ if (!scanner()->HasAnyLineTerminatorAfterNext() &&
PeekAhead() == Token::FUNCTION) {
Consume(Token::ASYNC);
return ParseAsyncFunctionLiteral(CHECK_OK);
@@ -1789,8 +1818,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
}
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
- function_state_->set_next_function_is_parenthesized(peek() ==
- Token::FUNCTION);
+ if (peek() == Token::FUNCTION ||
+ (peek() == Token::ASYNC && PeekAhead() == Token::FUNCTION)) {
+ function_state_->set_next_function_is_likely_called();
+ }
ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
return expr;
@@ -1815,7 +1846,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL:
BindingPatternUnexpectedToken();
- return ParseTemplateLiteral(impl()->NoTemplateTag(), beg_pos, ok);
+ return ParseTemplateLiteral(impl()->NoTemplateTag(), beg_pos, false, ok);
case Token::MOD:
if (allow_natives() || extension_ != NULL) {
@@ -1902,6 +1933,13 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) {
// a trailing comma is allowed at the end of an arrow parameter list
break;
}
+
+ // Pass on the 'set_next_function_is_likely_called' flag if we have
+ // several function literals separated by comma.
+ if (peek() == Token::FUNCTION &&
+ function_state_->previous_function_was_likely_called()) {
+ function_state_->set_next_function_is_likely_called();
+ }
}
return result;
@@ -1958,11 +1996,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
}
Expect(Token::RBRACK, CHECK_OK);
- // Update the scope information before the pre-parsing bailout.
- int literal_index = function_state_->NextMaterializedLiteralIndex();
-
- ExpressionT result = factory()->NewArrayLiteral(values, first_spread_index,
- literal_index, pos);
+ ExpressionT result =
+ factory()->NewArrayLiteral(values, first_spread_index, pos);
if (first_spread_index >= 0) {
result = factory()->NewRewritableExpression(result);
impl()->QueueNonPatternForRewriting(result, ok);
@@ -2025,7 +2060,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
Token::Value token = peek();
int pos = peek_position();
- if (allow_harmony_async_await() && !*is_generator && token == Token::ASYNC &&
+ if (!*is_generator && token == Token::ASYNC &&
!scanner()->HasAnyLineTerminatorAfterNext()) {
Consume(Token::ASYNC);
token = peek();
@@ -2091,6 +2126,29 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
break;
}
+ case Token::ELLIPSIS:
+ if (allow_harmony_object_rest_spread()) {
+ *name = impl()->EmptyIdentifier();
+ Consume(Token::ELLIPSIS);
+ expression = ParseAssignmentExpression(true, CHECK_OK);
+ *kind = PropertyKind::kSpreadProperty;
+
+ if (expression->IsAssignment()) {
+ classifier()->RecordPatternError(
+ scanner()->location(),
+ MessageTemplate::kInvalidDestructuringTarget);
+ } else {
+ CheckDestructuringElement(expression, pos,
+ scanner()->location().end_pos);
+ }
+
+ if (peek() != Token::RBRACE) {
+ classifier()->RecordPatternError(scanner()->location(),
+ MessageTemplate::kElementAfterRest);
+ }
+ return expression;
+ }
+
default:
*name = ParseIdentifierName(CHECK_OK);
break;
@@ -2114,25 +2172,28 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
template <typename Impl>
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);
+ParserBase<Impl>::ParseClassPropertyDefinition(
+ ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name,
+ bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind,
+ bool* is_static, bool* has_name_static_property, bool* ok) {
+ DCHECK_NOT_NULL(has_seen_constructor);
+ DCHECK_NOT_NULL(has_name_static_property);
bool is_get = false;
bool is_set = false;
bool is_generator = false;
bool is_async = false;
- bool is_static = false;
+ *is_static = false;
+ *property_kind = ClassLiteralProperty::METHOD;
PropertyKind kind = PropertyKind::kNotSet;
Token::Value name_token = peek();
+ int function_token_position = scanner()->peek_location().beg_pos;
IdentifierT name = impl()->EmptyIdentifier();
ExpressionT name_expression;
if (name_token == Token::STATIC) {
Consume(Token::STATIC);
+ function_token_position = scanner()->peek_location().beg_pos;
if (peek() == Token::LPAREN) {
kind = PropertyKind::kMethodProperty;
name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
@@ -2142,7 +2203,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
name_expression = factory()->NewStringLiteral(name, position());
} else {
- is_static = true;
+ *is_static = true;
name_expression = ParsePropertyName(
&name, &kind, &is_generator, &is_get, &is_set, &is_async,
is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
@@ -2153,6 +2214,10 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
}
+ if (!*has_name_static_property && *is_static && impl()->IsName(name)) {
+ *has_name_static_property = true;
+ }
+
switch (kind) {
case PropertyKind::kClassField:
case PropertyKind::kNotSet: // This case is a name followed by a name or
@@ -2169,9 +2234,10 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
ExpressionT function_literal = ParseClassFieldForInitializer(
has_initializer, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
ExpectSemicolon(CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ *property_kind = ClassLiteralProperty::FIELD;
return factory()->NewClassLiteralProperty(
- name_expression, function_literal, ClassLiteralProperty::FIELD,
- is_static, *is_computed_name);
+ name_expression, function_literal, *property_kind, *is_static,
+ *is_computed_name);
} else {
ReportUnexpectedToken(Next());
*ok = false;
@@ -2188,7 +2254,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
if (!*is_computed_name) {
checker->CheckClassMethodName(
name_token, PropertyKind::kMethodProperty, is_generator, is_async,
- is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ *is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
}
FunctionKind kind = is_generator
@@ -2196,20 +2262,23 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
: is_async ? FunctionKind::kAsyncConciseMethod
: FunctionKind::kConciseMethod;
- if (!is_static && impl()->IsConstructor(name)) {
+ if (!*is_static && impl()->IsConstructor(name)) {
*has_seen_constructor = true;
- kind = has_extends ? FunctionKind::kSubclassConstructor
+ kind = has_extends ? FunctionKind::kDerivedConstructor
: FunctionKind::kBaseConstructor;
}
ExpressionT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
- language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ FLAG_harmony_function_tostring ? function_token_position
+ : kNoSourcePosition,
+ FunctionLiteral::kAccessorOrMethod, language_mode(),
+ CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ *property_kind = ClassLiteralProperty::METHOD;
return factory()->NewClassLiteralProperty(name_expression, value,
- ClassLiteralProperty::METHOD,
- is_static, *is_computed_name);
+ *property_kind, *is_static,
+ *is_computed_name);
}
case PropertyKind::kAccessorProperty: {
@@ -2218,7 +2287,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
if (!*is_computed_name) {
checker->CheckClassMethodName(
name_token, PropertyKind::kAccessorProperty, false, false,
- is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ *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.
@@ -2231,18 +2300,23 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
FunctionLiteralT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
- language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
+ FLAG_harmony_function_tostring ? function_token_position
+ : 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);
+ *property_kind =
+ is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER;
+ return factory()->NewClassLiteralProperty(name_expression, value,
+ *property_kind, *is_static,
+ *is_computed_name);
}
+ case PropertyKind::kSpreadProperty:
+ UNREACHABLE();
}
UNREACHABLE();
return impl()->EmptyClassLiteralProperty();
@@ -2257,9 +2331,8 @@ ParserBase<Impl>::ParseClassFieldForInitializer(bool has_initializer,
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);
+ FunctionState initializer_state(&function_state_, &scope_, initializer_scope);
+ DCHECK_EQ(initializer_scope, scope());
scope()->SetLanguageMode(STRICT);
ExpressionClassifier expression_classifier(this);
ExpressionT value;
@@ -2275,12 +2348,10 @@ ParserBase<Impl>::ParseClassFieldForInitializer(bool has_initializer,
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, 0,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression, default_eager_compile_hint_,
- initializer_scope->start_position(), true);
- function_literal->set_is_class_field_initializer(true);
+ initializer_scope->start_position(), true, GetNextFunctionLiteralId());
return function_literal;
}
@@ -2288,6 +2359,7 @@ template <typename Impl>
typename ParserBase<Impl>::ObjectLiteralPropertyT
ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
bool* is_computed_name,
+ bool* is_rest_property,
bool* ok) {
bool is_get = false;
bool is_set = false;
@@ -2305,6 +2377,19 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
is_computed_name, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
switch (kind) {
+ case PropertyKind::kSpreadProperty:
+ DCHECK(allow_harmony_object_rest_spread());
+ DCHECK(!is_get && !is_set && !is_generator && !is_async &&
+ !*is_computed_name);
+ DCHECK(name_token == Token::ELLIPSIS);
+
+ *is_computed_name = true;
+ *is_rest_property = true;
+
+ return factory()->NewObjectLiteralProperty(
+ impl()->GetLiteralTheHole(kNoSourcePosition), name_expression,
+ ObjectLiteralProperty::SPREAD, true);
+
case PropertyKind::kValueProperty: {
DCHECK(!is_get && !is_set && !is_generator && !is_async);
@@ -2347,7 +2432,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
DCHECK(!*is_computed_name);
if (classifier()->duplicate_finder() != nullptr &&
- scanner()->FindSymbol(classifier()->duplicate_finder(), 1) != 0) {
+ scanner()->FindSymbol(classifier()->duplicate_finder())) {
classifier()->RecordDuplicateFormalParameterError(
scanner()->location());
}
@@ -2411,8 +2496,9 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
ExpressionT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
- language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
+ FunctionLiteral::kAccessorOrMethod, language_mode(),
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
return factory()->NewObjectLiteralProperty(
name_expression, value, ObjectLiteralProperty::COMPUTED,
@@ -2440,8 +2526,9 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
FunctionLiteralT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- kNoSourcePosition, FunctionLiteral::kAccessorOrMethod,
- language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
+ FunctionLiteral::kAccessorOrMethod, language_mode(),
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (!*is_computed_name) {
impl()->AddAccessorPrefixToFunctionName(is_get, value, name);
@@ -2473,7 +2560,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
typename Types::ObjectPropertyList properties =
impl()->NewObjectPropertyList(4);
int number_of_boilerplate_properties = 0;
+
bool has_computed_names = false;
+ bool has_rest_property = false;
ObjectLiteralChecker checker(this);
Expect(Token::LBRACE, CHECK_OK);
@@ -2482,17 +2571,24 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
FuncNameInferrer::State fni_state(fni_);
bool is_computed_name = false;
- ObjectLiteralPropertyT property =
- ParseObjectPropertyDefinition(&checker, &is_computed_name, CHECK_OK);
+ bool is_rest_property = false;
+ ObjectLiteralPropertyT property = ParseObjectPropertyDefinition(
+ &checker, &is_computed_name, &is_rest_property, CHECK_OK);
if (is_computed_name) {
has_computed_names = true;
}
- // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
- if (!has_computed_names && impl()->IsBoilerplateProperty(property)) {
+ if (is_rest_property) {
+ has_rest_property = true;
+ }
+
+ if (impl()->IsBoilerplateProperty(property) && !has_computed_names) {
+ // Count CONSTANT or COMPUTED properties to maintain the enumeration
+ // order.
number_of_boilerplate_properties++;
}
+
properties->Add(property, zone());
if (peek() != Token::RBRACE) {
@@ -2504,13 +2600,18 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
}
Expect(Token::RBRACE, CHECK_OK);
- // Computation of literal_index must happen before pre parse bailout.
- int literal_index = function_state_->NextMaterializedLiteralIndex();
+ // In pattern rewriter, we rewrite rest property to call out to a
+ // runtime function passing all the other properties as arguments to
+ // this runtime function. Here, we make sure that the number of
+ // properties is less than number of arguments allowed for a runtime
+ // call.
+ if (has_rest_property && properties->length() > Code::kMaxArguments) {
+ this->classifier()->RecordPatternError(Scanner::Location(pos, position()),
+ MessageTemplate::kTooManyArguments);
+ }
- return factory()->NewObjectLiteral(properties,
- literal_index,
- number_of_boilerplate_properties,
- pos);
+ return factory()->NewObjectLiteral(
+ properties, number_of_boilerplate_properties, pos, has_rest_property);
}
template <typename Impl>
@@ -2523,8 +2624,6 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
ExpressionListT result = impl()->NewExpressionList(4);
Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList));
bool done = (peek() == Token::RPAREN);
- bool was_unspread = false;
- int unspread_sequences_count = 0;
while (!done) {
int start_pos = peek_position();
bool is_spread = Check(Token::ELLIPSIS);
@@ -2544,15 +2643,6 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
}
result->Add(argument, zone_);
- // unspread_sequences_count is the number of sequences of parameters which
- // are not prefixed with a spread '...' operator.
- if (is_spread) {
- was_unspread = false;
- } else if (!was_unspread) {
- was_unspread = true;
- unspread_sequences_count++;
- }
-
if (result->length() > Code::kMaxArguments) {
ReportMessage(MessageTemplate::kTooManyArguments);
*ok = false;
@@ -2579,12 +2669,6 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
if (maybe_arrow) {
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
- impl()->MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
- }
}
return result;
@@ -2611,8 +2695,10 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
this, classifier()->duplicate_finder());
Scope::Snapshot scope_snapshot(scope());
+ int rewritable_length =
+ function_state_->destructuring_assignments_to_rewrite().length();
- bool is_async = allow_harmony_async_await() && peek() == Token::ASYNC &&
+ bool is_async = peek() == Token::ASYNC &&
!scanner()->HasAnyLineTerminatorAfterNext() &&
IsValidArrowFormalParametersStart(PeekAhead());
@@ -2664,6 +2750,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
this->scope()->PropagateUsageFlagsToScope(scope);
scope_snapshot.Reparent(scope);
+ function_state_->SetDestructuringAssignmentsScope(rewritable_length, scope);
FormalParametersT parameters(scope);
if (!classifier()->is_simple_parameter_list()) {
@@ -2680,7 +2767,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
if (duplicate_loc.IsValid()) {
classifier()->RecordDuplicateFormalParameterError(duplicate_loc);
}
- expression = ParseArrowFunctionLiteral(accept_IN, parameters, CHECK_OK);
+ expression = ParseArrowFunctionLiteral(accept_IN, parameters,
+ rewritable_length, CHECK_OK);
impl()->Discard();
classifier()->RecordPatternError(arrow_loc,
MessageTemplate::kUnexpectedToken,
@@ -2732,7 +2820,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
}
- expression = impl()->MarkExpressionAsAssigned(expression);
+ impl()->MarkExpressionAsAssigned(expression);
Token::Value op = Next(); // Get assignment operator.
if (op != Token::ASSIGN) {
@@ -2944,6 +3032,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
op = Next();
int pos = position();
+
+ // Assume "! function ..." indicates the function is likely to be called.
+ if (op == Token::NOT && peek() == Token::FUNCTION) {
+ function_state_->set_next_function_is_likely_called();
+ }
+
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
@@ -2973,7 +3067,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
expression = CheckAndRewriteReferenceExpression(
expression, beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
- expression = impl()->MarkExpressionAsAssigned(expression);
+ impl()->MarkExpressionAsAssigned(expression);
impl()->RewriteNonPattern(CHECK_OK);
return factory()->NewCountOperation(op,
@@ -3013,7 +3107,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
expression = CheckAndRewriteReferenceExpression(
expression, lhs_beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
- expression = impl()->MarkExpressionAsAssigned(expression);
+ impl()->MarkExpressionAsAssigned(expression);
impl()->RewriteNonPattern(CHECK_OK);
Token::Value next = Next();
@@ -3119,8 +3213,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
bool is_super_call = result->IsSuperCallReference();
if (spread_pos.IsValid()) {
- args = impl()->PrepareSpreadArguments(args);
- result = impl()->SpreadCall(result, args, pos);
+ result = impl()->SpreadCall(result, args, pos, is_possibly_eval);
} else {
result = factory()->NewCall(result, args, pos, is_possibly_eval);
}
@@ -3128,7 +3221,6 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
// Explicit calls to the super constructor using super() perform an
// implicit binding assignment to the 'this' variable.
if (is_super_call) {
- result = impl()->RewriteSuperCall(result);
ExpressionT this_expr = impl()->ThisExpression(pos);
result =
factory()->NewAssignment(Token::INIT, this_expr, result, pos);
@@ -3156,7 +3248,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
impl()->RewriteNonPattern(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
- result = ParseTemplateLiteral(result, position(), CHECK_OK);
+ result = ParseTemplateLiteral(result, position(), true, CHECK_OK);
break;
}
@@ -3199,6 +3291,11 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
if (peek() == Token::SUPER) {
const bool is_new = true;
result = ParseSuperExpression(is_new, CHECK_OK);
+ } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) {
+ impl()->ReportMessageAt(scanner()->peek_location(),
+ MessageTemplate::kImportCallNotNewExpression);
+ *ok = false;
+ return impl()->EmptyExpression();
} else if (peek() == Token::PERIOD) {
return ParseNewTargetExpression(CHECK_OK);
} else {
@@ -3211,7 +3308,6 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK);
if (spread_pos.IsValid()) {
- args = impl()->PrepareSpreadArguments(args);
result = impl()->SpreadCallNew(result, args, new_pos);
} else {
result = factory()->NewCallNew(result, args, new_pos);
@@ -3233,7 +3329,11 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
// MemberExpression ::
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
-
+ //
+ // CallExpression ::
+ // (SuperCall | ImportCall)
+ // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
+ //
// The '[' Expression ']' and '.' Identifier parts are parsed by
// ParseMemberExpressionContinuation, and the Arguments part is parsed by the
// caller.
@@ -3271,7 +3371,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
Scanner::Location function_name_location = Scanner::Location::invalid();
FunctionLiteral::FunctionType function_type =
FunctionLiteral::kAnonymousExpression;
- if (peek_any_identifier()) {
+ if (impl()->ParsingDynamicFunctionDeclaration()) {
+ // We don't want dynamic functions to actually declare their name
+ // "anonymous". We just want that name in the toString().
+ Consume(Token::IDENTIFIER);
+ DCHECK(scanner()->UnescapedLiteralMatches("anonymous", 9));
+ } else if (peek_any_identifier()) {
name = ParseIdentifierOrStrictReservedWord(
function_kind, &is_strict_reserved_name, CHECK_OK);
function_name_location = scanner()->location();
@@ -3286,6 +3391,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
} else if (peek() == Token::SUPER) {
const bool is_new = false;
result = ParseSuperExpression(is_new, CHECK_OK);
+ } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) {
+ result = ParseDynamicImportExpression(CHECK_OK);
} else {
result = ParsePrimaryExpression(is_async, CHECK_OK);
}
@@ -3295,6 +3402,20 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
}
template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseDynamicImportExpression(bool* ok) {
+ DCHECK(allow_harmony_dynamic_import());
+ Consume(Token::IMPORT);
+ int pos = position();
+ Expect(Token::LPAREN, CHECK_OK);
+ ExpressionT arg = ParseAssignmentExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+ ZoneList<ExpressionT>* args = new (zone()) ZoneList<ExpressionT>(1, zone());
+ args->Add(arg, zone());
+ return factory()->NewCallRuntime(Runtime::kDynamicImportCall, args, pos);
+}
+
+template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
bool is_new, bool* ok) {
Expect(Token::SUPER, CHECK_OK);
@@ -3310,7 +3431,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
}
// new super() is never allowed.
// super() is only allowed in derived constructor
- if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) {
+ if (!is_new && peek() == Token::LPAREN && IsDerivedConstructor(kind)) {
// TODO(rossberg): This might not be the correct FunctionState for the
// method here.
return impl()->NewSuperCallReference(pos);
@@ -3407,7 +3528,7 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
expression->AsFunctionLiteral()->SetShouldEagerCompile();
}
}
- expression = ParseTemplateLiteral(expression, pos, CHECK_OK);
+ expression = ParseTemplateLiteral(expression, pos, true, CHECK_OK);
break;
}
case Token::ILLEGAL: {
@@ -3501,10 +3622,7 @@ void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters,
}
}
- for (int i = 0; i < parameters->arity; ++i) {
- auto parameter = parameters->at(i);
- impl()->DeclareFormalParameter(parameters->scope, parameter);
- }
+ impl()->DeclareFormalParameters(parameters->scope, parameters->params);
}
template <typename Impl>
@@ -3551,12 +3669,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
}
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.
@@ -3725,8 +3838,22 @@ ParserBase<Impl>::ParseHoistableDeclaration(
pos, FunctionLiteral::kDeclaration, language_mode(),
CHECK_OK_CUSTOM(NullStatement));
- return impl()->DeclareFunction(variable_name, function, pos, is_generator,
- is_async, names, ok);
+ // In ES6, a function behaves as a lexical binding, except in
+ // a script scope, or the initial scope of eval or another function.
+ VariableMode mode =
+ (!scope()->is_declaration_scope() || scope()->is_module_scope()) ? LET
+ : VAR;
+ // Async functions don't undergo sloppy mode block scoped hoisting, and don't
+ // allow duplicates in a block. Both are represented by the
+ // sloppy_block_function_map. Don't add them to the map for async functions.
+ // Generators are also supposed to be prohibited; currently doing this behind
+ // a flag and UseCounting violations to assess web compatibility.
+ bool is_sloppy_block_function =
+ is_sloppy(language_mode()) && !scope()->is_declaration_scope() &&
+ !is_async && !(allow_harmony_restrictive_generators() && is_generator);
+
+ return impl()->DeclareFunction(variable_name, function, mode, pos,
+ is_sloppy_block_function, names, ok);
}
template <typename Impl>
@@ -3815,6 +3942,107 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration(
}
template <typename Impl>
+void ParserBase<Impl>::ParseFunctionBody(
+ typename ParserBase<Impl>::StatementListT result, IdentifierT function_name,
+ int pos, const FormalParametersT& parameters, FunctionKind kind,
+ FunctionLiteral::FunctionType function_type, bool* ok) {
+ static const int kFunctionNameAssignmentIndex = 0;
+ if (function_type == FunctionLiteral::kNamedExpression) {
+ DCHECK(!impl()->IsEmptyIdentifier(function_name));
+ // If we have a named function expression, we add a local variable
+ // declaration to the body of the function with the name of the
+ // function and let it refer to the function itself (closure).
+ // Not having parsed the function body, the language mode may still change,
+ // so we reserve a spot and create the actual const assignment later.
+ DCHECK_EQ(kFunctionNameAssignmentIndex, result->length());
+ result->Add(impl()->NullStatement(), zone());
+ }
+
+ DeclarationScope* function_scope = scope()->AsDeclarationScope();
+ DeclarationScope* inner_scope = function_scope;
+ BlockT inner_block = impl()->NullBlock();
+
+ StatementListT body = result;
+ if (!parameters.is_simple) {
+ inner_scope = NewVarblockScope();
+ inner_scope->set_start_position(scanner()->location().beg_pos);
+ inner_block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition);
+ inner_block->set_scope(inner_scope);
+ body = inner_block->statements();
+ }
+
+ {
+ BlockState block_state(&scope_, inner_scope);
+
+ if (IsGeneratorFunction(kind)) {
+ impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body, ok);
+ } else if (IsAsyncFunction(kind)) {
+ const bool accept_IN = true;
+ ParseAsyncFunctionBody(inner_scope, body, kind, FunctionBodyType::kNormal,
+ accept_IN, pos, CHECK_OK_VOID);
+ } else {
+ ParseStatementList(body, Token::RBRACE, CHECK_OK_VOID);
+ }
+
+ if (IsDerivedConstructor(kind)) {
+ body->Add(factory()->NewReturnStatement(impl()->ThisExpression(),
+ kNoSourcePosition),
+ zone());
+ }
+ }
+
+ Expect(Token::RBRACE, CHECK_OK_VOID);
+ scope()->set_end_position(scanner()->location().end_pos);
+
+ if (!parameters.is_simple) {
+ DCHECK_NOT_NULL(inner_scope);
+ DCHECK_EQ(function_scope, scope());
+ DCHECK_EQ(function_scope, inner_scope->outer_scope());
+ impl()->SetLanguageMode(function_scope, inner_scope->language_mode());
+ BlockT init_block =
+ impl()->BuildParameterInitializationBlock(parameters, CHECK_OK_VOID);
+
+ if (is_sloppy(inner_scope->language_mode())) {
+ impl()->InsertSloppyBlockFunctionVarBindings(inner_scope);
+ }
+
+ // TODO(littledan): Merge the two rejection blocks into one
+ if (IsAsyncFunction(kind)) {
+ init_block = impl()->BuildRejectPromiseOnException(init_block);
+ }
+
+ inner_scope->set_end_position(scanner()->location().end_pos);
+ if (inner_scope->FinalizeBlockScope() != nullptr) {
+ impl()->CheckConflictingVarDeclarations(inner_scope, CHECK_OK_VOID);
+ impl()->InsertShadowingVarBindingInitializers(inner_block);
+ } else {
+ inner_block->set_scope(nullptr);
+ }
+ inner_scope = nullptr;
+
+ result->Add(init_block, zone());
+ result->Add(inner_block, zone());
+ } else {
+ DCHECK_EQ(inner_scope, function_scope);
+ if (is_sloppy(function_scope->language_mode())) {
+ impl()->InsertSloppyBlockFunctionVarBindings(function_scope);
+ }
+ }
+
+ if (!IsArrowFunction(kind)) {
+ // Declare arguments after parsing the function since lexical 'arguments'
+ // masks the arguments object. Declare arguments before declaring the
+ // function var since the arguments object masks 'function arguments'.
+ function_scope->DeclareArguments(ast_value_factory());
+ }
+
+ impl()->CreateFunctionNameAssignment(function_name, pos, function_type,
+ function_scope, result,
+ kFunctionNameAssignmentIndex);
+ impl()->MarkCollectedTailCallExpressions();
+}
+
+template <typename Impl>
void ParserBase<Impl>::CheckArityRestrictions(int param_count,
FunctionKind function_kind,
bool has_rest,
@@ -3889,11 +4117,16 @@ bool ParserBase<Impl>::IsTrivialExpression() {
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseArrowFunctionLiteral(
- bool accept_IN, const FormalParametersT& formal_parameters, bool* ok) {
+ bool accept_IN, const FormalParametersT& formal_parameters,
+ int rewritable_length, bool* ok) {
+ const RuntimeCallStats::CounterId counters[2][2] = {
+ {&RuntimeCallStats::ParseBackgroundArrowFunctionLiteral,
+ &RuntimeCallStats::ParseArrowFunctionLiteral},
+ {&RuntimeCallStats::PreParseBackgroundArrowFunctionLiteral,
+ &RuntimeCallStats::PreParseArrowFunctionLiteral}};
RuntimeCallTimerScope runtime_timer(
runtime_call_stats_,
- Impl::IsPreParser() ? &RuntimeCallStats::ParseArrowFunctionLiteral
- : &RuntimeCallStats::PreParseArrowFunctionLiteral);
+ counters[Impl::IsPreParser()][parsing_on_main_thread_]);
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
// ASI inserts `;` after arrow parameters if a line terminator is found.
@@ -3905,8 +4138,8 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
}
StatementListT body = impl()->NullStatementList();
- int materialized_literal_count = -1;
int expected_property_count = -1;
+ int function_literal_id = GetNextFunctionLiteralId();
FunctionKind kind = formal_parameters.scope->function_kind();
FunctionLiteral::EagerCompileHint eager_compile_hint =
@@ -3920,14 +4153,9 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
bool should_be_used_once_hint = false;
bool has_braces = true;
{
- FunctionState function_state(&function_state_, &scope_state_,
+ FunctionState function_state(&function_state_, &scope_,
formal_parameters.scope);
- function_state.SkipMaterializedLiterals(
- formal_parameters.materialized_literals_count);
-
- impl()->ReindexLiterals(formal_parameters);
-
Expect(Token::ARROW, CHECK_OK);
if (peek() == Token::LBRACE) {
@@ -3948,16 +4176,10 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
LazyParsingResult result = impl()->SkipFunction(
kind, formal_parameters.scope, &dummy_num_parameters,
&dummy_function_length, &dummy_has_duplicate_parameters,
- &materialized_literal_count, &expected_property_count, false, true,
- CHECK_OK);
+ &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;
- }
-
if (result == kLazyParsingAborted) {
bookmark.Apply();
// Trigger eager (re-)parsing, just below this block.
@@ -3972,11 +4194,11 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
}
if (!is_lazy_top_level_function) {
Consume(Token::LBRACE);
- body = impl()->ParseEagerFunctionBody(
- impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters,
- kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
- materialized_literal_count =
- function_state.materialized_literal_count();
+ body = impl()->NewStatementList(8);
+ impl()->ParseFunctionBody(body, impl()->EmptyIdentifier(),
+ kNoSourcePosition, formal_parameters, kind,
+ FunctionLiteral::kAnonymousExpression,
+ CHECK_OK);
expected_property_count = function_state.expected_property_count();
}
} else {
@@ -3999,15 +4221,13 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
} else {
ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
- body->Add(
- factory()->NewReturnStatement(expression, expression->position()),
- zone());
+ body->Add(BuildReturnStatement(expression, expression->position()),
+ zone());
if (allow_tailcalls() && !is_sloppy(language_mode())) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
impl()->MarkTailPosition(expression);
}
}
- materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
impl()->MarkCollectedTailCallExpressions();
}
@@ -4029,6 +4249,14 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
}
impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
+ if (is_lazy_top_level_function) {
+ FunctionState* parent_state = function_state.outer();
+ DCHECK_NOT_NULL(parent_state);
+ DCHECK_GE(parent_state->destructuring_assignments_to_rewrite().length(),
+ rewritable_length);
+ parent_state->RewindDestructuringAssignments(rewritable_length);
+ }
+
impl()->RewriteDestructuringAssignments();
}
@@ -4040,11 +4268,12 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
}
FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
impl()->EmptyIdentifierString(), formal_parameters.scope, body,
- materialized_literal_count, expected_property_count,
- formal_parameters.num_parameters(), formal_parameters.function_length,
+ expected_property_count, formal_parameters.num_parameters(),
+ formal_parameters.function_length,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression, eager_compile_hint,
- formal_parameters.scope->start_position(), has_braces);
+ formal_parameters.scope->start_position(), has_braces,
+ function_literal_id);
function_literal->set_function_token_position(
formal_parameters.scope->start_position());
@@ -4075,21 +4304,18 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
return impl()->EmptyExpression();
}
- BlockState block_state(zone(), &scope_state_);
+ BlockState block_state(zone(), &scope_);
RaiseLanguageMode(STRICT);
ClassInfo class_info(this);
- impl()->DeclareClassVariable(name, block_state.scope(), &class_info,
- class_token_pos, CHECK_OK);
+ impl()->DeclareClassVariable(name, &class_info, class_token_pos, CHECK_OK);
+ scope()->set_start_position(scanner()->location().end_pos);
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);
@@ -4102,14 +4328,26 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
FuncNameInferrer::State fni_state(fni_);
bool is_computed_name = false; // Classes do not care about computed
// property names here.
+ bool is_static;
+ ClassLiteralProperty::Kind property_kind;
ExpressionClassifier property_classifier(this);
+ // If we haven't seen the constructor yet, it potentially is the next
+ // property.
+ bool is_constructor = !class_info.has_seen_constructor;
ClassLiteralPropertyT property = ParseClassPropertyDefinition(
&checker, has_extends, &is_computed_name,
- &class_info.has_seen_constructor, CHECK_OK);
+ &class_info.has_seen_constructor, &property_kind, &is_static,
+ &class_info.has_name_static_property, CHECK_OK);
+ if (!class_info.has_static_computed_names && is_static &&
+ is_computed_name) {
+ class_info.has_static_computed_names = true;
+ }
+ is_constructor &= class_info.has_seen_constructor;
impl()->RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
- impl()->DeclareClassProperty(name, property, &class_info, CHECK_OK);
+ impl()->DeclareClassProperty(name, property, property_kind, is_static,
+ is_constructor, &class_info, CHECK_OK);
impl()->InferFunctionName();
}
@@ -4123,8 +4361,6 @@ void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body,
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);
@@ -4160,7 +4396,12 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
IdentifierT name = impl()->EmptyIdentifier();
FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
- if (peek_any_identifier()) {
+ if (impl()->ParsingDynamicFunctionDeclaration()) {
+ // We don't want dynamic functions to actually declare their name
+ // "anonymous". We just want that name in the toString().
+ Consume(Token::IDENTIFIER);
+ DCHECK(scanner()->UnescapedLiteralMatches("anonymous", 9));
+ } else if (peek_any_identifier()) {
type = FunctionLiteral::kNamedExpression;
name = ParseIdentifierOrStrictReservedWord(FunctionKind::kAsyncFunction,
&is_strict_reserved, CHECK_OK);
@@ -4174,7 +4415,7 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
- ExpressionT tag, int start, bool* ok) {
+ ExpressionT tag, int start, bool tagged, 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.
@@ -4187,22 +4428,25 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
// TEMPLATE_SPAN, or a TEMPLATE_TAIL.
CHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL);
+ bool forbid_illegal_escapes = !allow_harmony_template_escapes() || !tagged;
+
// If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate.
// In this case we may simply consume the token and build a template with a
// single TEMPLATE_SPAN and no expressions.
if (peek() == Token::TEMPLATE_TAIL) {
Consume(Token::TEMPLATE_TAIL);
int pos = position();
- CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos);
- impl()->AddTemplateSpan(&ts, true);
+ bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK);
+ impl()->AddTemplateSpan(&ts, is_valid, true);
return impl()->CloseTemplateLiteral(&ts, start, tag);
}
Consume(Token::TEMPLATE_SPAN);
int pos = position();
typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos);
- impl()->AddTemplateSpan(&ts, false);
+ bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK);
+ impl()->AddTemplateSpan(&ts, is_valid, false);
Token::Value next;
// If we open with a TEMPLATE_SPAN, we must scan the subsequent expression,
@@ -4210,7 +4454,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
// case, representing a TemplateMiddle).
do {
- CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
next = peek();
if (next == Token::EOS) {
impl()->ReportMessageAt(Scanner::Location(start, peek_position()),
@@ -4256,11 +4499,11 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
return impl()->EmptyExpression();
}
- impl()->AddTemplateSpan(&ts, next == Token::TEMPLATE_TAIL);
+ bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK);
+ impl()->AddTemplateSpan(&ts, is_valid, next == Token::TEMPLATE_TAIL);
} while (next == Token::TEMPLATE_SPAN);
DCHECK_EQ(next, Token::TEMPLATE_TAIL);
- CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
// Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
return impl()->CloseTemplateLiteral(&ts, start, tag);
}
@@ -4291,7 +4534,12 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression(
}
if (expression->IsCall()) {
// If it is a call, make it a runtime error for legacy web compatibility.
+ // Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480
// Rewrite `expr' to `expr[throw ReferenceError]'.
+ impl()->CountUsage(
+ is_strict(language_mode())
+ ? v8::Isolate::kAssigmentExpressionLHSIsCallInStrict
+ : v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy);
ExpressionT error = impl()->NewThrowReferenceError(message, beg_pos);
return factory()->NewProperty(expression, error, beg_pos);
}
@@ -4473,7 +4721,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem(
}
break;
case Token::ASYNC:
- if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
+ if (PeekAhead() == Token::FUNCTION &&
!scanner()->HasAnyLineTerminatorAfterNext()) {
Consume(Token::ASYNC);
return ParseAsyncFunctionDeclaration(nullptr, false, ok);
@@ -4525,6 +4773,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
case Token::WHILE:
return ParseWhileStatement(labels, ok);
case Token::FOR:
+ if (V8_UNLIKELY(allow_harmony_async_iteration() && is_async_function() &&
+ PeekAhead() == Token::AWAIT)) {
+ return ParseForAwaitStatement(labels, ok);
+ }
return ParseForStatement(labels, ok);
case Token::CONTINUE:
case Token::BREAK:
@@ -4607,8 +4859,8 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
// 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);
+ BlockState block_state(zone(), &scope_);
+ scope()->set_start_position(scanner()->location().beg_pos);
typename Types::Target target(this, body);
while (peek() != Token::RBRACE) {
@@ -4619,30 +4871,27 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
}
Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullBlock));
- block_state.set_end_position(scanner()->location().end_pos);
- body->set_scope(block_state.FinalizedBlockScope());
+ scope()->set_end_position(scanner()->location().end_pos);
+ body->set_scope(scope()->FinalizeBlockScope());
}
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) {
- return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ if (is_strict(language_mode()) || peek() != Token::FUNCTION) {
+ return ParseStatement(labels, 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);
+ BlockState block_state(zone(), &scope_);
+ scope()->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());
+ scope()->set_end_position(scanner()->location().end_pos);
+ block->set_scope(scope()->FinalizeBlockScope());
return block;
}
}
@@ -4710,6 +4959,19 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
ReportUnexpectedToken(Next());
*ok = false;
return impl()->NullStatement();
+ case Token::LET: {
+ Token::Value next_next = PeekAhead();
+ // "let" followed by either "[", "{" or an identifier means a lexical
+ // declaration, which should not appear here.
+ if (next_next != Token::LBRACK && next_next != Token::LBRACE &&
+ next_next != Token::IDENTIFIER) {
+ break;
+ }
+ impl()->ReportMessageAt(scanner()->peek_location(),
+ MessageTemplate::kUnexpectedLexicalDeclaration);
+ *ok = false;
+ return impl()->NullStatement();
+ }
default:
break;
}
@@ -4724,14 +4986,11 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
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);
- }
+ if (peek() == Token::FUNCTION && is_sloppy(language_mode()) &&
+ allow_function == kAllowLabelledFunctionStatement) {
+ return ParseFunctionDeclaration(ok);
}
- return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
+ return ParseStatement(labels, ok);
}
// If we have an extension, we allow a native function declaration.
@@ -4759,10 +5018,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
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 then_statement = ParseScopedStatement(labels, CHECK_OK);
StatementT else_statement = impl()->NullStatement();
if (Check(Token::ELSE)) {
- else_statement = ParseScopedStatement(labels, false, CHECK_OK);
+ else_statement = ParseScopedStatement(labels, CHECK_OK);
} else {
else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
}
@@ -4866,13 +5125,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
ExpressionT return_value = impl()->EmptyExpression();
if (scanner()->HasAnyLineTerminatorBeforeNext() || tok == Token::SEMICOLON ||
tok == Token::RBRACE || tok == Token::EOS) {
- if (IsSubclassConstructor(function_state_->kind())) {
+ if (IsDerivedConstructor(function_state_->kind())) {
return_value = impl()->ThisExpression(loc.beg_pos);
} else {
return_value = impl()->GetLiteralUndefined(position());
}
} else {
- if (IsSubclassConstructor(function_state_->kind())) {
+ if (IsDerivedConstructor(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.
@@ -4890,7 +5149,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
}
ExpectSemicolon(CHECK_OK);
return_value = impl()->RewriteReturn(return_value, loc.beg_pos);
- return factory()->NewReturnStatement(return_value, loc.beg_pos);
+ return BuildReturnStatement(return_value, loc.beg_pos);
}
template <typename Impl>
@@ -4915,9 +5174,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
Scope* with_scope = NewScope(WITH_SCOPE);
StatementT body = impl()->NullStatement();
{
- BlockState block_state(&scope_state_, with_scope);
+ BlockState block_state(&scope_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos);
- body = ParseScopedStatement(labels, true, CHECK_OK);
+ body = ParseStatement(labels, CHECK_OK);
with_scope->set_end_position(scanner()->location().end_pos);
}
return factory()->NewWithStatement(with_scope, expr, body, pos);
@@ -4933,7 +5192,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
typename Types::Target target(this, loop);
Expect(Token::DO, CHECK_OK);
- StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
+ StatementT body = ParseStatement(nullptr, CHECK_OK);
Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
@@ -4963,7 +5222,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
Expect(Token::LPAREN, CHECK_OK);
ExpressionT cond = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
+ StatementT body = ParseStatement(nullptr, CHECK_OK);
loop->Initialize(cond, body);
return loop;
@@ -5007,9 +5266,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
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();
+ BlockState cases_block_state(zone(), &scope_);
+ scope()->set_start_position(switch_pos);
+ scope()->SetNonlinear();
typename Types::Target target(this, switch_statement);
bool default_seen = false;
@@ -5042,9 +5301,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
}
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());
+ scope()->set_end_position(scanner()->location().end_pos);
+ return impl()->RewriteSwitchStatement(tag, switch_statement, cases,
+ scope()->FinalizeBlockScope());
}
}
@@ -5073,7 +5332,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
}
CatchInfo catch_info(this);
- catch_info.for_promise_reject = allow_natives() && Check(Token::MOD);
if (peek() != Token::CATCH && peek() != Token::FINALLY) {
ReportMessage(MessageTemplate::kNoCatchOrFinally);
@@ -5091,16 +5349,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
CollectExpressionsInTailPositionToListScope
collect_tail_call_expressions_scope(
function_state_, &catch_info.tail_call_expressions);
- BlockState catch_block_state(&scope_state_, catch_info.scope);
+ BlockState catch_block_state(&scope_, 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);
+ BlockState catch_variable_block_state(zone(), &scope_);
+ scope()->set_start_position(scanner()->location().beg_pos);
typename Types::Target target(this, catch_block);
// This does not simply call ParsePrimaryExpression to avoid
@@ -5125,10 +5382,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
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());
+ scope()->set_end_position(scanner()->location().end_pos);
+ catch_block->set_scope(scope()->FinalizeBlockScope());
}
}
@@ -5153,180 +5408,198 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
bool bound_names_are_lexical = false;
// Create an in-between scope for let-bound iteration variables.
- BlockState for_state(zone(), &scope_state_);
+ BlockState for_state(zone(), &scope_);
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
- for_state.set_start_position(scanner()->location().beg_pos);
- for_state.set_is_hidden();
+ scope()->set_start_position(scanner()->location().beg_pos);
+ scope()->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.position = scanner()->location().beg_pos;
-
- 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))) {
- 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);
+ 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.position = scanner()->location().beg_pos;
+
+ if (CheckInOrOf(&for_info.mode)) {
+ return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels,
+ ok);
+ }
+
+ // 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 if (peek() != Token::SEMICOLON) {
+ // The initializer does not contain declarations.
+ int lhs_beg_pos = peek_position();
+ ExpressionClassifier classifier(this);
+ ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK);
+ int lhs_end_pos = 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);
+ }
- auto loop =
- factory()->NewForEachStatement(for_info.mode, labels, stmt_pos);
- typename Types::Target target(this, loop);
+ if (is_for_each) {
+ return ParseForEachStatementWithoutDeclarations(stmt_pos, expression,
+ lhs_beg_pos, lhs_end_pos,
+ &for_info, labels, ok);
+ }
+ // Initializer is just an expression.
+ init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
+ }
- int each_keyword_pos = scanner()->location().beg_pos;
+ // Standard 'for' loop, we have parsed the initializer at this point.
+ return ParseStandardForLoop(stmt_pos, init, bound_names_are_lexical,
+ &for_info, &for_state, labels, ok);
+}
- 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);
- }
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseForEachStatementWithDeclarations(
+ int stmt_pos, ForInfo* for_info, ZoneList<const AstRawString*>* labels,
+ bool* ok) {
+ // 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 ||
+ IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) ||
+ !impl()->IsIdentifier(
+ for_info->parsing_result.declarations[0].pattern))) {
+ impl()->ReportMessageAt(for_info->parsing_result.first_initializer_loc,
+ MessageTemplate::kForInOfLoopInitializer,
+ ForEachStatement::VisitModeString(for_info->mode));
+ *ok = false;
+ return impl()->NullStatement();
+ }
- Expect(Token::RPAREN, CHECK_OK);
+ BlockT init_block = impl()->RewriteForVarInLegacy(*for_info);
- 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());
- }
+ auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos);
+ typename Types::Target target(this, loop);
- init_block =
- impl()->CreateForEachStatementTDZ(init_block, for_info, ok);
+ int each_keyword_pos = scanner()->location().beg_pos;
- 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;
+ 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);
+ }
- bool is_for_each = CheckInOrOf(&for_info.mode);
- bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
- expression->IsObjectLiteral());
+ Expect(Token::RPAREN, CHECK_OK);
- if (is_destructuring) {
- ValidateAssignmentPattern(CHECK_OK);
- } else {
- impl()->RewriteNonPattern(CHECK_OK);
- }
+ StatementT final_loop = impl()->NullStatement();
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
+ BlockState block_state(zone(), &scope_);
+ scope()->set_start_position(scanner()->location().beg_pos);
- 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);
- }
+ StatementT body = ParseStatement(nullptr, CHECK_OK);
- auto loop =
- factory()->NewForEachStatement(for_info.mode, labels, stmt_pos);
- typename Types::Target target(this, loop);
+ 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);
- int each_keyword_pos = scanner()->location().beg_pos;
+ scope()->set_end_position(scanner()->location().end_pos);
+ body_block->set_scope(scope()->FinalizeBlockScope());
+ }
- 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);
- }
+ init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, ok);
- Expect(Token::RPAREN, CHECK_OK);
+ scope()->set_end_position(scanner()->location().end_pos);
+ Scope* for_scope = scope()->FinalizeBlockScope();
+ // 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;
+ }
- {
- 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);
- }
- }
+ DCHECK_NULL(for_scope);
+ return final_loop;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT
+ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
+ int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
+ ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) {
+ // Initializer is reference followed by in/of.
+ if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) {
+ expression = impl()->CheckAndRewriteReferenceExpression(
+ expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
+ kSyntaxError, CHECK_OK);
}
- // Standard 'for' loop, we have parsed the initializer at this point.
+ 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);
+ Scope* for_scope = scope();
+
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
+ BlockState block_state(zone(), &scope_);
+ scope()->set_start_position(scanner()->location().beg_pos);
+
+ StatementT body = ParseStatement(nullptr, CHECK_OK);
+ scope()->set_end_position(scanner()->location().end_pos);
+ StatementT final_loop = impl()->InitializeForEachStatement(
+ loop, expression, enumerable, body, each_keyword_pos);
+
+ for_scope = for_scope->FinalizeBlockScope();
+ USE(for_scope);
+ DCHECK_NULL(for_scope);
+ Scope* block_scope = scope()->FinalizeBlockScope();
+ USE(block_scope);
+ DCHECK_NULL(block_scope);
+ return final_loop;
+ }
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop(
+ int stmt_pos, StatementT init, bool bound_names_are_lexical,
+ ForInfo* for_info, BlockState* for_state,
+ ZoneList<const AstRawString*>* labels, bool* ok) {
auto loop = factory()->NewForStatement(labels, stmt_pos);
typename Types::Target target(this, loop);
@@ -5339,13 +5612,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
// 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) {
+ 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);
+ BlockState block_state(&scope_, inner_scope);
if (peek() != Token::SEMICOLON) {
cond = ParseExpression(true, CHECK_OK);
@@ -5358,53 +5630,201 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
}
Expect(Token::RPAREN, CHECK_OK);
- body = ParseScopedStatement(nullptr, true, CHECK_OK);
+ body = ParseStatement(nullptr, CHECK_OK);
}
- if (bound_names_are_lexical && for_info.bound_names.length() > 0) {
+ 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);
+ loop, init, cond, next, body, inner_scope, *for_info, CHECK_OK);
+ scope()->set_end_position(scanner()->location().end_pos);
+ inner_scope->set_end_position(scanner()->location().end_pos);
return result;
+ }
+
+ scope()->set_end_position(scanner()->location().end_pos);
+ Scope* for_scope = scope()->FinalizeBlockScope();
+ 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;
+ }
+
+ loop->Initialize(init, cond, next, body);
+ return loop;
+}
+
+template <typename Impl>
+void ParserBase<Impl>::MarkLoopVariableAsAssigned(Scope* scope, Variable* var) {
+ if (!IsLexicalVariableMode(var->mode()) && !scope->is_function_scope()) {
+ var->set_maybe_assigned();
+ }
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
+ ZoneList<const AstRawString*>* labels, bool* ok) {
+ // for await '(' ForDeclaration of AssignmentExpression ')'
+ DCHECK(is_async_function());
+ DCHECK(allow_harmony_async_iteration());
+
+ int stmt_pos = peek_position();
+
+ ForInfo for_info(this);
+ for_info.mode = ForEachStatement::ITERATE;
+
+ // Create an in-between scope for let-bound iteration variables.
+ BlockState for_state(zone(), &scope_);
+ Expect(Token::FOR, CHECK_OK);
+ Expect(Token::AWAIT, CHECK_OK);
+ Expect(Token::LPAREN, CHECK_OK);
+ scope()->set_start_position(scanner()->location().beg_pos);
+ scope()->set_is_hidden();
+
+ auto loop = factory()->NewForOfStatement(labels, stmt_pos);
+ typename Types::Target target(this, loop);
+
+ ExpressionT each_variable = impl()->EmptyExpression();
+
+ bool has_declarations = false;
+
+ if (peek() == Token::VAR || peek() == Token::CONST ||
+ (peek() == Token::LET && IsNextLetKeyword())) {
+ // The initializer contains declarations
+ // 'for' 'await' '(' ForDeclaration 'of' AssignmentExpression ')'
+ // Statement
+ // 'for' 'await' '(' 'var' ForBinding 'of' AssignmentExpression ')'
+ // Statement
+ has_declarations = true;
+ ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr,
+ CHECK_OK);
+ for_info.position = scanner()->location().beg_pos;
+
+ // Only a single declaration is allowed in for-await-of loops
+ if (for_info.parsing_result.declarations.length() != 1) {
+ impl()->ReportMessageAt(for_info.parsing_result.bindings_loc,
+ MessageTemplate::kForInOfLoopMultiBindings,
+ "for-await-of");
+ *ok = false;
+ return impl()->NullStatement();
+ }
+
+ // for-await-of's declarations do not permit initializers.
+ if (for_info.parsing_result.first_initializer_loc.IsValid()) {
+ impl()->ReportMessageAt(for_info.parsing_result.first_initializer_loc,
+ MessageTemplate::kForInOfLoopInitializer,
+ "for-await-of");
+ *ok = false;
+ return impl()->NullStatement();
+ }
} 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;
+ // The initializer does not contain declarations.
+ // 'for' 'await' '(' LeftHandSideExpression 'of' AssignmentExpression ')'
+ // Statement
+ int lhs_beg_pos = peek_position();
+ ExpressionClassifier classifier(this);
+ ExpressionT lhs = each_variable = ParseLeftHandSideExpression(CHECK_OK);
+ int lhs_end_pos = scanner()->location().end_pos;
+
+ if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) {
+ ValidateAssignmentPattern(CHECK_OK);
} else {
- loop->Initialize(init, cond, next, body);
- return loop;
+ impl()->RewriteNonPattern(CHECK_OK);
+ each_variable = impl()->CheckAndRewriteReferenceExpression(
+ lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
+ kSyntaxError, CHECK_OK);
}
}
-}
-#undef CHECK_OK
-#undef CHECK_OK_CUSTOM
+ ExpectContextualKeyword(CStrVector("of"), CHECK_OK);
+ int each_keyword_pos = scanner()->location().beg_pos;
+
+ const bool kAllowIn = true;
+ ExpressionT iterable = impl()->EmptyExpression();
+
+ {
+ ExpressionClassifier classifier(this);
+ iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
+ }
+
+ Expect(Token::RPAREN, CHECK_OK);
+
+ StatementT final_loop = impl()->NullStatement();
+ Scope* for_scope = scope();
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
+ BlockState block_state(zone(), &scope_);
+ scope()->set_start_position(scanner()->location().beg_pos);
+
+ StatementT body = ParseStatement(nullptr, CHECK_OK);
+ scope()->set_end_position(scanner()->location().end_pos);
+
+ if (has_declarations) {
+ BlockT body_block = impl()->NullBlock();
+ impl()->DesugarBindingInForEachStatement(&for_info, &body_block,
+ &each_variable, CHECK_OK);
+ body_block->statements()->Add(body, zone());
+ body_block->set_scope(scope()->FinalizeBlockScope());
+
+ const bool finalize = true;
+ final_loop = impl()->InitializeForOfStatement(
+ loop, each_variable, iterable, body_block, finalize,
+ IteratorType::kAsync, each_keyword_pos);
+ } else {
+ const bool finalize = true;
+ final_loop = impl()->InitializeForOfStatement(
+ loop, each_variable, iterable, body, finalize, IteratorType::kAsync,
+ each_keyword_pos);
+
+ for_scope = for_scope->FinalizeBlockScope();
+ DCHECK_NULL(for_scope);
+ USE(for_scope);
+ Scope* block_scope = scope()->FinalizeBlockScope();
+ DCHECK_NULL(block_scope);
+ USE(block_scope);
+ return final_loop;
+ }
+ }
+
+ DCHECK(has_declarations);
+ BlockT init_block =
+ impl()->CreateForEachStatementTDZ(impl()->NullBlock(), for_info, ok);
+
+ for_scope->set_end_position(scanner()->location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ // 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;
+ }
+ DCHECK_NULL(for_scope);
+ return final_loop;
+}
template <typename Impl>
void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto(
@@ -5456,6 +5876,9 @@ void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
}
}
+#undef CHECK_OK
+#undef CHECK_OK_CUSTOM
+#undef CHECK_OK_VOID
} // namespace internal
} // namespace v8