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/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;