Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/parsing/expression-classifier.h b/src/parsing/expression-classifier.h
index 71fa3d3..3f70ed8 100644
--- a/src/parsing/expression-classifier.h
+++ b/src/parsing/expression-classifier.h
@@ -39,17 +39,23 @@
ArrowFormalParametersProduction = 1 << 6,
LetPatternProduction = 1 << 7,
CoverInitializedNameProduction = 1 << 8,
+ TailCallExpressionProduction = 1 << 9,
+ AsyncArrowFormalParametersProduction = 1 << 10,
+ AsyncBindingPatternProduction = 1 << 11,
ExpressionProductions =
- (ExpressionProduction | FormalParameterInitializerProduction),
- PatternProductions = (BindingPatternProduction |
- AssignmentPatternProduction | LetPatternProduction),
+ (ExpressionProduction | FormalParameterInitializerProduction |
+ TailCallExpressionProduction),
+ PatternProductions =
+ (BindingPatternProduction | AssignmentPatternProduction |
+ LetPatternProduction | AsyncBindingPatternProduction),
FormalParametersProductions = (DistinctFormalParametersProduction |
StrictModeFormalParametersProduction),
StandardProductions = ExpressionProductions | PatternProductions,
AllProductions =
(StandardProductions | FormalParametersProductions |
- ArrowFormalParametersProduction | CoverInitializedNameProduction)
+ ArrowFormalParametersProduction | CoverInitializedNameProduction |
+ AsyncArrowFormalParametersProduction | AsyncBindingPatternProduction)
};
enum FunctionProperties { NonSimpleParameter = 1 << 0 };
@@ -110,6 +116,14 @@
bool is_valid_let_pattern() const { return is_valid(LetPatternProduction); }
+ bool is_valid_async_arrow_formal_parameters() const {
+ return is_valid(AsyncArrowFormalParametersProduction);
+ }
+
+ bool is_valid_async_binding_pattern() const {
+ return is_valid(AsyncBindingPatternProduction);
+ }
+
const Error& expression_error() const { return expression_error_; }
const Error& formal_parameter_initializer_error() const {
@@ -143,6 +157,20 @@
return cover_initialized_name_error_;
}
+ bool has_tail_call_expression() const {
+ return !is_valid(TailCallExpressionProduction);
+ }
+ const Error& tail_call_expression_error() const {
+ return tail_call_expression_error_;
+ }
+ const Error& async_arrow_formal_parameters_error() const {
+ return async_arrow_formal_parameters_error_;
+ }
+
+ const Error& async_binding_pattern_error() const {
+ return async_binding_pattern_error_;
+ }
+
bool is_simple_parameter_list() const {
return !(function_properties_ & NonSimpleParameter);
}
@@ -219,6 +247,26 @@
arrow_formal_parameters_error_.arg = arg;
}
+ void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc,
+ MessageTemplate::Template message,
+ const char* arg = nullptr) {
+ if (!is_valid_async_arrow_formal_parameters()) return;
+ invalid_productions_ |= AsyncArrowFormalParametersProduction;
+ async_arrow_formal_parameters_error_.location = loc;
+ async_arrow_formal_parameters_error_.message = message;
+ async_arrow_formal_parameters_error_.arg = arg;
+ }
+
+ void RecordAsyncBindingPatternError(const Scanner::Location& loc,
+ MessageTemplate::Template message,
+ const char* arg = nullptr) {
+ if (!is_valid_async_binding_pattern()) return;
+ invalid_productions_ |= AsyncBindingPatternProduction;
+ async_binding_pattern_error_.location = loc;
+ async_binding_pattern_error_.message = message;
+ async_binding_pattern_error_.arg = arg;
+ }
+
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
if (!is_valid_formal_parameter_list_without_duplicates()) return;
invalid_productions_ |= DistinctFormalParametersProduction;
@@ -260,6 +308,16 @@
cover_initialized_name_error_.arg = arg;
}
+ void RecordTailCallExpressionError(const Scanner::Location& loc,
+ MessageTemplate::Template message,
+ const char* arg = nullptr) {
+ if (has_tail_call_expression()) return;
+ invalid_productions_ |= TailCallExpressionProduction;
+ tail_call_expression_error_.location = loc;
+ tail_call_expression_error_.message = message;
+ tail_call_expression_error_.arg = arg;
+ }
+
void ForgiveCoverInitializedNameError() {
invalid_productions_ &= ~CoverInitializedNameProduction;
cover_initialized_name_error_ = Error();
@@ -305,6 +363,13 @@
let_pattern_error_ = inner->let_pattern_error_;
if (errors & CoverInitializedNameProduction)
cover_initialized_name_error_ = inner->cover_initialized_name_error_;
+ if (errors & TailCallExpressionProduction)
+ tail_call_expression_error_ = inner->tail_call_expression_error_;
+ if (errors & AsyncArrowFormalParametersProduction)
+ async_arrow_formal_parameters_error_ =
+ inner->async_arrow_formal_parameters_error_;
+ if (errors & AsyncBindingPatternProduction)
+ async_binding_pattern_error_ = inner->async_binding_pattern_error_;
}
// As an exception to the above, the result continues to be a valid arrow
@@ -340,6 +405,8 @@
int non_pattern_begin_;
unsigned invalid_productions_;
unsigned function_properties_;
+ // TODO(ishell): consider using Zone[Hash]Map<TargetProduction, Error>
+ // here to consume less stack space during parsing.
Error expression_error_;
Error formal_parameter_initializer_error_;
Error binding_pattern_error_;
@@ -349,6 +416,9 @@
Error strict_mode_formal_parameter_error_;
Error let_pattern_error_;
Error cover_initialized_name_error_;
+ Error tail_call_expression_error_;
+ Error async_arrow_formal_parameters_error_;
+ Error async_binding_pattern_error_;
DuplicateFinder* duplicate_finder_;
};
diff --git a/src/parsing/parameter-initializer-rewriter.cc b/src/parsing/parameter-initializer-rewriter.cc
index 3e3587b..6362c63 100644
--- a/src/parsing/parameter-initializer-rewriter.cc
+++ b/src/parsing/parameter-initializer-rewriter.cc
@@ -4,6 +4,10 @@
#include "src/parsing/parameter-initializer-rewriter.h"
+#include <algorithm>
+#include <utility>
+#include <vector>
+
#include "src/ast/ast.h"
#include "src/ast/ast-expression-visitor.h"
#include "src/ast/scopes.h"
@@ -21,6 +25,7 @@
: AstExpressionVisitor(stack_limit, initializer),
old_scope_(old_scope),
new_scope_(new_scope) {}
+ ~Rewriter();
private:
void VisitExpression(Expression* expr) override {}
@@ -29,10 +34,32 @@
void VisitClassLiteral(ClassLiteral* expr) override;
void VisitVariableProxy(VariableProxy* expr) override;
+ void VisitBlock(Block* stmt) override;
+ void VisitTryCatchStatement(TryCatchStatement* stmt) override;
+ void VisitWithStatement(WithStatement* stmt) override;
+
Scope* old_scope_;
Scope* new_scope_;
+ std::vector<std::pair<Variable*, int>> temps_;
};
+struct LessThanSecond {
+ bool operator()(const std::pair<Variable*, int>& left,
+ const std::pair<Variable*, int>& right) {
+ return left.second < right.second;
+ }
+};
+
+Rewriter::~Rewriter() {
+ if (!temps_.empty()) {
+ // Ensure that we add temporaries in the order they appeared in old_scope_.
+ std::sort(temps_.begin(), temps_.end(), LessThanSecond());
+ for (auto var_and_index : temps_) {
+ var_and_index.first->set_scope(new_scope_);
+ new_scope_->AddTemporary(var_and_index.first);
+ }
+ }
+}
void Rewriter::VisitFunctionLiteral(FunctionLiteral* function_literal) {
function_literal->scope()->ReplaceOuterScope(new_scope_);
@@ -63,9 +90,13 @@
if (proxy->is_resolved()) {
Variable* var = proxy->var();
if (var->mode() != TEMPORARY) return;
- if (old_scope_->RemoveTemporary(var)) {
- var->set_scope(new_scope_);
- new_scope_->AddTemporary(var);
+ // For rewriting inside the same ClosureScope (e.g., putting default
+ // parameter values in their own inner scope in certain cases), refrain
+ // from invalidly moving temporaries to a block scope.
+ if (var->scope()->ClosureScope() == new_scope_->ClosureScope()) return;
+ int index = old_scope_->RemoveTemporary(var);
+ if (index >= 0) {
+ temps_.push_back(std::make_pair(var, index));
}
} else if (old_scope_->RemoveUnresolved(proxy)) {
new_scope_->AddUnresolved(proxy);
@@ -73,6 +104,26 @@
}
+void Rewriter::VisitBlock(Block* stmt) {
+ if (stmt->scope() != nullptr)
+ stmt->scope()->ReplaceOuterScope(new_scope_);
+ else
+ VisitStatements(stmt->statements());
+}
+
+
+void Rewriter::VisitTryCatchStatement(TryCatchStatement* stmt) {
+ Visit(stmt->try_block());
+ stmt->scope()->ReplaceOuterScope(new_scope_);
+}
+
+
+void Rewriter::VisitWithStatement(WithStatement* stmt) {
+ Visit(stmt->expression());
+ stmt->scope()->ReplaceOuterScope(new_scope_);
+}
+
+
} // anonymous namespace
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index dde6b1d..6086f7a 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -29,6 +29,86 @@
kDisallowLabelledFunctionStatement,
};
+enum class FunctionBody { Normal, SingleExpression };
+
+enum class ParseFunctionFlags {
+ kIsNormal = 0,
+ kIsGenerator = 1,
+ kIsAsync = 2,
+ kIsDefault = 4
+};
+
+static inline ParseFunctionFlags operator|(ParseFunctionFlags lhs,
+ ParseFunctionFlags rhs) {
+ typedef unsigned char T;
+ return static_cast<ParseFunctionFlags>(static_cast<T>(lhs) |
+ static_cast<T>(rhs));
+}
+
+static inline ParseFunctionFlags& operator|=(ParseFunctionFlags& lhs,
+ const ParseFunctionFlags& rhs) {
+ lhs = lhs | rhs;
+ return lhs;
+}
+
+static inline bool operator&(ParseFunctionFlags bitfield,
+ ParseFunctionFlags mask) {
+ typedef unsigned char T;
+ return static_cast<T>(bitfield) & static_cast<T>(mask);
+}
+
+enum class MethodKind {
+ Normal = 0,
+ Static = 1 << 0,
+ Generator = 1 << 1,
+ StaticGenerator = Static | Generator,
+ Async = 1 << 2,
+ StaticAsync = Static | Async,
+
+ /* Any non-ordinary method kinds */
+ SpecialMask = Generator | Async
+};
+
+inline bool IsValidMethodKind(MethodKind kind) {
+ return kind == MethodKind::Normal || kind == MethodKind::Static ||
+ kind == MethodKind::Generator || kind == MethodKind::StaticGenerator ||
+ kind == MethodKind::Async || kind == MethodKind::StaticAsync;
+}
+
+static inline MethodKind operator|(MethodKind lhs, MethodKind rhs) {
+ typedef unsigned char T;
+ return static_cast<MethodKind>(static_cast<T>(lhs) | static_cast<T>(rhs));
+}
+
+static inline MethodKind& operator|=(MethodKind& lhs, const MethodKind& rhs) {
+ lhs = lhs | rhs;
+ DCHECK(IsValidMethodKind(lhs));
+ return lhs;
+}
+
+static inline bool operator&(MethodKind bitfield, MethodKind mask) {
+ typedef unsigned char T;
+ return static_cast<T>(bitfield) & static_cast<T>(mask);
+}
+
+inline bool IsNormalMethod(MethodKind kind) {
+ return kind == MethodKind::Normal;
+}
+
+inline bool IsSpecialMethod(MethodKind kind) {
+ return kind & MethodKind::SpecialMask;
+}
+
+inline bool IsStaticMethod(MethodKind kind) {
+ return kind & MethodKind::Static;
+}
+
+inline bool IsGeneratorMethod(MethodKind kind) {
+ return kind & MethodKind::Generator;
+}
+
+inline bool IsAsyncMethod(MethodKind kind) { return kind & MethodKind::Async; }
+
struct FormalParametersBase {
explicit FormalParametersBase(Scope* scope) : scope(scope) {}
Scope* scope;
@@ -98,7 +178,6 @@
v8::Extension* extension, AstValueFactory* ast_value_factory,
ParserRecorder* log, typename Traits::Type::Parser this_object)
: Traits(this_object),
- parenthesized_function_(false),
scope_(NULL),
function_state_(NULL),
extension_(extension),
@@ -106,6 +185,7 @@
ast_value_factory_(ast_value_factory),
log_(log),
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
+ parsing_module_(false),
stack_limit_(stack_limit),
zone_(zone),
scanner_(scanner),
@@ -113,13 +193,12 @@
allow_lazy_(false),
allow_natives_(false),
allow_tailcalls_(false),
- allow_harmony_sloppy_(false),
- allow_harmony_sloppy_function_(false),
- allow_harmony_sloppy_let_(false),
allow_harmony_restrictive_declarations_(false),
allow_harmony_do_expressions_(false),
+ allow_harmony_for_in_(false),
allow_harmony_function_name_(false),
- allow_harmony_function_sent_(false) {}
+ allow_harmony_function_sent_(false),
+ allow_harmony_async_await_(false) {}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
@@ -134,13 +213,12 @@
ALLOW_ACCESSORS(lazy);
ALLOW_ACCESSORS(natives);
ALLOW_ACCESSORS(tailcalls);
- ALLOW_ACCESSORS(harmony_sloppy);
- ALLOW_ACCESSORS(harmony_sloppy_function);
- ALLOW_ACCESSORS(harmony_sloppy_let);
ALLOW_ACCESSORS(harmony_restrictive_declarations);
ALLOW_ACCESSORS(harmony_do_expressions);
+ ALLOW_ACCESSORS(harmony_for_in);
ALLOW_ACCESSORS(harmony_function_name);
ALLOW_ACCESSORS(harmony_function_sent);
+ ALLOW_ACCESSORS(harmony_async_await);
SCANNER_ACCESSORS(harmony_exponentiation_operator);
#undef SCANNER_ACCESSORS
@@ -195,6 +273,64 @@
Scope* scope;
};
+ class TailCallExpressionList {
+ public:
+ explicit TailCallExpressionList(Zone* zone)
+ : zone_(zone), expressions_(0, zone), has_explicit_tail_calls_(false) {}
+
+ const ZoneList<ExpressionT>& expressions() const { return expressions_; }
+ const Scanner::Location& location() const { return loc_; }
+
+ bool has_explicit_tail_calls() const { return has_explicit_tail_calls_; }
+
+ void Swap(TailCallExpressionList& other) {
+ expressions_.Swap(&other.expressions_);
+ std::swap(loc_, other.loc_);
+ std::swap(has_explicit_tail_calls_, other.has_explicit_tail_calls_);
+ }
+
+ void AddImplicitTailCall(ExpressionT expr) {
+ expressions_.Add(expr, zone_);
+ }
+
+ void AddExplicitTailCall(ExpressionT expr, const Scanner::Location& loc) {
+ if (!has_explicit_tail_calls()) {
+ loc_ = loc;
+ has_explicit_tail_calls_ = true;
+ }
+ expressions_.Add(expr, zone_);
+ }
+
+ void Append(const TailCallExpressionList& other) {
+ if (!has_explicit_tail_calls()) {
+ loc_ = other.loc_;
+ has_explicit_tail_calls_ = other.has_explicit_tail_calls_;
+ }
+ expressions_.AddAll(other.expressions_, zone_);
+ }
+
+ private:
+ Zone* zone_;
+ ZoneList<ExpressionT> expressions_;
+ Scanner::Location loc_;
+ bool has_explicit_tail_calls_;
+ };
+
+ // Defines whether tail call expressions are allowed or not.
+ enum class ReturnExprContext {
+ // We are inside return statement which is allowed to contain tail call
+ // expressions. Tail call expressions are allowed.
+ kInsideValidReturnStatement,
+
+ // We are inside a block in which tail call expressions are allowed but
+ // not yet inside a return statement.
+ kInsideValidBlock,
+
+ // Tail call expressions are not allowed in the following blocks.
+ kInsideTryBlock,
+ kInsideForInOfBody,
+ };
+
class FunctionState BASE_EMBEDDED {
public:
FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
@@ -230,6 +366,8 @@
}
bool is_generator() const { return IsGeneratorFunction(kind_); }
+ bool is_async_function() const { return IsAsyncFunction(kind_); }
+ bool is_resumable() const { return is_generator() || is_async_function(); }
FunctionKind kind() const { return kind_; }
FunctionState* outer() const { return outer_function_state_; }
@@ -237,7 +375,7 @@
void set_generator_object_variable(
typename Traits::Type::GeneratorVariable* variable) {
DCHECK(variable != NULL);
- DCHECK(is_generator());
+ DCHECK(is_resumable());
generator_object_variable_ = variable;
}
typename Traits::Type::GeneratorVariable* generator_object_variable()
@@ -252,26 +390,43 @@
return destructuring_assignments_to_rewrite_;
}
- List<ExpressionT>& expressions_in_tail_position() {
- return expressions_in_tail_position_;
+ TailCallExpressionList& tail_call_expressions() {
+ return tail_call_expressions_;
}
- void AddExpressionInTailPosition(ExpressionT expression) {
- if (collect_expressions_in_tail_position_) {
- expressions_in_tail_position_.Add(expression);
+ void AddImplicitTailCallExpression(ExpressionT expression) {
+ if (return_expr_context() ==
+ ReturnExprContext::kInsideValidReturnStatement) {
+ tail_call_expressions_.AddImplicitTailCall(expression);
+ }
+ }
+ void AddExplicitTailCallExpression(ExpressionT expression,
+ const Scanner::Location& loc) {
+ DCHECK(expression->IsCall());
+ if (return_expr_context() ==
+ ReturnExprContext::kInsideValidReturnStatement) {
+ tail_call_expressions_.AddExplicitTailCall(expression, loc);
}
}
- bool collect_expressions_in_tail_position() const {
- return collect_expressions_in_tail_position_;
+ ReturnExprContext return_expr_context() const {
+ return return_expr_context_;
}
- void set_collect_expressions_in_tail_position(bool collect) {
- collect_expressions_in_tail_position_ = collect;
+ void set_return_expr_context(ReturnExprContext context) {
+ return_expr_context_ = context;
}
ZoneList<ExpressionT>* non_patterns_to_rewrite() {
return &non_patterns_to_rewrite_;
}
+ void next_function_is_parenthesized(bool parenthesized) {
+ next_function_is_parenthesized_ = parenthesized;
+ }
+
+ bool this_function_is_parenthesized() const {
+ return this_function_is_parenthesized_;
+ }
+
private:
void AddDestructuringAssignment(DestructuringAssignment pair) {
destructuring_assignments_to_rewrite_.Add(pair);
@@ -312,17 +467,67 @@
Scope* outer_scope_;
List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
- List<ExpressionT> expressions_in_tail_position_;
- bool collect_expressions_in_tail_position_;
+ TailCallExpressionList tail_call_expressions_;
+ ReturnExprContext return_expr_context_;
ZoneList<ExpressionT> non_patterns_to_rewrite_;
typename Traits::Type::Factory* factory_;
+ // 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_;
+
friend class ParserTraits;
friend class PreParserTraits;
friend class Checkpoint;
};
+ // This scope sets current ReturnExprContext to given value.
+ class ReturnExprScope {
+ public:
+ explicit ReturnExprScope(FunctionState* function_state,
+ ReturnExprContext return_expr_context)
+ : function_state_(function_state),
+ sav_return_expr_context_(function_state->return_expr_context()) {
+ // Don't update context if we are requested to enable tail call
+ // expressions but current block does not allow them.
+ if (return_expr_context !=
+ ReturnExprContext::kInsideValidReturnStatement ||
+ sav_return_expr_context_ == ReturnExprContext::kInsideValidBlock) {
+ function_state->set_return_expr_context(return_expr_context);
+ }
+ }
+ ~ReturnExprScope() {
+ function_state_->set_return_expr_context(sav_return_expr_context_);
+ }
+
+ private:
+ FunctionState* function_state_;
+ ReturnExprContext sav_return_expr_context_;
+ };
+
+ // Collects all return expressions at tail call position in this scope
+ // to a separate list.
+ class CollectExpressionsInTailPositionToListScope {
+ public:
+ CollectExpressionsInTailPositionToListScope(FunctionState* function_state,
+ TailCallExpressionList* list)
+ : function_state_(function_state), list_(list) {
+ function_state->tail_call_expressions().Swap(*list_);
+ }
+ ~CollectExpressionsInTailPositionToListScope() {
+ function_state_->tail_call_expressions().Swap(*list_);
+ }
+
+ private:
+ FunctionState* function_state_;
+ TailCallExpressionList* list_;
+ };
+
// Annoyingly, arrow functions first parse as comma expressions, then when we
// see the => we have to go back and reinterpret the arguments as being formal
// parameters. To do so we need to reset some of the parser state back to
@@ -455,7 +660,8 @@
bool peek_any_identifier() {
Token::Value next = peek();
- return next == Token::IDENTIFIER || next == Token::FUTURE_RESERVED_WORD ||
+ return next == Token::IDENTIFIER || next == Token::ENUM ||
+ next == Token::AWAIT || next == Token::ASYNC ||
next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
next == Token::STATIC || next == Token::YIELD;
}
@@ -512,6 +718,18 @@
*ok = false;
}
}
+ // for now, this check just collects statistics.
+ void CheckDecimalLiteralWithLeadingZero(int* use_counts, int beg_pos,
+ int end_pos) {
+ Scanner::Location token_location =
+ scanner()->decimal_with_leading_zero_position();
+ if (token_location.IsValid() && beg_pos <= token_location.beg_pos &&
+ token_location.end_pos <= end_pos) {
+ scanner()->clear_decimal_with_leading_zero_position();
+ if (use_counts != nullptr)
+ ++use_counts[v8::Isolate::kDecimalWithLeadingZeroInStrictMode];
+ }
+ }
inline void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kStrictOctalLiteral,
@@ -563,14 +781,10 @@
LanguageMode language_mode() { return scope_->language_mode(); }
bool is_generator() const { return function_state_->is_generator(); }
-
- bool allow_const() {
- return is_strict(language_mode()) || allow_harmony_sloppy();
+ bool is_async_function() const {
+ return function_state_->is_async_function();
}
-
- bool allow_let() {
- return is_strict(language_mode()) || allow_harmony_sloppy_let();
- }
+ bool is_resumable() const { return function_state_->is_resumable(); }
// Report syntax errors.
void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
@@ -627,8 +841,16 @@
void ValidateBindingPattern(const ExpressionClassifier* classifier,
bool* ok) {
- if (!classifier->is_valid_binding_pattern()) {
- ReportClassifierError(classifier->binding_pattern_error());
+ if (!classifier->is_valid_binding_pattern() ||
+ !classifier->is_valid_async_binding_pattern()) {
+ const Scanner::Location& a = classifier->binding_pattern_error().location;
+ const Scanner::Location& b =
+ classifier->async_binding_pattern_error().location;
+ if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) {
+ ReportClassifierError(classifier->async_binding_pattern_error());
+ } else {
+ ReportClassifierError(classifier->binding_pattern_error());
+ }
*ok = false;
}
}
@@ -657,7 +879,8 @@
void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
ExpressionT expr,
- bool parenthesized_formals, bool* ok) {
+ bool parenthesized_formals, bool is_async,
+ bool* ok) {
if (classifier->is_valid_binding_pattern()) {
// A simple arrow formal parameter: IDENTIFIER => BODY.
if (!this->IsIdentifier(expr)) {
@@ -677,6 +900,12 @@
ReportClassifierError(error);
*ok = false;
}
+ if (is_async && !classifier->is_valid_async_arrow_formal_parameters()) {
+ const typename ExpressionClassifier::Error& error =
+ classifier->async_arrow_formal_parameters_error();
+ ReportClassifierError(error);
+ *ok = false;
+ }
}
void ValidateLetPattern(const ExpressionClassifier* classifier, bool* ok) {
@@ -686,6 +915,15 @@
}
}
+ void CheckNoTailCallExpressions(const ExpressionClassifier* classifier,
+ bool* ok) {
+ if (FLAG_harmony_explicit_tailcalls &&
+ classifier->has_tail_call_expression()) {
+ ReportClassifierError(classifier->tail_call_expression_error());
+ *ok = false;
+ }
+ }
+
void ExpressionUnexpectedToken(ExpressionClassifier* classifier) {
MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
const char* arg;
@@ -741,27 +979,40 @@
ExpressionClassifier* classifier, bool* ok);
ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
- bool* ok);
+ bool* is_async, bool* ok);
+ ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
+ bool* ok) {
+ bool is_async;
+ return ParsePrimaryExpression(classifier, &is_async, ok);
+ }
ExpressionT ParseExpression(bool accept_IN, bool* ok);
ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier,
bool* ok);
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
- bool* is_computed_name,
+ bool* is_await, bool* is_computed_name,
ExpressionClassifier* classifier, bool* ok);
ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition(
ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
- bool is_static, bool* is_computed_name, bool* has_seen_constructor,
+ MethodKind kind, bool* is_computed_name, bool* has_seen_constructor,
ExpressionClassifier* classifier, IdentifierT* name, bool* ok);
typename Traits::Type::ExpressionList ParseArguments(
+ Scanner::Location* first_spread_pos, bool maybe_arrow,
+ ExpressionClassifier* classifier, bool* ok);
+ typename Traits::Type::ExpressionList ParseArguments(
Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
- bool* ok);
+ bool* ok) {
+ return ParseArguments(first_spread_pos, false, classifier, ok);
+ }
ExpressionT ParseAssignmentExpression(bool accept_IN,
ExpressionClassifier* classifier,
bool* ok);
- ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok);
+ ExpressionT ParseYieldExpression(bool accept_IN,
+ ExpressionClassifier* classifier, bool* ok);
+ ExpressionT ParseTailCallExpression(ExpressionClassifier* classifier,
+ bool* ok);
ExpressionT ParseConditionalExpression(bool accept_IN,
ExpressionClassifier* classifier,
bool* ok);
@@ -773,12 +1024,15 @@
ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier,
bool* ok);
ExpressionT ParseMemberWithNewPrefixesExpression(
- ExpressionClassifier* classifier, bool* ok);
- ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
+ ExpressionClassifier* classifier, bool* is_async, bool* ok);
+ ExpressionT ParseMemberExpression(ExpressionClassifier* classifier,
+ bool* is_async, bool* ok);
ExpressionT ParseMemberExpressionContinuation(
- ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
+ ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
+ bool* ok);
ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
const FormalParametersT& parameters,
+ bool is_async,
const ExpressionClassifier& classifier,
bool* ok);
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
@@ -850,7 +1104,7 @@
explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
virtual void CheckProperty(Token::Value property, PropertyKind type,
- bool is_static, bool is_generator, bool* ok) = 0;
+ MethodKind method_type, bool* ok) = 0;
virtual ~ObjectLiteralCheckerBase() {}
@@ -868,8 +1122,8 @@
explicit ObjectLiteralChecker(ParserBase* parser)
: ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
- void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
- bool is_generator, bool* ok) override;
+ void CheckProperty(Token::Value property, PropertyKind type,
+ MethodKind method_type, bool* ok) override;
private:
bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
@@ -883,8 +1137,8 @@
explicit ClassLiteralChecker(ParserBase* parser)
: ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
- void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
- bool is_generator, bool* ok) override;
+ void CheckProperty(Token::Value property, PropertyKind type,
+ MethodKind method_type, bool* ok) override;
private:
bool IsConstructor() {
@@ -897,12 +1151,6 @@
bool has_seen_constructor_;
};
- // If true, the next (and immediately following) function literal is
- // preceded by a parenthesis.
- // Heuristically that means that the function will be called immediately,
- // so never lazily compile it.
- bool parenthesized_function_;
-
Scope* scope_; // Scope stack.
FunctionState* function_state_; // Function state stack.
v8::Extension* extension_;
@@ -910,6 +1158,7 @@
AstValueFactory* ast_value_factory_; // Not owned.
ParserRecorder* log_;
Mode mode_;
+ bool parsing_module_;
uintptr_t stack_limit_;
private:
@@ -921,13 +1170,12 @@
bool allow_lazy_;
bool allow_natives_;
bool allow_tailcalls_;
- bool allow_harmony_sloppy_;
- bool allow_harmony_sloppy_function_;
- bool allow_harmony_sloppy_let_;
bool allow_harmony_restrictive_declarations_;
bool allow_harmony_do_expressions_;
+ bool allow_harmony_for_in_;
bool allow_harmony_function_name_;
bool allow_harmony_function_sent_;
+ bool allow_harmony_async_await_;
};
template <class Traits>
@@ -945,11 +1193,19 @@
outer_function_state_(*function_state_stack),
scope_stack_(scope_stack),
outer_scope_(*scope_stack),
- collect_expressions_in_tail_position_(true),
+ tail_call_expressions_(scope->zone()),
+ return_expr_context_(ReturnExprContext::kInsideValidBlock),
non_patterns_to_rewrite_(0, scope->zone()),
- factory_(factory) {
+ factory_(factory),
+ next_function_is_parenthesized_(false),
+ this_function_is_parenthesized_(false) {
*scope_stack_ = scope;
*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;
+ }
}
@@ -979,7 +1235,8 @@
case Token::IDENTIFIER:
*message = MessageTemplate::kUnexpectedTokenIdentifier;
break;
- case Token::FUTURE_RESERVED_WORD:
+ case Token::AWAIT:
+ case Token::ENUM:
*message = MessageTemplate::kUnexpectedReserved;
break;
case Token::LET:
@@ -1054,7 +1311,8 @@
ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
bool* ok) {
Token::Value next = Next();
- if (next == Token::IDENTIFIER) {
+ if (next == Token::IDENTIFIER || next == Token::ASYNC ||
+ (next == Token::AWAIT && !parsing_module_)) {
IdentifierT name = this->GetSymbol(scanner());
// When this function is used to read a formal parameter, we don't always
// know whether the function is going to be strict or sloppy. Indeed for
@@ -1079,6 +1337,14 @@
scanner()->location(), MessageTemplate::kStrictEvalArguments);
}
}
+ if (this->IsAwait(name)) {
+ if (is_async_function()) {
+ classifier->RecordPatternError(
+ scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
+ }
+ classifier->RecordAsyncArrowFormalParametersError(
+ scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
+ }
if (classifier->duplicate_finder() != nullptr &&
scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
@@ -1118,7 +1384,8 @@
ParserBase<Traits>::ParseIdentifierOrStrictReservedWord(
bool is_generator, bool* is_strict_reserved, bool* ok) {
Token::Value next = Next();
- if (next == Token::IDENTIFIER) {
+ if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_) ||
+ next == Token::ASYNC) {
*is_strict_reserved = false;
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
next == Token::STATIC || (next == Token::YIELD && !is_generator)) {
@@ -1134,13 +1401,13 @@
return name;
}
-
template <class Traits>
typename ParserBase<Traits>::IdentifierT
ParserBase<Traits>::ParseIdentifierName(bool* ok) {
Token::Value next = Next();
- if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
- next != Token::LET && next != Token::STATIC && next != Token::YIELD &&
+ if (next != Token::IDENTIFIER && next != Token::ASYNC &&
+ next != Token::ENUM && next != Token::AWAIT && next != Token::LET &&
+ next != Token::STATIC && next != Token::YIELD &&
next != Token::FUTURE_STRICT_RESERVED_WORD &&
next != Token::ESCAPED_KEYWORD &&
next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
@@ -1195,11 +1462,10 @@
#define DUMMY ) // to make indentation work
#undef DUMMY
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
- bool* ok) {
+ bool* is_async, bool* ok) {
// PrimaryExpression ::
// 'this'
// 'null'
@@ -1215,6 +1481,7 @@
// '(' Expression ')'
// TemplateLiteral
// do Block
+ // AsyncFunctionExpression
int beg_pos = peek_position();
switch (peek()) {
@@ -1234,10 +1501,21 @@
BindingPatternUnexpectedToken(classifier);
return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
+ case Token::ASYNC:
+ if (allow_harmony_async_await() &&
+ !scanner()->HasAnyLineTerminatorAfterNext() &&
+ PeekAhead() == Token::FUNCTION) {
+ Consume(Token::ASYNC);
+ return this->ParseAsyncFunctionExpression(CHECK_OK);
+ }
+ // CoverCallExpressionAndAsyncArrowHead
+ *is_async = true;
+ /* falls through */
case Token::IDENTIFIER:
case Token::LET:
case Token::STATIC:
case Token::YIELD:
+ case Token::AWAIT:
case Token::ESCAPED_STRICT_RESERVED_WORD:
case Token::FUTURE_STRICT_RESERVED_WORD: {
// Using eval or arguments in this context is OK even in strict mode.
@@ -1315,7 +1593,8 @@
}
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
- parenthesized_function_ = (peek() == Token::FUNCTION);
+ function_state_->next_function_is_parenthesized(peek() ==
+ Token::FUNCTION);
ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
return expr;
@@ -1324,11 +1603,6 @@
case Token::CLASS: {
BindingPatternUnexpectedToken(classifier);
Consume(Token::CLASS);
- if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
- ReportMessage(MessageTemplate::kSloppyLexical);
- *ok = false;
- return this->EmptyExpression();
- }
int class_token_position = position();
IdentifierT name = this->EmptyIdentifier();
bool is_strict_reserved_name = false;
@@ -1382,7 +1656,6 @@
return result;
}
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
@@ -1398,6 +1671,7 @@
bool is_simple_parameter_list = this->IsIdentifier(result);
bool seen_rest = false;
while (peek() == Token::COMMA) {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
if (seen_rest) {
// At this point the production can't possibly be valid, but we don't know
// which error to signal.
@@ -1461,6 +1735,7 @@
int expr_pos = peek_position();
ExpressionT argument =
this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
elem = factory()->NewSpread(argument, start_pos, expr_pos);
if (first_spread_index < 0) {
@@ -1484,6 +1759,7 @@
} else {
int beg_pos = peek_position();
elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
CheckDestructuringElement(elem, classifier, beg_pos,
scanner()->location().end_pos);
}
@@ -1506,11 +1782,10 @@
return result;
}
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
- IdentifierT* name, bool* is_get, bool* is_set, bool* is_computed_name,
- ExpressionClassifier* classifier, bool* ok) {
+ IdentifierT* name, bool* is_get, bool* is_set, bool* is_await,
+ bool* is_computed_name, ExpressionClassifier* classifier, bool* ok) {
Token::Value token = peek();
int pos = peek_position();
@@ -1555,6 +1830,9 @@
default:
*name = ParseIdentifierName(CHECK_OK);
scanner()->IsGetOrSet(is_get, is_set);
+ if (this->IsAwait(*name)) {
+ *is_await = true;
+ }
break;
}
@@ -1564,38 +1842,50 @@
: factory()->NewStringLiteral(*name, pos);
}
-
template <class Traits>
typename ParserBase<Traits>::ObjectLiteralPropertyT
ParserBase<Traits>::ParsePropertyDefinition(
ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
- bool is_static, bool* is_computed_name, bool* has_seen_constructor,
+ MethodKind method_kind, bool* is_computed_name, bool* has_seen_constructor,
ExpressionClassifier* classifier, IdentifierT* name, bool* ok) {
- DCHECK(!in_class || is_static || has_seen_constructor != nullptr);
+ DCHECK(!in_class || IsStaticMethod(method_kind) ||
+ has_seen_constructor != nullptr);
ExpressionT value = this->EmptyExpression();
bool is_get = false;
bool is_set = false;
+ bool is_await = false;
bool is_generator = Check(Token::MUL);
+ bool is_async = false;
+ const bool is_static = IsStaticMethod(method_kind);
Token::Value name_token = peek();
+
+ if (is_generator) {
+ method_kind |= MethodKind::Generator;
+ } else if (allow_harmony_async_await() && name_token == Token::ASYNC &&
+ !scanner()->HasAnyLineTerminatorAfterNext() &&
+ PeekAhead() != Token::LPAREN && PeekAhead()) {
+ is_async = true;
+ }
+
int next_beg_pos = scanner()->peek_location().beg_pos;
int next_end_pos = scanner()->peek_location().end_pos;
- ExpressionT name_expression =
- ParsePropertyName(name, &is_get, &is_set, is_computed_name, classifier,
- CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ ExpressionT name_expression = ParsePropertyName(
+ name, &is_get, &is_set, &is_await, is_computed_name, classifier,
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (fni_ != nullptr && !*is_computed_name) {
this->PushLiteralName(fni_, *name);
}
if (!in_class && !is_generator) {
- DCHECK(!is_static);
+ DCHECK(!IsStaticMethod(method_kind));
if (peek() == Token::COLON) {
// PropertyDefinition
// PropertyName ':' AssignmentExpression
if (!*is_computed_name) {
- checker->CheckProperty(name_token, kValueProperty, false, false,
+ checker->CheckProperty(name_token, kValueProperty, MethodKind::Normal,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
}
Consume(Token::COLON);
@@ -1605,12 +1895,12 @@
CheckDestructuringElement(value, classifier, beg_pos,
scanner()->location().end_pos);
- return factory()->NewObjectLiteralProperty(name_expression, value, false,
- *is_computed_name);
+ return factory()->NewObjectLiteralProperty(name_expression, value,
+ is_static, *is_computed_name);
}
- if (Token::IsIdentifier(name_token, language_mode(),
- this->is_generator()) &&
+ if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(),
+ parsing_module_) &&
(peek() == Token::COMMA || peek() == Token::RBRACE ||
peek() == Token::ASSIGN)) {
// PropertyDefinition
@@ -1627,7 +1917,11 @@
classifier->RecordLetPatternError(
scanner()->location(), MessageTemplate::kLetInLexicalBinding);
}
-
+ if (is_await && is_async_function()) {
+ classifier->RecordPatternError(
+ Scanner::Location(next_beg_pos, next_end_pos),
+ MessageTemplate::kAwaitBindingIdentifier);
+ }
ExpressionT lhs = this->ExpressionFromIdentifier(
*name, next_beg_pos, next_end_pos, scope_, factory());
CheckDestructuringElement(lhs, classifier, next_beg_pos, next_end_pos);
@@ -1655,7 +1949,7 @@
}
return factory()->NewObjectLiteralProperty(
- name_expression, value, ObjectLiteralProperty::COMPUTED, false,
+ name_expression, value, ObjectLiteralProperty::COMPUTED, is_static,
false);
}
}
@@ -1665,20 +1959,32 @@
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
MessageTemplate::kInvalidDestructuringTarget);
+ if (is_async && !IsSpecialMethod(method_kind)) {
+ DCHECK(!is_get);
+ DCHECK(!is_set);
+ bool dont_care;
+ name_expression = ParsePropertyName(
+ name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier,
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ method_kind |= MethodKind::Async;
+ }
+
if (is_generator || peek() == Token::LPAREN) {
// MethodDefinition
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
if (!*is_computed_name) {
- checker->CheckProperty(name_token, kMethodProperty, is_static,
- is_generator,
+ checker->CheckProperty(name_token, kMethodProperty, method_kind,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
}
- FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
- : FunctionKind::kConciseMethod;
+ FunctionKind kind = is_generator
+ ? FunctionKind::kConciseGeneratorMethod
+ : is_async ? FunctionKind::kAsyncConciseMethod
+ : FunctionKind::kConciseMethod;
- if (in_class && !is_static && this->IsConstructor(*name)) {
+ if (in_class && !IsStaticMethod(method_kind) &&
+ this->IsConstructor(*name)) {
*has_seen_constructor = true;
kind = has_extends ? FunctionKind::kSubclassConstructor
: FunctionKind::kBaseConstructor;
@@ -1694,13 +2000,13 @@
is_static, *is_computed_name);
}
- if (in_class && name_token == Token::STATIC && !is_static) {
+ if (in_class && name_token == Token::STATIC && IsNormalMethod(method_kind)) {
// ClassElement (static)
// 'static' MethodDefinition
*name = this->EmptyIdentifier();
ObjectLiteralPropertyT property = ParsePropertyDefinition(
- checker, true, has_extends, true, is_computed_name, nullptr, classifier,
- name, ok);
+ checker, true, has_extends, MethodKind::Static, is_computed_name,
+ nullptr, classifier, name, ok);
Traits::RewriteNonPattern(classifier, ok);
return property;
}
@@ -1714,12 +2020,11 @@
name_token = peek();
name_expression = ParsePropertyName(
- name, &dont_care, &dont_care, is_computed_name, classifier,
+ name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (!*is_computed_name) {
- checker->CheckProperty(name_token, kAccessorProperty, is_static,
- is_generator,
+ checker->CheckProperty(name_token, kAccessorProperty, method_kind,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
}
@@ -1769,13 +2074,12 @@
FuncNameInferrer::State fni_state(fni_);
const bool in_class = false;
- const bool is_static = false;
const bool has_extends = false;
bool is_computed_name = false;
IdentifierT name = this->EmptyIdentifier();
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
- &checker, in_class, has_extends, is_static, &is_computed_name, NULL,
- classifier, &name, CHECK_OK);
+ &checker, in_class, has_extends, MethodKind::Normal, &is_computed_name,
+ NULL, classifier, &name, CHECK_OK);
if (is_computed_name) {
has_computed_names = true;
@@ -1809,11 +2113,10 @@
pos);
}
-
template <class Traits>
typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
- Scanner::Location* first_spread_arg_loc, ExpressionClassifier* classifier,
- bool* ok) {
+ Scanner::Location* first_spread_arg_loc, bool maybe_arrow,
+ ExpressionClassifier* classifier, bool* ok) {
// Arguments ::
// '(' (AssignmentExpression)*[','] ')'
@@ -1831,6 +2134,7 @@
ExpressionT argument = this->ParseAssignmentExpression(
true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
+ CheckNoTailCallExpressions(classifier, CHECK_OK_CUSTOM(NullExpressionList));
Traits::RewriteNonPattern(classifier, CHECK_OK_CUSTOM(NullExpressionList));
if (is_spread) {
if (!spread_arg.IsValid()) {
@@ -1868,7 +2172,7 @@
}
*first_spread_arg_loc = spread_arg;
- if (spread_arg.IsValid()) {
+ if ((!maybe_arrow || peek() != Token::ARROW) && 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
@@ -1893,25 +2197,38 @@
int lhs_beg_pos = peek_position();
if (peek() == Token::YIELD && is_generator()) {
- return this->ParseYieldExpression(classifier, ok);
+ return this->ParseYieldExpression(accept_IN, classifier, ok);
}
FuncNameInferrer::State fni_state(fni_);
ParserBase<Traits>::Checkpoint checkpoint(this);
ExpressionClassifier arrow_formals_classifier(this,
classifier->duplicate_finder());
+
+ bool is_async = allow_harmony_async_await() && peek() == Token::ASYNC &&
+ !scanner()->HasAnyLineTerminatorAfterNext();
+
bool parenthesized_formals = peek() == Token::LPAREN;
- if (!parenthesized_formals) {
+ if (!is_async && !parenthesized_formals) {
ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
}
ExpressionT expression = this->ParseConditionalExpression(
accept_IN, &arrow_formals_classifier, CHECK_OK);
+
+ if (is_async && peek_any_identifier() && PeekAhead() == Token::ARROW) {
+ // async Identifier => AsyncConciseBody
+ IdentifierT name =
+ ParseAndClassifyIdentifier(&arrow_formals_classifier, CHECK_OK);
+ expression = this->ExpressionFromIdentifier(
+ name, position(), scanner()->location().end_pos, scope_, factory());
+ }
+
if (peek() == Token::ARROW) {
classifier->RecordPatternError(scanner()->peek_location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::ARROW));
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
- parenthesized_formals, CHECK_OK);
+ parenthesized_formals, is_async, CHECK_OK);
// This reads strangely, but is correct: it checks whether any
// sub-expression of the parameter list failed to be a valid formal
// parameter initializer. Since YieldExpressions are banned anywhere
@@ -1919,9 +2236,11 @@
// TODO(adamk): Rename "FormalParameterInitializerError" to refer to
// "YieldExpression", which is its only use.
ValidateFormalParameterInitializer(&arrow_formals_classifier, ok);
+
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
- Scope* scope =
- this->NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
+ Scope* scope = this->NewScope(scope_, FUNCTION_SCOPE,
+ is_async ? FunctionKind::kAsyncArrowFunction
+ : FunctionKind::kArrowFunction);
// Because the arrow's parameters were parsed in the outer scope, any
// usage flags that might have been triggered there need to be copied
// to the arrow scope.
@@ -1943,7 +2262,7 @@
duplicate_loc);
}
expression = this->ParseArrowFunctionLiteral(
- accept_IN, parameters, arrow_formals_classifier, CHECK_OK);
+ accept_IN, parameters, is_async, arrow_formals_classifier, CHECK_OK);
if (fni_ != nullptr) fni_->Infer();
@@ -1960,8 +2279,10 @@
classifier->Accumulate(
&arrow_formals_classifier,
ExpressionClassifier::StandardProductions |
- ExpressionClassifier::FormalParametersProductions |
- ExpressionClassifier::CoverInitializedNameProduction,
+ ExpressionClassifier::FormalParametersProductions |
+ ExpressionClassifier::CoverInitializedNameProduction |
+ ExpressionClassifier::AsyncArrowFormalParametersProduction |
+ ExpressionClassifier::AsyncBindingPatternProduction,
false);
if (!Token::IsAssignmentOp(peek())) {
@@ -1974,6 +2295,8 @@
// Now pending non-pattern expressions must be discarded.
arrow_formals_classifier.Discard();
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
+
if (IsValidPattern(expression) && peek() == Token::ASSIGN) {
classifier->ForgiveCoverInitializedNameError();
ValidateAssignmentPattern(classifier, CHECK_OK);
@@ -1998,10 +2321,13 @@
ExpressionT right =
this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK);
+ CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK);
Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK);
classifier->Accumulate(
- &rhs_classifier, ExpressionClassifier::ExpressionProductions |
- ExpressionClassifier::CoverInitializedNameProduction);
+ &rhs_classifier,
+ ExpressionClassifier::ExpressionProductions |
+ ExpressionClassifier::CoverInitializedNameProduction |
+ ExpressionClassifier::AsyncArrowFormalParametersProduction);
// TODO(1231235): We try to estimate the set of properties set by
// constructors. We define a new property whenever there is an
@@ -2047,7 +2373,8 @@
template <class Traits>
typename ParserBase<Traits>::ExpressionT
-ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
+ParserBase<Traits>::ParseYieldExpression(bool accept_IN,
+ ExpressionClassifier* classifier,
bool* ok) {
// YieldExpression ::
// 'yield' ([no line terminator] '*'? AssignmentExpression)?
@@ -2078,7 +2405,7 @@
if (!delegating) break;
// Delegating yields require an RHS; fall through.
default:
- expression = ParseAssignmentExpression(false, classifier, CHECK_OK);
+ expression = ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
break;
}
@@ -2096,6 +2423,67 @@
return yield;
}
+template <class Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseTailCallExpression(ExpressionClassifier* classifier,
+ bool* ok) {
+ // TailCallExpression::
+ // 'continue' MemberExpression Arguments
+ // 'continue' CallExpression Arguments
+ // 'continue' MemberExpression TemplateLiteral
+ // 'continue' CallExpression TemplateLiteral
+ Expect(Token::CONTINUE, CHECK_OK);
+ int pos = position();
+ int sub_expression_pos = peek_position();
+ ExpressionT expression =
+ this->ParseLeftHandSideExpression(classifier, CHECK_OK);
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
+
+ Scanner::Location loc(pos, scanner()->location().end_pos);
+ if (!expression->IsCall()) {
+ Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
+ ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedInsideTailCall);
+ *ok = false;
+ return Traits::EmptyExpression();
+ }
+ if (Traits::IsDirectEvalCall(expression)) {
+ Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
+ ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCallOfEval);
+ *ok = false;
+ return Traits::EmptyExpression();
+ }
+ if (!is_strict(language_mode())) {
+ ReportMessageAt(loc, MessageTemplate::kUnexpectedSloppyTailCall);
+ *ok = false;
+ return Traits::EmptyExpression();
+ }
+ ReturnExprContext return_expr_context =
+ function_state_->return_expr_context();
+ if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) {
+ MessageTemplate::Template msg = MessageTemplate::kNone;
+ switch (return_expr_context) {
+ case ReturnExprContext::kInsideValidReturnStatement:
+ UNREACHABLE();
+ return Traits::EmptyExpression();
+ case ReturnExprContext::kInsideValidBlock:
+ msg = MessageTemplate::kUnexpectedTailCall;
+ break;
+ case ReturnExprContext::kInsideTryBlock:
+ msg = MessageTemplate::kUnexpectedTailCallInTryBlock;
+ break;
+ case ReturnExprContext::kInsideForInOfBody:
+ msg = MessageTemplate::kUnexpectedTailCallInForInOf;
+ break;
+ }
+ ReportMessageAt(loc, msg);
+ *ok = false;
+ return Traits::EmptyExpression();
+ }
+ classifier->RecordTailCallExpressionError(
+ loc, MessageTemplate::kUnexpectedTailCall);
+ function_state_->AddExplicitTailCallExpression(expression, loc);
+ return expression;
+}
// Precedence = 3
template <class Traits>
@@ -2112,6 +2500,7 @@
ExpressionT expression =
this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
if (peek() != Token::CONDITIONAL) return expression;
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
ArrowFormalParametersUnexpectedToken(classifier);
BindingPatternUnexpectedToken(classifier);
@@ -2140,6 +2529,7 @@
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
// prec1 >= 4
while (Precedence(peek(), accept_IN) == prec1) {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2150,6 +2540,9 @@
const int next_prec = is_right_associative ? prec1 : prec1 + 1;
ExpressionT y =
ParseBinaryExpression(next_prec, accept_IN, classifier, CHECK_OK);
+ if (op != Token::OR && op != Token::AND) {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
+ }
Traits::RewriteNonPattern(classifier, CHECK_OK);
if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos,
@@ -2168,16 +2561,11 @@
case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
default: break;
}
- if (FLAG_harmony_instanceof && cmp == Token::INSTANCEOF) {
- x = Traits::RewriteInstanceof(x, y, pos);
- } else {
- x = factory()->NewCompareOperation(cmp, x, y, pos);
- if (cmp != op) {
- // The comparison was negated - add a NOT.
- x = factory()->NewUnaryOperation(Token::NOT, x, pos);
- }
+ x = factory()->NewCompareOperation(cmp, x, y, pos);
+ if (cmp != op) {
+ // The comparison was negated - add a NOT.
+ x = factory()->NewUnaryOperation(Token::NOT, x, pos);
}
-
} else if (op == Token::EXP) {
x = Traits::RewriteExponentiation(x, y, pos);
} else {
@@ -2205,6 +2593,7 @@
// '-' UnaryExpression
// '~' UnaryExpression
// '!' UnaryExpression
+ // [+Await] AwaitExpression[?Yield]
Token::Value op = peek();
if (Token::IsUnaryOp(op)) {
@@ -2214,6 +2603,7 @@
op = Next();
int pos = position();
ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK);
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
if (op == Token::DELETE && is_strict(language_mode())) {
@@ -2239,6 +2629,7 @@
op = Next();
int beg_pos = peek_position();
ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
expression = this->CheckAndRewriteReferenceExpression(
expression, beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
@@ -2250,6 +2641,40 @@
expression,
position());
+ } else if (is_async_function() && peek() == Token::AWAIT) {
+ int beg_pos = peek_position();
+ switch (PeekAhead()) {
+ case Token::RPAREN:
+ case Token::RBRACK:
+ case Token::RBRACE:
+ case Token::ASSIGN:
+ case Token::COMMA: {
+ Next();
+ IdentifierT name = this->GetSymbol(scanner());
+
+ // Possibly async arrow formals --- record ExpressionError just in case.
+ ExpressionUnexpectedToken(classifier);
+ classifier->RecordAsyncBindingPatternError(
+ Scanner::Location(beg_pos, scanner()->location().end_pos),
+ MessageTemplate::kAwaitBindingIdentifier);
+ classifier->RecordAsyncArrowFormalParametersError(
+ Scanner::Location(beg_pos, scanner()->location().end_pos),
+ MessageTemplate::kAwaitBindingIdentifier);
+
+ return this->ExpressionFromIdentifier(
+ name, beg_pos, scanner()->location().end_pos, scope_, factory());
+ }
+ default:
+ break;
+ }
+ Consume(Token::AWAIT);
+
+ ExpressionT value = ParseUnaryExpression(classifier, CHECK_OK);
+
+ classifier->RecordFormalParameterInitializerError(
+ Scanner::Location(beg_pos, scanner()->location().end_pos),
+ MessageTemplate::kAwaitExpressionFormalParameter);
+ return Traits::RewriteAwaitExpression(value, beg_pos);
} else {
return this->ParsePostfixExpression(classifier, ok);
}
@@ -2268,6 +2693,7 @@
this->ParseLeftHandSideExpression(classifier, CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2287,7 +2713,6 @@
return expression;
}
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseLeftHandSideExpression(
@@ -2295,12 +2720,18 @@
// LeftHandSideExpression ::
// (NewExpression | MemberExpression) ...
- ExpressionT result =
- this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
+ if (FLAG_harmony_explicit_tailcalls && peek() == Token::CONTINUE) {
+ return this->ParseTailCallExpression(classifier, ok);
+ }
+
+ bool is_async = false;
+ ExpressionT result = this->ParseMemberWithNewPrefixesExpression(
+ classifier, &is_async, CHECK_OK);
while (true) {
switch (peek()) {
case Token::LBRACK: {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2314,13 +2745,13 @@
}
case Token::LPAREN: {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
+ int pos;
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
- ArrowFormalParametersUnexpectedToken(classifier);
-
- int pos;
if (scanner()->current_token() == Token::IDENTIFIER ||
- scanner()->current_token() == Token::SUPER) {
+ scanner()->current_token() == Token::SUPER ||
+ scanner()->current_token() == Token::ASYNC) {
// For call of an identifier we want to report position of
// the identifier as position of the call in the stack trace.
pos = position();
@@ -2340,7 +2771,18 @@
}
Scanner::Location spread_pos;
typename Traits::Type::ExpressionList args =
- ParseArguments(&spread_pos, classifier, CHECK_OK);
+ ParseArguments(&spread_pos, is_async, classifier, CHECK_OK);
+
+ if (V8_UNLIKELY(is_async && peek() == Token::ARROW)) {
+ if (args->length()) {
+ // async ( Arguments ) => ...
+ return Traits::ExpressionListToExpression(args);
+ }
+ // async () => ...
+ return factory()->NewEmptyParentheses(pos);
+ }
+
+ ArrowFormalParametersUnexpectedToken(classifier);
// Keep track of eval() calls since they disable all local variable
// optimizations.
@@ -2372,6 +2814,7 @@
}
case Token::PERIOD: {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2386,6 +2829,7 @@
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2399,11 +2843,10 @@
}
}
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
- ExpressionClassifier* classifier, bool* ok) {
+ ExpressionClassifier* classifier, bool* is_async, bool* ok) {
// NewExpression ::
// ('new')+ MemberExpression
//
@@ -2436,7 +2879,8 @@
} else if (peek() == Token::PERIOD) {
return ParseNewTargetExpression(CHECK_OK);
} else {
- result = this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
+ result = this->ParseMemberWithNewPrefixesExpression(classifier, is_async,
+ CHECK_OK);
}
Traits::RewriteNonPattern(classifier, CHECK_OK);
if (peek() == Token::LPAREN) {
@@ -2452,8 +2896,8 @@
result = factory()->NewCallNew(result, args, new_pos);
}
// The expression can still continue with . or [ after the arguments.
- result =
- this->ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
+ result = this->ParseMemberExpressionContinuation(result, is_async,
+ classifier, CHECK_OK);
return result;
}
// NewExpression without arguments.
@@ -2461,14 +2905,13 @@
new_pos);
}
// No 'new' or 'super' keyword.
- return this->ParseMemberExpression(classifier, ok);
+ return this->ParseMemberExpression(classifier, is_async, ok);
}
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
- bool* ok) {
+ bool* is_async, bool* ok) {
// MemberExpression ::
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
@@ -2525,10 +2968,11 @@
const bool is_new = false;
result = ParseSuperExpression(is_new, classifier, CHECK_OK);
} else {
- result = ParsePrimaryExpression(classifier, CHECK_OK);
+ result = ParsePrimaryExpression(classifier, is_async, CHECK_OK);
}
- result = ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
+ result =
+ ParseMemberExpressionContinuation(result, is_async, classifier, CHECK_OK);
return result;
}
@@ -2595,16 +3039,17 @@
return this->NewTargetExpression(scope_, factory(), pos);
}
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseMemberExpressionContinuation(
- ExpressionT expression, ExpressionClassifier* classifier, bool* ok) {
+ ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
+ bool* ok) {
// Parses this part of MemberExpression:
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
while (true) {
switch (peek()) {
case Token::LBRACK: {
+ *is_async = false;
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2621,6 +3066,7 @@
break;
}
case Token::PERIOD: {
+ *is_async = false;
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2637,6 +3083,7 @@
}
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
+ *is_async = false;
Traits::RewriteNonPattern(classifier, CHECK_OK);
BindingPatternUnexpectedToken(classifier);
ArrowFormalParametersUnexpectedToken(classifier);
@@ -2790,28 +3237,32 @@
template <class Traits>
bool ParserBase<Traits>::IsNextLetKeyword() {
DCHECK(peek() == Token::LET);
- if (!allow_let()) {
- return false;
- }
Token::Value next_next = PeekAhead();
switch (next_next) {
case Token::LBRACE:
case Token::LBRACK:
case Token::IDENTIFIER:
case Token::STATIC:
- case Token::LET: // Yes, you can do let let = ... in sloppy mode
+ case Token::LET: // `let let;` is disallowed by static semantics, but the
+ // token must be first interpreted as a keyword in order
+ // for those semantics to apply. This ensures that ASI is
+ // not honored when a LineTerminator separates the
+ // tokens.
case Token::YIELD:
+ case Token::AWAIT:
+ case Token::ASYNC:
return true;
+ case Token::FUTURE_STRICT_RESERVED_WORD:
+ return is_sloppy(language_mode());
default:
return false;
}
}
-
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseArrowFunctionLiteral(
- bool accept_IN, const FormalParametersT& formal_parameters,
+ bool accept_IN, const FormalParametersT& formal_parameters, bool is_async,
const ExpressionClassifier& formals_classifier, bool* ok) {
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
// ASI inserts `;` after arrow parameters if a line terminator is found.
@@ -2828,10 +3279,11 @@
int expected_property_count = -1;
Scanner::Location super_loc;
+ FunctionKind arrow_kind = is_async ? kAsyncArrowFunction : kArrowFunction;
{
typename Traits::Type::Factory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_,
- formal_parameters.scope, kArrowFunction,
+ formal_parameters.scope, arrow_kind,
&function_factory);
function_state.SkipMaterializedLiterals(
@@ -2857,7 +3309,7 @@
} else {
body = this->ParseEagerFunctionBody(
this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
- kArrowFunction, FunctionLiteral::kAnonymousExpression, CHECK_OK);
+ arrow_kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
materialized_literal_count =
function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
@@ -2865,20 +3317,31 @@
} else {
// Single-expression body
int pos = position();
- parenthesized_function_ = false;
ExpressionClassifier classifier(this);
- ExpressionT expression =
- ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
- Traits::RewriteNonPattern(&classifier, CHECK_OK);
+ DCHECK(ReturnExprContext::kInsideValidBlock ==
+ function_state_->return_expr_context());
+ ReturnExprScope allow_tail_calls(
+ function_state_, ReturnExprContext::kInsideValidReturnStatement);
body = this->NewStatementList(1, zone());
- this->AddParameterInitializationBlock(formal_parameters, body, CHECK_OK);
- body->Add(factory()->NewReturnStatement(expression, pos), zone());
+ this->AddParameterInitializationBlock(formal_parameters, body, is_async,
+ CHECK_OK);
+ if (is_async) {
+ this->ParseAsyncArrowSingleExpressionBody(body, accept_IN, &classifier,
+ pos, CHECK_OK);
+ Traits::RewriteNonPattern(&classifier, CHECK_OK);
+ } else {
+ ExpressionT expression =
+ ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
+ Traits::RewriteNonPattern(&classifier, CHECK_OK);
+ body->Add(factory()->NewReturnStatement(expression, pos), zone());
+ if (allow_tailcalls() && !is_sloppy(language_mode())) {
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ this->MarkTailPosition(expression);
+ }
+ }
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
- // ES6 14.6.1 Static Semantics: IsInTailPosition
- if (allow_tailcalls() && !is_sloppy(language_mode())) {
- this->MarkTailPosition(expression);
- }
+ this->MarkCollectedTailCallExpressions();
}
super_loc = function_state.super_location();
@@ -2897,9 +3360,7 @@
CheckStrictOctalLiteral(formal_parameters.scope->start_position(),
scanner()->location().end_pos, CHECK_OK);
}
- if (is_strict(language_mode()) || allow_harmony_sloppy()) {
- this->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
- }
+ this->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
Traits::RewriteDestructuringAssignments();
}
@@ -2909,7 +3370,7 @@
materialized_literal_count, expected_property_count, num_parameters,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression,
- FunctionLiteral::kShouldLazyCompile, FunctionKind::kArrowFunction,
+ FunctionLiteral::kShouldLazyCompile, arrow_kind,
formal_parameters.scope->start_position());
function_literal->set_function_token_position(
@@ -2979,6 +3440,7 @@
int expr_pos = peek_position();
ExpressionT expression = this->ParseExpression(true, classifier, CHECK_OK);
+ CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
Traits::AddTemplateExpression(&ts, expression);
@@ -3077,13 +3539,12 @@
#undef CHECK_OK
#undef CHECK_OK_CUSTOM
-
template <typename Traits>
void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
- Token::Value property, PropertyKind type, bool is_static, bool is_generator,
+ Token::Value property, PropertyKind type, MethodKind method_type,
bool* ok) {
- DCHECK(!is_static);
- DCHECK(!is_generator || type == kMethodProperty);
+ DCHECK(!IsStaticMethod(method_type));
+ DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty);
if (property == Token::SMI || property == Token::NUMBER) return;
@@ -3098,26 +3559,28 @@
}
}
-
template <typename Traits>
void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
- Token::Value property, PropertyKind type, bool is_static, bool is_generator,
+ Token::Value property, PropertyKind type, MethodKind method_type,
bool* ok) {
DCHECK(type == kMethodProperty || type == kAccessorProperty);
if (property == Token::SMI || property == Token::NUMBER) return;
- if (is_static) {
+ if (IsStaticMethod(method_type)) {
if (IsPrototype()) {
this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
*ok = false;
return;
}
} else if (IsConstructor()) {
- if (is_generator || type == kAccessorProperty) {
+ const bool is_generator = IsGeneratorMethod(method_type);
+ const bool is_async = IsAsyncMethod(method_type);
+ if (is_generator || is_async || type == kAccessorProperty) {
MessageTemplate::Template msg =
is_generator ? MessageTemplate::kConstructorIsGenerator
- : MessageTemplate::kConstructorIsAccessor;
+ : is_async ? MessageTemplate::kConstructorIsAsync
+ : MessageTemplate::kConstructorIsAccessor;
this->parser()->ReportMessage(msg);
*ok = false;
return;
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index fa2893b..822c49e 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -39,7 +39,6 @@
}
}
-
ParseInfo::ParseInfo(Zone* zone)
: zone_(zone),
flags_(0),
@@ -51,15 +50,14 @@
unicode_cache_(nullptr),
stack_limit_(0),
hash_seed_(0),
+ isolate_(nullptr),
cached_data_(nullptr),
ast_value_factory_(nullptr),
literal_(nullptr),
scope_(nullptr) {}
-
ParseInfo::ParseInfo(Zone* zone, Handle<JSFunction> function)
: ParseInfo(zone, Handle<SharedFunctionInfo>(function->shared())) {
- set_closure(function);
set_context(Handle<Context>(function->context()));
}
@@ -332,6 +330,10 @@
return identifier == parser_->ast_value_factory()->undefined_string();
}
+bool ParserTraits::IsAwait(const AstRawString* identifier) const {
+ return identifier == parser_->ast_value_factory()->await_string();
+}
+
bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
return identifier == parser_->ast_value_factory()->prototype_string();
}
@@ -604,8 +606,7 @@
const AstRawString* ParserTraits::GetNumberAsSymbol(Scanner* scanner) {
double double_value = parser_->scanner()->DoubleValue();
char array[100];
- const char* string =
- DoubleToCString(double_value, Vector<char>(array, arraysize(array)));
+ const char* string = DoubleToCString(double_value, ArrayVector(array));
return parser_->ast_value_factory()->GetOneByteString(string);
}
@@ -768,6 +769,10 @@
expression->MarkTail();
}
+void ParserTraits::MarkCollectedTailCallExpressions() {
+ parser_->MarkCollectedTailCallExpressions();
+}
+
Parser::Parser(ParseInfo* info)
: ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(),
info->extension(), info->ast_value_factory(),
@@ -789,16 +794,15 @@
set_allow_natives(FLAG_allow_natives_syntax || info->is_native());
set_allow_tailcalls(FLAG_harmony_tailcalls && !info->is_native() &&
info->isolate()->is_tail_call_elimination_enabled());
- set_allow_harmony_sloppy(FLAG_harmony_sloppy);
- set_allow_harmony_sloppy_function(FLAG_harmony_sloppy_function);
- set_allow_harmony_sloppy_let(FLAG_harmony_sloppy_let);
set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
+ set_allow_harmony_for_in(FLAG_harmony_for_in);
set_allow_harmony_function_name(FLAG_harmony_function_name);
set_allow_harmony_function_sent(FLAG_harmony_function_sent);
set_allow_harmony_restrictive_declarations(
FLAG_harmony_restrictive_declarations);
set_allow_harmony_exponentiation_operator(
FLAG_harmony_exponentiation_operator);
+ set_allow_harmony_async_await(FLAG_harmony_async_await);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@@ -821,6 +825,7 @@
DCHECK(parsing_on_main_thread_);
HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
+ RuntimeCallTimerScope runtime_timer(isolate, &RuntimeCallStats::Parse);
TRACE_EVENT0("v8", "V8.Parse");
Handle<String> source(String::cast(info->script()->source()));
isolate->counters()->total_parse_size()->Increment(source->length());
@@ -925,15 +930,16 @@
FunctionState function_state(&function_state_, &scope_, scope,
kNormalFunction, &function_factory);
- // Don't count the mode in the use counters--give the program a chance
- // to enable script/module-wide strict mode below.
- scope_->SetLanguageMode(info->language_mode());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
bool ok = true;
int beg_pos = scanner()->location().beg_pos;
- if (info->is_module()) {
+ parsing_module_ = info->is_module();
+ if (parsing_module_) {
ParseModuleItemList(body, &ok);
} else {
+ // Don't count the mode in the use counters--give the program a chance
+ // to enable script-wide strict mode below.
+ scope_->SetLanguageMode(info->language_mode());
ParseStatementList(body, Token::EOS, &ok);
}
@@ -943,8 +949,10 @@
if (ok && is_strict(language_mode())) {
CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
+ CheckDecimalLiteralWithLeadingZero(use_counts_, beg_pos,
+ scanner()->location().end_pos);
}
- if (ok && is_sloppy(language_mode()) && allow_harmony_sloppy_function()) {
+ if (ok && is_sloppy(language_mode())) {
// TODO(littledan): Function bindings on the global object that modify
// pre-existing bindings should be made writable, enumerable and
// nonconfigurable if possible, whereas this code will leave attributes
@@ -984,6 +992,7 @@
// It's OK to use the Isolate & counters here, since this function is only
// called in the main thread.
DCHECK(parsing_on_main_thread_);
+ RuntimeCallTimerScope runtime_timer(isolate, &RuntimeCallStats::ParseLazy);
HistogramTimerScope timer_scope(isolate->counters()->parse_lazy());
TRACE_EVENT0("v8", "V8.ParseLazy");
Handle<String> source(String::cast(info->script()->source()));
@@ -1054,12 +1063,12 @@
// Parse the function literal.
Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
info->set_script_scope(scope);
- if (!info->closure().is_null()) {
+ if (!info->context().is_null()) {
// Ok to use Isolate here, since lazy function parsing is only done in the
// main thread.
DCHECK(parsing_on_main_thread_);
- scope = Scope::DeserializeScopeChain(isolate, zone(),
- info->closure()->context(), scope);
+ scope = Scope::DeserializeScopeChain(isolate, zone(), *info->context(),
+ scope);
}
original_scope_ = scope;
AstNodeFactory function_factory(ast_value_factory());
@@ -1073,6 +1082,13 @@
bool ok = true;
if (shared_info->is_arrow()) {
+ bool is_async = allow_harmony_async_await() && shared_info->is_async();
+ if (is_async) {
+ DCHECK(!scanner()->HasAnyLineTerminatorAfterNext());
+ Consume(Token::ASYNC);
+ DCHECK(peek_any_identifier() || peek() == Token::LPAREN);
+ }
+
// TODO(adamk): We should construct this scope from the ScopeInfo.
Scope* scope =
NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
@@ -1113,8 +1129,8 @@
checkpoint.Restore(&formals.materialized_literals_count);
// Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
// not be observable, or else the preparser would have failed.
- Expression* expression =
- ParseArrowFunctionLiteral(true, formals, formals_classifier, &ok);
+ Expression* expression = ParseArrowFunctionLiteral(
+ true, formals, is_async, formals_classifier, &ok);
if (ok) {
// Scanning must end at the same position that was recorded
// previously. If not, parsing has been interrupted due to a stack
@@ -1253,18 +1269,15 @@
// StatementListItem:
// Statement
// Declaration
-
- switch (peek()) {
+ const Token::Value peeked = peek();
+ switch (peeked) {
case Token::FUNCTION:
- return ParseFunctionDeclaration(NULL, ok);
+ return ParseHoistableDeclaration(NULL, ok);
case Token::CLASS:
Consume(Token::CLASS);
return ParseClassDeclaration(NULL, ok);
case Token::CONST:
- if (allow_const()) {
- return ParseVariableStatement(kStatementListItem, NULL, ok);
- }
- break;
+ return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::VAR:
return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::LET:
@@ -1272,6 +1285,13 @@
return ParseVariableStatement(kStatementListItem, NULL, ok);
}
break;
+ case Token::ASYNC:
+ if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
+ !scanner()->HasAnyLineTerminatorAfterNext()) {
+ Consume(Token::ASYNC);
+ return ParseAsyncFunctionDeclaration(NULL, ok);
+ }
+ /* falls through */
default:
break;
}
@@ -1306,7 +1326,6 @@
// ModuleItem*
DCHECK(scope_->is_module_scope());
- RaiseLanguageMode(STRICT);
while (peek() != Token::EOS) {
Statement* stat = ParseModuleItem(CHECK_OK);
@@ -1367,7 +1386,7 @@
// Keep track of the first reserved word encountered in case our
// caller needs to report an error.
if (!reserved_loc->IsValid() &&
- !Token::IsIdentifier(name_tok, STRICT, false)) {
+ !Token::IsIdentifier(name_tok, STRICT, false, parsing_module_)) {
*reserved_loc = scanner()->location();
}
const AstRawString* local_name = ParseIdentifierName(CHECK_OK);
@@ -1418,7 +1437,8 @@
if (CheckContextualKeyword(CStrVector("as"))) {
local_name = ParseIdentifierName(CHECK_OK);
}
- if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false)) {
+ if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false,
+ parsing_module_)) {
*ok = false;
ReportMessage(MessageTemplate::kUnexpectedReserved);
return NULL;
@@ -1427,7 +1447,7 @@
ReportMessage(MessageTemplate::kStrictEvalArguments);
return NULL;
}
- VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
+ VariableProxy* proxy = NewUnresolved(local_name, CONST);
ImportDeclaration* declaration =
factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
@@ -1475,7 +1495,7 @@
if (tok != Token::MUL && tok != Token::LBRACE) {
const AstRawString* local_name =
ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
- VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
+ VariableProxy* proxy = NewUnresolved(local_name, CONST);
import_default_declaration = factory()->NewImportDeclaration(
proxy, ast_value_factory()->default_string(), NULL, scope_, pos);
Declare(import_default_declaration, DeclarationDescriptor::NORMAL, true,
@@ -1561,7 +1581,10 @@
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
} else {
- result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK);
+ result = ParseHoistableDeclaration(
+ pos, is_generator ? ParseFunctionFlags::kIsGenerator
+ : ParseFunctionFlags::kIsNormal,
+ &names, CHECK_OK);
}
break;
}
@@ -1580,6 +1603,30 @@
}
break;
+ case Token::ASYNC:
+ if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
+ !scanner()->HasAnyLineTerminatorAfterNext()) {
+ Consume(Token::ASYNC);
+ Consume(Token::FUNCTION);
+ int pos = position();
+ if (peek() == Token::LPAREN) {
+ // AsyncFunctionDeclaration[+Default] ::
+ // async [no LineTerminator here] function ( FormalParameters ) {
+ // AsyncFunctionBody
+ // }
+ default_export = ParseFunctionLiteral(
+ default_string, Scanner::Location::invalid(),
+ kSkipFunctionNameCheck, FunctionKind::kAsyncFunction, pos,
+ FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
+ result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ } else {
+ result = ParseHoistableDeclaration(pos, ParseFunctionFlags::kIsAsync,
+ &names, CHECK_OK);
+ }
+ break;
+ }
+ /* falls through */
+
default: {
int pos = peek_position();
ExpressionClassifier classifier(this);
@@ -1690,7 +1737,7 @@
}
case Token::FUNCTION:
- result = ParseFunctionDeclaration(&names, CHECK_OK);
+ result = ParseHoistableDeclaration(&names, CHECK_OK);
break;
case Token::CLASS:
@@ -1704,6 +1751,14 @@
result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
break;
+ case Token::ASYNC:
+ if (allow_harmony_async_await()) {
+ Consume(Token::ASYNC);
+ result = ParseAsyncFunctionDeclaration(&names, CHECK_OK);
+ break;
+ }
+ /* falls through */
+
default:
*ok = false;
ReportUnexpectedToken(scanner()->current_token());
@@ -1881,6 +1936,7 @@
DCHECK(proxy->raw_name() != NULL);
const AstRawString* name = proxy->raw_name();
VariableMode mode = declaration->mode();
+ DCHECK(IsDeclaredVariableMode(mode) && mode != CONST_LEGACY);
bool is_function_declaration = declaration->IsFunctionDeclaration();
if (scope == nullptr) scope = scope_;
Scope* declaration_scope =
@@ -1912,11 +1968,8 @@
}
var = declaration_scope->DeclareLocal(
name, mode, declaration->initialization(), kind, kNotAssigned);
- } else if ((IsLexicalVariableMode(mode) ||
- IsLexicalVariableMode(var->mode())) &&
- // Lexical bindings may appear for some parameters in sloppy
- // mode even with --harmony-sloppy off.
- (is_strict(language_mode()) || allow_harmony_sloppy())) {
+ } else if (IsLexicalVariableMode(mode) ||
+ IsLexicalVariableMode(var->mode())) {
// Allow duplicate function decls for web compat, see bug 4693.
if (is_sloppy(language_mode()) && is_function_declaration &&
var->is_function()) {
@@ -1986,14 +2039,6 @@
// RuntimeHidden_DeclareLookupSlot calls.
declaration_scope->AddDeclaration(declaration);
- if (mode == CONST_LEGACY && declaration_scope->is_script_scope()) {
- // For global const variables we bind the proxy to a variable.
- DCHECK(resolve); // should be set by all callers
- Variable::Kind kind = Variable::NORMAL;
- var = new (zone()) Variable(declaration_scope, name, mode, kind,
- kNeedsInitialization, kNotAssigned);
- }
-
// If requested and we have a local variable, bind the proxy to the variable
// at parse-time. This is used for functions (and consts) declared inside
// statements: the corresponding function (or const) variable must be in the
@@ -2069,17 +2114,33 @@
}
-Statement* Parser::ParseFunctionDeclaration(
+Statement* Parser::ParseHoistableDeclaration(
ZoneList<const AstRawString*>* names, bool* ok) {
Expect(Token::FUNCTION, CHECK_OK);
int pos = position();
- bool is_generator = Check(Token::MUL);
- return ParseFunctionDeclaration(pos, is_generator, names, ok);
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ if (Check(Token::MUL)) {
+ flags |= ParseFunctionFlags::kIsGenerator;
+ }
+ return ParseHoistableDeclaration(pos, flags, names, ok);
}
+Statement* Parser::ParseAsyncFunctionDeclaration(
+ ZoneList<const AstRawString*>* names, bool* ok) {
+ DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
+ int pos = position();
+ if (scanner()->HasAnyLineTerminatorBeforeNext()) {
+ *ok = false;
+ ReportUnexpectedToken(scanner()->current_token());
+ return nullptr;
+ }
+ Expect(Token::FUNCTION, CHECK_OK);
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
+ return ParseHoistableDeclaration(pos, flags, names, ok);
+}
-Statement* Parser::ParseFunctionDeclaration(
- int pos, bool is_generator, ZoneList<const AstRawString*>* names,
+Statement* Parser::ParseHoistableDeclaration(
+ int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
@@ -2087,10 +2148,21 @@
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
//
// 'function' and '*' (if present) have been consumed by the caller.
+ const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
+ const bool is_async = flags & ParseFunctionFlags::kIsAsync;
+ DCHECK(!is_generator || !is_async);
+
bool is_strict_reserved = false;
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
+ if (V8_UNLIKELY(is_async_function() && this->IsAwait(name))) {
+ ReportMessageAt(scanner()->location(),
+ MessageTemplate::kAwaitBindingIdentifier);
+ *ok = false;
+ return nullptr;
+ }
+
FuncNameInferrer::State fni_state(fni_);
if (fni_ != NULL) fni_->PushEnclosingName(name);
FunctionLiteral* fun = ParseFunctionLiteral(
@@ -2098,7 +2170,8 @@
is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
- : FunctionKind::kNormalFunction,
+ : is_async ? FunctionKind::kAsyncFunction
+ : FunctionKind::kNormalFunction,
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
// Even if we're not at the top-level of the global or a function
@@ -2107,18 +2180,15 @@
// In ES6, a function behaves as a lexical binding, except in
// a script scope, or the initial scope of eval or another function.
VariableMode mode =
- (is_strict(language_mode()) || allow_harmony_sloppy_function()) &&
- !scope_->is_declaration_scope()
- ? LET
- : VAR;
+ (!scope_->is_declaration_scope() || scope_->is_module_scope()) ? LET
+ : VAR;
VariableProxy* proxy = NewUnresolved(name, mode);
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos);
Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
if (names) names->Add(name, zone());
EmptyStatement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- if (is_sloppy(language_mode()) && allow_harmony_sloppy_function() &&
- !scope_->is_declaration_scope()) {
+ if (is_sloppy(language_mode()) && !scope_->is_declaration_scope()) {
SloppyBlockFunctionStatement* delegate =
factory()->NewSloppyBlockFunctionStatement(empty, scope_);
scope_->DeclarationScope()->sloppy_block_function_map()->Declare(name,
@@ -2146,12 +2216,6 @@
//
// so rewrite it as such.
- if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
- ReportMessage(MessageTemplate::kSloppyLexical);
- *ok = false;
- return NULL;
- }
-
int pos = position();
bool is_strict_reserved = false;
const AstRawString* name =
@@ -2282,12 +2346,11 @@
if (peek() == Token::VAR) {
Consume(Token::VAR);
- } else if (peek() == Token::CONST && allow_const()) {
+ } else if (peek() == Token::CONST) {
Consume(Token::CONST);
- DCHECK(is_strict(language_mode()) || allow_harmony_sloppy());
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = CONST;
- } else if (peek() == Token::LET && allow_let()) {
+ } else if (peek() == Token::LET) {
Consume(Token::LET);
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = LET;
@@ -2370,9 +2433,8 @@
return nullptr;
}
- // 'let x' and (legacy) 'const x' initialize 'x' to undefined.
- if (parsing_result->descriptor.mode == LET ||
- parsing_result->descriptor.mode == CONST_LEGACY) {
+ // 'let x' initializes 'x' to undefined.
+ if (parsing_result->descriptor.mode == LET) {
value = GetLiteralUndefined(position());
}
}
@@ -2419,6 +2481,23 @@
return false;
}
+Statement* Parser::ParseFunctionDeclaration(bool* ok) {
+ Consume(Token::FUNCTION);
+ int pos = position();
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ if (Check(Token::MUL)) {
+ flags |= ParseFunctionFlags::kIsGenerator;
+ if (allow_harmony_restrictive_declarations()) {
+ ParserTraits::ReportMessageAt(scanner()->location(),
+ MessageTemplate::kGeneratorInLegacyContext);
+ *ok = false;
+ return nullptr;
+ }
+ }
+
+ return ParseHoistableDeclaration(pos, flags, nullptr, CHECK_OK);
+}
+
Statement* Parser::ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok) {
@@ -2475,7 +2554,7 @@
// ES#sec-labelled-function-declarations Labelled Function Declarations
if (peek() == Token::FUNCTION && is_sloppy(language_mode())) {
if (allow_function == kAllowLabelledFunctionStatement) {
- return ParseFunctionDeclaration(labels, ok);
+ return ParseFunctionDeclaration(ok);
} else {
return ParseScopedStatement(labels, true, ok);
}
@@ -2496,15 +2575,6 @@
}
// Parsed expression statement, followed by semicolon.
- // Detect attempts at 'let' declarations in sloppy mode.
- if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
- expr->AsVariableProxy() != NULL &&
- expr->AsVariableProxy()->raw_name() ==
- ast_value_factory()->let_string()) {
- ReportMessage(MessageTemplate::kSloppyLexical, NULL);
- *ok = false;
- return NULL;
- }
ExpectSemicolon(CHECK_OK);
return factory()->NewExpressionStatement(expr, pos);
}
@@ -2624,9 +2694,13 @@
}
} else {
int pos = peek_position();
- return_value = ParseExpression(true, CHECK_OK);
if (IsSubclassConstructor(function_state_->kind())) {
+ // Because of the return code rewriting that happens in case of a subclass
+ // constructor we don't want to accept tail calls, therefore we don't set
+ // ReturnExprScope to kInsideValidReturnStatement here.
+ return_value = ParseExpression(true, CHECK_OK);
+
// For subclass constructors we need to return this in case of undefined
// return a Smi (transformed into an exception in the ConstructStub)
// for a non object.
@@ -2665,17 +2739,23 @@
return_value = factory()->NewConditional(
is_undefined, ThisExpression(scope_, factory(), pos),
is_object_conditional, pos);
- }
+ } else {
+ ReturnExprScope maybe_allow_tail_calls(
+ function_state_, ReturnExprContext::kInsideValidReturnStatement);
+ return_value = ParseExpression(true, CHECK_OK);
- // ES6 14.6.1 Static Semantics: IsInTailPosition
- if (allow_tailcalls() && !is_sloppy(language_mode())) {
- function_state_->AddExpressionInTailPosition(return_value);
+ if (allow_tailcalls() && !is_sloppy(language_mode())) {
+ // ES6 14.6.1 Static Semantics: IsInTailPosition
+ function_state_->AddImplicitTailCallExpression(return_value);
+ }
}
}
ExpectSemicolon(CHECK_OK);
if (is_generator()) {
return_value = BuildIteratorResult(return_value, true);
+ } else if (is_async_function()) {
+ return_value = BuildPromiseResolve(return_value, return_value->position());
}
result = factory()->NewReturnStatement(return_value, loc.beg_pos);
@@ -2849,40 +2929,6 @@
factory()->NewThrow(exception, pos), pos);
}
-class Parser::DontCollectExpressionsInTailPositionScope {
- public:
- DontCollectExpressionsInTailPositionScope(
- Parser::FunctionState* function_state)
- : function_state_(function_state),
- old_value_(function_state->collect_expressions_in_tail_position()) {
- function_state->set_collect_expressions_in_tail_position(false);
- }
- ~DontCollectExpressionsInTailPositionScope() {
- function_state_->set_collect_expressions_in_tail_position(old_value_);
- }
-
- private:
- Parser::FunctionState* function_state_;
- bool old_value_;
-};
-
-// Collects all return expressions at tail call position in this scope
-// to a separate list.
-class Parser::CollectExpressionsInTailPositionToListScope {
- public:
- CollectExpressionsInTailPositionToListScope(
- Parser::FunctionState* function_state, List<Expression*>* list)
- : function_state_(function_state), list_(list) {
- function_state->expressions_in_tail_position().Swap(list_);
- }
- ~CollectExpressionsInTailPositionToListScope() {
- function_state_->expressions_in_tail_position().Swap(list_);
- }
-
- private:
- Parser::FunctionState* function_state_;
- List<Expression*>* list_;
-};
TryStatement* Parser::ParseTryStatement(bool* ok) {
// TryStatement ::
@@ -2901,7 +2947,8 @@
Block* try_block;
{
- DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_);
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideTryBlock);
try_block = ParseBlock(NULL, CHECK_OK);
}
@@ -2915,7 +2962,7 @@
Scope* catch_scope = NULL;
Variable* catch_variable = NULL;
Block* catch_block = NULL;
- List<Expression*> expressions_in_tail_position_in_catch_block;
+ TailCallExpressionList tail_call_expressions_in_catch_block(zone());
if (tok == Token::CATCH) {
Consume(Token::CATCH);
@@ -2942,8 +2989,8 @@
{
CollectExpressionsInTailPositionToListScope
- collect_expressions_in_tail_position_scope(
- function_state_, &expressions_in_tail_position_in_catch_block);
+ collect_tail_call_expressions_scope(
+ function_state_, &tail_call_expressions_in_catch_block);
BlockState block_state(&scope_, catch_scope);
// TODO(adamk): Make a version of ParseBlock that takes a scope and
@@ -2967,8 +3014,11 @@
descriptor.declaration_pos = pattern->position();
descriptor.initialization_pos = pattern->position();
+ // Initializer position for variables declared by the pattern.
+ const int initializer_position = position();
+
DeclarationParsingResult::Declaration decl(
- pattern, pattern->position(),
+ pattern, initializer_position,
factory()->NewVariableProxy(catch_variable));
Block* init_block =
@@ -3023,14 +3073,23 @@
if (catch_block != NULL) {
// For a try-catch construct append return expressions from the catch block
// to the list of return expressions.
- function_state_->expressions_in_tail_position().AddAll(
- expressions_in_tail_position_in_catch_block);
+ function_state_->tail_call_expressions().Append(
+ tail_call_expressions_in_catch_block);
DCHECK(finally_block == NULL);
DCHECK(catch_scope != NULL && catch_variable != NULL);
result = factory()->NewTryCatchStatement(try_block, catch_scope,
catch_variable, catch_block, pos);
} else {
+ if (FLAG_harmony_explicit_tailcalls &&
+ tail_call_expressions_in_catch_block.has_explicit_tail_calls()) {
+ // TODO(ishell): update chapter number.
+ // ES8 XX.YY.ZZ
+ ReportMessageAt(tail_call_expressions_in_catch_block.location(),
+ MessageTemplate::kUnexpectedTailCallInCatchBlock);
+ *ok = false;
+ return NULL;
+ }
DCHECK(finally_block != NULL);
result = factory()->NewTryFinallyStatement(try_block, finally_block, pos);
}
@@ -3125,11 +3184,10 @@
void Parser::InitializeForEachStatement(ForEachStatement* stmt,
Expression* each, Expression* subject,
- Statement* body) {
+ Statement* body, int each_keyword_pos) {
ForOfStatement* for_of = stmt->AsForOfStatement();
if (for_of != NULL) {
- InitializeForOfStatement(for_of, each, subject, body,
- RelocInfo::kNoPosition);
+ InitializeForOfStatement(for_of, each, subject, body, each_keyword_pos);
} else {
if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
Variable* temp =
@@ -3148,13 +3206,13 @@
body = block;
each = factory()->NewVariableProxy(temp);
}
- stmt->Initialize(each, subject, body);
+ stmt->AsForInStatement()->Initialize(each, subject, body);
}
}
void Parser::InitializeForOfStatement(ForOfStatement* for_of, Expression* each,
Expression* iterable, Statement* body,
- int iterable_pos) {
+ int next_result_pos) {
Variable* iterator =
scope_->NewTemporary(ast_value_factory()->dot_iterator_string());
Variable* result =
@@ -3165,14 +3223,7 @@
Expression* result_done;
Expression* assign_each;
- // Hackily disambiguate o from o.next and o [Symbol.iterator]().
- // TODO(verwaest): Come up with a better solution.
- int get_iterator_pos = iterable_pos != RelocInfo::kNoPosition
- ? iterable_pos
- : iterable->position() - 2;
- int next_result_pos = iterable_pos != RelocInfo::kNoPosition
- ? iterable_pos
- : iterable->position() - 1;
+ int get_iterator_pos = iterable->position();
// iterator = iterable[Symbol.iterator]()
assign_iterator = factory()->NewAssignment(
@@ -3212,8 +3263,8 @@
}
}
- for_of->Initialize(each, iterable, body, iterator, assign_iterator,
- next_result, result_done, assign_each);
+ for_of->Initialize(body, iterator, assign_iterator, next_result, result_done,
+ assign_each);
}
Statement* Parser::DesugarLexicalBindingsInForStatement(
@@ -3476,9 +3527,10 @@
// Make a block around the statement for a lexical binding
// is introduced by a FunctionDeclaration.
Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
+ body_scope->set_start_position(scanner()->location().beg_pos);
BlockState block_state(&scope_, body_scope);
Block* block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
- Statement* body = ParseFunctionDeclaration(NULL, CHECK_OK);
+ Statement* body = ParseFunctionDeclaration(CHECK_OK);
block->statements()->Add(body, zone());
body_scope->set_end_position(scanner()->location().end_pos);
body_scope = body_scope->FinalizeBlockScope();
@@ -3500,10 +3552,10 @@
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
for_scope->set_start_position(scanner()->location().beg_pos);
- bool is_let_identifier_expression = false;
+ for_scope->set_is_hidden();
DeclarationParsingResult parsing_result;
if (peek() != Token::SEMICOLON) {
- if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
+ if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && IsNextLetKeyword())) {
ParseVariableDeclarations(kForStatement, &parsing_result, nullptr,
CHECK_OK);
@@ -3527,7 +3579,12 @@
if (parsing_result.first_initializer_loc.IsValid() &&
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
IsLexicalVariableMode(parsing_result.descriptor.mode) ||
- !decl.pattern->IsVariableProxy())) {
+ !decl.pattern->IsVariableProxy() || allow_harmony_for_in())) {
+ // Only increment the use count if we would have let this through
+ // without the flag.
+ if (allow_harmony_for_in()) {
+ ++use_counts_[v8::Isolate::kForInInitializer];
+ }
ParserTraits::ReportMessageAt(
parsing_result.first_initializer_loc,
MessageTemplate::kForInOfLoopInitializer,
@@ -3541,6 +3598,7 @@
// special case for legacy for (var/const x =.... in)
if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
+ DCHECK(!allow_harmony_for_in());
++use_counts_[v8::Isolate::kForInInitializer];
const AstRawString* name =
decl.pattern->AsVariableProxy()->raw_name();
@@ -3579,6 +3637,8 @@
factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop);
+ int each_keyword_position = scanner()->location().beg_pos;
+
Expression* enumerable;
if (mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
@@ -3597,8 +3657,8 @@
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
{
- DontCollectExpressionsInTailPositionScope no_tail_calls(
- function_state_);
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
BlockState block_state(&scope_, body_scope);
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
@@ -3622,7 +3682,8 @@
body_block->statements()->Add(body, zone());
VariableProxy* temp_proxy =
factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
- InitializeForEachStatement(loop, temp_proxy, enumerable, body_block);
+ InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
+ each_keyword_position);
}
body_scope->set_end_position(scanner()->location().end_pos);
body_scope = body_scope->FinalizeBlockScope();
@@ -3678,10 +3739,6 @@
Expression* expression = ParseExpression(false, &classifier, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
ForEachStatement::VisitMode mode = ForEachStatement::ENUMERATE;
- is_let_identifier_expression =
- expression->IsVariableProxy() &&
- expression->AsVariableProxy()->raw_name() ==
- ast_value_factory()->let_string();
bool is_for_each = CheckInOrOf(&mode, ok);
if (!*ok) return nullptr;
@@ -3705,6 +3762,8 @@
factory()->NewForEachStatement(mode, labels, stmt_pos);
Target target(&this->target_stack_, loop);
+ int each_keyword_position = scanner()->location().beg_pos;
+
Expression* enumerable;
if (mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
@@ -3719,7 +3778,8 @@
// For legacy compat reasons, give for loops similar treatment to
// if statements in allowing a function declaration for a body
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
- InitializeForEachStatement(loop, expression, enumerable, body);
+ InitializeForEachStatement(loop, expression, enumerable, body,
+ each_keyword_position);
Statement* final_loop = loop->IsForOfStatement()
? FinalizeForOfStatement(
@@ -3742,13 +3802,6 @@
Target target(&this->target_stack_, loop);
// Parsed initializer at this point.
- // Detect attempts at 'let' declarations in sloppy mode.
- if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
- is_sloppy(language_mode()) && is_let_identifier_expression) {
- ReportMessage(MessageTemplate::kSloppyLexical, NULL);
- *ok = false;
- return NULL;
- }
Expect(Token::SEMICOLON, CHECK_OK);
Expression* cond = NULL;
@@ -3882,16 +3935,9 @@
return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
}
-
void ParserTraits::ParseArrowFunctionFormalParameters(
- ParserFormalParameters* parameters, Expression* expr,
- const Scanner::Location& params_loc, bool* ok) {
- if (parameters->Arity() >= Code::kMaxArguments) {
- ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
- *ok = false;
- return;
- }
-
+ ParserFormalParameters* parameters, Expression* expr, int end_pos,
+ bool* ok) {
// ArrowFunctionFormals ::
// Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail)
// Tail
@@ -3912,7 +3958,8 @@
DCHECK_EQ(binop->op(), Token::COMMA);
Expression* left = binop->left();
Expression* right = binop->right();
- ParseArrowFunctionFormalParameters(parameters, left, params_loc, ok);
+ int comma_pos = binop->position();
+ ParseArrowFunctionFormalParameters(parameters, left, comma_pos, ok);
if (!*ok) return;
// LHS of comma expression should be unparenthesized.
expr = right;
@@ -3949,13 +3996,66 @@
parser_->scope_, parameters->scope);
}
- // TODO(adamk): params_loc.end_pos is not the correct initializer position,
- // but it should be conservative enough to trigger hole checks for variables
- // referenced in the initializer (if any).
- AddFormalParameter(parameters, expr, initializer, params_loc.end_pos,
- is_rest);
+ AddFormalParameter(parameters, expr, initializer, end_pos, is_rest);
}
+void ParserTraits::ParseAsyncArrowSingleExpressionBody(
+ ZoneList<Statement*>* body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok) {
+ parser_->DesugarAsyncFunctionBody(
+ parser_->ast_value_factory()->empty_string(), parser_->scope_, body,
+ classifier, kAsyncArrowFunction, FunctionBody::SingleExpression,
+ accept_IN, pos, ok);
+}
+
+void Parser::DesugarAsyncFunctionBody(const AstRawString* function_name,
+ Scope* scope, ZoneList<Statement*>* body,
+ ExpressionClassifier* classifier,
+ FunctionKind kind, FunctionBody body_type,
+ bool accept_IN, int pos, bool* ok) {
+ // function async_function() {
+ // try {
+ // .generator_object = %CreateGeneratorObject();
+ // ... function body ...
+ // } catch (e) {
+ // return Promise.reject(e);
+ // }
+ // }
+ scope->ForceContextAllocation();
+ Variable* temp =
+ scope_->NewTemporary(ast_value_factory()->dot_generator_object_string());
+ function_state_->set_generator_object_variable(temp);
+
+ Expression* init_generator_variable = factory()->NewAssignment(
+ Token::INIT, factory()->NewVariableProxy(temp),
+ BuildCreateJSGeneratorObject(pos, kind), RelocInfo::kNoPosition);
+ body->Add(factory()->NewExpressionStatement(init_generator_variable,
+ RelocInfo::kNoPosition),
+ zone());
+
+ Block* try_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
+
+ ZoneList<Statement*>* inner_body = try_block->statements();
+
+ Expression* return_value = nullptr;
+ if (body_type == FunctionBody::Normal) {
+ ParseStatementList(inner_body, Token::RBRACE, ok);
+ if (!*ok) return;
+ return_value = factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
+ } else {
+ return_value = ParseAssignmentExpression(accept_IN, classifier, ok);
+ if (!*ok) return;
+ ParserTraits::RewriteNonPattern(classifier, ok);
+ if (!*ok) return;
+ }
+
+ return_value = BuildPromiseResolve(return_value, return_value->position());
+ inner_body->Add(
+ factory()->NewReturnStatement(return_value, return_value->position()),
+ zone());
+ body->Add(BuildRejectPromiseOnException(try_block), zone());
+ scope->set_end_position(scanner()->location().end_pos);
+}
DoExpression* Parser::ParseDoExpression(bool* ok) {
// AssignmentExpression ::
@@ -3982,9 +4082,15 @@
Scanner::Location* duplicate_loc, bool* ok) {
if (expr->IsEmptyParentheses()) return;
- ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
+ ParseArrowFunctionFormalParameters(parameters, expr, params_loc.end_pos, ok);
if (!*ok) return;
+ if (parameters->Arity() > Code::kMaxArguments) {
+ ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
+ *ok = false;
+ return;
+ }
+
Type::ExpressionClassifier classifier(parser_);
if (!parameters->is_simple) {
classifier.RecordNonSimpleParameter();
@@ -4044,53 +4150,17 @@
function_name = ast_value_factory()->empty_string();
}
- // Function declarations are function scoped in normal mode, so they are
- // hoisted. In harmony block scoping mode they are block scoped, so they
- // are not hoisted.
- //
- // One tricky case are function declarations in a local sloppy-mode eval:
- // their declaration is hoisted, but they still see the local scope. E.g.,
- //
- // function() {
- // var x = 0
- // try { throw 1 } catch (x) { eval("function g() { return x }") }
- // return g()
- // }
- //
- // needs to return 1. To distinguish such cases, we need to detect
- // (1) whether a function stems from a sloppy eval, and
- // (2) whether it actually hoists across the eval.
- // Unfortunately, we do not represent sloppy eval scopes, so we do not have
- // either information available directly, especially not when lazily compiling
- // a function like 'g'. We hence rely on the following invariants:
- // - (1) is the case iff the innermost scope of the deserialized scope chain
- // under which we compile is _not_ a declaration scope. This holds because
- // in all normal cases, function declarations are fully hoisted to a
- // declaration scope and compiled relative to that.
- // - (2) is the case iff the current declaration scope is still the original
- // one relative to the deserialized scope chain. Otherwise we must be
- // compiling a function in an inner declaration scope in the eval, e.g. a
- // nested function, and hoisting works normally relative to that.
- Scope* declaration_scope = scope_->DeclarationScope();
- Scope* original_declaration_scope = original_scope_->DeclarationScope();
- Scope* scope = function_type == FunctionLiteral::kDeclaration &&
- is_sloppy(language_mode) &&
- !allow_harmony_sloppy_function() &&
- (original_scope_ == original_declaration_scope ||
- declaration_scope != original_declaration_scope)
- ? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
- : NewScope(scope_, FUNCTION_SCOPE, kind);
+ Scope* scope = NewScope(scope_, FUNCTION_SCOPE, kind);
SetLanguageMode(scope, language_mode);
ZoneList<Statement*>* body = NULL;
int arity = -1;
int materialized_literal_count = -1;
int expected_property_count = -1;
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
- FunctionLiteral::EagerCompileHint eager_compile_hint =
- parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
- : FunctionLiteral::kShouldLazyCompile;
bool should_be_used_once_hint = false;
bool has_duplicate_parameters;
+ FunctionLiteral::EagerCompileHint eager_compile_hint;
+
// Parse function.
{
AstNodeFactory function_factory(ast_value_factory());
@@ -4099,6 +4169,10 @@
scope_->SetScopeName(function_name);
ExpressionClassifier formals_classifier(this, &duplicate_finder);
+ eager_compile_hint = function_state_->this_function_is_parenthesized()
+ ? FunctionLiteral::kShouldEagerCompile
+ : FunctionLiteral::kShouldLazyCompile;
+
if (is_generator) {
// For generators, allocating variables in contexts is currently a win
// because it minimizes the work needed to suspend and resume an
@@ -4126,7 +4200,6 @@
CheckArityRestrictions(arity, kind, formals.has_rest, start_position,
formals_end_position, CHECK_OK);
Expect(Token::LBRACE, CHECK_OK);
-
// Don't include the rest parameter into the function's formal parameter
// count (esp. the SharedFunctionInfo::internal_formal_parameter_count,
// which says whether we need to create an arguments adaptor frame).
@@ -4167,8 +4240,7 @@
// logic where only top-level functions will be parsed lazily.
bool is_lazily_parsed = mode() == PARSE_LAZILY &&
scope_->AllowsLazyParsing() &&
- !parenthesized_function_;
- parenthesized_function_ = false; // The bit was set for this function only.
+ !function_state_->this_function_is_parenthesized();
// Eager or lazy parse?
// If is_lazily_parsed, we'll parse lazy. If we can set a bookmark, we'll
@@ -4211,10 +4283,13 @@
// FunctionExpression; even without enclosing parentheses it might be
// immediately invoked.
// - The function literal shouldn't be hinted to eagerly compile.
+ // - For asm.js functions the body needs to be available when module
+ // validation is active, because we examine the entire module at once.
bool use_temp_zone =
FLAG_lazy && !allow_natives() && extension_ == NULL && allow_lazy() &&
function_type == FunctionLiteral::kDeclaration &&
- eager_compile_hint != FunctionLiteral::kShouldEagerCompile;
+ eager_compile_hint != FunctionLiteral::kShouldEagerCompile &&
+ !(FLAG_validate_asm && scope->asm_function());
// Open a new BodyScope, which sets our AstNodeFactory to allocate in the
// new temporary zone if the preconditions are satisfied, and ensures that
// the previous zone is always restored after parsing the body.
@@ -4253,8 +4328,10 @@
if (is_strict(language_mode)) {
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
CHECK_OK);
+ CheckDecimalLiteralWithLeadingZero(use_counts_, scope->start_position(),
+ scope->end_position());
}
- if (is_sloppy(language_mode) && allow_harmony_sloppy_function()) {
+ if (is_sloppy(language_mode)) {
InsertSloppyBlockFunctionVarBindings(scope, CHECK_OK);
}
CheckConflictingVarDeclarations(scope, CHECK_OK);
@@ -4283,6 +4360,36 @@
return function_literal;
}
+Expression* Parser::ParseAsyncFunctionExpression(bool* ok) {
+ // AsyncFunctionDeclaration ::
+ // async [no LineTerminator here] function ( FormalParameters[Await] )
+ // { AsyncFunctionBody }
+ //
+ // async [no LineTerminator here] function BindingIdentifier[Await]
+ // ( FormalParameters[Await] ) { AsyncFunctionBody }
+ DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
+ int pos = position();
+ Expect(Token::FUNCTION, CHECK_OK);
+ bool is_strict_reserved = false;
+ const AstRawString* name = nullptr;
+ FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
+
+ if (peek_any_identifier()) {
+ type = FunctionLiteral::kNamedExpression;
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
+ if (this->IsAwait(name)) {
+ ReportMessageAt(scanner()->location(),
+ MessageTemplate::kAwaitBindingIdentifier);
+ *ok = false;
+ return nullptr;
+ }
+ }
+ return ParseFunctionLiteral(name, scanner()->location(),
+ is_strict_reserved ? kFunctionNameIsStrictReserved
+ : kFunctionNameValidityUnknown,
+ FunctionKind::kAsyncFunction, pos, type,
+ language_mode(), CHECK_OK);
+}
void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
int* expected_property_count, bool* ok,
@@ -4473,12 +4580,18 @@
if (!parameter.is_simple() && scope_->calls_sloppy_eval()) {
param_scope = NewScope(scope_, BLOCK_SCOPE);
param_scope->set_is_declaration_scope();
- param_scope->set_start_position(parameter.pattern->position());
- param_scope->set_end_position(RelocInfo::kNoPosition);
+ param_scope->set_start_position(descriptor.initialization_pos);
+ param_scope->set_end_position(parameter.initializer_end_position);
param_scope->RecordEvalCall();
param_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
param_block->set_scope(param_scope);
descriptor.hoist_scope = scope_;
+ // Pass the appropriate scope in so that PatternRewriter can appropriately
+ // rewrite inner initializers of the pattern to param_scope
+ descriptor.scope = param_scope;
+ // Rewrite the outer initializer to point to param_scope
+ RewriteParameterInitializerScope(stack_limit(), initial_value, scope_,
+ param_scope);
}
{
@@ -4500,6 +4613,57 @@
return init_block;
}
+Block* Parser::BuildRejectPromiseOnException(Block* block) {
+ // try { <block> } catch (error) { return Promise.reject(error); }
+ Block* try_block = block;
+ Scope* catch_scope = NewScope(scope_, CATCH_SCOPE);
+ catch_scope->set_is_hidden();
+ Variable* catch_variable =
+ catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), VAR,
+ kCreatedInitialized, Variable::NORMAL);
+ Block* catch_block =
+ factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+
+ Expression* promise_reject = BuildPromiseReject(
+ factory()->NewVariableProxy(catch_variable), RelocInfo::kNoPosition);
+
+ ReturnStatement* return_promise_reject =
+ factory()->NewReturnStatement(promise_reject, RelocInfo::kNoPosition);
+ catch_block->statements()->Add(return_promise_reject, zone());
+ TryStatement* try_catch_statement =
+ factory()->NewTryCatchStatement(try_block, catch_scope, catch_variable,
+ catch_block, RelocInfo::kNoPosition);
+
+ block = factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+ block->statements()->Add(try_catch_statement, zone());
+ return block;
+}
+
+Expression* Parser::BuildCreateJSGeneratorObject(int pos, FunctionKind kind) {
+ DCHECK_NOT_NULL(function_state_->generator_object_variable());
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
+ args->Add(factory()->NewThisFunction(pos), zone());
+ args->Add(IsArrowFunction(kind)
+ ? GetLiteralUndefined(pos)
+ : ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
+ zone());
+ return factory()->NewCallRuntime(Runtime::kCreateJSGeneratorObject, args,
+ pos);
+}
+
+Expression* Parser::BuildPromiseResolve(Expression* value, int pos) {
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(value, zone());
+ return factory()->NewCallRuntime(Context::PROMISE_CREATE_RESOLVED_INDEX, args,
+ pos);
+}
+
+Expression* Parser::BuildPromiseReject(Expression* value, int pos) {
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(value, zone());
+ return factory()->NewCallRuntime(Context::PROMISE_CREATE_REJECTED_INDEX, args,
+ pos);
+}
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
const AstRawString* function_name, int pos,
@@ -4553,10 +4717,7 @@
factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition);
{
- ZoneList<Expression*>* arguments =
- new (zone()) ZoneList<Expression*>(0, zone());
- CallRuntime* allocation = factory()->NewCallRuntime(
- Runtime::kCreateJSGeneratorObject, arguments, pos);
+ Expression* allocation = BuildCreateJSGeneratorObject(pos, kind);
VariableProxy* init_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
Assignment* assignment = factory()->NewAssignment(
@@ -4592,6 +4753,10 @@
body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
RelocInfo::kNoPosition),
zone());
+ } else if (IsAsyncFunction(kind)) {
+ const bool accept_IN = true;
+ DesugarAsyncFunctionBody(function_name, inner_scope, body, nullptr, kind,
+ FunctionBody::Normal, accept_IN, pos, CHECK_OK);
} else {
ParseStatementList(body, Token::RBRACE, CHECK_OK);
}
@@ -4613,6 +4778,11 @@
DCHECK_EQ(body, inner_block->statements());
SetLanguageMode(scope_, inner_scope->language_mode());
Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK);
+
+ if (IsAsyncFunction(kind)) {
+ init_block = BuildRejectPromiseOnException(init_block);
+ }
+
DCHECK_NOT_NULL(init_block);
inner_scope->set_end_position(scanner()->location().end_pos);
@@ -4650,13 +4820,7 @@
RelocInfo::kNoPosition));
}
- // ES6 14.6.1 Static Semantics: IsInTailPosition
- // Mark collected return expressions that are in tail call position.
- const List<Expression*>& expressions_in_tail_position =
- function_state_->expressions_in_tail_position();
- for (int i = 0; i < expressions_in_tail_position.length(); ++i) {
- MarkTailPosition(expressions_in_tail_position[i]);
- }
+ MarkCollectedTailCallExpressions();
return result;
}
@@ -4678,19 +4842,18 @@
reusable_preparser_->set_allow_lazy(true);
#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
SET_ALLOW(natives);
- SET_ALLOW(harmony_sloppy);
- SET_ALLOW(harmony_sloppy_function);
- SET_ALLOW(harmony_sloppy_let);
SET_ALLOW(harmony_do_expressions);
+ SET_ALLOW(harmony_for_in);
SET_ALLOW(harmony_function_name);
SET_ALLOW(harmony_function_sent);
SET_ALLOW(harmony_exponentiation_operator);
SET_ALLOW(harmony_restrictive_declarations);
+ SET_ALLOW(harmony_async_await);
#undef SET_ALLOW
}
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
language_mode(), function_state_->kind(), scope_->has_simple_parameters(),
- logger, bookmark);
+ parsing_module_, logger, bookmark, use_counts_);
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Stop();
}
@@ -4733,6 +4896,7 @@
block_scope->set_start_position(scanner()->location().end_pos);
ExpressionClassifier extends_classifier(this);
extends = ParseLeftHandSideExpression(&extends_classifier, CHECK_OK);
+ CheckNoTailCallExpressions(&extends_classifier, CHECK_OK);
RewriteNonPattern(&extends_classifier, CHECK_OK);
if (classifier != nullptr) {
classifier->Accumulate(&extends_classifier,
@@ -4755,13 +4919,12 @@
if (Check(Token::SEMICOLON)) continue;
FuncNameInferrer::State fni_state(fni_);
const bool in_class = true;
- const bool is_static = false;
bool is_computed_name = false; // Classes do not care about computed
// property names here.
ExpressionClassifier property_classifier(this);
const AstRawString* property_name = nullptr;
ObjectLiteral::Property* property = ParsePropertyDefinition(
- &checker, in_class, has_extends, is_static, &is_computed_name,
+ &checker, in_class, has_extends, MethodKind::Normal, &is_computed_name,
&has_seen_constructor, &property_classifier, &property_name, CHECK_OK);
RewriteNonPattern(&property_classifier, CHECK_OK);
if (classifier != nullptr) {
@@ -5379,6 +5542,29 @@
SetLanguageMode(scope_, old > mode ? old : mode);
}
+void Parser::MarkCollectedTailCallExpressions() {
+ const ZoneList<Expression*>& tail_call_expressions =
+ function_state_->tail_call_expressions().expressions();
+ for (int i = 0; i < tail_call_expressions.length(); ++i) {
+ Expression* expression = tail_call_expressions[i];
+ // If only FLAG_harmony_explicit_tailcalls is enabled then expression
+ // must be a Call expression.
+ DCHECK(FLAG_harmony_tailcalls || !FLAG_harmony_explicit_tailcalls ||
+ expression->IsCall());
+ MarkTailPosition(expression);
+ }
+}
+
+Expression* ParserTraits::ExpressionListToExpression(
+ ZoneList<Expression*>* args) {
+ AstNodeFactory* factory = parser_->factory();
+ Expression* expr = args->at(0);
+ for (int i = 1; i < args->length(); ++i) {
+ expr = factory->NewBinaryOperation(Token::COMMA, expr, args->at(i),
+ expr->position());
+ }
+ return expr;
+}
void ParserTraits::RewriteDestructuringAssignments() {
parser_->RewriteDestructuringAssignments();
@@ -5400,6 +5586,30 @@
parser_->RewriteNonPattern(classifier, ok);
}
+Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) {
+ // yield %AsyncFunctionAwait(.generator_object, <operand>)
+ Variable* generator_object_variable =
+ parser_->function_state_->generator_object_variable();
+
+ // If generator_object_variable is null,
+ if (!generator_object_variable) return value;
+
+ Expression* generator_object =
+ parser_->factory()->NewVariableProxy(generator_object_variable);
+
+ ZoneList<Expression*>* async_function_await_args =
+ new (zone()) ZoneList<Expression*>(2, zone());
+ async_function_await_args->Add(generator_object, zone());
+ async_function_await_args->Add(value, zone());
+ Expression* async_function_await = parser_->factory()->NewCallRuntime(
+ Context::ASYNC_FUNCTION_AWAIT_INDEX, async_function_await_args,
+ RelocInfo::kNoPosition);
+
+ generator_object =
+ parser_->factory()->NewVariableProxy(generator_object_variable);
+ return parser_->factory()->NewYield(generator_object, async_function_await,
+ pos);
+}
Zone* ParserTraits::zone() const {
return parser_->function_state_->scope()->zone();
@@ -5606,7 +5816,7 @@
ForEachStatement::ITERATE, nullptr, RelocInfo::kNoPosition);
InitializeForOfStatement(loop->AsForOfStatement(),
factory()->NewVariableProxy(each), subject,
- append_body, spread->expression_position());
+ append_body);
do_block->statements()->Add(loop, zone());
}
}
@@ -5749,15 +5959,19 @@
// }
// }
//
-// output.value;
+// if (mode === kReturn) {
+// return {value: output.value, done: true};
+// }
+// output.value
// }
//
// IteratorClose(iterator) expands to the following:
//
// let iteratorReturn = iterator.return;
-// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return;
-// let output = %_Call(iteratorReturn, iterator);
-// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+// if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
+// let output = %_Call(iteratorReturn, iterator);
+// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+// }
//
// IteratorClose(iterator, input, output) expands to the following:
//
@@ -5766,7 +5980,6 @@
// output = %_Call(iteratorReturn, iterator, input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
-
Expression* ParserTraits::RewriteYieldStar(
Expression* generator, Expression* iterable, int pos) {
@@ -5798,7 +6011,7 @@
Statement* initialize_mode;
{
Expression* mode_proxy = factory->NewVariableProxy(var_mode);
- Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::kNext, nopos);
Expression* assignment =
factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
initialize_mode = factory->NewExpressionStatement(assignment, nopos);
@@ -5929,9 +6142,9 @@
Statement* throw_call = factory->NewExpressionStatement(call, nopos);
Block* then = factory->NewBlock(nullptr, 4+1, false, nopos);
- Variable* var_tmp = scope->NewTemporary(avfactory->empty_string());
- BuildIteratorClose(then->statements(), var_iterator, Nothing<Variable*>(),
- var_tmp);
+ parser_->BuildIteratorCloseForCompletion(
+ then->statements(), var_iterator,
+ factory->NewSmiLiteral(Parser::kNormalCompletion, nopos));
then->statements()->Add(throw_call, zone);
check_throw = factory->NewIfStatement(
condition, then, factory->NewEmptyStatement(nopos), nopos);
@@ -5996,7 +6209,7 @@
{
Expression* mode_proxy = factory->NewVariableProxy(var_mode);
Expression* kreturn =
- factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+ factory->NewSmiLiteral(JSGeneratorObject::kReturn, nopos);
Expression* assignment =
factory->NewAssignment(Token::ASSIGN, mode_proxy, kreturn, nopos);
set_mode_return = factory->NewExpressionStatement(assignment, nopos);
@@ -6015,7 +6228,7 @@
Statement* set_mode_next;
{
Expression* mode_proxy = factory->NewVariableProxy(var_mode);
- Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::kNext, nopos);
Expression* assignment =
factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
set_mode_next = factory->NewExpressionStatement(assignment, nopos);
@@ -6027,7 +6240,7 @@
{
Expression* mode_proxy = factory->NewVariableProxy(var_mode);
Expression* kthrow =
- factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+ factory->NewSmiLiteral(JSGeneratorObject::kThrow, nopos);
Expression* assignment =
factory->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos);
set_mode_throw = factory->NewExpressionStatement(assignment, nopos);
@@ -6045,7 +6258,30 @@
}
- // output.value;
+ // if (mode === kReturn) {
+ // return {value: output.value, done: true};
+ // }
+ Statement* maybe_return_value;
+ {
+ Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ Expression* kreturn =
+ factory->NewSmiLiteral(JSGeneratorObject::kReturn, nopos);
+ Expression* condition = factory->NewCompareOperation(
+ Token::EQ_STRICT, mode_proxy, kreturn, nopos);
+
+ Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* literal =
+ factory->NewStringLiteral(avfactory->value_string(), nopos);
+ Expression* property = factory->NewProperty(output_proxy, literal, nopos);
+ Statement* return_value =
+ factory->NewReturnStatement(BuildIteratorResult(property, true), nopos);
+
+ maybe_return_value = factory->NewIfStatement(
+ condition, return_value, factory->NewEmptyStatement(nopos), nopos);
+ }
+
+
+ // output.value
Statement* get_value;
{
Expression* output_proxy = factory->NewVariableProxy(var_output);
@@ -6070,6 +6306,7 @@
catch_block->statements()->Add(set_mode_throw, zone);
Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+ catch_scope->set_is_hidden();
const AstRawString* name = avfactory->dot_catch_string();
Variable* catch_variable =
catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
@@ -6104,7 +6341,7 @@
case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
auto case_return = new (zone) ZoneList<Statement*>(5, zone);
- BuildIteratorClose(case_return, var_iterator, Just(var_input), var_output);
+ BuildIteratorClose(case_return, var_iterator, var_input, var_output);
case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
@@ -6115,11 +6352,11 @@
case_throw->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
auto cases = new (zone) ZoneList<CaseClause*>(3, zone);
- Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::kNext, nopos);
Expression* kreturn =
- factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+ factory->NewSmiLiteral(JSGeneratorObject::kReturn, nopos);
Expression* kthrow =
- factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+ factory->NewSmiLiteral(JSGeneratorObject::kThrow, nopos);
cases->Add(factory->NewCaseClause(knext, case_next, nopos), zone);
cases->Add(factory->NewCaseClause(kreturn, case_return, nopos), zone);
cases->Add(factory->NewCaseClause(kthrow, case_throw, nopos), zone);
@@ -6147,13 +6384,14 @@
// The rewriter needs to process the get_value statement only, hence we
// put the preceding statements into an init block.
- Block* do_block_ = factory->NewBlock(nullptr, 6, true, nopos);
+ Block* do_block_ = factory->NewBlock(nullptr, 7, true, nopos);
do_block_->statements()->Add(initialize_input, zone);
do_block_->statements()->Add(initialize_mode, zone);
do_block_->statements()->Add(initialize_output, zone);
do_block_->statements()->Add(get_iterator, zone);
do_block_->statements()->Add(validate_iterator, zone);
do_block_->statements()->Add(loop, zone);
+ do_block_->statements()->Add(maybe_return_value, zone);
Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
do_block->statements()->Add(do_block_, zone);
@@ -6167,180 +6405,6 @@
return yield_star;
}
-// Desugaring of (lhs) instanceof (rhs)
-// ====================================
-//
-// We desugar instanceof into a load of property @@hasInstance on the rhs.
-// We end up with roughly the following code (O, C):
-//
-// do {
-// let O = lhs;
-// let C = rhs;
-// if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
-// let handler_result = C[Symbol.hasInstance];
-// if (handler_result === undefined) {
-// if (!IS_CALLABLE(C)) {
-// throw MakeTypeError(kCalledNonCallableInstanceOf);
-// }
-// handler_result = %_GetOrdinaryHasInstance()
-// handler_result = %_Call(handler_result, C, O);
-// } else {
-// handler_result = !!(%_Call(handler_result, C, O));
-// }
-// handler_result;
-// }
-//
-Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
- int pos) {
- const int nopos = RelocInfo::kNoPosition;
-
- auto factory = parser_->factory();
- auto avfactory = parser_->ast_value_factory();
- auto scope = parser_->scope_;
- auto zone = parser_->zone();
-
- // let O = lhs;
- Variable* var_O = scope->NewTemporary(avfactory->empty_string());
- Statement* get_O;
- {
- Expression* O_proxy = factory->NewVariableProxy(var_O);
- Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, O_proxy, lhs, nopos);
- get_O = factory->NewExpressionStatement(assignment, nopos);
- }
-
- // let C = lhs;
- Variable* var_C = scope->NewTemporary(avfactory->empty_string());
- Statement* get_C;
- {
- Expression* C_proxy = factory->NewVariableProxy(var_C);
- Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, C_proxy, rhs, nopos);
- get_C = factory->NewExpressionStatement(assignment, nopos);
- }
-
- // if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
- Statement* validate_C;
- {
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_C), zone);
- Expression* is_receiver_call =
- factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
- Expression* call =
- NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck,
- avfactory->empty_string(), pos);
- Statement* throw_call = factory->NewExpressionStatement(call, pos);
-
- validate_C =
- factory->NewIfStatement(is_receiver_call,
- factory->NewEmptyStatement(nopos),
- throw_call,
- nopos);
- }
-
- // let handler_result = C[Symbol.hasInstance];
- Variable* var_handler_result = scope->NewTemporary(avfactory->empty_string());
- Statement* initialize_handler;
- {
- Expression* hasInstance_symbol_literal =
- factory->NewSymbolLiteral("hasInstance_symbol", RelocInfo::kNoPosition);
- Expression* prop = factory->NewProperty(factory->NewVariableProxy(var_C),
- hasInstance_symbol_literal, pos);
- Expression* handler_proxy = factory->NewVariableProxy(var_handler_result);
- Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, handler_proxy, prop, nopos);
- initialize_handler = factory->NewExpressionStatement(assignment, nopos);
- }
-
- // if (handler_result === undefined) {
- // if (!IS_CALLABLE(C)) {
- // throw MakeTypeError(kCalledNonCallableInstanceOf);
- // }
- // handler_result = %_GetOrdinaryHasInstance()
- // handler_result = %_Call(handler_result, C, O);
- // } else {
- // handler_result = !!%_Call(handler_result, C, O);
- // }
- Statement* call_handler;
- {
- Expression* condition = factory->NewCompareOperation(
- Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result),
- factory->NewUndefinedLiteral(nopos), nopos);
-
- Block* then_side = factory->NewBlock(nullptr, 3, false, nopos);
- {
- Expression* throw_expr =
- NewThrowTypeError(MessageTemplate::kCalledNonCallableInstanceOf,
- avfactory->empty_string(), pos);
- Statement* validate_C = CheckCallable(var_C, throw_expr, pos);
-
- ZoneList<Expression*>* empty_args =
- new (zone) ZoneList<Expression*>(0, zone);
- Expression* ordinary_has_instance = factory->NewCallRuntime(
- Runtime::kInlineGetOrdinaryHasInstance, empty_args, pos);
- Expression* handler_proxy = factory->NewVariableProxy(var_handler_result);
- Expression* assignment_handler = factory->NewAssignment(
- Token::ASSIGN, handler_proxy, ordinary_has_instance, nopos);
- Statement* assignment_get_handler =
- factory->NewExpressionStatement(assignment_handler, nopos);
-
- ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(3, zone);
- args->Add(factory->NewVariableProxy(var_handler_result), zone);
- args->Add(factory->NewVariableProxy(var_C), zone);
- args->Add(factory->NewVariableProxy(var_O), zone);
- Expression* call =
- factory->NewCallRuntime(Runtime::kInlineCall, args, pos);
- Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
- Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos);
- Statement* assignment_return =
- factory->NewExpressionStatement(assignment, nopos);
-
- then_side->statements()->Add(validate_C, zone);
- then_side->statements()->Add(assignment_get_handler, zone);
- then_side->statements()->Add(assignment_return, zone);
- }
-
- Statement* else_side;
- {
- auto args = new (zone) ZoneList<Expression*>(3, zone);
- args->Add(factory->NewVariableProxy(var_handler_result), zone);
- args->Add(factory->NewVariableProxy(var_C), zone);
- args->Add(factory->NewVariableProxy(var_O), zone);
- Expression* call =
- factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
- Expression* inner_not =
- factory->NewUnaryOperation(Token::NOT, call, nopos);
- Expression* outer_not =
- factory->NewUnaryOperation(Token::NOT, inner_not, nopos);
- Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
- Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, result_proxy, outer_not, nopos);
-
- else_side = factory->NewExpressionStatement(assignment, nopos);
- }
- call_handler =
- factory->NewIfStatement(condition, then_side, else_side, nopos);
- }
-
- // do { ... }
- DoExpression* instanceof;
- {
- Block* block = factory->NewBlock(nullptr, 5, true, nopos);
- block->statements()->Add(get_O, zone);
- block->statements()->Add(get_C, zone);
- block->statements()->Add(validate_C, zone);
- block->statements()->Add(initialize_handler, zone);
- block->statements()->Add(call_handler, zone);
-
- // Here is the desugared instanceof.
- instanceof = factory->NewDoExpression(block, var_handler_result, nopos);
- Rewriter::Rewrite(parser_, instanceof, avfactory);
- }
-
- return instanceof;
-}
-
Statement* ParserTraits::CheckCallable(Variable* var, Expression* error,
int pos) {
auto factory = parser_->factory();
@@ -6364,22 +6428,19 @@
}
void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
- Variable* iterator,
- Maybe<Variable*> input,
+ Variable* iterator, Variable* input,
Variable* var_output) {
//
// This function adds four statements to [statements], corresponding to the
// following code:
//
// let iteratorReturn = iterator.return;
- // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return |input|;
- // output = %_Call(iteratorReturn, iterator|, input|);
+ // if (IS_NULL_OR_UNDEFINED(iteratorReturn) {
+ // return {value: input, done: true};
+ // }
+ // output = %_Call(iteratorReturn, iterator, input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
//
- // Here, |...| denotes optional parts, depending on the presence of the
- // input variable. The reason for allowing input is that BuildIteratorClose
- // can then be reused to handle the return case in yield*.
- //
const int nopos = RelocInfo::kNoPosition;
auto factory = parser_->factory();
@@ -6401,33 +6462,31 @@
get_return = factory->NewExpressionStatement(assignment, nopos);
}
- // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return |input|;
+ // if (IS_NULL_OR_UNDEFINED(iteratorReturn) {
+ // return {value: input, done: true};
+ // }
Statement* check_return;
{
Expression* condition = factory->NewCompareOperation(
Token::EQ, factory->NewVariableProxy(var_return),
factory->NewNullLiteral(nopos), nopos);
- Expression* value = input.IsJust()
- ? static_cast<Expression*>(
- factory->NewVariableProxy(input.FromJust()))
- : factory->NewUndefinedLiteral(nopos);
+ Expression* value = factory->NewVariableProxy(input);
- Statement* return_input = factory->NewReturnStatement(value, nopos);
+ Statement* return_input =
+ factory->NewReturnStatement(BuildIteratorResult(value, true), nopos);
check_return = factory->NewIfStatement(
condition, return_input, factory->NewEmptyStatement(nopos), nopos);
}
- // output = %_Call(iteratorReturn, iterator, |input|);
+ // output = %_Call(iteratorReturn, iterator, input);
Statement* call_return;
{
auto args = new (zone) ZoneList<Expression*>(3, zone);
args->Add(factory->NewVariableProxy(var_return), zone);
args->Add(factory->NewVariableProxy(iterator), zone);
- if (input.IsJust()) {
- args->Add(factory->NewVariableProxy(input.FromJust()), zone);
- }
+ args->Add(factory->NewVariableProxy(input), zone);
Expression* call =
factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
@@ -6529,8 +6588,8 @@
Block* maybe_close;
{
Block* block = factory->NewBlock(nullptr, 2, true, nopos);
- parser_->BuildIteratorCloseForCompletion(block->statements(), iter,
- completion);
+ Expression* proxy = factory->NewVariableProxy(completion);
+ parser_->BuildIteratorCloseForCompletion(block->statements(), iter, proxy);
DCHECK(block->statements()->length() == 2);
maybe_close = factory->NewBlock(nullptr, 1, true, nopos);
@@ -6551,6 +6610,7 @@
Variable* catch_variable =
catch_scope->DeclareLocal(avfactory->dot_catch_string(), VAR,
kCreatedInitialized, Variable::NORMAL);
+ catch_scope->set_is_hidden();
Statement* rethrow;
// We use %ReThrow rather than the ordinary throw because we want to
@@ -6588,7 +6648,7 @@
void ParserTraits::BuildIteratorCloseForCompletion(
ZoneList<Statement*>* statements, Variable* iterator,
- Variable* completion) {
+ Expression* completion) {
//
// This function adds two statements to [statements], corresponding to the
// following code:
@@ -6662,6 +6722,7 @@
Variable* catch_variable = catch_scope->DeclareLocal(
avfactory->dot_catch_string(), VAR, kCreatedInitialized,
Variable::NORMAL);
+ catch_scope->set_is_hidden();
try_call_return = factory->NewTryCatchStatement(
try_block, catch_scope, catch_variable, catch_block, nopos);
@@ -6722,7 +6783,7 @@
Statement* call_return_carefully;
{
Expression* condition = factory->NewCompareOperation(
- Token::EQ_STRICT, factory->NewVariableProxy(completion),
+ Token::EQ_STRICT, completion,
factory->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos);
Block* then_block = factory->NewBlock(nullptr, 2, false, nopos);
diff --git a/src/parsing/parser.h b/src/parsing/parser.h
index c82682e..174b983 100644
--- a/src/parsing/parser.h
+++ b/src/parsing/parser.h
@@ -125,7 +125,6 @@
// TODO(titzer): these should not be part of ParseInfo.
//--------------------------------------------------------------------------
Isolate* isolate() { return isolate_; }
- Handle<JSFunction> closure() { return closure_; }
Handle<SharedFunctionInfo> shared_info() { return shared_; }
Handle<Script> script() { return script_; }
Handle<Context> context() { return context_; }
@@ -145,7 +144,6 @@
}
void ReopenHandlesInNewHandleScope() {
- closure_ = Handle<JSFunction>(*closure_);
shared_ = Handle<SharedFunctionInfo>(*shared_);
script_ = Handle<Script>(*script_);
context_ = Handle<Context>(*context_);
@@ -186,7 +184,6 @@
// TODO(titzer): Move handles and isolate out of ParseInfo.
Isolate* isolate_;
- Handle<JSFunction> closure_;
Handle<SharedFunctionInfo> shared_;
Handle<Script> script_;
Handle<Context> context_;
@@ -202,8 +199,6 @@
void SetFlag(Flag f) { flags_ |= f; }
void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; }
bool GetFlag(Flag f) const { return (flags_ & f) != 0; }
-
- void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
};
class FunctionEntry BASE_EMBEDDED {
@@ -360,6 +355,7 @@
bool IsArguments(const AstRawString* identifier) const;
bool IsEvalOrArguments(const AstRawString* identifier) const;
bool IsUndefined(const AstRawString* identifier) const;
+ bool IsAwait(const AstRawString* identifier) const;
V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
// Returns true if the expression is of type "this.foo".
@@ -376,6 +372,12 @@
return expression->AsVariableProxy()->raw_name();
}
+ bool IsDirectEvalCall(Expression* expression) {
+ if (!expression->IsCall()) return false;
+ expression = expression->AsCall()->expression();
+ return IsIdentifier(expression) && IsEval(AsIdentifier(expression));
+ }
+
static bool IsBoilerplateProperty(ObjectLiteral::Property* property) {
return ObjectLiteral::IsBoilerplateProperty(property);
}
@@ -533,7 +535,11 @@
V8_INLINE void AddParameterInitializationBlock(
const ParserFormalParameters& parameters,
- ZoneList<v8::internal::Statement*>* body, bool* ok);
+ ZoneList<v8::internal::Statement*>* body, bool is_async, bool* ok);
+
+ void ParseAsyncArrowSingleExpressionBody(
+ ZoneList<Statement*>* body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok);
V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
FunctionKind kind = kNormalFunction);
@@ -546,14 +552,15 @@
Scope* scope, const ParserFormalParameters::Parameter& parameter,
Type::ExpressionClassifier* classifier);
void ParseArrowFunctionFormalParameters(ParserFormalParameters* parameters,
- Expression* params,
- const Scanner::Location& params_loc,
+ Expression* params, int end_pos,
bool* ok);
void ParseArrowFunctionFormalParameterList(
ParserFormalParameters* parameters, Expression* params,
const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok);
+ V8_INLINE Expression* ParseAsyncFunctionExpression(bool* ok);
+
V8_INLINE DoExpression* ParseDoExpression(bool* ok);
void ReindexLiterals(const ParserFormalParameters& parameters);
@@ -579,6 +586,7 @@
bool name_is_strict_reserved, int pos,
bool* ok);
+ V8_INLINE void MarkCollectedTailCallExpressions();
V8_INLINE void MarkTailPosition(Expression* expression);
V8_INLINE void CheckConflictingVarDeclarations(v8::internal::Scope* scope,
@@ -636,6 +644,8 @@
ZoneList<v8::internal::Expression*>* args,
int pos);
+ Expression* ExpressionListToExpression(ZoneList<Expression*>* args);
+
// Rewrite all DestructuringAssignments in the current FunctionState.
V8_INLINE void RewriteDestructuringAssignments();
@@ -644,6 +654,8 @@
V8_INLINE Expression* RewriteAssignExponentiation(Expression* left,
Expression* right, int pos);
+ V8_INLINE Expression* RewriteAwaitExpression(Expression* value, int pos);
+
V8_INLINE void QueueDestructuringAssignmentForRewriting(
Expression* assignment);
V8_INLINE void QueueNonPatternForRewriting(Expression* expr);
@@ -665,16 +677,14 @@
Expression* RewriteYieldStar(
Expression* generator, Expression* expression, int pos);
- Expression* RewriteInstanceof(Expression* lhs, Expression* rhs, int pos);
-
private:
Parser* parser_;
void BuildIteratorClose(ZoneList<Statement*>* statements, Variable* iterator,
- Maybe<Variable*> input, Variable* output);
- void BuildIteratorCloseForCompletion(
- ZoneList<Statement*>* statements, Variable* iterator,
- Variable* body_threw);
+ Variable* input, Variable* output);
+ void BuildIteratorCloseForCompletion(ZoneList<Statement*>* statements,
+ Variable* iterator,
+ Expression* completion);
Statement* CheckCallable(Variable* var, Expression* error, int pos);
};
@@ -768,8 +778,15 @@
bool* ok);
Statement* ParseStatementAsUnlabelled(ZoneList<const AstRawString*>* labels,
bool* ok);
- Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
+ Statement* ParseFunctionDeclaration(bool* ok);
+ Statement* ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
bool* ok);
+ Statement* ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
+ ZoneList<const AstRawString*>* names,
+ bool* ok);
+ Statement* ParseAsyncFunctionDeclaration(ZoneList<const AstRawString*>* names,
+ bool* ok);
+ Expression* ParseAsyncFunctionExpression(bool* ok);
Statement* ParseFunctionDeclaration(int pos, bool is_generator,
ZoneList<const AstRawString*>* names,
bool* ok);
@@ -838,8 +855,6 @@
Assignment* assignment,
Scope* scope);
- void set_initializer_position(int pos) { initializer_position_ = pos; }
-
private:
PatternRewriter() {}
@@ -880,6 +895,8 @@
PatternContext SetAssignmentContextIfNeeded(Expression* node);
PatternContext SetInitializerContextIfNeeded(Expression* node);
+ void RewriteParameterScopes(Expression* expr);
+
Variable* CreateTempVar(Expression* value = nullptr);
AstNodeFactory* factory() const { return parser_->factory(); }
@@ -927,8 +944,6 @@
Statement* ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseThrowStatement(bool* ok);
Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
- class DontCollectExpressionsInTailPositionScope;
- class CollectExpressionsInTailPositionToListScope;
TryStatement* ParseTryStatement(bool* ok);
DebuggerStatement* ParseDebuggerStatement(bool* ok);
// Parse a SubStatement in strict mode, or with an extra block scope in
@@ -948,15 +963,22 @@
// Initialize the components of a for-in / for-of statement.
void InitializeForEachStatement(ForEachStatement* stmt, Expression* each,
- Expression* subject, Statement* body);
+ Expression* subject, Statement* body,
+ int each_keyword_pos);
void InitializeForOfStatement(ForOfStatement* stmt, Expression* each,
Expression* iterable, Statement* body,
- int iterable_pos);
+ int next_result_pos = RelocInfo::kNoPosition);
Statement* DesugarLexicalBindingsInForStatement(
Scope* inner_scope, VariableMode mode,
ZoneList<const AstRawString*>* names, ForStatement* loop, Statement* init,
Expression* cond, Statement* next, Statement* body, bool* ok);
+ void DesugarAsyncFunctionBody(const AstRawString* function_name, Scope* scope,
+ ZoneList<Statement*>* body,
+ Type::ExpressionClassifier* classifier,
+ FunctionKind kind, FunctionBody type,
+ bool accept_IN, int pos, bool* ok);
+
void RewriteDoExpression(Expression* expr, bool* ok);
FunctionLiteral* ParseFunctionLiteral(
@@ -1027,6 +1049,7 @@
Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok);
+ Block* BuildRejectPromiseOnException(Block* block);
// Consumes the ending }.
ZoneList<Statement*>* ParseEagerFunctionBody(
@@ -1054,6 +1077,8 @@
void SetLanguageMode(Scope* scope, LanguageMode mode);
void RaiseLanguageMode(LanguageMode mode);
+ V8_INLINE void MarkCollectedTailCallExpressions();
+
V8_INLINE void RewriteDestructuringAssignments();
V8_INLINE Expression* RewriteExponentiation(Expression* left,
@@ -1069,6 +1094,10 @@
friend class InitializerRewriter;
void RewriteParameterInitializer(Expression* expr, Scope* scope);
+ Expression* BuildCreateJSGeneratorObject(int pos, FunctionKind kind);
+ Expression* BuildPromiseResolve(Expression* value, int pos);
+ Expression* BuildPromiseReject(Expression* value, int pos);
+
Scanner scanner_;
PreParser* reusable_preparser_;
Scope* original_scope_; // for ES5 function declarations in sloppy eval
@@ -1238,20 +1267,27 @@
}
}
-
void ParserTraits::AddParameterInitializationBlock(
const ParserFormalParameters& parameters,
- ZoneList<v8::internal::Statement*>* body, bool* ok) {
+ ZoneList<v8::internal::Statement*>* body, bool is_async, bool* ok) {
if (!parameters.is_simple) {
auto* init_block =
parser_->BuildParameterInitializationBlock(parameters, ok);
if (!*ok) return;
+
+ if (is_async) {
+ init_block = parser_->BuildRejectPromiseOnException(init_block);
+ }
+
if (init_block != nullptr) {
body->Add(init_block, parser_->zone());
}
}
}
+Expression* ParserTraits::ParseAsyncFunctionExpression(bool* ok) {
+ return parser_->ParseAsyncFunctionExpression(ok);
+}
DoExpression* ParserTraits::ParseDoExpression(bool* ok) {
return parser_->ParseDoExpression(ok);
diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc
index e699255..3dcff98 100644
--- a/src/parsing/pattern-rewriter.cc
+++ b/src/parsing/pattern-rewriter.cc
@@ -272,15 +272,9 @@
factory()->NewExpressionStatement(initialize, initialize->position()),
zone());
}
- } else if (value != nullptr && (descriptor_->mode == CONST_LEGACY ||
- IsLexicalVariableMode(descriptor_->mode))) {
- // Constant initializations always assign to the declared constant which
- // is always at the function scope level. This is only relevant for
- // dynamically looked-up variables and constants (the
- // start context for constant lookups is always the function context,
- // while it is the top context for var declared variables). Sigh...
- // For 'let' and 'const' declared variables in harmony mode the
- // initialization also always assigns to the declared variable.
+ } else if (value != nullptr && IsLexicalVariableMode(descriptor_->mode)) {
+ // For 'let' and 'const' declared variables the initialization always
+ // assigns to the declared variable.
DCHECK_NOT_NULL(proxy);
DCHECK_NOT_NULL(proxy->var());
DCHECK_NOT_NULL(value);
@@ -387,6 +381,37 @@
return set_context(old_context);
}
+// Two cases for scope rewriting the scope of default parameters:
+// - Eagerly parsed arrow functions are initially parsed as having
+// expressions in the enclosing scope, but when the arrow is encountered,
+// need to be in the scope of the function.
+// - When an extra declaration scope needs to be inserted to account for
+// a sloppy eval in a default parameter or function body, the expressions
+// needs to be in that new inner scope which was added after initial
+// parsing.
+// Each of these cases can be handled by rewriting the contents of the
+// expression to the current scope. The source scope is typically the outer
+// scope when one case occurs; when both cases occur, both scopes need to
+// be included as the outer scope. (Both rewritings still need to be done
+// to account for lazily parsed arrow functions which hit the second case.)
+// TODO(littledan): Remove the outer_scope parameter of
+// RewriteParameterInitializerScope
+void Parser::PatternRewriter::RewriteParameterScopes(Expression* expr) {
+ if (!IsBindingContext()) return;
+ if (descriptor_->declaration_kind != DeclarationDescriptor::PARAMETER) return;
+ if (!scope()->is_arrow_scope() && !scope()->is_block_scope()) return;
+
+ // Either this scope is an arrow scope or a declaration block scope.
+ DCHECK(scope()->is_declaration_scope());
+
+ if (scope()->outer_scope()->is_arrow_scope() && scope()->is_block_scope()) {
+ RewriteParameterInitializerScope(parser_->stack_limit(), expr,
+ scope()->outer_scope()->outer_scope(),
+ scope());
+ }
+ RewriteParameterInitializerScope(parser_->stack_limit(), expr,
+ scope()->outer_scope(), scope());
+}
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
Variable** temp_var) {
@@ -396,6 +421,11 @@
for (ObjectLiteralProperty* property : *pattern->properties()) {
PatternContext context = SetInitializerContextIfNeeded(property->value());
+
+ // Computed property names contain expressions which might require
+ // scope rewriting.
+ if (!property->key()->IsLiteral()) RewriteParameterScopes(property->key());
+
RecurseIntoSubpattern(
property->value(),
factory()->NewProperty(factory()->NewVariableProxy(temp),
@@ -552,11 +582,11 @@
// let array = [];
// while (!done) {
+ // done = true; // If .next, .done or .value throws, don't close.
// result = IteratorNext(iterator);
- // if (result.done) {
- // done = true;
- // } else {
+ // if (!result.done) {
// %AppendElement(array, result.value);
+ // done = false;
// }
// }
@@ -571,12 +601,6 @@
node->literal_index(), RelocInfo::kNoPosition));
}
- // result = IteratorNext(iterator);
- Statement* get_next = factory()->NewExpressionStatement(
- parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
- result, nopos),
- nopos);
-
// done = true;
Statement* set_done = factory()->NewExpressionStatement(
factory()->NewAssignment(
@@ -584,6 +608,12 @@
factory()->NewBooleanLiteral(true, nopos), nopos),
nopos);
+ // result = IteratorNext(iterator);
+ Statement* get_next = factory()->NewExpressionStatement(
+ parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
+ result, nopos),
+ nopos);
+
// %AppendElement(array, result.value);
Statement* append_element;
{
@@ -600,29 +630,44 @@
nopos);
}
- // if (result.done) { #set_done } else { #append_element }
- Statement* set_done_or_append;
+ // done = false;
+ Statement* unset_done = factory()->NewExpressionStatement(
+ factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(done),
+ factory()->NewBooleanLiteral(false, nopos), nopos),
+ nopos);
+
+ // if (!result.done) { #append_element; #unset_done }
+ Statement* maybe_append_and_unset_done;
{
Expression* result_done =
factory()->NewProperty(factory()->NewVariableProxy(result),
factory()->NewStringLiteral(
ast_value_factory()->done_string(), nopos),
nopos);
- set_done_or_append = factory()->NewIfStatement(result_done, set_done,
- append_element, nopos);
+
+ Block* then = factory()->NewBlock(nullptr, 2, true, nopos);
+ then->statements()->Add(append_element, zone());
+ then->statements()->Add(unset_done, zone());
+
+ maybe_append_and_unset_done = factory()->NewIfStatement(
+ factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
+ factory()->NewEmptyStatement(nopos), nopos);
}
// while (!done) {
+ // #set_done;
// #get_next;
- // #set_done_or_append;
+ // #maybe_append_and_unset_done;
// }
WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
{
Expression* condition = factory()->NewUnaryOperation(
Token::NOT, factory()->NewVariableProxy(done), nopos);
- Block* body = factory()->NewBlock(nullptr, 2, true, nopos);
+ Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
+ body->statements()->Add(set_done, zone());
body->statements()->Add(get_next, zone());
- body->statements()->Add(set_done_or_append, zone());
+ body->statements()->Add(maybe_append_and_unset_done, zone());
loop->Initialize(condition, body);
}
@@ -668,12 +713,8 @@
RelocInfo::kNoPosition);
}
- if (IsBindingContext() &&
- descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
- scope()->is_arrow_scope()) {
- RewriteParameterInitializerScope(parser_->stack_limit(), initializer,
- scope()->outer_scope(), scope());
- }
+ // Initializer may have been parsed in the wrong scope.
+ RewriteParameterScopes(initializer);
PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
RecurseIntoSubpattern(node->target(), value);
diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc
index da1c35b..0a091c6 100644
--- a/src/parsing/preparser.cc
+++ b/src/parsing/preparser.cc
@@ -12,8 +12,8 @@
#include "src/hashmap.h"
#include "src/list.h"
#include "src/parsing/parser-base.h"
-#include "src/parsing/preparse-data.h"
#include "src/parsing/preparse-data-format.h"
+#include "src/parsing/preparse-data.h"
#include "src/parsing/preparser.h"
#include "src/unicode.h"
#include "src/utils.h"
@@ -38,8 +38,10 @@
PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
- if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) {
- return PreParserIdentifier::FutureReserved();
+ if (scanner->current_token() == Token::ENUM) {
+ return PreParserIdentifier::Enum();
+ } else if (scanner->current_token() == Token::AWAIT) {
+ return PreParserIdentifier::Await();
} else if (scanner->current_token() ==
Token::FUTURE_STRICT_RESERVED_WORD) {
return PreParserIdentifier::FutureStrictReserved();
@@ -49,6 +51,8 @@
return PreParserIdentifier::Static();
} else if (scanner->current_token() == Token::YIELD) {
return PreParserIdentifier::Yield();
+ } else if (scanner->current_token() == Token::ASYNC) {
+ return PreParserIdentifier::Async();
}
if (scanner->UnescapedLiteralMatches("eval", 4)) {
return PreParserIdentifier::Eval();
@@ -98,11 +102,13 @@
function_token_position, type, language_mode, ok);
}
-
PreParser::PreParseResult PreParser::PreParseLazyFunction(
LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
- ParserRecorder* log, Scanner::BookmarkScope* bookmark) {
+ bool parsing_module, ParserRecorder* log, Scanner::BookmarkScope* bookmark,
+ int* use_counts) {
+ parsing_module_ = parsing_module;
log_ = log;
+ use_counts_ = use_counts;
// Lazy functions always have trivial outer scopes (no with/catch scopes).
Scope* top_scope = NewScope(scope_, SCRIPT_SCOPE);
PreParserFactory top_factory(NULL);
@@ -118,6 +124,7 @@
bool ok = true;
int start_position = peek_position();
ParseLazyFunctionLiteralBody(&ok, bookmark);
+ use_counts_ = nullptr;
if (bookmark && bookmark->HasBeenReset()) {
// Do nothing, as we've just aborted scanning this function.
} else if (stack_overflow()) {
@@ -129,6 +136,7 @@
if (is_strict(scope_->language_mode())) {
int end_pos = scanner()->location().end_pos;
CheckStrictOctalLiteral(start_position, end_pos, &ok);
+ CheckDecimalLiteralWithLeadingZero(use_counts, start_position, end_pos);
if (!ok) return kPreParseSuccess;
}
}
@@ -178,19 +186,23 @@
switch (peek()) {
case Token::FUNCTION:
- return ParseFunctionDeclaration(ok);
+ return ParseHoistableDeclaration(ok);
case Token::CLASS:
return ParseClassDeclaration(ok);
case Token::CONST:
- if (allow_const()) {
- return ParseVariableStatement(kStatementListItem, ok);
- }
- break;
+ return ParseVariableStatement(kStatementListItem, ok);
case Token::LET:
if (IsNextLetKeyword()) {
return ParseVariableStatement(kStatementListItem, ok);
}
break;
+ case Token::ASYNC:
+ if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
+ !scanner()->HasAnyLineTerminatorAfterNext()) {
+ Consume(Token::ASYNC);
+ return ParseAsyncFunctionDeclaration(ok);
+ }
+ /* falls through */
default:
break;
}
@@ -281,7 +293,9 @@
(legacy && allow_harmony_restrictive_declarations())) {
return ParseSubStatement(kDisallowLabelledFunctionStatement, ok);
} else {
- return ParseFunctionDeclaration(CHECK_OK);
+ Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
+ BlockState block_state(&scope_, body_scope);
+ return ParseFunctionDeclaration(ok);
}
}
@@ -377,37 +391,64 @@
}
}
+PreParser::Statement PreParser::ParseHoistableDeclaration(
+ int pos, ParseFunctionFlags flags, bool* ok) {
+ const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
+ const bool is_async = flags & ParseFunctionFlags::kIsAsync;
+ DCHECK(!is_generator || !is_async);
-PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
- // FunctionDeclaration ::
- // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
- // GeneratorDeclaration ::
- // 'function' '*' Identifier '(' FormalParameterListopt ')'
- // '{' FunctionBody '}'
- Expect(Token::FUNCTION, CHECK_OK);
- int pos = position();
- bool is_generator = Check(Token::MUL);
bool is_strict_reserved = false;
Identifier name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
+
+ if (V8_UNLIKELY(is_async_function() && this->IsAwait(name))) {
+ ReportMessageAt(scanner()->location(),
+ MessageTemplate::kAwaitBindingIdentifier);
+ *ok = false;
+ return Statement::Default();
+ }
+
ParseFunctionLiteral(name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
- : FunctionKind::kNormalFunction,
+ : is_async ? FunctionKind::kAsyncFunction
+ : FunctionKind::kNormalFunction,
pos, FunctionLiteral::kDeclaration, language_mode(),
CHECK_OK);
return Statement::FunctionDeclaration();
}
+PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(bool* ok) {
+ // AsyncFunctionDeclaration ::
+ // async [no LineTerminator here] function BindingIdentifier[Await]
+ // ( FormalParameters[Await] ) { AsyncFunctionBody }
+ DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
+ int pos = position();
+ Expect(Token::FUNCTION, CHECK_OK);
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
+ return ParseHoistableDeclaration(pos, flags, ok);
+}
+
+PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
+ // FunctionDeclaration ::
+ // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+ // GeneratorDeclaration ::
+ // 'function' '*' Identifier '(' FormalParameterListopt ')'
+ // '{' FunctionBody '}'
+
+ Expect(Token::FUNCTION, CHECK_OK);
+ int pos = position();
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ if (Check(Token::MUL)) {
+ flags |= ParseFunctionFlags::kIsGenerator;
+ }
+ return ParseHoistableDeclaration(pos, flags, ok);
+}
+
PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
Expect(Token::CLASS, CHECK_OK);
- if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
- ReportMessage(MessageTemplate::kSloppyLexical);
- *ok = false;
- return Statement::Default();
- }
int pos = position();
bool is_strict_reserved = false;
@@ -423,10 +464,14 @@
// Block ::
// '{' StatementList '}'
+ Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
Expect(Token::LBRACE, CHECK_OK);
Statement final = Statement::Default();
- while (peek() != Token::RBRACE) {
- final = ParseStatementListItem(CHECK_OK);
+ {
+ BlockState block_state(&scope_, block_scope);
+ while (peek() != Token::RBRACE) {
+ final = ParseStatementListItem(CHECK_OK);
+ }
}
Expect(Token::RBRACE, ok);
return final;
@@ -473,7 +518,7 @@
bool is_pattern = false;
if (peek() == Token::VAR) {
Consume(Token::VAR);
- } else if (peek() == Token::CONST && allow_const()) {
+ } else if (peek() == Token::CONST) {
// TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
//
// ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
@@ -485,12 +530,10 @@
// existing pages. Therefore we keep allowing const with the old
// non-harmony semantics in sloppy mode.
Consume(Token::CONST);
- if (is_strict(language_mode()) || allow_harmony_sloppy()) {
- DCHECK(var_context != kStatement);
- require_initializer = true;
- lexical = true;
- }
- } else if (peek() == Token::LET && allow_let()) {
+ DCHECK(var_context != kStatement);
+ require_initializer = true;
+ lexical = true;
+ } else if (peek() == Token::LET) {
Consume(Token::LET);
DCHECK(var_context != kStatement);
lexical = true;
@@ -556,6 +599,22 @@
return Statement::Default();
}
+PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
+ Consume(Token::FUNCTION);
+ int pos = position();
+ ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ if (Check(Token::MUL)) {
+ flags |= ParseFunctionFlags::kIsGenerator;
+ if (allow_harmony_restrictive_declarations()) {
+ PreParserTraits::ReportMessageAt(
+ scanner()->location(), MessageTemplate::kGeneratorInLegacyContext);
+ *ok = false;
+ return Statement::Default();
+ }
+ }
+ return ParseHoistableDeclaration(pos, flags, ok);
+}
+
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
AllowLabelledFunctionStatement allow_function, bool* ok) {
// ExpressionStatement | LabelledStatement ::
@@ -586,7 +645,8 @@
if (starts_with_identifier && expr.IsIdentifier() && peek() == Token::COLON) {
// Expression is a single identifier, and not, e.g., a parenthesized
// identifier.
- DCHECK(!expr.AsIdentifier().IsFutureReserved());
+ DCHECK(!expr.AsIdentifier().IsEnum());
+ DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait());
DCHECK(is_sloppy(language_mode()) ||
!IsFutureStrictReserved(expr.AsIdentifier()));
Consume(Token::COLON);
@@ -606,14 +666,6 @@
// accept "native function" in the preparser.
}
// Parsed expression statement.
- // Detect attempts at 'let' declarations in sloppy mode.
- if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
- is_sloppy(language_mode()) && expr.IsIdentifier() &&
- expr.AsIdentifier().IsLet()) {
- ReportMessage(MessageTemplate::kSloppyLexical, NULL);
- *ok = false;
- return Statement::Default();
- }
ExpectSemicolon(CHECK_OK);
return Statement::ExpressionStatement(expr);
}
@@ -696,6 +748,16 @@
tok != Token::SEMICOLON &&
tok != Token::RBRACE &&
tok != Token::EOS) {
+ // 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.
+ ReturnExprContext return_expr_context =
+ IsSubclassConstructor(function_state_->kind())
+ ? function_state_->return_expr_context()
+ : ReturnExprContext::kInsideValidReturnStatement;
+
+ ReturnExprScope maybe_allow_tail_calls(function_state_,
+ return_expr_context);
ParseExpression(true, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
@@ -732,23 +794,27 @@
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- Expect(Token::LBRACE, CHECK_OK);
- Token::Value token = peek();
- while (token != Token::RBRACE) {
- if (token == Token::CASE) {
- Expect(Token::CASE, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- } else {
- Expect(Token::DEFAULT, CHECK_OK);
- }
- Expect(Token::COLON, CHECK_OK);
- token = peek();
- Statement statement = Statement::Jump();
- while (token != Token::CASE &&
- token != Token::DEFAULT &&
- token != Token::RBRACE) {
- statement = ParseStatementListItem(CHECK_OK);
+ Scope* cases_scope = NewScope(scope_, BLOCK_SCOPE);
+ {
+ BlockState cases_block_state(&scope_, cases_scope);
+ Expect(Token::LBRACE, CHECK_OK);
+ Token::Value token = peek();
+ while (token != Token::RBRACE) {
+ if (token == Token::CASE) {
+ Expect(Token::CASE, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ } else {
+ Expect(Token::DEFAULT, CHECK_OK);
+ }
+ Expect(Token::COLON, CHECK_OK);
token = peek();
+ Statement statement = Statement::Jump();
+ while (token != Token::CASE &&
+ token != Token::DEFAULT &&
+ token != Token::RBRACE) {
+ statement = ParseStatementListItem(CHECK_OK);
+ token = peek();
+ }
}
}
Expect(Token::RBRACE, ok);
@@ -788,12 +854,16 @@
// ForStatement ::
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
+ // Create an in-between scope for let-bound iteration variables.
+ Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
+ bool has_lexical = false;
+
+ BlockState block_state(&scope_, for_scope);
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
- bool is_let_identifier_expression = false;
if (peek() != Token::SEMICOLON) {
ForEachStatement::VisitMode mode;
- if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
+ if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && IsNextLetKeyword())) {
int decl_count;
bool is_lexical;
@@ -803,6 +873,7 @@
ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical,
&is_binding_pattern, &first_initializer_loc,
&bindings_loc, CHECK_OK);
+ if (is_lexical) has_lexical = true;
if (CheckInOrOf(&mode, ok)) {
if (!*ok) return Statement::Default();
if (decl_count != 1) {
@@ -814,7 +885,12 @@
}
if (first_initializer_loc.IsValid() &&
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
- is_lexical || is_binding_pattern)) {
+ is_lexical || is_binding_pattern || allow_harmony_for_in())) {
+ // Only increment the use count if we would have let this through
+ // without the flag.
+ if (use_counts_ != nullptr && allow_harmony_for_in()) {
+ ++use_counts_[v8::Isolate::kForInInitializer];
+ }
PreParserTraits::ReportMessageAt(
first_initializer_loc, MessageTemplate::kForInOfLoopInitializer,
ForEachStatement::VisitModeString(mode));
@@ -831,7 +907,11 @@
}
Expect(Token::RPAREN, CHECK_OK);
- ParseScopedStatement(true, CHECK_OK);
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
+ ParseScopedStatement(true, CHECK_OK);
+ }
return Statement::Default();
}
} else {
@@ -839,8 +919,6 @@
ExpressionClassifier classifier(this);
Expression lhs = ParseExpression(false, &classifier, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
- is_let_identifier_expression =
- lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
bool is_for_each = CheckInOrOf(&mode, ok);
if (!*ok) return Statement::Default();
bool is_destructuring = is_for_each &&
@@ -868,33 +946,39 @@
}
Expect(Token::RPAREN, CHECK_OK);
- ParseScopedStatement(true, CHECK_OK);
+ Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
+ {
+ BlockState block_state(&scope_, body_scope);
+ ParseScopedStatement(true, CHECK_OK);
+ }
return Statement::Default();
}
}
}
// Parsed initializer at this point.
- // Detect attempts at 'let' declarations in sloppy mode.
- if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER &&
- is_sloppy(language_mode()) && is_let_identifier_expression) {
- ReportMessage(MessageTemplate::kSloppyLexical, NULL);
- *ok = false;
- return Statement::Default();
- }
Expect(Token::SEMICOLON, CHECK_OK);
- if (peek() != Token::SEMICOLON) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(Token::SEMICOLON, CHECK_OK);
+ // If 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_;
+ if (has_lexical) inner_scope = NewScope(for_scope, BLOCK_SCOPE);
- if (peek() != Token::RPAREN) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(Token::RPAREN, CHECK_OK);
+ {
+ BlockState block_state(&scope_, inner_scope);
- ParseScopedStatement(true, ok);
+ if (peek() != Token::SEMICOLON) {
+ ParseExpression(true, CHECK_OK);
+ }
+ Expect(Token::SEMICOLON, CHECK_OK);
+
+ if (peek() != Token::RPAREN) {
+ ParseExpression(true, CHECK_OK);
+ }
+ Expect(Token::RPAREN, CHECK_OK);
+
+ ParseScopedStatement(true, ok);
+ }
return Statement::Default();
}
@@ -929,7 +1013,11 @@
Expect(Token::TRY, CHECK_OK);
- ParseBlock(CHECK_OK);
+ {
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideTryBlock);
+ ParseBlock(CHECK_OK);
+ }
Token::Value tok = peek();
if (tok != Token::CATCH && tok != Token::FINALLY) {
@@ -937,24 +1025,42 @@
*ok = false;
return Statement::Default();
}
+ TailCallExpressionList tail_call_expressions_in_catch_block(zone());
+ bool catch_block_exists = false;
if (tok == Token::CATCH) {
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
+ Scope* catch_scope = NewScope(scope_, CATCH_SCOPE);
ExpressionClassifier pattern_classifier(this);
ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
{
- // TODO(adamk): Make this CATCH_SCOPE
- Scope* with_scope = NewScope(scope_, WITH_SCOPE);
- BlockState block_state(&scope_, with_scope);
- ParseBlock(CHECK_OK);
+ CollectExpressionsInTailPositionToListScope
+ collect_tail_call_expressions_scope(
+ function_state_, &tail_call_expressions_in_catch_block);
+ BlockState block_state(&scope_, catch_scope);
+ Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+ {
+ BlockState block_state(&scope_, block_scope);
+ ParseBlock(CHECK_OK);
+ }
}
+ catch_block_exists = true;
tok = peek();
}
if (tok == Token::FINALLY) {
Consume(Token::FINALLY);
ParseBlock(CHECK_OK);
+ if (FLAG_harmony_explicit_tailcalls && catch_block_exists &&
+ tail_call_expressions_in_catch_block.has_explicit_tail_calls()) {
+ // TODO(ishell): update chapter number.
+ // ES8 XX.YY.ZZ
+ ReportMessageAt(tail_call_expressions_in_catch_block.location(),
+ MessageTemplate::kUnexpectedTailCallInCatchBlock);
+ *ok = false;
+ return Statement::Default();
+ }
}
return Statement::Default();
}
@@ -1012,9 +1118,8 @@
// See Parser::ParseFunctionLiteral for more information about lazy parsing
// and lazy compilation.
- bool is_lazily_parsed =
- (outer_is_script_scope && allow_lazy() && !parenthesized_function_);
- parenthesized_function_ = false;
+ bool is_lazily_parsed = (outer_is_script_scope && allow_lazy() &&
+ !function_state_->this_function_is_parenthesized());
Expect(Token::LBRACE, CHECK_OK);
if (is_lazily_parsed) {
@@ -1039,11 +1144,44 @@
if (is_strict(language_mode)) {
int end_position = scanner()->location().end_pos;
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
+ CheckDecimalLiteralWithLeadingZero(use_counts_, start_position,
+ end_position);
}
return Expression::Default();
}
+PreParser::Expression PreParser::ParseAsyncFunctionExpression(bool* ok) {
+ // AsyncFunctionDeclaration ::
+ // async [no LineTerminator here] function ( FormalParameters[Await] )
+ // { AsyncFunctionBody }
+ //
+ // async [no LineTerminator here] function BindingIdentifier[Await]
+ // ( FormalParameters[Await] ) { AsyncFunctionBody }
+ int pos = position();
+ Expect(Token::FUNCTION, CHECK_OK);
+ bool is_strict_reserved = false;
+ Identifier name;
+ FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
+
+ if (peek_any_identifier()) {
+ type = FunctionLiteral::kNamedExpression;
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
+ if (this->IsAwait(name)) {
+ ReportMessageAt(scanner()->location(),
+ MessageTemplate::kAwaitBindingIdentifier);
+ *ok = false;
+ return Expression::Default();
+ }
+ }
+
+ ParseFunctionLiteral(name, scanner()->location(),
+ is_strict_reserved ? kFunctionNameIsStrictReserved
+ : kFunctionNameValidityUnknown,
+ FunctionKind::kAsyncFunction, pos, type, language_mode(),
+ CHECK_OK);
+ return Expression::Default();
+}
void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
Scanner::BookmarkScope* bookmark) {
@@ -1090,6 +1228,7 @@
if (has_extends) {
ExpressionClassifier extends_classifier(this);
ParseLeftHandSideExpression(&extends_classifier, CHECK_OK);
+ CheckNoTailCallExpressions(&extends_classifier, CHECK_OK);
ValidateExpression(&extends_classifier, CHECK_OK);
if (classifier != nullptr) {
classifier->Accumulate(&extends_classifier,
@@ -1104,12 +1243,11 @@
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
const bool in_class = true;
- const bool is_static = false;
bool is_computed_name = false; // Classes do not care about computed
// property names here.
Identifier name;
ExpressionClassifier property_classifier(this);
- ParsePropertyDefinition(&checker, in_class, has_extends, is_static,
+ ParsePropertyDefinition(&checker, in_class, has_extends, MethodKind::Normal,
&is_computed_name, &has_seen_constructor,
&property_classifier, &name, CHECK_OK);
ValidateExpression(&property_classifier, CHECK_OK);
@@ -1151,15 +1289,24 @@
// do '{' StatementList '}'
Expect(Token::DO, CHECK_OK);
Expect(Token::LBRACE, CHECK_OK);
- Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
- {
- BlockState block_state(&scope_, block_scope);
- while (peek() != Token::RBRACE) {
- ParseStatementListItem(CHECK_OK);
- }
- Expect(Token::RBRACE, CHECK_OK);
- return PreParserExpression::Default();
+ while (peek() != Token::RBRACE) {
+ ParseStatementListItem(CHECK_OK);
}
+ Expect(Token::RBRACE, CHECK_OK);
+ return PreParserExpression::Default();
+}
+
+void PreParserTraits::ParseAsyncArrowSingleExpressionBody(
+ PreParserStatementList body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok) {
+ Scope* scope = pre_parser_->scope_;
+ scope->ForceContextAllocation();
+
+ PreParserExpression return_value =
+ pre_parser_->ParseAssignmentExpression(accept_IN, classifier, ok);
+ if (!*ok) return;
+
+ body->Add(PreParserStatement::ExpressionStatement(return_value), zone());
}
#undef CHECK_OK
diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h
index f2f6951..16eeab4 100644
--- a/src/parsing/preparser.h
+++ b/src/parsing/preparser.h
@@ -55,6 +55,15 @@
static PreParserIdentifier Constructor() {
return PreParserIdentifier(kConstructorIdentifier);
}
+ static PreParserIdentifier Enum() {
+ return PreParserIdentifier(kEnumIdentifier);
+ }
+ static PreParserIdentifier Await() {
+ return PreParserIdentifier(kAwaitIdentifier);
+ }
+ static PreParserIdentifier Async() {
+ return PreParserIdentifier(kAsyncIdentifier);
+ }
bool IsEval() const { return type_ == kEvalIdentifier; }
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
@@ -64,7 +73,9 @@
bool IsYield() const { return type_ == kYieldIdentifier; }
bool IsPrototype() const { return type_ == kPrototypeIdentifier; }
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
- bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; }
+ bool IsEnum() const { return type_ == kEnumIdentifier; }
+ bool IsAwait() const { return type_ == kAwaitIdentifier; }
+ bool IsAsync() const { return type_ == kAsyncIdentifier; }
bool IsFutureStrictReserved() const {
return type_ == kFutureStrictReservedIdentifier ||
type_ == kLetIdentifier || type_ == kStaticIdentifier ||
@@ -91,7 +102,10 @@
kArgumentsIdentifier,
kUndefinedIdentifier,
kPrototypeIdentifier,
- kConstructorIdentifier
+ kConstructorIdentifier,
+ kEnumIdentifier,
+ kAwaitIdentifier,
+ kAsyncIdentifier
};
explicit PreParserIdentifier(Type type) : type_(type) {}
@@ -166,6 +180,12 @@
ExpressionTypeField::encode(kCallExpression));
}
+ static PreParserExpression CallEval() {
+ return PreParserExpression(
+ TypeField::encode(kExpression) |
+ ExpressionTypeField::encode(kCallEvalExpression));
+ }
+
static PreParserExpression SuperCallReference() {
return PreParserExpression(
TypeField::encode(kExpression) |
@@ -227,7 +247,13 @@
bool IsCall() const {
return TypeField::decode(code_) == kExpression &&
- ExpressionTypeField::decode(code_) == kCallExpression;
+ (ExpressionTypeField::decode(code_) == kCallExpression ||
+ ExpressionTypeField::decode(code_) == kCallEvalExpression);
+ }
+
+ bool IsDirectEvalCall() const {
+ return TypeField::decode(code_) == kExpression &&
+ ExpressionTypeField::decode(code_) == kCallEvalExpression;
}
bool IsSuperCallReference() const {
@@ -285,6 +311,7 @@
kThisPropertyExpression,
kPropertyExpression,
kCallExpression,
+ kCallEvalExpression,
kSuperCallReference,
kNoTemplateTagExpression,
kAssignment
@@ -494,6 +521,9 @@
PreParserExpression NewCall(PreParserExpression expression,
PreParserExpressionList arguments,
int pos) {
+ if (expression.IsIdentifier() && expression.AsIdentifier().IsEval()) {
+ return PreParserExpression::CallEval();
+ }
return PreParserExpression::Call();
}
PreParserExpression NewCallNew(PreParserExpression expression,
@@ -597,6 +627,14 @@
return identifier.IsArguments();
}
+ static bool IsAwait(PreParserIdentifier identifier) {
+ return identifier.IsAwait();
+ }
+
+ static bool IsAsync(PreParserIdentifier identifier) {
+ return identifier.IsAsync();
+ }
+
static bool IsEvalOrArguments(PreParserIdentifier identifier) {
return identifier.IsEvalOrArguments();
}
@@ -626,6 +664,14 @@
return expression.AsIdentifier();
}
+ static bool IsEvalIdentifier(PreParserExpression expression) {
+ return IsIdentifier(expression) && IsEval(AsIdentifier(expression));
+ }
+
+ static bool IsDirectEvalCall(PreParserExpression expression) {
+ return expression.IsDirectEvalCall();
+ }
+
static bool IsFutureStrictReserved(PreParserIdentifier identifier) {
return identifier.IsFutureStrictReserved();
}
@@ -814,8 +860,8 @@
}
static void AddParameterInitializationBlock(
- const PreParserFormalParameters& parameters,
- PreParserStatementList list, bool* ok) {}
+ const PreParserFormalParameters& parameters, PreParserStatementList list,
+ bool is_async, bool* ok) {}
V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
int* expected_property_count, bool* ok) {
@@ -832,6 +878,12 @@
PreParserExpression expression, const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok);
+ void ParseAsyncArrowSingleExpressionBody(
+ PreParserStatementList body, bool accept_IN,
+ Type::ExpressionClassifier* classifier, int pos, bool* ok);
+
+ V8_INLINE PreParserExpression ParseAsyncFunctionExpression(bool* ok);
+
void ReindexLiterals(const PreParserFormalParameters& paramaters) {}
struct TemplateLiteralState {};
@@ -888,6 +940,7 @@
bool name_is_strict_reserved, int pos,
bool* ok);
+ V8_INLINE void MarkCollectedTailCallExpressions() {}
V8_INLINE void MarkTailPosition(PreParserExpression) {}
PreParserExpressionList PrepareSpreadArguments(PreParserExpressionList list) {
@@ -903,6 +956,11 @@
PreParserExpressionList args,
int pos);
+ inline PreParserExpression ExpressionListToExpression(
+ PreParserExpressionList args) {
+ return PreParserExpression::Default();
+ }
+
inline void RewriteDestructuringAssignments() {}
inline PreParserExpression RewriteExponentiation(PreParserExpression left,
@@ -926,14 +984,14 @@
inline void RewriteNonPattern(Type::ExpressionClassifier* classifier,
bool* ok);
+ inline PreParserExpression RewriteAwaitExpression(PreParserExpression value,
+ int pos);
+
V8_INLINE Zone* zone() const;
V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const;
inline PreParserExpression RewriteYieldStar(
PreParserExpression generator, PreParserExpression expr, int pos);
- inline PreParserExpression RewriteInstanceof(PreParserExpression lhs,
- PreParserExpression rhs,
- int pos);
private:
PreParser* pre_parser_;
@@ -966,19 +1024,30 @@
PreParser(Zone* zone, Scanner* scanner, AstValueFactory* ast_value_factory,
ParserRecorder* log, uintptr_t stack_limit)
: ParserBase<PreParserTraits>(zone, scanner, stack_limit, NULL,
- ast_value_factory, log, this) {}
+ ast_value_factory, log, this),
+ use_counts_(nullptr) {}
// Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully
// captured the syntax error), and false if a stack-overflow happened
// during parsing.
- PreParseResult PreParseProgram(int* materialized_literals = 0) {
+ PreParseResult PreParseProgram(int* materialized_literals = 0,
+ bool is_module = false) {
Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
+
+ // ModuleDeclarationInstantiation for Source Text Module Records creates a
+ // new Module Environment Record whose outer lexical environment record is
+ // the global scope.
+ if (is_module) {
+ scope = NewScope(scope, MODULE_SCOPE);
+ }
+
PreParserFactory factory(NULL);
FunctionState top_scope(&function_state_, &scope_, scope, kNormalFunction,
&factory);
bool ok = true;
int start_position = scanner()->peek_location().beg_pos;
+ parsing_module_ = is_module;
ParseStatementList(Token::EOS, &ok);
if (stack_overflow()) return kPreParseStackOverflow;
if (!ok) {
@@ -986,6 +1055,8 @@
} else if (is_strict(scope_->language_mode())) {
CheckStrictOctalLiteral(start_position, scanner()->location().end_pos,
&ok);
+ CheckDecimalLiteralWithLeadingZero(use_counts_, start_position,
+ scanner()->location().end_pos);
}
if (materialized_literals) {
*materialized_literals = function_state_->materialized_literal_count();
@@ -1001,9 +1072,12 @@
// keyword and parameters, and have consumed the initial '{'.
// At return, unless an error occurred, the scanner is positioned before the
// the final '}'.
- PreParseResult PreParseLazyFunction(
- LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
- ParserRecorder* log, Scanner::BookmarkScope* bookmark = nullptr);
+ PreParseResult PreParseLazyFunction(LanguageMode language_mode,
+ FunctionKind kind,
+ bool has_simple_parameters,
+ bool parsing_module, ParserRecorder* log,
+ Scanner::BookmarkScope* bookmark,
+ int* use_counts);
private:
friend class PreParserTraits;
@@ -1027,7 +1101,12 @@
Statement ParseSubStatement(AllowLabelledFunctionStatement allow_function,
bool* ok);
Statement ParseScopedStatement(bool legacy, bool* ok);
+ Statement ParseHoistableDeclaration(bool* ok);
+ Statement ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
+ bool* ok);
Statement ParseFunctionDeclaration(bool* ok);
+ Statement ParseAsyncFunctionDeclaration(bool* ok);
+ Expression ParseAsyncFunctionExpression(bool* ok);
Statement ParseClassDeclaration(bool* ok);
Statement ParseBlock(bool* ok);
Statement ParseVariableStatement(VariableDeclarationContext var_context,
@@ -1077,6 +1156,8 @@
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
+
+ int* use_counts_;
};
@@ -1114,6 +1195,9 @@
// lists that are too long.
}
+PreParserExpression PreParserTraits::ParseAsyncFunctionExpression(bool* ok) {
+ return pre_parser_->ParseAsyncFunctionExpression(ok);
+}
PreParserExpression PreParserTraits::ParseDoExpression(bool* ok) {
return pre_parser_->ParseDoExpression(ok);
@@ -1125,6 +1209,10 @@
pre_parser_->ValidateExpression(classifier, ok);
}
+PreParserExpression PreParserTraits::RewriteAwaitExpression(
+ PreParserExpression value, int pos) {
+ return value;
+}
Zone* PreParserTraits::zone() const {
return pre_parser_->function_state_->scope()->zone();
@@ -1141,20 +1229,20 @@
return PreParserExpression::Default();
}
-PreParserExpression PreParserTraits::RewriteInstanceof(PreParserExpression lhs,
- PreParserExpression rhs,
- int pos) {
- return PreParserExpression::Default();
-}
-
PreParserStatementList PreParser::ParseEagerFunctionBody(
PreParserIdentifier function_name, int pos,
const PreParserFormalParameters& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok) {
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
- ParseStatementList(Token::RBRACE, ok);
- if (!*ok) return PreParserStatementList();
+ Scope* inner_scope = scope_;
+ if (!parameters.is_simple) inner_scope = NewScope(scope_, BLOCK_SCOPE);
+
+ {
+ BlockState block_state(&scope_, inner_scope);
+ ParseStatementList(Token::RBRACE, ok);
+ if (!*ok) return PreParserStatementList();
+ }
Expect(Token::RBRACE, ok);
return PreParserStatementList();
diff --git a/src/parsing/scanner-character-streams.h b/src/parsing/scanner-character-streams.h
index 603db93..7e065cf 100644
--- a/src/parsing/scanner-character-streams.h
+++ b/src/parsing/scanner-character-streams.h
@@ -158,8 +158,10 @@
void PushBack(uc32 character) override {
DCHECK(buffer_cursor_ > raw_data_);
- buffer_cursor_--;
pos_--;
+ if (character != kEndOfInput) {
+ buffer_cursor_--;
+ }
}
bool SetBookmark() override;
diff --git a/src/parsing/scanner.cc b/src/parsing/scanner.cc
index 698cb5e..6a9b32e 100644
--- a/src/parsing/scanner.cc
+++ b/src/parsing/scanner.cc
@@ -40,6 +40,7 @@
: unicode_cache_(unicode_cache),
bookmark_c0_(kNoBookmark),
octal_pos_(Location::invalid()),
+ decimal_with_leading_zero_pos_(Location::invalid()),
found_html_comment_(false),
allow_harmony_exponentiation_operator_(false) {
bookmark_current_.literal_chars = &bookmark_current_literal_;
@@ -249,6 +250,7 @@
if (V8_UNLIKELY(next_next_.token != Token::UNINITIALIZED)) {
next_ = next_next_;
next_next_.token = Token::UNINITIALIZED;
+ has_line_terminator_before_next_ = has_line_terminator_after_next_;
return current_.token;
}
has_line_terminator_before_next_ = false;
@@ -274,7 +276,12 @@
return next_next_.token;
}
TokenDesc prev = current_;
+ bool has_line_terminator_before_next =
+ has_line_terminator_before_next_ || has_multiline_comment_before_next_;
Next();
+ has_line_terminator_after_next_ =
+ has_line_terminator_before_next_ || has_multiline_comment_before_next_;
+ has_line_terminator_before_next_ = has_line_terminator_before_next;
Token::Value ret = next_.token;
next_next_ = next_;
next_ = current_;
@@ -975,10 +982,18 @@
Token::Value Scanner::ScanNumber(bool seen_period) {
DCHECK(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
- enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
+ enum {
+ DECIMAL,
+ DECIMAL_WITH_LEADING_ZERO,
+ HEX,
+ OCTAL,
+ IMPLICIT_OCTAL,
+ BINARY
+ } kind = DECIMAL;
LiteralScope literal(this);
bool at_start = !seen_period;
+ int start_pos = source_pos(); // For reporting octal positions.
if (seen_period) {
// we have already seen a decimal point of the float
AddLiteralChar('.');
@@ -987,7 +1002,6 @@
} else {
// if the first character is '0' we must check for octals and hex
if (c0_ == '0') {
- int start_pos = source_pos(); // For reporting octal positions.
AddLiteralCharAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or
@@ -1029,7 +1043,7 @@
while (true) {
if (c0_ == '8' || c0_ == '9') {
at_start = false;
- kind = DECIMAL;
+ kind = DECIMAL_WITH_LEADING_ZERO;
break;
}
if (c0_ < '0' || '7' < c0_) {
@@ -1039,11 +1053,13 @@
}
AddLiteralCharAdvance();
}
+ } else if (c0_ == '8' || c0_ == '9') {
+ kind = DECIMAL_WITH_LEADING_ZERO;
}
}
// Parse decimal digits and allow trailing fractional part.
- if (kind == DECIMAL) {
+ if (kind == DECIMAL || kind == DECIMAL_WITH_LEADING_ZERO) {
if (at_start) {
uint64_t value = 0;
while (IsDecimalDigit(c0_)) {
@@ -1060,6 +1076,8 @@
literal.Complete();
HandleLeadSurrogate();
+ if (kind == DECIMAL_WITH_LEADING_ZERO)
+ decimal_with_leading_zero_pos_ = Location(start_pos, source_pos());
return Token::SMI;
}
HandleLeadSurrogate();
@@ -1076,7 +1094,8 @@
// scan exponent, if any
if (c0_ == 'e' || c0_ == 'E') {
DCHECK(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
- if (kind != DECIMAL) return Token::ILLEGAL;
+ if (!(kind == DECIMAL || kind == DECIMAL_WITH_LEADING_ZERO))
+ return Token::ILLEGAL;
// scan exponent
AddLiteralCharAdvance();
if (c0_ == '+' || c0_ == '-')
@@ -1098,6 +1117,8 @@
literal.Complete();
+ if (kind == DECIMAL_WITH_LEADING_ZERO)
+ decimal_with_leading_zero_pos_ = Location(start_pos, source_pos());
return Token::NUMBER;
}
@@ -1135,6 +1156,9 @@
// Keyword Matcher
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('a') \
+ KEYWORD("async", Token::ASYNC) \
+ KEYWORD("await", Token::AWAIT) \
KEYWORD_GROUP('b') \
KEYWORD("break", Token::BREAK) \
KEYWORD_GROUP('c') \
@@ -1150,7 +1174,7 @@
KEYWORD("do", Token::DO) \
KEYWORD_GROUP('e') \
KEYWORD("else", Token::ELSE) \
- KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("enum", Token::ENUM) \
KEYWORD("export", Token::EXPORT) \
KEYWORD("extends", Token::EXTENDS) \
KEYWORD_GROUP('f') \
@@ -1196,7 +1220,6 @@
KEYWORD_GROUP('y') \
KEYWORD("yield", Token::YIELD)
-
static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
int input_length, bool escaped) {
DCHECK(input_length >= 1);
diff --git a/src/parsing/scanner.h b/src/parsing/scanner.h
index 22c504c..0acc7ab 100644
--- a/src/parsing/scanner.h
+++ b/src/parsing/scanner.h
@@ -225,8 +225,14 @@
} else {
is_one_byte_ = other->is_one_byte_;
position_ = other->position_;
- backing_store_.Dispose();
- backing_store_ = other->backing_store_.Clone();
+ if (position_ < backing_store_.length()) {
+ std::copy(other->backing_store_.begin(),
+ other->backing_store_.begin() + position_,
+ backing_store_.begin());
+ } else {
+ backing_store_.Dispose();
+ backing_store_ = other->backing_store_.Clone();
+ }
}
}
@@ -419,6 +425,13 @@
// Returns the location of the last seen octal literal.
Location octal_position() const { return octal_pos_; }
void clear_octal_position() { octal_pos_ = Location::invalid(); }
+ // Returns the location of the last seen decimal literal with a leading zero.
+ Location decimal_with_leading_zero_position() const {
+ return decimal_with_leading_zero_pos_;
+ }
+ void clear_decimal_with_leading_zero_position() {
+ decimal_with_leading_zero_pos_ = Location::invalid();
+ }
// Returns the value of the last smi that was scanned.
int smi_value() const { return current_.smi_value_; }
@@ -436,6 +449,12 @@
has_multiline_comment_before_next_;
}
+ bool HasAnyLineTerminatorAfterNext() {
+ Token::Value ensure_next_next = PeekAhead();
+ USE(ensure_next_next);
+ return has_line_terminator_after_next_;
+ }
+
// Scans the input as a regular expression pattern, previous
// character(s) must be /(=). Returns true if a pattern is scanned.
bool ScanRegExpPattern(bool seen_equal);
@@ -582,7 +601,7 @@
}
void PushBack(uc32 ch) {
- if (ch > static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
+ if (c0_ > static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
source_->PushBack(unibrow::Utf16::TrailSurrogate(c0_));
source_->PushBack(unibrow::Utf16::LeadSurrogate(c0_));
} else {
@@ -766,9 +785,9 @@
// Input stream. Must be initialized to an Utf16CharacterStream.
Utf16CharacterStream* source_;
-
- // Start position of the octal literal last scanned.
+ // Last-seen positions of potentially problematic tokens.
Location octal_pos_;
+ Location decimal_with_leading_zero_pos_;
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
uc32 c0_;
@@ -780,6 +799,7 @@
// Whether there is a multi-line comment that contains a
// line-terminator after the current token, and before the next.
bool has_multiline_comment_before_next_;
+ bool has_line_terminator_after_next_;
// Whether this scanner encountered an HTML comment.
bool found_html_comment_;
diff --git a/src/parsing/token.h b/src/parsing/token.h
index fae9ea8..8b44cda 100644
--- a/src/parsing/token.h
+++ b/src/parsing/token.h
@@ -148,10 +148,13 @@
T(IDENTIFIER, NULL, 0) \
\
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
- T(FUTURE_RESERVED_WORD, NULL, 0) \
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
+ K(ASYNC, "async", 0) \
+ /* `await` is a reserved word in module code only */ \
+ K(AWAIT, "await", 0) \
K(CLASS, "class", 0) \
K(CONST, "const", 0) \
+ K(ENUM, "enum", 0) \
K(EXPORT, "export", 0) \
K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \
@@ -173,7 +176,6 @@
T(TEMPLATE_SPAN, NULL, 0) \
T(TEMPLATE_TAIL, NULL, 0)
-
class Token {
public:
// All token values.
@@ -197,9 +199,10 @@
}
static bool IsIdentifier(Value tok, LanguageMode language_mode,
- bool is_generator) {
+ bool is_generator, bool is_module) {
switch (tok) {
case IDENTIFIER:
+ case ASYNC:
return true;
case ESCAPED_STRICT_RESERVED_WORD:
case FUTURE_STRICT_RESERVED_WORD:
@@ -208,6 +211,8 @@
return is_sloppy(language_mode);
case YIELD:
return !is_generator && is_sloppy(language_mode);
+ case AWAIT:
+ return !is_module;
default:
return false;
}