summaryrefslogtreecommitdiff
path: root/deps/v8/src/parsing/parser.cc
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2016-09-06 22:49:51 +0200
committerMichaël Zasso <targos@protonmail.com>2016-09-22 09:51:19 +0200
commitec02b811a8a5c999bab4de312be2d732b7d9d50b (patch)
treeca3068017254f238cf413a451c57a803572983a4 /deps/v8/src/parsing/parser.cc
parentd2eb7ce0105369a9cad82787cb33a665e9bd00ad (diff)
downloadandroid-node-v8-ec02b811a8a5c999bab4de312be2d732b7d9d50b.tar.gz
android-node-v8-ec02b811a8a5c999bab4de312be2d732b7d9d50b.tar.bz2
android-node-v8-ec02b811a8a5c999bab4de312be2d732b7d9d50b.zip
deps: update V8 to 5.4.500.27
Pick up latest commit from the 5.4-lkgr branch. deps: edit V8 gitignore to allow trace event copy deps: update V8 trace event to 315bf1e2d45be7d53346c31cfcc37424a32c30c8 deps: edit V8 gitignore to allow gtest_prod.h copy deps: update V8 gtest to 6f8a66431cb592dad629028a50b3dd418a408c87 PR-URL: https://github.com/nodejs/node/pull/8317 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/parsing/parser.cc')
-rw-r--r--deps/v8/src/parsing/parser.cc4622
1 files changed, 2295 insertions, 2327 deletions
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc
index c9897cdd92..25571470dc 100644
--- a/deps/v8/src/parsing/parser.cc
+++ b/deps/v8/src/parsing/parser.cc
@@ -4,21 +4,19 @@
#include "src/parsing/parser.h"
+#include <memory>
+
#include "src/api.h"
-#include "src/ast/ast.h"
#include "src/ast/ast-expression-rewriter.h"
-#include "src/ast/ast-expression-visitor.h"
#include "src/ast/ast-literal-reindexer.h"
-#include "src/ast/scopeinfo.h"
+#include "src/ast/ast-traversal-visitor.h"
+#include "src/ast/ast.h"
#include "src/bailout-reason.h"
#include "src/base/platform/platform.h"
-#include "src/bootstrapper.h"
#include "src/char-predicates-inl.h"
-#include "src/codegen.h"
-#include "src/compiler.h"
#include "src/messages.h"
#include "src/parsing/parameter-initializer-rewriter.h"
-#include "src/parsing/parser-base.h"
+#include "src/parsing/parse-info.h"
#include "src/parsing/rewriter.h"
#include "src/parsing/scanner-character-streams.h"
#include "src/runtime/runtime.h"
@@ -39,64 +37,6 @@ ScriptData::ScriptData(const byte* data, int length)
}
}
-
-ParseInfo::ParseInfo(Zone* zone)
- : zone_(zone),
- flags_(0),
- source_stream_(nullptr),
- source_stream_encoding_(ScriptCompiler::StreamedSource::ONE_BYTE),
- extension_(nullptr),
- compile_options_(ScriptCompiler::kNoCompileOptions),
- script_scope_(nullptr),
- unicode_cache_(nullptr),
- stack_limit_(0),
- hash_seed_(0),
- 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()));
-}
-
-
-ParseInfo::ParseInfo(Zone* zone, Handle<SharedFunctionInfo> shared)
- : ParseInfo(zone) {
- isolate_ = shared->GetIsolate();
-
- set_lazy();
- set_hash_seed(isolate_->heap()->HashSeed());
- set_stack_limit(isolate_->stack_guard()->real_climit());
- set_unicode_cache(isolate_->unicode_cache());
- set_language_mode(shared->language_mode());
- set_shared_info(shared);
-
- Handle<Script> script(Script::cast(shared->script()));
- set_script(script);
- if (!script.is_null() && script->type() == Script::TYPE_NATIVE) {
- set_native();
- }
-}
-
-
-ParseInfo::ParseInfo(Zone* zone, Handle<Script> script) : ParseInfo(zone) {
- isolate_ = script->GetIsolate();
-
- set_hash_seed(isolate_->heap()->HashSeed());
- set_stack_limit(isolate_->stack_guard()->real_climit());
- set_unicode_cache(isolate_->unicode_cache());
- set_script(script);
-
- if (script->type() == Script::TYPE_NATIVE) {
- set_native();
- }
-}
-
-
FunctionEntry ParseData::GetFunctionEntry(int start) {
// The current pre-data entry must be a FunctionEntry with the given
// start position.
@@ -168,6 +108,35 @@ int ParseData::FunctionsSize() {
return static_cast<int>(Data()[PreparseDataConstants::kFunctionsSizeOffset]);
}
+// Helper for putting parts of the parse results into a temporary zone when
+// parsing inner function bodies.
+class DiscardableZoneScope {
+ public:
+ DiscardableZoneScope(Parser* parser, Zone* temp_zone, bool use_temp_zone)
+ : ast_node_factory_scope_(parser->factory(), temp_zone, use_temp_zone),
+ fni_(parser->ast_value_factory_, temp_zone),
+ parser_(parser),
+ prev_fni_(parser->fni_),
+ prev_zone_(parser->zone_) {
+ if (use_temp_zone) {
+ parser_->fni_ = &fni_;
+ parser_->zone_ = temp_zone;
+ }
+ }
+ ~DiscardableZoneScope() {
+ parser_->fni_ = prev_fni_;
+ parser_->zone_ = prev_zone_;
+ }
+
+ private:
+ AstNodeFactory::BodyScope ast_node_factory_scope_;
+ FuncNameInferrer fni_;
+ Parser* parser_;
+ FuncNameInferrer* prev_fni_;
+ Zone* prev_zone_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiscardableZoneScope);
+};
void Parser::SetCachedData(ParseInfo* info) {
if (compile_options_ == ScriptCompiler::kNoCompileOptions) {
@@ -181,8 +150,8 @@ void Parser::SetCachedData(ParseInfo* info) {
}
FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
- bool call_super, Scope* scope,
- int pos, int end_pos,
+ bool call_super, int pos,
+ int end_pos,
LanguageMode language_mode) {
int materialized_literal_count = -1;
int expected_property_count = -1;
@@ -191,7 +160,7 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor
: FunctionKind::kDefaultBaseConstructor;
- Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind);
+ DeclarationScope* function_scope = NewFunctionScope(kind);
SetLanguageMode(function_scope,
static_cast<LanguageMode>(language_mode | STRICT));
// Set start and end position to the same value
@@ -200,32 +169,40 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
ZoneList<Statement*>* body = NULL;
{
- AstNodeFactory function_factory(ast_value_factory());
- FunctionState function_state(&function_state_, &scope_, function_scope,
- kind, &function_factory);
+ FunctionState function_state(&function_state_, &scope_state_,
+ function_scope, kind);
body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone());
if (call_super) {
// $super_constructor = %_GetSuperConstructor(<this-function>)
- // %reflect_construct($super_constructor, arguments, new.target)
+ // %reflect_construct(
+ // $super_constructor, InternalArray(...args), new.target)
+ auto constructor_args_name = ast_value_factory()->empty_string();
+ bool is_duplicate;
+ bool is_rest = true;
+ bool is_optional = false;
+ Variable* constructor_args = function_scope->DeclareParameter(
+ constructor_args_name, TEMPORARY, is_optional, is_rest, &is_duplicate,
+ ast_value_factory());
+
ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(2, zone());
- VariableProxy* this_function_proxy = scope_->NewUnresolved(
- factory(), ast_value_factory()->this_function_string(),
- Variable::NORMAL, pos);
+ VariableProxy* this_function_proxy =
+ NewUnresolved(ast_value_factory()->this_function_string(), pos);
ZoneList<Expression*>* tmp =
new (zone()) ZoneList<Expression*>(1, zone());
tmp->Add(this_function_proxy, zone());
Expression* super_constructor = factory()->NewCallRuntime(
Runtime::kInlineGetSuperConstructor, tmp, pos);
args->Add(super_constructor, zone());
- VariableProxy* arguments_proxy = scope_->NewUnresolved(
- factory(), ast_value_factory()->arguments_string(), Variable::NORMAL,
- pos);
- args->Add(arguments_proxy, zone());
- VariableProxy* new_target_proxy = scope_->NewUnresolved(
- factory(), ast_value_factory()->new_target_string(), Variable::NORMAL,
- pos);
+ Spread* spread_args = factory()->NewSpread(
+ factory()->NewVariableProxy(constructor_args), pos, pos);
+ ZoneList<Expression*>* spread_args_expr =
+ new (zone()) ZoneList<Expression*>(1, zone());
+ spread_args_expr->Add(spread_args, zone());
+ args->AddAll(*PrepareSpreadArguments(spread_args_expr), zone());
+ VariableProxy* new_target_proxy =
+ NewUnresolved(ast_value_factory()->new_target_string(), pos);
args->Add(new_target_proxy, zone());
CallRuntime* call = factory()->NewCallRuntime(
Context::REFLECT_CONSTRUCT_INDEX, args, pos);
@@ -299,14 +276,20 @@ class TargetScope BASE_EMBEDDED {
// thus it must never be used where only a single statement
// is correct (e.g. an if statement branch w/o braces)!
-#define CHECK_OK ok); \
- if (!*ok) return NULL; \
+#define CHECK_OK ok); \
+ if (!*ok) return nullptr; \
((void)0
#define DUMMY ) // to make indentation work
#undef DUMMY
-#define CHECK_FAILED /**/); \
- if (failed_) return NULL; \
+#define CHECK_OK_VOID ok); \
+ if (!*ok) return; \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
+#define CHECK_FAILED /**/); \
+ if (failed_) return nullptr; \
((void)0
#define DUMMY ) // to make indentation work
#undef DUMMY
@@ -314,77 +297,74 @@ class TargetScope BASE_EMBEDDED {
// ----------------------------------------------------------------------------
// Implementation of Parser
-bool ParserTraits::IsEval(const AstRawString* identifier) const {
- return identifier == parser_->ast_value_factory()->eval_string();
+bool ParserBaseTraits<Parser>::IsEval(const AstRawString* identifier) const {
+ return identifier == delegate()->ast_value_factory()->eval_string();
}
-
-bool ParserTraits::IsArguments(const AstRawString* identifier) const {
- return identifier == parser_->ast_value_factory()->arguments_string();
+bool ParserBaseTraits<Parser>::IsArguments(
+ const AstRawString* identifier) const {
+ return identifier == delegate()->ast_value_factory()->arguments_string();
}
-
-bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const {
+bool ParserBaseTraits<Parser>::IsEvalOrArguments(
+ const AstRawString* identifier) const {
return IsEval(identifier) || IsArguments(identifier);
}
-bool ParserTraits::IsUndefined(const AstRawString* identifier) const {
- return identifier == parser_->ast_value_factory()->undefined_string();
+bool ParserBaseTraits<Parser>::IsUndefined(
+ const AstRawString* identifier) const {
+ return identifier == delegate()->ast_value_factory()->undefined_string();
}
-bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
- return identifier == parser_->ast_value_factory()->prototype_string();
+bool ParserBaseTraits<Parser>::IsPrototype(
+ const AstRawString* identifier) const {
+ return identifier == delegate()->ast_value_factory()->prototype_string();
}
-
-bool ParserTraits::IsConstructor(const AstRawString* identifier) const {
- return identifier == parser_->ast_value_factory()->constructor_string();
+bool ParserBaseTraits<Parser>::IsConstructor(
+ const AstRawString* identifier) const {
+ return identifier == delegate()->ast_value_factory()->constructor_string();
}
-
-bool ParserTraits::IsThisProperty(Expression* expression) {
+bool ParserBaseTraits<Parser>::IsThisProperty(Expression* expression) {
DCHECK(expression != NULL);
Property* property = expression->AsProperty();
return property != NULL && property->obj()->IsVariableProxy() &&
property->obj()->AsVariableProxy()->is_this();
}
-
-bool ParserTraits::IsIdentifier(Expression* expression) {
+bool ParserBaseTraits<Parser>::IsIdentifier(Expression* expression) {
VariableProxy* operand = expression->AsVariableProxy();
return operand != NULL && !operand->is_this();
}
-
-void ParserTraits::PushPropertyName(FuncNameInferrer* fni,
- Expression* expression) {
+void ParserBaseTraits<Parser>::PushPropertyName(FuncNameInferrer* fni,
+ Expression* expression) {
if (expression->IsPropertyName()) {
fni->PushLiteralName(expression->AsLiteral()->AsRawPropertyName());
} else {
fni->PushLiteralName(
- parser_->ast_value_factory()->anonymous_function_string());
+ delegate()->ast_value_factory()->anonymous_function_string());
}
}
-
-void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
- Expression* right) {
+void ParserBaseTraits<Parser>::CheckAssigningFunctionLiteralToProperty(
+ Expression* left, Expression* right) {
DCHECK(left != NULL);
if (left->IsProperty() && right->IsFunctionLiteral()) {
right->AsFunctionLiteral()->set_pretenure();
}
}
-
-Expression* ParserTraits::MarkExpressionAsAssigned(Expression* expression) {
+Expression* ParserBaseTraits<Parser>::MarkExpressionAsAssigned(
+ Expression* expression) {
VariableProxy* proxy =
expression != NULL ? expression->AsVariableProxy() : NULL;
if (proxy != NULL) proxy->set_is_assigned();
return expression;
}
-
-bool ParserTraits::ShortcutNumericLiteralBinaryExpression(
+bool ParserBaseTraits<Parser>::ShortcutNumericLiteralBinaryExpression(
Expression** x, Expression* y, Token::Value op, int pos,
AstNodeFactory* factory) {
if ((*x)->AsLiteral() && (*x)->AsLiteral()->raw_value()->IsNumber() &&
@@ -454,10 +434,8 @@ bool ParserTraits::ShortcutNumericLiteralBinaryExpression(
return false;
}
-
-Expression* ParserTraits::BuildUnaryExpression(Expression* expression,
- Token::Value op, int pos,
- AstNodeFactory* factory) {
+Expression* ParserBaseTraits<Parser>::BuildUnaryExpression(
+ Expression* expression, Token::Value op, int pos, AstNodeFactory* factory) {
DCHECK(expression != NULL);
if (expression->IsLiteral()) {
const AstValue* literal = expression->AsLiteral()->raw_value();
@@ -499,10 +477,11 @@ Expression* ParserTraits::BuildUnaryExpression(Expression* expression,
return factory->NewUnaryOperation(op, expression, pos);
}
-Expression* ParserTraits::BuildIteratorResult(Expression* value, bool done) {
- int pos = RelocInfo::kNoPosition;
- AstNodeFactory* factory = parser_->factory();
- Zone* zone = parser_->zone();
+Expression* ParserBaseTraits<Parser>::BuildIteratorResult(Expression* value,
+ bool done) {
+ int pos = kNoSourcePosition;
+ AstNodeFactory* factory = delegate()->factory();
+ Zone* zone = delegate()->zone();
if (value == nullptr) value = factory->NewUndefinedLiteral(pos);
@@ -514,173 +493,136 @@ Expression* ParserTraits::BuildIteratorResult(Expression* value, bool done) {
pos);
}
-Expression* ParserTraits::NewThrowReferenceError(
+Expression* ParserBaseTraits<Parser>::NewThrowReferenceError(
MessageTemplate::Template message, int pos) {
- return NewThrowError(Runtime::kNewReferenceError, message,
- parser_->ast_value_factory()->empty_string(), pos);
+ return delegate()->NewThrowError(
+ Runtime::kNewReferenceError, message,
+ delegate()->ast_value_factory()->empty_string(), pos);
}
-
-Expression* ParserTraits::NewThrowSyntaxError(MessageTemplate::Template message,
- const AstRawString* arg,
- int pos) {
- return NewThrowError(Runtime::kNewSyntaxError, message, arg, pos);
+Expression* ParserBaseTraits<Parser>::NewThrowSyntaxError(
+ MessageTemplate::Template message, const AstRawString* arg, int pos) {
+ return delegate()->NewThrowError(Runtime::kNewSyntaxError, message, arg, pos);
}
-
-Expression* ParserTraits::NewThrowTypeError(MessageTemplate::Template message,
- const AstRawString* arg, int pos) {
- return NewThrowError(Runtime::kNewTypeError, message, arg, pos);
+Expression* ParserBaseTraits<Parser>::NewThrowTypeError(
+ MessageTemplate::Template message, const AstRawString* arg, int pos) {
+ return delegate()->NewThrowError(Runtime::kNewTypeError, message, arg, pos);
}
-
-Expression* ParserTraits::NewThrowError(Runtime::FunctionId id,
- MessageTemplate::Template message,
- const AstRawString* arg, int pos) {
- Zone* zone = parser_->zone();
- ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone);
- args->Add(parser_->factory()->NewSmiLiteral(message, pos), zone);
- args->Add(parser_->factory()->NewStringLiteral(arg, pos), zone);
- CallRuntime* call_constructor =
- parser_->factory()->NewCallRuntime(id, args, pos);
- return parser_->factory()->NewThrow(call_constructor, pos);
+Expression* Parser::NewThrowError(Runtime::FunctionId id,
+ MessageTemplate::Template message,
+ const AstRawString* arg, int pos) {
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
+ args->Add(factory()->NewSmiLiteral(message, pos), zone());
+ args->Add(factory()->NewStringLiteral(arg, pos), zone());
+ CallRuntime* call_constructor = factory()->NewCallRuntime(id, args, pos);
+ return factory()->NewThrow(call_constructor, pos);
}
-
-void ParserTraits::ReportMessageAt(Scanner::Location source_location,
- MessageTemplate::Template message,
- const char* arg, ParseErrorType error_type) {
- if (parser_->stack_overflow()) {
+void ParserBaseTraits<Parser>::ReportMessageAt(
+ Scanner::Location source_location, MessageTemplate::Template message,
+ const char* arg, ParseErrorType error_type) {
+ if (delegate()->stack_overflow()) {
// Suppress the error message (syntax error or such) in the presence of a
// stack overflow. The isolate allows only one pending exception at at time
// and we want to report the stack overflow later.
return;
}
- parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
- source_location.end_pos,
- message, arg, error_type);
-}
-
-
-void ParserTraits::ReportMessage(MessageTemplate::Template message,
- const char* arg, ParseErrorType error_type) {
- Scanner::Location source_location = parser_->scanner()->location();
- ReportMessageAt(source_location, message, arg, error_type);
-}
-
-
-void ParserTraits::ReportMessage(MessageTemplate::Template message,
- const AstRawString* arg,
- ParseErrorType error_type) {
- Scanner::Location source_location = parser_->scanner()->location();
- ReportMessageAt(source_location, message, arg, error_type);
+ delegate()->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
+ source_location.end_pos,
+ message, arg, error_type);
}
-
-void ParserTraits::ReportMessageAt(Scanner::Location source_location,
- MessageTemplate::Template message,
- const AstRawString* arg,
- ParseErrorType error_type) {
- if (parser_->stack_overflow()) {
+void ParserBaseTraits<Parser>::ReportMessageAt(
+ Scanner::Location source_location, MessageTemplate::Template message,
+ const AstRawString* arg, ParseErrorType error_type) {
+ if (delegate()->stack_overflow()) {
// Suppress the error message (syntax error or such) in the presence of a
// stack overflow. The isolate allows only one pending exception at at time
// and we want to report the stack overflow later.
return;
}
- parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
- source_location.end_pos,
- message, arg, error_type);
+ delegate()->pending_error_handler_.ReportMessageAt(source_location.beg_pos,
+ source_location.end_pos,
+ message, arg, error_type);
}
-
-const AstRawString* ParserTraits::GetSymbol(Scanner* scanner) {
+const AstRawString* ParserBaseTraits<Parser>::GetSymbol(
+ Scanner* scanner) const {
const AstRawString* result =
- parser_->scanner()->CurrentSymbol(parser_->ast_value_factory());
+ delegate()->scanner()->CurrentSymbol(delegate()->ast_value_factory());
DCHECK(result != NULL);
return result;
}
-
-const AstRawString* ParserTraits::GetNumberAsSymbol(Scanner* scanner) {
- double double_value = parser_->scanner()->DoubleValue();
+const AstRawString* ParserBaseTraits<Parser>::GetNumberAsSymbol(
+ Scanner* scanner) const {
+ double double_value = delegate()->scanner()->DoubleValue();
char array[100];
- const char* string =
- DoubleToCString(double_value, Vector<char>(array, arraysize(array)));
- return parser_->ast_value_factory()->GetOneByteString(string);
+ const char* string = DoubleToCString(double_value, ArrayVector(array));
+ return delegate()->ast_value_factory()->GetOneByteString(string);
}
-
-const AstRawString* ParserTraits::GetNextSymbol(Scanner* scanner) {
- return parser_->scanner()->NextSymbol(parser_->ast_value_factory());
+const AstRawString* ParserBaseTraits<Parser>::GetNextSymbol(
+ Scanner* scanner) const {
+ return delegate()->scanner()->NextSymbol(delegate()->ast_value_factory());
}
-
-Expression* ParserTraits::ThisExpression(Scope* scope, AstNodeFactory* factory,
- int pos) {
- return scope->NewUnresolved(factory,
- parser_->ast_value_factory()->this_string(),
- Variable::THIS, pos, pos + 4);
+Expression* ParserBaseTraits<Parser>::ThisExpression(int pos) {
+ return delegate()->NewUnresolved(
+ delegate()->ast_value_factory()->this_string(), pos, pos + 4,
+ Variable::THIS);
}
-
-Expression* ParserTraits::SuperPropertyReference(Scope* scope,
- AstNodeFactory* factory,
- int pos) {
+Expression* ParserBaseTraits<Parser>::NewSuperPropertyReference(
+ AstNodeFactory* factory, int pos) {
// this_function[home_object_symbol]
- VariableProxy* this_function_proxy = scope->NewUnresolved(
- factory, parser_->ast_value_factory()->this_function_string(),
- Variable::NORMAL, pos);
+ VariableProxy* this_function_proxy = delegate()->NewUnresolved(
+ delegate()->ast_value_factory()->this_function_string(), pos);
Expression* home_object_symbol_literal =
- factory->NewSymbolLiteral("home_object_symbol", RelocInfo::kNoPosition);
+ factory->NewSymbolLiteral("home_object_symbol", kNoSourcePosition);
Expression* home_object = factory->NewProperty(
this_function_proxy, home_object_symbol_literal, pos);
return factory->NewSuperPropertyReference(
- ThisExpression(scope, factory, pos)->AsVariableProxy(), home_object, pos);
+ ThisExpression(pos)->AsVariableProxy(), home_object, pos);
}
-
-Expression* ParserTraits::SuperCallReference(Scope* scope,
- AstNodeFactory* factory, int pos) {
- VariableProxy* new_target_proxy = scope->NewUnresolved(
- factory, parser_->ast_value_factory()->new_target_string(),
- Variable::NORMAL, pos);
- VariableProxy* this_function_proxy = scope->NewUnresolved(
- factory, parser_->ast_value_factory()->this_function_string(),
- Variable::NORMAL, pos);
- return factory->NewSuperCallReference(
- ThisExpression(scope, factory, pos)->AsVariableProxy(), new_target_proxy,
- this_function_proxy, pos);
+Expression* ParserBaseTraits<Parser>::NewSuperCallReference(
+ AstNodeFactory* factory, int pos) {
+ VariableProxy* new_target_proxy = delegate()->NewUnresolved(
+ delegate()->ast_value_factory()->new_target_string(), pos);
+ VariableProxy* this_function_proxy = delegate()->NewUnresolved(
+ delegate()->ast_value_factory()->this_function_string(), pos);
+ return factory->NewSuperCallReference(ThisExpression(pos)->AsVariableProxy(),
+ new_target_proxy, this_function_proxy,
+ pos);
}
-
-Expression* ParserTraits::NewTargetExpression(Scope* scope,
- AstNodeFactory* factory,
- int pos) {
+Expression* ParserBaseTraits<Parser>::NewTargetExpression(int pos) {
static const int kNewTargetStringLength = 10;
- auto proxy = scope->NewUnresolved(
- factory, parser_->ast_value_factory()->new_target_string(),
- Variable::NORMAL, pos, pos + kNewTargetStringLength);
+ auto proxy = delegate()->NewUnresolved(
+ delegate()->ast_value_factory()->new_target_string(), pos,
+ pos + kNewTargetStringLength);
proxy->set_is_new_target();
return proxy;
}
-
-Expression* ParserTraits::FunctionSentExpression(Scope* scope,
- AstNodeFactory* factory,
- int pos) {
- // We desugar function.sent into %GeneratorGetInput(generator).
- Zone* zone = parser_->zone();
+Expression* ParserBaseTraits<Parser>::FunctionSentExpression(
+ AstNodeFactory* factory, int pos) const {
+ // We desugar function.sent into %_GeneratorGetInputOrDebugPos(generator).
+ Zone* zone = delegate()->zone();
ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(1, zone);
VariableProxy* generator = factory->NewVariableProxy(
- parser_->function_state_->generator_object_variable());
+ delegate()->function_state_->generator_object_variable());
args->Add(generator, zone);
- return factory->NewCallRuntime(Runtime::kGeneratorGetInput, args, pos);
+ return factory->NewCallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos,
+ args, pos);
}
-
-Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
- Scanner* scanner,
- AstNodeFactory* factory) {
+Literal* ParserBaseTraits<Parser>::ExpressionFromLiteral(
+ Token::Value token, int pos, Scanner* scanner,
+ AstNodeFactory* factory) const {
switch (token) {
case Token::NULL_LITERAL:
return factory->NewNullLiteral(pos);
@@ -703,75 +645,46 @@ Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
return NULL;
}
-
-Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
- int start_position,
- int end_position,
- Scope* scope,
- AstNodeFactory* factory) {
- if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
- return scope->NewUnresolved(factory, name, Variable::NORMAL, start_position,
- end_position);
+Expression* ParserBaseTraits<Parser>::ExpressionFromIdentifier(
+ const AstRawString* name, int start_position, int end_position,
+ InferName infer) {
+ if (infer == InferName::kYes && delegate()->fni_ != NULL) {
+ delegate()->fni_->PushVariableName(name);
+ }
+ return delegate()->NewUnresolved(name, start_position, end_position);
}
-
-Expression* ParserTraits::ExpressionFromString(int pos, Scanner* scanner,
- AstNodeFactory* factory) {
+Expression* ParserBaseTraits<Parser>::ExpressionFromString(
+ int pos, Scanner* scanner, AstNodeFactory* factory) const {
const AstRawString* symbol = GetSymbol(scanner);
- if (parser_->fni_ != NULL) parser_->fni_->PushLiteralName(symbol);
+ if (delegate()->fni_ != NULL) delegate()->fni_->PushLiteralName(symbol);
return factory->NewStringLiteral(symbol, pos);
}
-
-Expression* ParserTraits::GetIterator(Expression* iterable,
- AstNodeFactory* factory, int pos) {
+Expression* ParserBaseTraits<Parser>::GetIterator(Expression* iterable,
+ AstNodeFactory* factory,
+ int pos) {
Expression* iterator_symbol_literal =
- factory->NewSymbolLiteral("iterator_symbol", RelocInfo::kNoPosition);
+ factory->NewSymbolLiteral("iterator_symbol", kNoSourcePosition);
Expression* prop =
factory->NewProperty(iterable, iterator_symbol_literal, pos);
- Zone* zone = parser_->zone();
+ Zone* zone = delegate()->zone();
ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(0, zone);
return factory->NewCall(prop, args, pos);
}
-
-Literal* ParserTraits::GetLiteralTheHole(int position,
- AstNodeFactory* factory) {
- return factory->NewTheHoleLiteral(RelocInfo::kNoPosition);
-}
-
-
-Expression* ParserTraits::ParseV8Intrinsic(bool* ok) {
- return parser_->ParseV8Intrinsic(ok);
-}
-
-
-FunctionLiteral* ParserTraits::ParseFunctionLiteral(
- const AstRawString* name, Scanner::Location function_name_location,
- FunctionNameValidity function_name_validity, FunctionKind kind,
- int function_token_position, FunctionLiteral::FunctionType type,
- LanguageMode language_mode, bool* ok) {
- return parser_->ParseFunctionLiteral(
- name, function_name_location, function_name_validity, kind,
- function_token_position, type, language_mode, ok);
+Literal* ParserBaseTraits<Parser>::GetLiteralTheHole(
+ int position, AstNodeFactory* factory) const {
+ return factory->NewTheHoleLiteral(kNoSourcePosition);
}
-ClassLiteral* ParserTraits::ParseClassLiteral(
- Type::ExpressionClassifier* classifier, const AstRawString* name,
- Scanner::Location class_name_location, bool name_is_strict_reserved,
- int pos, bool* ok) {
- return parser_->ParseClassLiteral(classifier, name, class_name_location,
- name_is_strict_reserved, pos, ok);
-}
-
-void ParserTraits::MarkTailPosition(Expression* expression) {
+void Parser::MarkTailPosition(Expression* expression) {
expression->MarkTail();
}
Parser::Parser(ParseInfo* info)
- : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(),
- info->extension(), info->ast_value_factory(),
- NULL, this),
+ : ParserBase<Parser>(info->zone(), &scanner_, info->stack_limit(),
+ info->extension(), info->ast_value_factory(), NULL),
scanner_(info->unicode_cache()),
reusable_preparser_(NULL),
original_scope_(NULL),
@@ -784,21 +697,20 @@ Parser::Parser(ParseInfo* info)
// Even though we were passed ParseInfo, we should not store it in
// Parser - this makes sure that Isolate is not accidentally accessed via
// ParseInfo during background parsing.
- DCHECK(!info->script().is_null() || info->source_stream() != NULL);
+ DCHECK(!info->script().is_null() || info->source_stream() != nullptr ||
+ info->character_stream() != nullptr);
set_allow_lazy(info->allow_lazy_parsing());
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_function_name(FLAG_harmony_function_name);
+ set_allow_harmony_for_in(FLAG_harmony_for_in);
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);
+ set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators);
+ set_allow_harmony_trailing_commas(FLAG_harmony_trailing_commas);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@@ -808,10 +720,38 @@ Parser::Parser(ParseInfo* info)
info->set_ast_value_factory(new AstValueFactory(zone(), info->hash_seed()));
info->set_ast_value_factory_owned();
ast_value_factory_ = info->ast_value_factory();
+ ast_node_factory_.set_ast_value_factory(ast_value_factory_);
+ }
+}
+
+void Parser::DeserializeScopeChain(
+ ParseInfo* info, Handle<Context> context,
+ Scope::DeserializationMode deserialization_mode) {
+ DCHECK(ThreadId::Current().Equals(info->isolate()->thread_id()));
+ // TODO(wingo): Add an outer SCRIPT_SCOPE corresponding to the native
+ // context, which will have the "this" binding for script scopes.
+ DeclarationScope* script_scope = NewScriptScope();
+ info->set_script_scope(script_scope);
+ Scope* scope = script_scope;
+ if (!context.is_null() && !context->IsNativeContext()) {
+ scope = Scope::DeserializeScopeChain(info->isolate(), zone(), *context,
+ script_scope, ast_value_factory(),
+ deserialization_mode);
+ if (info->context().is_null()) {
+ DCHECK(deserialization_mode ==
+ Scope::DeserializationMode::kDeserializeOffHeap);
+ } else {
+ // The Scope is backed up by ScopeInfo (which is in the V8 heap); this
+ // means the Parser cannot operate independent of the V8 heap. Tell the
+ // string table to internalize strings and values right after they're
+ // created. This kind of parsing can only be done in the main thread.
+ DCHECK(parsing_on_main_thread_);
+ ast_value_factory()->Internalize(info->isolate());
+ }
}
+ original_scope_ = scope;
}
-
FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
// TODO(bmeurer): We temporarily need to pass allow_nesting = true here,
// see comment for HistogramTimerScope class.
@@ -821,7 +761,9 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
DCHECK(parsing_on_main_thread_);
HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
- TRACE_EVENT0("v8", "V8.Parse");
+ RuntimeCallTimerScope runtime_timer(isolate, &RuntimeCallStats::Parse);
+ TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED(
+ isolate, &tracing::TraceEventStatsTable::Parse);
Handle<String> source(String::cast(info->script()->source()));
isolate->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
@@ -839,20 +781,25 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
cached_parse_data_->Initialize();
}
+ DeserializeScopeChain(info, info->context(),
+ Scope::DeserializationMode::kKeepScopeInfo);
+
source = String::Flatten(source);
FunctionLiteral* result;
- if (source->IsExternalTwoByteString()) {
- // Notice that the stream is destroyed at the end of the branch block.
- // The last line of the blocks can't be moved outside, even though they're
- // identical calls.
- ExternalTwoByteStringUtf16CharacterStream stream(
- Handle<ExternalTwoByteString>::cast(source), 0, source->length());
- scanner_.Initialize(&stream);
- result = DoParseProgram(info);
- } else {
- GenericStringUtf16CharacterStream stream(source, 0, source->length());
- scanner_.Initialize(&stream);
+ {
+ std::unique_ptr<Utf16CharacterStream> stream;
+ if (source->IsExternalTwoByteString()) {
+ stream.reset(new ExternalTwoByteStringUtf16CharacterStream(
+ Handle<ExternalTwoByteString>::cast(source), 0, source->length()));
+ } else if (source->IsExternalOneByteString()) {
+ stream.reset(new ExternalOneByteStringUtf16CharacterStream(
+ Handle<ExternalOneByteString>::cast(source), 0, source->length()));
+ } else {
+ stream.reset(
+ new GenericStringUtf16CharacterStream(source, 0, source->length()));
+ }
+ scanner_.Initialize(stream.get());
result = DoParseProgram(info);
}
if (result != NULL) {
@@ -866,7 +813,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
PrintF("[parsing eval");
} else if (info->script()->name()->IsString()) {
String* name = String::cast(info->script()->name());
- base::SmartArrayPointer<char> name_chars = name->ToCString();
+ std::unique_ptr<char[]> name_chars = name->ToCString();
PrintF("[parsing script: %s", name_chars.get());
} else {
PrintF("[parsing script");
@@ -885,55 +832,54 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
// Note that this function can be called from the main thread or from a
// background thread. We should not access anything Isolate / heap dependent
// via ParseInfo, and also not pass it forward.
- DCHECK(scope_ == NULL);
- DCHECK(target_stack_ == NULL);
+ DCHECK_NULL(scope_state_);
+ DCHECK_NULL(target_stack_);
Mode parsing_mode = FLAG_lazy && allow_lazy() ? PARSE_LAZILY : PARSE_EAGERLY;
if (allow_natives() || extension_ != NULL) parsing_mode = PARSE_EAGERLY;
FunctionLiteral* result = NULL;
{
- // TODO(wingo): Add an outer SCRIPT_SCOPE corresponding to the native
- // context, which will have the "this" binding for script scopes.
- Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
- info->set_script_scope(scope);
- if (!info->context().is_null() && !info->context()->IsNativeContext()) {
- scope = Scope::DeserializeScopeChain(info->isolate(), zone(),
- *info->context(), scope);
- // The Scope is backed up by ScopeInfo (which is in the V8 heap); this
- // means the Parser cannot operate independent of the V8 heap. Tell the
- // string table to internalize strings and values right after they're
- // created. This kind of parsing can only be done in the main thread.
- DCHECK(parsing_on_main_thread_);
- ast_value_factory()->Internalize(info->isolate());
+ Scope* outer = original_scope_;
+ // If there's a chance that there's a reference to global 'this', predeclare
+ // it as a dynamic global on the script scope.
+ if (outer->GetReceiverScope()->is_script_scope()) {
+ info->script_scope()->DeclareDynamicGlobal(
+ ast_value_factory()->this_string(), Variable::THIS);
}
- original_scope_ = scope;
+ DCHECK(outer);
if (info->is_eval()) {
- if (!scope->is_script_scope() || is_strict(info->language_mode())) {
+ if (!outer->is_script_scope() || is_strict(info->language_mode())) {
parsing_mode = PARSE_EAGERLY;
}
- scope = NewScope(scope, EVAL_SCOPE);
+ outer = NewEvalScope(outer);
} else if (info->is_module()) {
- scope = NewScope(scope, MODULE_SCOPE);
+ DCHECK_EQ(outer, info->script_scope());
+ outer = NewModuleScope(info->script_scope());
}
+ DeclarationScope* scope = outer->AsDeclarationScope();
+
scope->set_start_position(0);
// Enter 'scope' with the given parsing mode.
ParsingModeScope parsing_mode_scope(this, parsing_mode);
- AstNodeFactory function_factory(ast_value_factory());
- FunctionState function_state(&function_state_, &scope_, scope,
- kNormalFunction, &function_factory);
+ FunctionState function_state(&function_state_, &scope_state_, scope,
+ kNormalFunction);
- // 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);
+ ok = ok &&
+ module()->Validate(this->scope()->AsModuleScope(),
+ &pending_error_handler_, zone());
} else {
+ // Don't count the mode in the use counters--give the program a chance
+ // to enable script-wide strict mode below.
+ this->scope()->SetLanguageMode(info->language_mode());
ParseStatementList(body, Token::EOS, &ok);
}
@@ -943,16 +889,18 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
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
// unchanged if the property already exists.
- InsertSloppyBlockFunctionVarBindings(scope, &ok);
+ InsertSloppyBlockFunctionVarBindings(scope, nullptr, &ok);
}
if (ok) {
- CheckConflictingVarDeclarations(scope_, &ok);
+ CheckConflictingVarDeclarations(scope, &ok);
}
if (ok && info->parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
@@ -966,9 +914,9 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
}
if (ok) {
- ParserTraits::RewriteDestructuringAssignments();
+ RewriteDestructuringAssignments();
result = factory()->NewScriptOrEvalFunctionLiteral(
- scope_, body, function_state.materialized_literal_count(),
+ scope, body, function_state.materialized_literal_count(),
function_state.expected_property_count());
}
}
@@ -984,8 +932,10 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) {
// 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");
+ TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED(
+ isolate, &tracing::TraceEventStatsTable::ParseLazy);
Handle<String> source(String::cast(info->script()->source()));
isolate->counters()->total_parse_size()->Increment(source->length());
base::ElapsedTimer timer;
@@ -993,100 +943,115 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) {
timer.Start();
}
Handle<SharedFunctionInfo> shared_info = info->shared_info();
+ DeserializeScopeChain(info, info->context(),
+ Scope::DeserializationMode::kKeepScopeInfo);
// Initialize parser state.
source = String::Flatten(source);
FunctionLiteral* result;
- if (source->IsExternalTwoByteString()) {
- ExternalTwoByteStringUtf16CharacterStream stream(
- Handle<ExternalTwoByteString>::cast(source),
- shared_info->start_position(),
- shared_info->end_position());
- result = ParseLazy(isolate, info, &stream);
- } else {
- GenericStringUtf16CharacterStream stream(source,
- shared_info->start_position(),
- shared_info->end_position());
- result = ParseLazy(isolate, info, &stream);
+ {
+ std::unique_ptr<Utf16CharacterStream> stream;
+ if (source->IsExternalTwoByteString()) {
+ stream.reset(new ExternalTwoByteStringUtf16CharacterStream(
+ Handle<ExternalTwoByteString>::cast(source),
+ shared_info->start_position(), shared_info->end_position()));
+ } else if (source->IsExternalOneByteString()) {
+ stream.reset(new ExternalOneByteStringUtf16CharacterStream(
+ Handle<ExternalOneByteString>::cast(source),
+ shared_info->start_position(), shared_info->end_position()));
+ } else {
+ stream.reset(new GenericStringUtf16CharacterStream(
+ source, shared_info->start_position(), shared_info->end_position()));
+ }
+ Handle<String> name(String::cast(shared_info->name()));
+ result =
+ DoParseLazy(info, ast_value_factory()->GetString(name), stream.get());
+ if (result != nullptr) {
+ Handle<String> inferred_name(shared_info->inferred_name());
+ result->set_inferred_name(inferred_name);
+ }
}
if (FLAG_trace_parse && result != NULL) {
double ms = timer.Elapsed().InMillisecondsF();
- base::SmartArrayPointer<char> name_chars =
- result->debug_name()->ToCString();
+ std::unique_ptr<char[]> name_chars = result->debug_name()->ToCString();
PrintF("[parsing function: %s - took %0.3f ms]\n", name_chars.get(), ms);
}
return result;
}
-static FunctionLiteral::FunctionType ComputeFunctionType(
- Handle<SharedFunctionInfo> shared_info) {
- if (shared_info->is_declaration()) {
+static FunctionLiteral::FunctionType ComputeFunctionType(ParseInfo* info) {
+ if (info->is_declaration()) {
return FunctionLiteral::kDeclaration;
- } else if (shared_info->is_named_expression()) {
+ } else if (info->is_named_expression()) {
return FunctionLiteral::kNamedExpression;
- } else if (IsConciseMethod(shared_info->kind()) ||
- IsAccessorFunction(shared_info->kind())) {
+ } else if (IsConciseMethod(info->function_kind()) ||
+ IsAccessorFunction(info->function_kind())) {
return FunctionLiteral::kAccessorOrMethod;
}
return FunctionLiteral::kAnonymousExpression;
}
-FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
- Utf16CharacterStream* source) {
- Handle<SharedFunctionInfo> shared_info = info->shared_info();
+FunctionLiteral* Parser::DoParseLazy(ParseInfo* info,
+ const AstRawString* raw_name,
+ Utf16CharacterStream* source) {
scanner_.Initialize(source);
- DCHECK(scope_ == NULL);
- DCHECK(target_stack_ == NULL);
+ DCHECK_NULL(scope_state_);
+ DCHECK_NULL(target_stack_);
- Handle<String> name(String::cast(shared_info->name()));
DCHECK(ast_value_factory());
fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
- const AstRawString* raw_name = ast_value_factory()->GetString(name);
fni_->PushEnclosingName(raw_name);
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
// Place holder for the result.
- FunctionLiteral* result = NULL;
+ FunctionLiteral* result = nullptr;
{
// Parse the function literal.
- Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
- info->set_script_scope(scope);
- if (!info->closure().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 = original_scope_;
+ DCHECK(scope);
+ // If there's a chance that there's a reference to global 'this', predeclare
+ // it as a dynamic global on the script scope.
+ if (info->is_arrow() && scope->GetReceiverScope()->is_script_scope()) {
+ info->script_scope()->DeclareDynamicGlobal(
+ ast_value_factory()->this_string(), Variable::THIS);
}
- original_scope_ = scope;
- AstNodeFactory function_factory(ast_value_factory());
- FunctionState function_state(&function_state_, &scope_, scope,
- shared_info->kind(), &function_factory);
+ FunctionState function_state(&function_state_, &scope_state_, scope,
+ info->function_kind());
DCHECK(is_sloppy(scope->language_mode()) ||
is_strict(info->language_mode()));
- DCHECK(info->language_mode() == shared_info->language_mode());
- FunctionLiteral::FunctionType function_type =
- ComputeFunctionType(shared_info);
+ FunctionLiteral::FunctionType function_type = ComputeFunctionType(info);
bool ok = true;
- if (shared_info->is_arrow()) {
+ if (info->is_arrow()) {
+ bool is_async = allow_harmony_async_await() && info->is_async();
+ if (is_async) {
+ DCHECK(!scanner()->HasAnyLineTerminatorAfterNext());
+ if (!Check(Token::ASYNC)) {
+ CHECK(stack_overflow());
+ return nullptr;
+ }
+ if (!(peek_any_identifier() || peek() == Token::LPAREN)) {
+ CHECK(stack_overflow());
+ return nullptr;
+ }
+ }
+
// TODO(adamk): We should construct this scope from the ScopeInfo.
- Scope* scope =
- NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
+ DeclarationScope* scope = NewFunctionScope(FunctionKind::kArrowFunction);
// These two bits only need to be explicitly set because we're
// not passing the ScopeInfo to the Scope constructor.
// TODO(adamk): Remove these calls once the above NewScope call
// passes the ScopeInfo.
- if (shared_info->scope_info()->CallsEval()) {
+ if (info->calls_eval()) {
scope->RecordEvalCall();
}
- SetLanguageMode(scope, shared_info->language_mode());
+ SetLanguageMode(scope, info->language_mode());
- scope->set_start_position(shared_info->start_position());
+ scope->set_start_position(info->start_position());
ExpressionClassifier formals_classifier(this);
ParserFormalParameters formals(scope);
Checkpoint checkpoint(this);
@@ -1094,7 +1059,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
// Parsing patterns as variable reference expression creates
// NewUnresolved references in current scope. Entrer arrow function
// scope for formal parameter parsing.
- BlockState block_state(&scope_, scope);
+ BlockState block_state(&scope_state_, scope);
if (Check(Token::LPAREN)) {
// '(' StrictFormalParameters ')'
ParseFormalParameterList(&formals, &formals_classifier, &ok);
@@ -1113,8 +1078,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
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
@@ -1122,7 +1087,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
// concise body happens to be a valid expression. This is a problem
// only for arrow functions with single expression bodies, since there
// is no end token such as "}" for normal functions.
- if (scanner()->location().end_pos == shared_info->end_position()) {
+ if (scanner()->location().end_pos == info->end_position()) {
// The pre-parser saw an arrow function here, so the full parser
// must produce a FunctionLiteral.
DCHECK(expression->IsFunctionLiteral());
@@ -1132,34 +1097,29 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
}
}
}
- } else if (shared_info->is_default_constructor()) {
+ } else if (info->is_default_constructor()) {
+ DCHECK_EQ(this->scope(), scope);
result = DefaultConstructor(
- raw_name, IsSubclassConstructor(shared_info->kind()), scope,
- shared_info->start_position(), shared_info->end_position(),
- shared_info->language_mode());
+ raw_name, IsSubclassConstructor(info->function_kind()),
+ info->start_position(), info->end_position(), info->language_mode());
} else {
result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
- kSkipFunctionNameCheck, shared_info->kind(),
- RelocInfo::kNoPosition, function_type,
- shared_info->language_mode(), &ok);
+ kSkipFunctionNameCheck,
+ info->function_kind(), kNoSourcePosition,
+ function_type, info->language_mode(), &ok);
}
// Make sure the results agree.
- DCHECK(ok == (result != NULL));
+ DCHECK(ok == (result != nullptr));
}
// Make sure the target stack is empty.
- DCHECK(target_stack_ == NULL);
-
- if (result != NULL) {
- Handle<String> inferred_name(shared_info->inferred_name());
- result->set_inferred_name(inferred_name);
- }
+ DCHECK_NULL(target_stack_);
return result;
}
-void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
- bool* ok) {
+void Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
+ bool* ok) {
// StatementList ::
// (StatementListItem)* <end_token>
@@ -1178,7 +1138,7 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
}
Scanner::Location token_loc = scanner()->peek_location();
- Statement* stat = ParseStatementListItem(CHECK_OK);
+ Statement* stat = ParseStatementListItem(CHECK_OK_VOID);
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
@@ -1199,26 +1159,26 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
token_loc.end_pos - token_loc.beg_pos ==
ast_value_factory()->use_strict_string()->length() + 2;
if (use_strict_found) {
- if (is_sloppy(scope_->language_mode())) {
+ if (is_sloppy(language_mode())) {
RaiseLanguageMode(STRICT);
}
- if (!scope_->HasSimpleParameters()) {
+ if (!this->scope()->HasSimpleParameters()) {
// TC39 deemed "use strict" directives to be an error when occurring
// in the body of a function with non-simple parameter list, on
// 29/7/2015. https://goo.gl/ueA7Ln
const AstRawString* string = literal->raw_value()->AsString();
- ParserTraits::ReportMessageAt(
- token_loc, MessageTemplate::kIllegalLanguageModeDirective,
- string);
+ ReportMessageAt(token_loc,
+ MessageTemplate::kIllegalLanguageModeDirective,
+ string);
*ok = false;
- return nullptr;
+ return;
}
// Because declarations in strict eval code don't leak into the scope
// of the eval call, it is likely that functions declared in strict
// eval code will be used within the eval code, so lazy parsing is
// probably not a win.
- if (scope_->is_eval_scope()) mode_ = PARSE_EAGERLY;
+ if (this->scope()->is_eval_scope()) mode_ = PARSE_EAGERLY;
} else if (literal->raw_value()->AsString() ==
ast_value_factory()->use_asm_string() &&
token_loc.end_pos - token_loc.beg_pos ==
@@ -1226,7 +1186,8 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
// Store the usage count; The actual use counter on the isolate is
// incremented after parsing is done.
++use_counts_[v8::Isolate::kUseAsm];
- scope_->SetAsmModule();
+ DCHECK(this->scope()->is_declaration_scope());
+ this->scope()->AsDeclarationScope()->set_asm_module();
} else {
// Should not change mode, but will increment UseCounter
// if appropriate. Ditto usages below.
@@ -1243,8 +1204,6 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
body->Add(stat, zone());
}
-
- return 0;
}
@@ -1253,18 +1212,15 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
// StatementListItem:
// Statement
// Declaration
-
- switch (peek()) {
+ const Token::Value peeked = peek();
+ switch (peeked) {
case Token::FUNCTION:
- return ParseFunctionDeclaration(NULL, ok);
+ return ParseHoistableDeclaration(NULL, false, ok);
case Token::CLASS:
Consume(Token::CLASS);
- return ParseClassDeclaration(NULL, ok);
+ return ParseClassDeclaration(NULL, false, 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 +1228,13 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
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, false, ok);
+ }
+ /* falls through */
default:
break;
}
@@ -1280,7 +1243,7 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
Statement* Parser::ParseModuleItem(bool* ok) {
- // (Ecma 262 6th Edition, 15.2):
+ // ecma262/#prod-ModuleItem
// ModuleItem :
// ImportDeclaration
// ExportDeclaration
@@ -1288,7 +1251,8 @@ Statement* Parser::ParseModuleItem(bool* ok) {
switch (peek()) {
case Token::IMPORT:
- return ParseImportDeclaration(ok);
+ ParseImportDeclaration(CHECK_OK);
+ return factory()->NewEmptyStatement(kNoSourcePosition);
case Token::EXPORT:
return ParseExportDeclaration(ok);
default:
@@ -1297,40 +1261,22 @@ Statement* Parser::ParseModuleItem(bool* ok) {
}
-void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
- // (Ecma 262 6th Edition, 15.2):
+void Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
+ // ecma262/#prod-Module
// Module :
// ModuleBody?
//
+ // ecma262/#prod-ModuleItemList
// ModuleBody :
// ModuleItem*
- DCHECK(scope_->is_module_scope());
- RaiseLanguageMode(STRICT);
-
+ DCHECK(scope()->is_module_scope());
while (peek() != Token::EOS) {
- Statement* stat = ParseModuleItem(CHECK_OK);
+ Statement* stat = ParseModuleItem(CHECK_OK_VOID);
if (stat && !stat->IsEmpty()) {
body->Add(stat, zone());
}
}
-
- // Check that all exports are bound.
- ModuleDescriptor* descriptor = scope_->module();
- for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
- it.Advance()) {
- if (scope_->LookupLocal(it.local_name()) == NULL) {
- // TODO(adamk): Pass both local_name and export_name once ParserTraits
- // supports multiple arg error messages.
- // Also try to report this at a better location.
- ParserTraits::ReportMessage(MessageTemplate::kModuleExportUndefined,
- it.local_name());
- *ok = false;
- return NULL;
- }
- }
-
- return NULL;
}
@@ -1343,10 +1289,10 @@ const AstRawString* Parser::ParseModuleSpecifier(bool* ok) {
}
-void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
- ZoneList<Scanner::Location>* export_locations,
- ZoneList<const AstRawString*>* local_names,
- Scanner::Location* reserved_loc, bool* ok) {
+void Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
+ ZoneList<Scanner::Location>* export_locations,
+ ZoneList<const AstRawString*>* local_names,
+ Scanner::Location* reserved_loc, bool* ok) {
// ExportClause :
// '{' '}'
// '{' ExportsList '}'
@@ -1360,20 +1306,20 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
// IdentifierName
// IdentifierName 'as' IdentifierName
- Expect(Token::LBRACE, CHECK_OK);
+ Expect(Token::LBRACE, CHECK_OK_VOID);
Token::Value name_tok;
while ((name_tok = peek()) != Token::RBRACE) {
// Keep track of the first reserved word encountered in case our
// caller needs to report an error.
if (!reserved_loc->IsValid() &&
- !Token::IsIdentifier(name_tok, STRICT, false)) {
+ !Token::IsIdentifier(name_tok, STRICT, false, parsing_module_)) {
*reserved_loc = scanner()->location();
}
- const AstRawString* local_name = ParseIdentifierName(CHECK_OK);
+ const AstRawString* local_name = ParseIdentifierName(CHECK_OK_VOID);
const AstRawString* export_name = NULL;
if (CheckContextualKeyword(CStrVector("as"))) {
- export_name = ParseIdentifierName(CHECK_OK);
+ export_name = ParseIdentifierName(CHECK_OK_VOID);
}
if (export_name == NULL) {
export_name = local_name;
@@ -1382,16 +1328,15 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
local_names->Add(local_name, zone());
export_locations->Add(scanner()->location(), zone());
if (peek() == Token::RBRACE) break;
- Expect(Token::COMMA, CHECK_OK);
+ Expect(Token::COMMA, CHECK_OK_VOID);
}
- Expect(Token::RBRACE, CHECK_OK);
-
- return 0;
+ Expect(Token::RBRACE, CHECK_OK_VOID);
}
-ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
+ZoneList<const Parser::NamedImport*>* Parser::ParseNamedImports(
+ int pos, bool* ok) {
// NamedImports :
// '{' '}'
// '{' ImportsList '}'
@@ -1407,8 +1352,7 @@ ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
Expect(Token::LBRACE, CHECK_OK);
- ZoneList<ImportDeclaration*>* result =
- new (zone()) ZoneList<ImportDeclaration*>(1, zone());
+ auto result = new (zone()) ZoneList<const NamedImport*>(1, zone());
while (peek() != Token::RBRACE) {
const AstRawString* import_name = ParseIdentifierName(CHECK_OK);
const AstRawString* local_name = import_name;
@@ -1418,39 +1362,42 @@ ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
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;
+ return nullptr;
} else if (IsEvalOrArguments(local_name)) {
*ok = false;
ReportMessage(MessageTemplate::kStrictEvalArguments);
- return NULL;
+ return nullptr;
}
- VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
- ImportDeclaration* declaration =
- factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
- result->Add(declaration, zone());
+
+ DeclareVariable(local_name, CONST, kNeedsInitialization, position(),
+ CHECK_OK);
+
+ NamedImport* import = new (zone()) NamedImport(
+ import_name, local_name, scanner()->location());
+ result->Add(import, zone());
+
if (peek() == Token::RBRACE) break;
Expect(Token::COMMA, CHECK_OK);
}
Expect(Token::RBRACE, CHECK_OK);
-
return result;
}
-Statement* Parser::ParseImportDeclaration(bool* ok) {
+void Parser::ParseImportDeclaration(bool* ok) {
// ImportDeclaration :
// 'import' ImportClause 'from' ModuleSpecifier ';'
// 'import' ModuleSpecifier ';'
//
// ImportClause :
+ // ImportedDefaultBinding
// NameSpaceImport
// NamedImports
- // ImportedDefaultBinding
// ImportedDefaultBinding ',' NameSpaceImport
// ImportedDefaultBinding ',' NamedImports
//
@@ -1458,158 +1405,159 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
// '*' 'as' ImportedBinding
int pos = peek_position();
- Expect(Token::IMPORT, CHECK_OK);
+ Expect(Token::IMPORT, CHECK_OK_VOID);
Token::Value tok = peek();
// 'import' ModuleSpecifier ';'
if (tok == Token::STRING) {
- const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
- scope_->module()->AddModuleRequest(module_specifier, zone());
- ExpectSemicolon(CHECK_OK);
- return factory()->NewEmptyStatement(pos);
+ const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK_VOID);
+ ExpectSemicolon(CHECK_OK_VOID);
+ module()->AddEmptyImport(module_specifier, scanner()->location(), zone());
+ return;
}
// Parse ImportedDefaultBinding if present.
- ImportDeclaration* import_default_declaration = NULL;
+ const AstRawString* import_default_binding = nullptr;
+ Scanner::Location import_default_binding_loc;
if (tok != Token::MUL && tok != Token::LBRACE) {
- const AstRawString* local_name =
- ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
- VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
- import_default_declaration = factory()->NewImportDeclaration(
- proxy, ast_value_factory()->default_string(), NULL, scope_, pos);
- Declare(import_default_declaration, DeclarationDescriptor::NORMAL, true,
- CHECK_OK);
- }
-
- const AstRawString* module_instance_binding = NULL;
- ZoneList<ImportDeclaration*>* named_declarations = NULL;
- if (import_default_declaration == NULL || Check(Token::COMMA)) {
+ import_default_binding =
+ ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK_VOID);
+ import_default_binding_loc = scanner()->location();
+ DeclareVariable(import_default_binding, CONST, kNeedsInitialization, pos,
+ CHECK_OK_VOID);
+ }
+
+ // Parse NameSpaceImport or NamedImports if present.
+ const AstRawString* module_namespace_binding = nullptr;
+ Scanner::Location module_namespace_binding_loc;
+ const ZoneList<const NamedImport*>* named_imports = nullptr;
+ if (import_default_binding == nullptr || Check(Token::COMMA)) {
switch (peek()) {
case Token::MUL: {
Consume(Token::MUL);
- ExpectContextualKeyword(CStrVector("as"), CHECK_OK);
- module_instance_binding =
- ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
- // TODO(ES6): Add an appropriate declaration.
+ ExpectContextualKeyword(CStrVector("as"), CHECK_OK_VOID);
+ module_namespace_binding =
+ ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK_VOID);
+ module_namespace_binding_loc = scanner()->location();
+ DeclareVariable(module_namespace_binding, CONST, kCreatedInitialized,
+ pos, CHECK_OK_VOID);
break;
}
case Token::LBRACE:
- named_declarations = ParseNamedImports(pos, CHECK_OK);
+ named_imports = ParseNamedImports(pos, CHECK_OK_VOID);
break;
default:
*ok = false;
ReportUnexpectedToken(scanner()->current_token());
- return NULL;
+ return;
}
}
- ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
- const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
- scope_->module()->AddModuleRequest(module_specifier, zone());
+ ExpectContextualKeyword(CStrVector("from"), CHECK_OK_VOID);
+ const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK_VOID);
+ ExpectSemicolon(CHECK_OK_VOID);
+
+ // Now that we have all the information, we can make the appropriate
+ // declarations.
- if (module_instance_binding != NULL) {
- // TODO(ES6): Set the module specifier for the module namespace binding.
+ // TODO(neis): Would prefer to call DeclareVariable for each case below rather
+ // than above and in ParseNamedImports, but then a possible error message
+ // would point to the wrong location. Maybe have a DeclareAt version of
+ // Declare that takes a location?
+
+ if (module_namespace_binding != nullptr) {
+ module()->AddStarImport(module_namespace_binding, module_specifier,
+ module_namespace_binding_loc, zone());
}
- if (import_default_declaration != NULL) {
- import_default_declaration->set_module_specifier(module_specifier);
+ if (import_default_binding != nullptr) {
+ module()->AddImport(ast_value_factory()->default_string(),
+ import_default_binding, module_specifier,
+ import_default_binding_loc, zone());
}
- if (named_declarations != NULL) {
- for (int i = 0; i < named_declarations->length(); ++i) {
- named_declarations->at(i)->set_module_specifier(module_specifier);
+ if (named_imports != nullptr) {
+ if (named_imports->length() == 0) {
+ module()->AddEmptyImport(module_specifier, scanner()->location(), zone());
+ } else {
+ for (int i = 0; i < named_imports->length(); ++i) {
+ const NamedImport* import = named_imports->at(i);
+ module()->AddImport(import->import_name, import->local_name,
+ module_specifier, import->location, zone());
+ }
}
}
-
- ExpectSemicolon(CHECK_OK);
- return factory()->NewEmptyStatement(pos);
}
Statement* Parser::ParseExportDefault(bool* ok) {
// Supports the following productions, starting after the 'default' token:
- // 'export' 'default' FunctionDeclaration
+ // 'export' 'default' HoistableDeclaration
// 'export' 'default' ClassDeclaration
// 'export' 'default' AssignmentExpression[In] ';'
Expect(Token::DEFAULT, CHECK_OK);
Scanner::Location default_loc = scanner()->location();
- const AstRawString* default_string = ast_value_factory()->default_string();
- ZoneList<const AstRawString*> names(1, zone());
+ ZoneList<const AstRawString*> local_names(1, zone());
Statement* result = nullptr;
- Expression* default_export = nullptr;
switch (peek()) {
- case Token::FUNCTION: {
- Consume(Token::FUNCTION);
- int pos = position();
- bool is_generator = Check(Token::MUL);
- if (peek() == Token::LPAREN) {
- // FunctionDeclaration[+Default] ::
- // 'function' '(' FormalParameters ')' '{' FunctionBody '}'
- //
- // GeneratorDeclaration[+Default] ::
- // 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
- default_export = ParseFunctionLiteral(
- default_string, Scanner::Location::invalid(),
- kSkipFunctionNameCheck,
- is_generator ? FunctionKind::kGeneratorFunction
- : FunctionKind::kNormalFunction,
- pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
- result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- } else {
- result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK);
- }
+ case Token::FUNCTION:
+ result = ParseHoistableDeclaration(&local_names, true, CHECK_OK);
break;
- }
case Token::CLASS:
Consume(Token::CLASS);
- if (peek() == Token::EXTENDS || peek() == Token::LBRACE) {
- // ClassDeclaration[+Default] ::
- // 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
- default_export = ParseClassLiteral(nullptr, default_string,
- Scanner::Location::invalid(), false,
- position(), CHECK_OK);
- result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- } else {
- result = ParseClassDeclaration(&names, CHECK_OK);
- }
+ result = ParseClassDeclaration(&local_names, true, CHECK_OK);
break;
+ case Token::ASYNC:
+ if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
+ !scanner()->HasAnyLineTerminatorAfterNext()) {
+ Consume(Token::ASYNC);
+ result = ParseAsyncFunctionDeclaration(&local_names, true, CHECK_OK);
+ break;
+ }
+ /* falls through */
+
default: {
- int pos = peek_position();
+ int pos = position();
ExpressionClassifier classifier(this);
- Expression* expr = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+ Expression* value =
+ ParseAssignmentExpression(true, &classifier, CHECK_OK);
RewriteNonPattern(&classifier, CHECK_OK);
+ SetFunctionName(value, ast_value_factory()->default_string());
+
+ const AstRawString* local_name =
+ ast_value_factory()->star_default_star_string();
+ local_names.Add(local_name, zone());
+
+ // It's fine to declare this as CONST because the user has no way of
+ // writing to it.
+ Declaration* decl = DeclareVariable(local_name, CONST, pos, CHECK_OK);
+ decl->proxy()->var()->set_initializer_position(position());
+
+ Assignment* assignment = factory()->NewAssignment(
+ Token::INIT, decl->proxy(), value, kNoSourcePosition);
+ result = factory()->NewExpressionStatement(assignment, kNoSourcePosition);
ExpectSemicolon(CHECK_OK);
- result = factory()->NewExpressionStatement(expr, pos);
break;
}
}
- DCHECK_LE(names.length(), 1);
- if (names.length() == 1) {
- scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
- if (!*ok) {
- ParserTraits::ReportMessageAt(
- default_loc, MessageTemplate::kDuplicateExport, default_string);
- return nullptr;
- }
- } else {
- // TODO(ES6): Assign result to a const binding with the name "*default*"
- // and add an export entry with "*default*" as the local name.
- USE(default_export);
- }
+ DCHECK_EQ(local_names.length(), 1);
+ module()->AddExport(local_names.first(),
+ ast_value_factory()->default_string(), default_loc,
+ zone());
+ DCHECK_NOT_NULL(result);
return result;
}
-
Statement* Parser::ParseExportDeclaration(bool* ok) {
// ExportDeclaration:
// 'export' '*' 'from' ModuleSpecifier ';'
@@ -1621,7 +1569,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
int pos = peek_position();
Expect(Token::EXPORT, CHECK_OK);
- Statement* result = NULL;
+ Statement* result = nullptr;
ZoneList<const AstRawString*> names(1, zone());
switch (peek()) {
case Token::DEFAULT:
@@ -1631,9 +1579,8 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
Consume(Token::MUL);
ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
- scope_->module()->AddModuleRequest(module_specifier, zone());
- // TODO(ES6): scope_->module()->AddStarExport(...)
ExpectSemicolon(CHECK_OK);
+ module()->AddStarExport(module_specifier, scanner()->location(), zone());
return factory()->NewEmptyStatement(pos);
}
@@ -1652,50 +1599,46 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
Scanner::Location reserved_loc = Scanner::Location::invalid();
ZoneList<const AstRawString*> export_names(1, zone());
ZoneList<Scanner::Location> export_locations(1, zone());
- ZoneList<const AstRawString*> local_names(1, zone());
- ParseExportClause(&export_names, &export_locations, &local_names,
+ ZoneList<const AstRawString*> original_names(1, zone());
+ ParseExportClause(&export_names, &export_locations, &original_names,
&reserved_loc, CHECK_OK);
- const AstRawString* indirect_export_module_specifier = NULL;
+ const AstRawString* module_specifier = nullptr;
if (CheckContextualKeyword(CStrVector("from"))) {
- indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK);
+ module_specifier = ParseModuleSpecifier(CHECK_OK);
} else if (reserved_loc.IsValid()) {
// No FromClause, so reserved words are invalid in ExportClause.
*ok = false;
ReportMessageAt(reserved_loc, MessageTemplate::kUnexpectedReserved);
- return NULL;
+ return nullptr;
}
ExpectSemicolon(CHECK_OK);
const int length = export_names.length();
- DCHECK_EQ(length, local_names.length());
+ DCHECK_EQ(length, original_names.length());
DCHECK_EQ(length, export_locations.length());
- if (indirect_export_module_specifier == NULL) {
+ if (module_specifier == nullptr) {
for (int i = 0; i < length; ++i) {
- scope_->module()->AddLocalExport(export_names[i], local_names[i],
- zone(), ok);
- if (!*ok) {
- ParserTraits::ReportMessageAt(export_locations[i],
- MessageTemplate::kDuplicateExport,
- export_names[i]);
- return NULL;
- }
+ module()->AddExport(original_names[i], export_names[i],
+ export_locations[i], zone());
}
+ } else if (length == 0) {
+ module()->AddEmptyImport(module_specifier, scanner()->location(),
+ zone());
} else {
- scope_->module()->AddModuleRequest(indirect_export_module_specifier,
- zone());
for (int i = 0; i < length; ++i) {
- // TODO(ES6): scope_->module()->AddIndirectExport(...);(
+ module()->AddExport(original_names[i], export_names[i],
+ module_specifier, export_locations[i], zone());
}
}
return factory()->NewEmptyStatement(pos);
}
case Token::FUNCTION:
- result = ParseFunctionDeclaration(&names, CHECK_OK);
+ result = ParseHoistableDeclaration(&names, false, CHECK_OK);
break;
case Token::CLASS:
Consume(Token::CLASS);
- result = ParseClassDeclaration(&names, CHECK_OK);
+ result = ParseClassDeclaration(&names, false, CHECK_OK);
break;
case Token::VAR:
@@ -1704,21 +1647,26 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
break;
+ case Token::ASYNC:
+ if (allow_harmony_async_await()) {
+ // TODO(neis): Why don't we have the same check here as in
+ // ParseStatementListItem?
+ Consume(Token::ASYNC);
+ result = ParseAsyncFunctionDeclaration(&names, false, CHECK_OK);
+ break;
+ }
+ /* falls through */
+
default:
*ok = false;
ReportUnexpectedToken(scanner()->current_token());
- return NULL;
+ return nullptr;
}
- // Extract declared names into export declarations.
- ModuleDescriptor* descriptor = scope_->module();
+ ModuleDescriptor* descriptor = module();
for (int i = 0; i < names.length(); ++i) {
- descriptor->AddLocalExport(names[i], names[i], zone(), ok);
- if (!*ok) {
- // TODO(adamk): Possibly report this error at the right place.
- ParserTraits::ReportMessage(MessageTemplate::kDuplicateExport, names[i]);
- return NULL;
- }
+ // TODO(neis): Provide better location.
+ descriptor->AddExport(names[i], names[i], scanner()->location(), zone());
}
DCHECK_NOT_NULL(result);
@@ -1734,7 +1682,7 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
if (peek() == Token::SEMICOLON) {
Next();
- return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ return factory()->NewEmptyStatement(kNoSourcePosition);
}
return ParseSubStatement(labels, allow_function, ok);
}
@@ -1771,7 +1719,7 @@ Statement* Parser::ParseSubStatement(
case Token::SEMICOLON:
Next();
- return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ return factory()->NewEmptyStatement(kNoSourcePosition);
case Token::IF:
return ParseIfStatement(labels, ok);
@@ -1796,7 +1744,7 @@ Statement* Parser::ParseSubStatement(
return ParseStatementAsUnlabelled(labels, ok);
} else {
Block* result =
- factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition);
+ factory()->NewBlock(labels, 1, false, kNoSourcePosition);
Target target(&this->target_stack_, result);
Statement* statement = ParseStatementAsUnlabelled(labels, CHECK_OK);
if (result) result->statements()->Add(statement, zone());
@@ -1858,70 +1806,102 @@ Statement* Parser::ParseStatementAsUnlabelled(
}
}
+VariableProxy* Parser::NewUnresolved(const AstRawString* name, int begin_pos,
+ int end_pos, Variable::Kind kind) {
+ return scope()->NewUnresolved(factory(), name, begin_pos, end_pos, kind);
+}
-VariableProxy* Parser::NewUnresolved(const AstRawString* name,
- VariableMode mode) {
- // If we are inside a function, a declaration of a var/const variable is a
- // truly local variable, and the scope of the variable is always the function
- // scope.
- // Let/const variables in harmony mode are always added to the immediately
- // enclosing scope.
- Scope* scope =
- IsLexicalVariableMode(mode) ? scope_ : scope_->DeclarationScope();
- return scope->NewUnresolved(factory(), name, Variable::NORMAL,
- scanner()->location().beg_pos,
- scanner()->location().end_pos);
+VariableProxy* Parser::NewUnresolved(const AstRawString* name) {
+ return scope()->NewUnresolved(factory(), name, scanner()->location().beg_pos,
+ scanner()->location().end_pos);
}
+InitializationFlag Parser::DefaultInitializationFlag(VariableMode mode) {
+ DCHECK(IsDeclaredVariableMode(mode));
+ return mode == VAR ? kCreatedInitialized : kNeedsInitialization;
+}
+
+Declaration* Parser::DeclareVariable(const AstRawString* name,
+ VariableMode mode, int pos, bool* ok) {
+ return DeclareVariable(name, mode, DefaultInitializationFlag(mode), pos, ok);
+}
+
+Declaration* Parser::DeclareVariable(const AstRawString* name,
+ VariableMode mode, InitializationFlag init,
+ int pos, bool* ok) {
+ DCHECK_NOT_NULL(name);
+ Scope* scope =
+ IsLexicalVariableMode(mode) ? this->scope() : GetDeclarationScope();
+ VariableProxy* proxy =
+ scope->NewUnresolved(factory(), name, scanner()->location().beg_pos,
+ scanner()->location().end_pos);
+ Declaration* declaration =
+ factory()->NewVariableDeclaration(proxy, this->scope(), pos);
+ Declare(declaration, DeclarationDescriptor::NORMAL, mode, init, CHECK_OK);
+ return declaration;
+}
Variable* Parser::Declare(Declaration* declaration,
DeclarationDescriptor::Kind declaration_kind,
- bool resolve, bool* ok, Scope* scope) {
+ VariableMode mode, InitializationFlag init, bool* ok,
+ Scope* scope) {
+ DCHECK(IsDeclaredVariableMode(mode) && mode != CONST_LEGACY);
+
VariableProxy* proxy = declaration->proxy();
DCHECK(proxy->raw_name() != NULL);
const AstRawString* name = proxy->raw_name();
- VariableMode mode = declaration->mode();
+
+ if (scope == nullptr) scope = this->scope();
+ if (mode == VAR) scope = scope->GetDeclarationScope();
+ DCHECK(!scope->is_catch_scope());
+ DCHECK(!scope->is_with_scope());
+ DCHECK(scope->is_declaration_scope() ||
+ (IsLexicalVariableMode(mode) && scope->is_block_scope()));
+
bool is_function_declaration = declaration->IsFunctionDeclaration();
- if (scope == nullptr) scope = scope_;
- Scope* declaration_scope =
- IsLexicalVariableMode(mode) ? scope : scope->DeclarationScope();
- Variable* var = NULL;
- // If a suitable scope exists, then we can statically declare this
- // variable and also set its mode. In any case, a Declaration node
- // will be added to the scope so that the declaration can be added
- // to the corresponding activation frame at runtime if necessary.
- // For instance, var declarations inside a sloppy eval scope need
- // to be added to the calling function context. Similarly, strict
- // mode eval scope and lexical eval bindings do not leak variable
- // declarations to the caller's scope so we declare all locals, too.
- if (declaration_scope->is_function_scope() ||
- declaration_scope->is_block_scope() ||
- declaration_scope->is_module_scope() ||
- declaration_scope->is_script_scope() ||
- (declaration_scope->is_eval_scope() &&
- (is_strict(declaration_scope->language_mode()) ||
- IsLexicalVariableMode(mode)))) {
+ Variable* var = NULL;
+ if (scope->is_eval_scope() && is_sloppy(scope->language_mode()) &&
+ mode == VAR) {
+ // In a var binding in a sloppy direct eval, pollute the enclosing scope
+ // with this new binding by doing the following:
+ // The proxy is bound to a lookup variable to force a dynamic declaration
+ // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
+ Variable::Kind kind = Variable::NORMAL;
+ // TODO(sigurds) figure out if kNotAssigned is OK here
+ var = new (zone()) Variable(scope, name, mode, kind, init, kNotAssigned);
+ var->AllocateTo(VariableLocation::LOOKUP, -1);
+ } else {
// Declare the variable in the declaration scope.
- var = declaration_scope->LookupLocal(name);
+ var = scope->LookupLocal(name);
if (var == NULL) {
// Declare the name.
Variable::Kind kind = Variable::NORMAL;
if (is_function_declaration) {
kind = Variable::FUNCTION;
}
- 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())) {
+ var = scope->DeclareLocal(name, mode, init, kind, kNotAssigned);
+ } 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 &&
+ bool duplicate_allowed = false;
+ if (is_sloppy(scope->language_mode()) && is_function_declaration &&
var->is_function()) {
DCHECK(IsLexicalVariableMode(mode) &&
IsLexicalVariableMode(var->mode()));
+ // If the duplication is allowed, then the var will show up
+ // in the SloppyBlockFunctionMap and the new FunctionKind
+ // will be a permitted duplicate.
+ FunctionKind function_kind =
+ declaration->AsFunctionDeclaration()->fun()->kind();
+ duplicate_allowed =
+ scope->GetDeclarationScope()->sloppy_block_function_map()->Lookup(
+ const_cast<AstRawString*>(name), name->hash()) != nullptr &&
+ !IsAsyncFunction(function_kind) &&
+ !(allow_harmony_restrictive_generators() &&
+ IsGeneratorFunction(function_kind));
+ }
+ if (duplicate_allowed) {
++use_counts_[v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition];
} else {
// The name was declared in this scope before; check for conflicting
@@ -1941,9 +1921,9 @@ Variable* Parser::Declare(Declaration* declaration,
// In harmony we treat re-declarations as early errors. See
// ES5 16 for a definition of early errors.
if (declaration_kind == DeclarationDescriptor::NORMAL) {
- ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name);
+ ReportMessage(MessageTemplate::kVarRedeclaration, name);
} else {
- ParserTraits::ReportMessage(MessageTemplate::kParamDupe);
+ ReportMessage(MessageTemplate::kParamDupe);
}
*ok = false;
return nullptr;
@@ -1951,76 +1931,20 @@ Variable* Parser::Declare(Declaration* declaration,
} else if (mode == VAR) {
var->set_maybe_assigned();
}
- } else if (declaration_scope->is_eval_scope() &&
- is_sloppy(declaration_scope->language_mode()) &&
- !IsLexicalVariableMode(mode)) {
- // In a var binding in a sloppy direct eval, pollute the enclosing scope
- // with this new binding by doing the following:
- // The proxy is bound to a lookup variable to force a dynamic declaration
- // using the DeclareLookupSlot runtime function.
- Variable::Kind kind = Variable::NORMAL;
- // TODO(sigurds) figure out if kNotAssigned is OK here
- var = new (zone()) Variable(declaration_scope, name, mode, kind,
- declaration->initialization(), kNotAssigned);
- var->AllocateTo(VariableLocation::LOOKUP, -1);
- var->SetFromEval();
- resolve = true;
}
-
+ DCHECK_NOT_NULL(var);
// We add a declaration node for every declaration. The compiler
// will only generate code if necessary. In particular, declarations
// for inner local variables that do not represent functions won't
// result in any generated code.
//
- // Note that we always add an unresolved proxy even if it's not
- // used, simply because we don't know in this method (w/o extra
- // parameters) if the proxy is needed or not. The proxy will be
- // bound during variable resolution time unless it was pre-bound
- // below.
- //
- // WARNING: This will lead to multiple declaration nodes for the
+ // This will lead to multiple declaration nodes for the
// same variable if it is declared several times. This is not a
- // semantic issue as long as we keep the source order, but it may be
- // a performance issue since it may lead to repeated
- // 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
- // function scope and not a statement-local scope, e.g. as provided with a
- // 'with' statement:
- //
- // with (obj) {
- // function f() {}
- // }
- //
- // which is translated into:
- //
- // with (obj) {
- // // in this case this is not: 'var f; f = function () {};'
- // var f = function () {};
- // }
- //
- // Note that if 'f' is accessed from inside the 'with' statement, it
- // will be allocated in the context (because we must be able to look
- // it up dynamically) but it will also be accessed statically, i.e.,
- // with a context slot index and a context chain length for this
- // initialization code. Thus, inside the 'with' statement, we need
- // both access to the static and the dynamic context chain; the
- // runtime needs to provide both.
- if (resolve && var != NULL) {
- proxy->BindTo(var);
- }
+ // semantic issue, but it may be a performance issue since it may
+ // lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
+ scope->AddDeclaration(declaration);
+ proxy->BindTo(var);
return var;
}
@@ -2051,88 +1975,122 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
// isn't lazily compiled. The extension structures are only
// accessible while parsing the first time not when reparsing
// because of lazy compilation.
- // TODO(adamk): Should this be ClosureScope()?
- scope_->DeclarationScope()->ForceEagerCompilation();
+ GetClosureScope()->ForceEagerCompilation();
// TODO(1240846): It's weird that native function declarations are
// introduced dynamically when we meet their declarations, whereas
// other functions are set up when entering the surrounding scope.
- VariableProxy* proxy = NewUnresolved(name, VAR);
- Declaration* declaration =
- factory()->NewVariableDeclaration(proxy, VAR, scope_, pos);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
- NativeFunctionLiteral* lit = factory()->NewNativeFunctionLiteral(
- name, extension_, RelocInfo::kNoPosition);
+ Declaration* decl = DeclareVariable(name, VAR, pos, CHECK_OK);
+ NativeFunctionLiteral* lit =
+ factory()->NewNativeFunctionLiteral(name, extension_, kNoSourcePosition);
return factory()->NewExpressionStatement(
- factory()->NewAssignment(Token::INIT, proxy, lit, RelocInfo::kNoPosition),
+ factory()->NewAssignment(Token::INIT, decl->proxy(), lit,
+ kNoSourcePosition),
pos);
}
-
-Statement* Parser::ParseFunctionDeclaration(
- ZoneList<const AstRawString*>* names, bool* ok) {
+Statement* Parser::ParseHoistableDeclaration(
+ ZoneList<const AstRawString*>* names, bool default_export, 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, default_export, ok);
}
+Statement* Parser::ParseAsyncFunctionDeclaration(
+ ZoneList<const AstRawString*>* names, bool default_export, 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, default_export, ok);
+}
-Statement* Parser::ParseFunctionDeclaration(
- int pos, bool is_generator, ZoneList<const AstRawString*>* names,
- bool* ok) {
+Statement* Parser::ParseHoistableDeclaration(
+ int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
+ bool default_export, bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ // 'function' '(' FormalParameters ')' '{' FunctionBody '}'
// GeneratorDeclaration ::
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+ // 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
+ //
+ // The anonymous forms are allowed iff [default_export] is true.
//
// 'function' and '*' (if present) have been consumed by the caller.
- bool is_strict_reserved = false;
- const AstRawString* name = ParseIdentifierOrStrictReservedWord(
- &is_strict_reserved, CHECK_OK);
+
+ const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
+ const bool is_async = flags & ParseFunctionFlags::kIsAsync;
+ DCHECK(!is_generator || !is_async);
+
+ const AstRawString* name;
+ FunctionNameValidity name_validity;
+ const AstRawString* variable_name;
+ if (default_export && peek() == Token::LPAREN) {
+ name = ast_value_factory()->default_string();
+ name_validity = kSkipFunctionNameCheck;
+ variable_name = ast_value_factory()->star_default_star_string();
+ } else {
+ bool is_strict_reserved;
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
+ name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved
+ : kFunctionNameValidityUnknown;
+ variable_name = name;
+ }
FuncNameInferrer::State fni_state(fni_);
if (fni_ != NULL) fni_->PushEnclosingName(name);
FunctionLiteral* fun = ParseFunctionLiteral(
- name, scanner()->location(),
- is_strict_reserved ? kFunctionNameIsStrictReserved
- : kFunctionNameValidityUnknown,
+ name, scanner()->location(), name_validity,
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
- // scope, we treat it as such and introduce the function with its
- // initial value upon entering the corresponding scope.
// 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;
- VariableProxy* proxy = NewUnresolved(name, mode);
+ (!scope()->is_declaration_scope() || scope()->is_module_scope()) ? LET
+ : VAR;
+ VariableProxy* proxy = NewUnresolved(variable_name);
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()) {
+ factory()->NewFunctionDeclaration(proxy, fun, scope(), pos);
+ Declare(declaration, DeclarationDescriptor::NORMAL, mode, kCreatedInitialized,
+ CHECK_OK);
+ if (names) names->Add(variable_name, zone());
+ EmptyStatement* empty = factory()->NewEmptyStatement(kNoSourcePosition);
+ // Async functions don't undergo sloppy mode block scoped hoisting, and don't
+ // allow duplicates in a block. Both are represented by the
+ // sloppy_block_function_map. Don't add them to the map for async functions.
+ // Generators are also supposed to be prohibited; currently doing this behind
+ // a flag and UseCounting violations to assess web compatibility.
+ if (is_sloppy(language_mode()) && !scope()->is_declaration_scope() &&
+ !is_async && !(allow_harmony_restrictive_generators() && is_generator)) {
SloppyBlockFunctionStatement* delegate =
- factory()->NewSloppyBlockFunctionStatement(empty, scope_);
- scope_->DeclarationScope()->sloppy_block_function_map()->Declare(name,
- delegate);
+ factory()->NewSloppyBlockFunctionStatement(empty, scope());
+ DeclarationScope* target_scope = GetDeclarationScope();
+ target_scope->DeclareSloppyBlockFunction(variable_name, delegate);
return delegate;
}
return empty;
}
-
Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
- bool* ok) {
+ bool default_export, bool* ok) {
// ClassDeclaration ::
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
+ // 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
+ //
+ // The anonymous form is allowed iff [default_export] is true.
//
// 'class' is expected to be consumed by the caller.
//
@@ -2146,49 +2104,47 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
//
// so rewrite it as such.
- if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
- ReportMessage(MessageTemplate::kSloppyLexical);
- *ok = false;
- return NULL;
+ int pos = position();
+
+ const AstRawString* name;
+ bool is_strict_reserved;
+ const AstRawString* variable_name;
+ if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) {
+ name = ast_value_factory()->default_string();
+ is_strict_reserved = false;
+ variable_name = ast_value_factory()->star_default_star_string();
+ } else {
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
+ variable_name = name;
}
- int pos = position();
- bool is_strict_reserved = false;
- const AstRawString* name =
- ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
- ClassLiteral* value = ParseClassLiteral(nullptr, name, scanner()->location(),
- is_strict_reserved, pos, CHECK_OK);
+ Expression* value = ParseClassLiteral(nullptr, name, scanner()->location(),
+ is_strict_reserved, pos, CHECK_OK);
- VariableProxy* proxy = NewUnresolved(name, LET);
- Declaration* declaration =
- factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
- proxy->var()->set_initializer_position(position());
+ Declaration* decl = DeclareVariable(variable_name, LET, pos, CHECK_OK);
+ decl->proxy()->var()->set_initializer_position(position());
Assignment* assignment =
- factory()->NewAssignment(Token::INIT, proxy, value, pos);
+ factory()->NewAssignment(Token::INIT, decl->proxy(), value, pos);
Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
- if (names) names->Add(name, zone());
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
+ if (names) names->Add(variable_name, zone());
return assignment_statement;
}
-
-Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels,
- bool finalize_block_scope, bool* ok) {
+Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
// The harmony mode uses block elements instead of statements.
//
// Block ::
// '{' StatementList '}'
// Construct block expecting 16 statements.
- Block* body =
- factory()->NewBlock(labels, 16, false, RelocInfo::kNoPosition);
- Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+ Block* body = factory()->NewBlock(labels, 16, false, kNoSourcePosition);
// Parse the statements and collect escaping labels.
Expect(Token::LBRACE, CHECK_OK);
- block_scope->set_start_position(scanner()->location().beg_pos);
- { BlockState block_state(&scope_, block_scope);
+ {
+ BlockState block_state(&scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
Target target(&this->target_stack_, body);
while (peek() != Token::RBRACE) {
@@ -2197,22 +2153,15 @@ Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels,
body->statements()->Add(stat, zone());
}
}
+
+ Expect(Token::RBRACE, CHECK_OK);
+ block_state.set_end_position(scanner()->location().end_pos);
+ body->set_scope(block_state.FinalizedBlockScope());
}
- Expect(Token::RBRACE, CHECK_OK);
- block_scope->set_end_position(scanner()->location().end_pos);
- if (finalize_block_scope) {
- block_scope = block_scope->FinalizeBlockScope();
- }
- body->set_scope(block_scope);
return body;
}
-Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
- return ParseBlock(labels, true, ok);
-}
-
-
Block* Parser::DeclarationParsingResult::BuildInitializationBlock(
ZoneList<const AstRawString*>* names, bool* ok) {
Block* result = descriptor.parser->factory()->NewBlock(
@@ -2231,11 +2180,11 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
// VariableStatement ::
// VariableDeclarations ';'
- // The scope of a var/const declared variable anywhere inside a function
+ // The scope of a var declared variable anywhere inside a function
// is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
- // transform a source-level var/const declaration into a (Function)
- // Scope declaration, and rewrite the source-level initialization into an
- // assignment statement. We use a block to collect multiple assignments.
+ // transform a source-level var declaration into a (Function) Scope
+ // declaration, and rewrite the source-level initialization into an assignment
+ // statement. We use a block to collect multiple assignments.
//
// We mark the block as initializer block because we don't want the
// rewriter to add a '.result' assignment to such a block (to get compliant
@@ -2282,12 +2231,11 @@ Block* Parser::ParseVariableDeclarations(
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;
@@ -2295,7 +2243,7 @@ Block* Parser::ParseVariableDeclarations(
UNREACHABLE(); // by current callers
}
- parsing_result->descriptor.scope = scope_;
+ parsing_result->descriptor.scope = scope();
parsing_result->descriptor.hoist_scope = nullptr;
@@ -2327,7 +2275,7 @@ Block* Parser::ParseVariableDeclarations(
}
Expression* value = NULL;
- int initializer_position = RelocInfo::kNoPosition;
+ int initializer_position = kNoSourcePosition;
if (Check(Token::ASSIGN)) {
ExpressionClassifier classifier(this);
value = ParseAssignmentExpression(var_context != kForStatement,
@@ -2349,9 +2297,8 @@ Block* Parser::ParseVariableDeclarations(
}
}
- if (allow_harmony_function_name()) {
- ParserTraits::SetFunctionNameFromIdentifierRef(value, pattern);
- }
+ ParserBaseTraits<Parser>::SetFunctionNameFromIdentifierRef(value,
+ pattern);
// End position of the initializer is after the assignment expression.
initializer_position = scanner()->location().end_pos;
@@ -2362,7 +2309,7 @@ Block* Parser::ParseVariableDeclarations(
// ES6 'const' and binding patterns require initializers.
if (parsing_result->descriptor.mode == CONST ||
!pattern->IsVariableProxy()) {
- ParserTraits::ReportMessageAt(
+ ReportMessageAt(
Scanner::Location(decl_pos, scanner()->location().end_pos),
MessageTemplate::kDeclarationMissingInitializer,
!pattern->IsVariableProxy() ? "destructuring" : "const");
@@ -2370,9 +2317,8 @@ Block* Parser::ParseVariableDeclarations(
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 +2365,23 @@ static bool ContainsLabel(ZoneList<const AstRawString*>* labels,
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()) {
+ ReportMessageAt(scanner()->location(),
+ MessageTemplate::kGeneratorInLegacyContext);
+ *ok = false;
+ return nullptr;
+ }
+ }
+
+ return ParseHoistableDeclaration(pos, flags, nullptr, false, CHECK_OK);
+}
+
Statement* Parser::ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok) {
@@ -2439,7 +2402,6 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
ReportUnexpectedToken(Next());
*ok = false;
return nullptr;
-
default:
break;
}
@@ -2459,7 +2421,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
// structured. However, these are probably changes we want to
// make later anyway so we should go back and fix this then.
if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
- ParserTraits::ReportMessage(MessageTemplate::kLabelRedeclaration, label);
+ ReportMessage(MessageTemplate::kLabelRedeclaration, label);
*ok = false;
return NULL;
}
@@ -2470,12 +2432,12 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
// Remove the "ghost" variable that turned out to be a label
// from the top scope. This way, we don't try to resolve it
// during the scope processing.
- scope_->RemoveUnresolved(var);
+ scope()->RemoveUnresolved(var);
Expect(Token::COLON, CHECK_OK);
// 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 +2458,6 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
}
// 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);
}
@@ -2526,7 +2479,7 @@ IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels,
Next();
else_statement = ParseScopedStatement(labels, false, CHECK_OK);
} else {
- else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
}
return factory()->NewIfStatement(
condition, then_statement, else_statement, pos);
@@ -2553,7 +2506,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
if (label != NULL) {
message = MessageTemplate::kUnknownLabel;
}
- ParserTraits::ReportMessage(message, label);
+ ReportMessage(message, label);
*ok = false;
return NULL;
}
@@ -2590,7 +2543,7 @@ Statement* Parser::ParseBreakStatement(ZoneList<const AstRawString*>* labels,
if (label != NULL) {
message = MessageTemplate::kUnknownLabel;
}
- ParserTraits::ReportMessage(message, label);
+ ReportMessage(message, label);
*ok = false;
return NULL;
}
@@ -2608,7 +2561,6 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// reported (underlining).
Expect(Token::RETURN, CHECK_OK);
Scanner::Location loc = scanner()->location();
- function_state_->set_return_location(loc);
Token::Value tok = peek();
Statement* result;
@@ -2618,15 +2570,19 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
tok == Token::RBRACE ||
tok == Token::EOS) {
if (IsSubclassConstructor(function_state_->kind())) {
- return_value = ThisExpression(scope_, factory(), loc.beg_pos);
+ return_value = ThisExpression(loc.beg_pos);
} else {
return_value = GetLiteralUndefined(position());
}
} 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.
@@ -2639,8 +2595,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// %_IsJSReceiver(temp) ? temp : 1;
// temp = expr
- Variable* temp = scope_->NewTemporary(
- ast_value_factory()->empty_string());
+ Variable* temp = NewTemporary(ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
@@ -2651,7 +2606,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
Expression* is_spec_object_call = factory()->NewCallRuntime(
Runtime::kInlineIsJSReceiver, is_spec_object_args, pos);
- // %_IsJSReceiver(temp) ? temp : throw_expression
+ // %_IsJSReceiver(temp) ? temp : 1;
Expression* is_object_conditional = factory()->NewConditional(
is_spec_object_call, factory()->NewVariableProxy(temp),
factory()->NewSmiLiteral(1, pos), pos);
@@ -2659,28 +2614,33 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// temp === undefined
Expression* is_undefined = factory()->NewCompareOperation(
Token::EQ_STRICT, assign,
- factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), pos);
+ factory()->NewUndefinedLiteral(kNoSourcePosition), pos);
// is_undefined ? this : is_object_conditional
return_value = factory()->NewConditional(
- is_undefined, ThisExpression(scope_, factory(), pos),
- is_object_conditional, pos);
- }
+ is_undefined, ThisExpression(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()) && !is_resumable()) {
+ // 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);
- Scope* decl_scope = scope_->DeclarationScope();
+ DeclarationScope* decl_scope = GetDeclarationScope();
if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) {
ReportMessageAt(loc, MessageTemplate::kIllegalReturn);
*ok = false;
@@ -2708,9 +2668,10 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- Scope* with_scope = NewScope(scope_, WITH_SCOPE);
+ Scope* with_scope = NewScope(WITH_SCOPE);
Statement* body;
- { BlockState block_state(&scope_, with_scope);
+ {
+ BlockState block_state(&scope_state_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos);
body = ParseScopedStatement(labels, true, CHECK_OK);
with_scope->set_end_position(scanner()->location().end_pos);
@@ -2766,8 +2727,7 @@ Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
// }
// }
- Block* switch_block =
- factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
+ Block* switch_block = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
int switch_pos = peek_position();
Expect(Token::SWITCH, CHECK_OK);
@@ -2776,12 +2736,12 @@ Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::RPAREN, CHECK_OK);
Variable* tag_variable =
- scope_->NewTemporary(ast_value_factory()->dot_switch_tag_string());
+ NewTemporary(ast_value_factory()->dot_switch_tag_string());
Assignment* tag_assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(tag_variable), tag,
tag->position());
Statement* tag_statement =
- factory()->NewExpressionStatement(tag_assign, RelocInfo::kNoPosition);
+ factory()->NewExpressionStatement(tag_assign, kNoSourcePosition);
switch_block->statements()->Add(tag_statement, zone());
// make statement: undefined;
@@ -2789,21 +2749,18 @@ Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
// statements don't have a value.
switch_block->statements()->Add(
factory()->NewExpressionStatement(
- factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
+ factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition),
zone());
- Block* cases_block =
- factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
- Scope* cases_scope = NewScope(scope_, BLOCK_SCOPE);
- cases_scope->SetNonlinear();
+ Block* cases_block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition);
SwitchStatement* switch_statement =
factory()->NewSwitchStatement(labels, switch_pos);
- cases_scope->set_start_position(scanner()->location().beg_pos);
{
- BlockState cases_block_state(&scope_, cases_scope);
+ BlockState cases_block_state(&scope_state_);
+ cases_block_state.set_start_position(scanner()->location().beg_pos);
+ cases_block_state.SetNonlinear();
Target target(&this->target_stack_, switch_statement);
Expression* tag_read = factory()->NewVariableProxy(tag_variable);
@@ -2818,12 +2775,11 @@ Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
}
switch_statement->Initialize(tag_read, cases);
cases_block->statements()->Add(switch_statement, zone());
- }
- Expect(Token::RBRACE, CHECK_OK);
+ Expect(Token::RBRACE, CHECK_OK);
- cases_scope->set_end_position(scanner()->location().end_pos);
- cases_scope = cases_scope->FinalizeBlockScope();
- cases_block->set_scope(cases_scope);
+ cases_block_state.set_end_position(scanner()->location().end_pos);
+ cases_block->set_scope(cases_block_state.FinalizedBlockScope());
+ }
switch_block->statements()->Add(cases_block, zone());
@@ -2849,40 +2805,6 @@ Statement* Parser::ParseThrowStatement(bool* ok) {
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,11 +2823,20 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Block* try_block;
{
- DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_);
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideTryBlock);
try_block = ParseBlock(NULL, CHECK_OK);
}
Token::Value tok = peek();
+
+ bool catch_for_promise_reject = false;
+ if (allow_natives() && tok == Token::MOD) {
+ Consume(Token::MOD);
+ catch_for_promise_reject = true;
+ tok = peek();
+ }
+
if (tok != Token::CATCH && tok != Token::FINALLY) {
ReportMessage(MessageTemplate::kNoCatchOrFinally);
*ok = false;
@@ -2915,81 +2846,94 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
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);
Expect(Token::LPAREN, CHECK_OK);
- catch_scope = NewScope(scope_, CATCH_SCOPE);
+ catch_scope = NewScope(CATCH_SCOPE);
catch_scope->set_start_position(scanner()->location().beg_pos);
- ExpressionClassifier pattern_classifier(this);
- Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
- ValidateBindingPattern(&pattern_classifier, CHECK_OK);
-
- const AstRawString* name = ast_value_factory()->dot_catch_string();
- bool is_simple = pattern->IsVariableProxy();
- if (is_simple) {
- auto proxy = pattern->AsVariableProxy();
- scope_->RemoveUnresolved(proxy);
- name = proxy->raw_name();
- }
-
- catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
- Variable::NORMAL);
-
- Expect(Token::RPAREN, CHECK_OK);
-
{
CollectExpressionsInTailPositionToListScope
- collect_expressions_in_tail_position_scope(
- function_state_, &expressions_in_tail_position_in_catch_block);
- BlockState block_state(&scope_, catch_scope);
+ collect_tail_call_expressions_scope(
+ function_state_, &tail_call_expressions_in_catch_block);
+ BlockState block_state(&scope_state_, catch_scope);
- // TODO(adamk): Make a version of ParseBlock that takes a scope and
- // a block.
- catch_block =
- factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
- Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+ catch_block = factory()->NewBlock(nullptr, 16, false, kNoSourcePosition);
- block_scope->set_start_position(scanner()->location().beg_pos);
+ // Create a block scope to hold any lexical declarations created
+ // as part of destructuring the catch parameter.
{
- BlockState block_state(&scope_, block_scope);
+ BlockState block_state(&scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
Target target(&this->target_stack_, catch_block);
- if (!is_simple) {
+ const AstRawString* name = ast_value_factory()->dot_catch_string();
+ Expression* pattern = nullptr;
+ if (peek_any_identifier()) {
+ name = ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
+ } else {
+ ExpressionClassifier pattern_classifier(this);
+ pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+ ValidateBindingPattern(&pattern_classifier, CHECK_OK);
+ }
+ catch_variable = catch_scope->DeclareLocal(
+ name, VAR, kCreatedInitialized, Variable::NORMAL);
+
+ Expect(Token::RPAREN, CHECK_OK);
+
+ ZoneList<const AstRawString*> bound_names(1, zone());
+ if (pattern != nullptr) {
DeclarationDescriptor descriptor;
descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
descriptor.parser = this;
- descriptor.scope = scope_;
+ descriptor.scope = scope();
descriptor.hoist_scope = nullptr;
descriptor.mode = LET;
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 =
- factory()->NewBlock(nullptr, 8, true, RelocInfo::kNoPosition);
+ factory()->NewBlock(nullptr, 8, true, kNoSourcePosition);
PatternRewriter::DeclareAndInitializeVariables(
- init_block, &descriptor, &decl, nullptr, CHECK_OK);
+ init_block, &descriptor, &decl, &bound_names, CHECK_OK);
catch_block->statements()->Add(init_block, zone());
+ } else {
+ bound_names.Add(name, zone());
}
- Expect(Token::LBRACE, CHECK_OK);
- while (peek() != Token::RBRACE) {
- Statement* stat = ParseStatementListItem(CHECK_OK);
- if (stat && !stat->IsEmpty()) {
- catch_block->statements()->Add(stat, zone());
+ Block* inner_block = ParseBlock(nullptr, CHECK_OK);
+ catch_block->statements()->Add(inner_block, zone());
+
+ // Check for `catch(e) { let e; }` and similar errors.
+ Scope* inner_block_scope = inner_block->scope();
+ if (inner_block_scope != nullptr) {
+ Declaration* decl =
+ inner_block_scope->CheckLexDeclarationsConflictingWith(
+ bound_names);
+ if (decl != nullptr) {
+ const AstRawString* name = decl->proxy()->raw_name();
+ int position = decl->proxy()->position();
+ Scanner::Location location =
+ position == kNoSourcePosition
+ ? Scanner::Location::invalid()
+ : Scanner::Location(position, position + 1);
+ ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
+ *ok = false;
+ return nullptr;
}
}
- Consume(Token::RBRACE);
+ block_state.set_end_position(scanner()->location().end_pos);
+ catch_block->set_scope(block_state.FinalizedBlockScope());
}
- block_scope->set_end_position(scanner()->location().end_pos);
- block_scope = block_scope->FinalizeBlockScope();
- catch_block->set_scope(block_scope);
}
catch_scope->set_end_position(scanner()->location().end_pos);
@@ -3011,10 +2955,18 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
if (catch_block != NULL && finally_block != NULL) {
// If we have both, create an inner try/catch.
DCHECK(catch_scope != NULL && catch_variable != NULL);
- TryCatchStatement* statement =
- factory()->NewTryCatchStatement(try_block, catch_scope, catch_variable,
- catch_block, RelocInfo::kNoPosition);
- try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
+ TryCatchStatement* statement;
+ if (catch_for_promise_reject) {
+ statement = factory()->NewTryCatchStatementForPromiseReject(
+ try_block, catch_scope, catch_variable, catch_block,
+ kNoSourcePosition);
+ } else {
+ statement = factory()->NewTryCatchStatement(try_block, catch_scope,
+ catch_variable, catch_block,
+ kNoSourcePosition);
+ }
+
+ try_block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition);
try_block->statements()->Add(statement, zone());
catch_block = NULL; // Clear to indicate it's been handled.
}
@@ -3023,14 +2975,23 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
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);
}
@@ -3091,9 +3052,9 @@ WhileStatement* Parser::ParseWhileStatement(
Expression* Parser::BuildIteratorNextResult(Expression* iterator,
Variable* result, int pos) {
Expression* next_literal = factory()->NewStringLiteral(
- ast_value_factory()->next_string(), RelocInfo::kNoPosition);
+ ast_value_factory()->next_string(), kNoSourcePosition);
Expression* next_property =
- factory()->NewProperty(iterator, next_literal, RelocInfo::kNoPosition);
+ factory()->NewProperty(iterator, next_literal, kNoSourcePosition);
ZoneList<Expression*>* next_arguments =
new (zone()) ZoneList<Expression*>(0, zone());
Expression* next_call =
@@ -3123,97 +3084,159 @@ Expression* Parser::BuildIteratorNextResult(Expression* iterator,
throw_call, pos);
}
-void Parser::InitializeForEachStatement(ForEachStatement* stmt,
- Expression* each, Expression* subject,
- Statement* body) {
+Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt,
+ Expression* each,
+ Expression* subject,
+ Statement* body,
+ int each_keyword_pos) {
ForOfStatement* for_of = stmt->AsForOfStatement();
if (for_of != NULL) {
- InitializeForOfStatement(for_of, each, subject, body,
- RelocInfo::kNoPosition);
+ const bool finalize = true;
+ return InitializeForOfStatement(for_of, each, subject, body, finalize,
+ each_keyword_pos);
} else {
if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
- Variable* temp =
- scope_->NewTemporary(ast_value_factory()->empty_string());
+ Variable* temp = NewTemporary(ast_value_factory()->empty_string());
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
Expression* assign_each = PatternRewriter::RewriteDestructuringAssignment(
this, factory()->NewAssignment(Token::ASSIGN, each, temp_proxy,
- RelocInfo::kNoPosition),
- scope_);
- auto block =
- factory()->NewBlock(nullptr, 2, false, RelocInfo::kNoPosition);
- block->statements()->Add(factory()->NewExpressionStatement(
- assign_each, RelocInfo::kNoPosition),
- zone());
+ kNoSourcePosition),
+ scope());
+ auto block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assign_each, kNoSourcePosition),
+ zone());
block->statements()->Add(body, zone());
body = block;
each = factory()->NewVariableProxy(temp);
}
- stmt->Initialize(each, subject, body);
+ stmt->AsForInStatement()->Initialize(each, subject, body);
}
+ return stmt;
}
-void Parser::InitializeForOfStatement(ForOfStatement* for_of, Expression* each,
- Expression* iterable, Statement* body,
- int iterable_pos) {
- Variable* iterator =
- scope_->NewTemporary(ast_value_factory()->dot_iterator_string());
- Variable* result =
- scope_->NewTemporary(ast_value_factory()->dot_result_string());
+Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
+ Expression* each,
+ Expression* iterable,
+ Statement* body, bool finalize,
+ int next_result_pos) {
+ // Create the auxiliary expressions needed for iterating over the iterable,
+ // and initialize the given ForOfStatement with them.
+ // If finalize is true, also instrument the loop with code that performs the
+ // proper ES6 iterator finalization. In that case, the result is not
+ // immediately a ForOfStatement.
- Expression* assign_iterator;
- Expression* next_result;
- Expression* result_done;
- Expression* assign_each;
+ const int nopos = kNoSourcePosition;
+ auto avfactory = ast_value_factory();
- // 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;
+ Variable* iterator = NewTemporary(ast_value_factory()->dot_iterator_string());
+ Variable* result = NewTemporary(ast_value_factory()->dot_result_string());
+ Variable* completion = NewTemporary(avfactory->empty_string());
// iterator = iterable[Symbol.iterator]()
- assign_iterator = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(iterator),
- GetIterator(iterable, factory(), get_iterator_pos), iterable->position());
+ Expression* assign_iterator;
+ {
+ assign_iterator = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(iterator),
+ GetIterator(iterable, factory(), iterable->position()),
+ iterable->position());
+ }
// !%_IsJSReceiver(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
+ Expression* next_result;
{
- // result = iterator.next()
Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
next_result =
BuildIteratorNextResult(iterator_proxy, result, next_result_pos);
}
// result.done
+ Expression* result_done;
{
Expression* done_literal = factory()->NewStringLiteral(
- ast_value_factory()->done_string(), RelocInfo::kNoPosition);
+ ast_value_factory()->done_string(), kNoSourcePosition);
Expression* result_proxy = factory()->NewVariableProxy(result);
- result_done = factory()->NewProperty(result_proxy, done_literal,
- RelocInfo::kNoPosition);
+ result_done =
+ factory()->NewProperty(result_proxy, done_literal, kNoSourcePosition);
}
- // each = result.value
+ // result.value
+ Expression* result_value;
{
- Expression* value_literal = factory()->NewStringLiteral(
- ast_value_factory()->value_string(), RelocInfo::kNoPosition);
+ Expression* value_literal =
+ factory()->NewStringLiteral(avfactory->value_string(), nopos);
Expression* result_proxy = factory()->NewVariableProxy(result);
- Expression* result_value = factory()->NewProperty(
- result_proxy, value_literal, RelocInfo::kNoPosition);
- assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value,
- RelocInfo::kNoPosition);
+ result_value = factory()->NewProperty(result_proxy, value_literal, nopos);
+ }
+
+ // {{completion = kAbruptCompletion;}}
+ Statement* set_completion_abrupt;
+ if (finalize) {
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ set_completion_abrupt = block;
+ }
+
+ // do { let tmp = #result_value; #set_completion_abrupt; tmp }
+ // Expression* result_value (gets overwritten)
+ if (finalize) {
+ Variable* var_tmp = NewTemporary(avfactory->empty_string());
+ Expression* tmp = factory()->NewVariableProxy(var_tmp);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, tmp, result_value, nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ block->statements()->Add(set_completion_abrupt, zone());
+
+ result_value = factory()->NewDoExpression(block, var_tmp, nopos);
+ }
+
+ // each = #result_value;
+ Expression* assign_each;
+ {
+ assign_each =
+ factory()->NewAssignment(Token::ASSIGN, each, result_value, nopos);
if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
assign_each = PatternRewriter::RewriteDestructuringAssignment(
- this, assign_each->AsAssignment(), scope_);
+ this, assign_each->AsAssignment(), scope());
}
}
- for_of->Initialize(each, iterable, body, iterator, assign_iterator,
- next_result, result_done, assign_each);
+ // {{completion = kNormalCompletion;}}
+ Statement* set_completion_normal;
+ if (finalize) {
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ set_completion_normal = block;
+ }
+
+ // { #loop-body; #set_completion_normal }
+ // Statement* body (gets overwritten)
+ if (finalize) {
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(body, zone());
+ block->statements()->Add(set_completion_normal, zone());
+ body = block;
+ }
+
+ for_of->Initialize(body, iterator, assign_iterator, next_result, result_done,
+ assign_each);
+ return finalize ? FinalizeForOfStatement(for_of, completion, nopos) : for_of;
}
Statement* Parser::DesugarLexicalBindingsInForStatement(
@@ -3260,8 +3283,8 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
DCHECK(names->length() > 0);
ZoneList<Variable*> temps(names->length(), zone());
- Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false,
- RelocInfo::kNoPosition);
+ Block* outer_block =
+ factory()->NewBlock(NULL, names->length() + 4, false, kNoSourcePosition);
// Add statement: let/const x = i.
outer_block->statements()->Add(init, zone());
@@ -3271,13 +3294,13 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// For each lexical variable x:
// make statement: temp_x = x.
for (int i = 0; i < names->length(); i++) {
- VariableProxy* proxy = NewUnresolved(names->at(i), LET);
- Variable* temp = scope_->NewTemporary(temp_name);
+ VariableProxy* proxy = NewUnresolved(names->at(i));
+ Variable* temp = NewTemporary(temp_name);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
- Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
- Statement* assignment_statement = factory()->NewExpressionStatement(
- assignment, RelocInfo::kNoPosition);
+ Assignment* assignment = factory()->NewAssignment(Token::ASSIGN, temp_proxy,
+ proxy, kNoSourcePosition);
+ Statement* assignment_statement =
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
outer_block->statements()->Add(assignment_statement, zone());
temps.Add(temp, zone());
}
@@ -3285,21 +3308,20 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
Variable* first = NULL;
// Make statement: first = 1.
if (next) {
- first = scope_->NewTemporary(temp_name);
+ first = NewTemporary(temp_name);
VariableProxy* first_proxy = factory()->NewVariableProxy(first);
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, first_proxy, const1, RelocInfo::kNoPosition);
+ Token::ASSIGN, first_proxy, const1, kNoSourcePosition);
Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
outer_block->statements()->Add(assignment_statement, zone());
}
// make statement: undefined;
outer_block->statements()->Add(
factory()->NewExpressionStatement(
- factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
+ factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition),
zone());
// Make statement: outer: for (;;)
@@ -3308,33 +3330,30 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// need to know about it. This should be safe because we don't run any code
// in this function that looks up break targets.
ForStatement* outer_loop =
- factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
+ factory()->NewForStatement(NULL, kNoSourcePosition);
outer_block->statements()->Add(outer_loop, zone());
- outer_block->set_scope(scope_);
+ outer_block->set_scope(scope());
- Block* inner_block =
- factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
+ Block* inner_block = factory()->NewBlock(NULL, 3, false, kNoSourcePosition);
{
- BlockState block_state(&scope_, inner_scope);
+ BlockState block_state(&scope_state_, inner_scope);
- Block* ignore_completion_block = factory()->NewBlock(
- NULL, names->length() + 3, true, RelocInfo::kNoPosition);
+ Block* ignore_completion_block =
+ factory()->NewBlock(NULL, names->length() + 3, true, kNoSourcePosition);
ZoneList<Variable*> inner_vars(names->length(), zone());
// For each let variable x:
// make statement: let/const x = temp_x.
for (int i = 0; i < names->length(); i++) {
- VariableProxy* proxy = NewUnresolved(names->at(i), mode);
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, mode, scope_, RelocInfo::kNoPosition);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
- inner_vars.Add(declaration->proxy()->var(), zone());
+ Declaration* decl =
+ DeclareVariable(names->at(i), mode, kNoSourcePosition, CHECK_OK);
+ inner_vars.Add(decl->proxy()->var(), zone());
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
Assignment* assignment = factory()->NewAssignment(
- Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
+ Token::INIT, decl->proxy(), temp_proxy, kNoSourcePosition);
Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
- DCHECK(init->position() != RelocInfo::kNoPosition);
- proxy->var()->set_initializer_position(init->position());
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
+ DCHECK(init->position() != kNoSourcePosition);
+ decl->proxy()->var()->set_initializer_position(init->position());
ignore_completion_block->statements()->Add(assignment_statement, zone());
}
@@ -3344,45 +3363,43 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
Expression* compare = NULL;
// Make compare expression: first == 1.
{
- Expression* const1 =
- factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
VariableProxy* first_proxy = factory()->NewVariableProxy(first);
compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
- RelocInfo::kNoPosition);
+ kNoSourcePosition);
}
Statement* clear_first = NULL;
// Make statement: first = 0.
{
VariableProxy* first_proxy = factory()->NewVariableProxy(first);
- Expression* const0 =
- factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+ Expression* const0 = factory()->NewSmiLiteral(0, kNoSourcePosition);
Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
- clear_first = factory()->NewExpressionStatement(assignment,
- RelocInfo::kNoPosition);
+ Token::ASSIGN, first_proxy, const0, kNoSourcePosition);
+ clear_first =
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
}
Statement* clear_first_or_next = factory()->NewIfStatement(
- compare, clear_first, next, RelocInfo::kNoPosition);
+ compare, clear_first, next, kNoSourcePosition);
ignore_completion_block->statements()->Add(clear_first_or_next, zone());
}
- Variable* flag = scope_->NewTemporary(temp_name);
+ Variable* flag = NewTemporary(temp_name);
// Make statement: flag = 1.
{
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
+ Token::ASSIGN, flag_proxy, const1, kNoSourcePosition);
Statement* assignment_statement =
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
ignore_completion_block->statements()->Add(assignment_statement, zone());
}
// Make statement: if (!cond) break.
if (cond) {
Statement* stop =
- factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
- Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+ factory()->NewBreakStatement(outer_loop, kNoSourcePosition);
+ Statement* noop = factory()->NewEmptyStatement(kNoSourcePosition);
ignore_completion_block->statements()->Add(
factory()->NewIfStatement(cond, noop, stop, cond->position()),
zone());
@@ -3392,10 +3409,10 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// Make cond expression for main loop: flag == 1.
Expression* flag_cond = NULL;
{
- Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
- RelocInfo::kNoPosition);
+ kNoSourcePosition);
}
// Create chain of expressions "flag = 0, temp_x = x, ..."
@@ -3405,10 +3422,9 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// Make expression: flag = 0.
{
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
- Expression* const0 =
- factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
- compound_next = factory()->NewAssignment(
- Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
+ Expression* const0 = factory()->NewSmiLiteral(0, kNoSourcePosition);
+ compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
+ const0, kNoSourcePosition);
}
// Make the comma-separated list of temp_x = x assignments.
@@ -3418,13 +3434,13 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
VariableProxy* proxy =
factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
Assignment* assignment = factory()->NewAssignment(
- Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
+ Token::ASSIGN, temp_proxy, proxy, kNoSourcePosition);
compound_next = factory()->NewBinaryOperation(
- Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+ Token::COMMA, compound_next, assignment, kNoSourcePosition);
}
- compound_next_statement = factory()->NewExpressionStatement(
- compound_next, RelocInfo::kNoPosition);
+ compound_next_statement =
+ factory()->NewExpressionStatement(compound_next, kNoSourcePosition);
}
// Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
@@ -3439,19 +3455,18 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
Expression* compare = NULL;
// Make compare expresion: flag == 1.
{
- Expression* const1 =
- factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+ Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition);
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
- RelocInfo::kNoPosition);
+ kNoSourcePosition);
}
Statement* stop =
- factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
- Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- Statement* if_flag_break = factory()->NewIfStatement(
- compare, stop, empty, RelocInfo::kNoPosition);
+ factory()->NewBreakStatement(outer_loop, kNoSourcePosition);
+ Statement* empty = factory()->NewEmptyStatement(kNoSourcePosition);
+ Statement* if_flag_break =
+ factory()->NewIfStatement(compare, stop, empty, kNoSourcePosition);
Block* ignore_completion_block =
- factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+ factory()->NewBlock(NULL, 1, true, kNoSourcePosition);
ignore_completion_block->statements()->Add(if_flag_break, zone());
inner_block->statements()->Add(ignore_completion_block, zone());
}
@@ -3475,14 +3490,13 @@ Statement* Parser::ParseScopedStatement(ZoneList<const AstRawString*>* labels,
}
// Make a block around the statement for a lexical binding
// is introduced by a FunctionDeclaration.
- Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
- BlockState block_state(&scope_, body_scope);
- Block* block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
- Statement* body = ParseFunctionDeclaration(NULL, CHECK_OK);
+ BlockState block_state(&scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
+ Block* block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition);
+ Statement* body = ParseFunctionDeclaration(CHECK_OK);
block->statements()->Add(body, zone());
- body_scope->set_end_position(scanner()->location().end_pos);
- body_scope = body_scope->FinalizeBlockScope();
- block->set_scope(body_scope);
+ block_state.set_end_position(scanner()->location().end_pos);
+ block->set_scope(block_state.FinalizedBlockScope());
return block;
}
}
@@ -3491,19 +3505,18 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
int stmt_pos = peek_position();
Statement* init = NULL;
- ZoneList<const AstRawString*> lexical_bindings(1, zone());
+ ZoneList<const AstRawString*> bound_names(1, zone());
+ bool bound_names_are_lexical = false;
// Create an in-between scope for let-bound iteration variables.
- Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
-
- BlockState block_state(&scope_, for_scope);
+ BlockState for_state(&scope_state_);
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_state.set_start_position(scanner()->location().beg_pos);
+ for_state.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);
@@ -3515,10 +3528,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
if (CheckInOrOf(&mode, ok)) {
if (!*ok) return nullptr;
if (parsing_result.declarations.length() != 1) {
- ParserTraits::ReportMessageAt(
- parsing_result.bindings_loc,
- MessageTemplate::kForInOfLoopMultiBindings,
- ForEachStatement::VisitModeString(mode));
+ ReportMessageAt(parsing_result.bindings_loc,
+ MessageTemplate::kForInOfLoopMultiBindings,
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return nullptr;
}
@@ -3527,33 +3539,38 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
if (parsing_result.first_initializer_loc.IsValid() &&
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
IsLexicalVariableMode(parsing_result.descriptor.mode) ||
- !decl.pattern->IsVariableProxy())) {
- ParserTraits::ReportMessageAt(
- parsing_result.first_initializer_loc,
- MessageTemplate::kForInOfLoopInitializer,
- ForEachStatement::VisitModeString(mode));
+ !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];
+ }
+ ReportMessageAt(parsing_result.first_initializer_loc,
+ MessageTemplate::kForInOfLoopInitializer,
+ ForEachStatement::VisitModeString(mode));
*ok = false;
return nullptr;
}
Block* init_block = nullptr;
+ bound_names_are_lexical =
+ IsLexicalVariableMode(parsing_result.descriptor.mode);
- // special case for legacy for (var/const x =.... in)
- if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
- decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
+ // special case for legacy for (var ... = ... in ...)
+ if (!bound_names_are_lexical && decl.pattern->IsVariableProxy() &&
+ decl.initializer != nullptr) {
+ DCHECK(!allow_harmony_for_in());
++use_counts_[v8::Isolate::kForInInitializer];
const AstRawString* name =
decl.pattern->AsVariableProxy()->raw_name();
- VariableProxy* single_var = scope_->NewUnresolved(
- factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos);
+ VariableProxy* single_var = NewUnresolved(name);
init_block = factory()->NewBlock(
nullptr, 2, true, parsing_result.descriptor.declaration_pos);
init_block->statements()->Add(
factory()->NewExpressionStatement(
factory()->NewAssignment(Token::ASSIGN, single_var,
- decl.initializer,
- RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
+ decl.initializer, kNoSourcePosition),
+ kNoSourcePosition),
zone());
}
@@ -3573,12 +3590,13 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// let x; // for TDZ
// }
- Variable* temp =
- scope_->NewTemporary(ast_value_factory()->dot_for_string());
+ Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());
ForEachStatement* loop =
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);
@@ -3590,72 +3608,95 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::RPAREN, CHECK_OK);
- Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
- body_scope->set_start_position(scanner()->location().beg_pos);
Block* body_block =
- factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
+ factory()->NewBlock(NULL, 3, false, kNoSourcePosition);
+ Statement* final_loop;
{
- DontCollectExpressionsInTailPositionScope no_tail_calls(
- function_state_);
- BlockState block_state(&scope_, body_scope);
+ ReturnExprScope no_tail_calls(function_state_,
+ ReturnExprContext::kInsideForInOfBody);
+ BlockState block_state(&scope_state_);
+ block_state.set_start_position(scanner()->location().beg_pos);
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
auto each_initialization_block =
- factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+ factory()->NewBlock(nullptr, 1, true, kNoSourcePosition);
{
auto descriptor = parsing_result.descriptor;
- descriptor.declaration_pos = RelocInfo::kNoPosition;
- descriptor.initialization_pos = RelocInfo::kNoPosition;
+ descriptor.declaration_pos = kNoSourcePosition;
+ descriptor.initialization_pos = kNoSourcePosition;
decl.initializer = factory()->NewVariableProxy(temp);
+ bool is_for_var_of =
+ mode == ForEachStatement::ITERATE &&
+ parsing_result.descriptor.mode == VariableMode::VAR;
+
PatternRewriter::DeclareAndInitializeVariables(
each_initialization_block, &descriptor, &decl,
- IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
- : nullptr,
+ bound_names_are_lexical || is_for_var_of ? &bound_names
+ : nullptr,
CHECK_OK);
+
+ // Annex B.3.5 prohibits the form
+ // `try {} catch(e) { for (var e of {}); }`
+ // So if we are parsing a statement like `for (var ... of ...)`
+ // we need to walk up the scope chain and look for catch scopes
+ // which have a simple binding, then compare their binding against
+ // all of the names declared in the init of the for-of we're
+ // parsing.
+ if (is_for_var_of) {
+ Scope* catch_scope = scope();
+ while (catch_scope != nullptr &&
+ !catch_scope->is_declaration_scope()) {
+ if (catch_scope->is_catch_scope()) {
+ auto name = catch_scope->catch_variable_name();
+ if (name !=
+ ast_value_factory()
+ ->dot_catch_string()) { // i.e. is a simple binding
+ if (bound_names.Contains(name)) {
+ ReportMessageAt(parsing_result.bindings_loc,
+ MessageTemplate::kVarRedeclaration, name);
+ *ok = false;
+ return nullptr;
+ }
+ }
+ }
+ catch_scope = catch_scope->outer_scope();
+ }
+ }
}
body_block->statements()->Add(each_initialization_block, zone());
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);
+ final_loop = InitializeForEachStatement(
+ loop, temp_proxy, enumerable, body_block, each_keyword_position);
+ block_state.set_end_position(scanner()->location().end_pos);
+ body_block->set_scope(block_state.FinalizedBlockScope());
}
- body_scope->set_end_position(scanner()->location().end_pos);
- body_scope = body_scope->FinalizeBlockScope();
- body_block->set_scope(body_scope);
// Create a TDZ for any lexically-bound names.
- if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
+ if (bound_names_are_lexical) {
DCHECK_NULL(init_block);
init_block =
- factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
+ factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
- for (int i = 0; i < lexical_bindings.length(); ++i) {
+ for (int i = 0; i < bound_names.length(); ++i) {
// TODO(adamk): This needs to be some sort of special
// INTERNAL variable that's invisible to the debugger
// but visible to everything else.
- VariableProxy* tdz_proxy =
- NewUnresolved(lexical_bindings[i], LET);
- Declaration* tdz_decl = factory()->NewVariableDeclaration(
- tdz_proxy, LET, scope_, RelocInfo::kNoPosition);
- Variable* tdz_var = Declare(
- tdz_decl, DeclarationDescriptor::NORMAL, true, CHECK_OK);
- tdz_var->set_initializer_position(position());
+ Declaration* tdz_decl = DeclareVariable(
+ bound_names[i], LET, kNoSourcePosition, CHECK_OK);
+ tdz_decl->proxy()->var()->set_initializer_position(position());
}
}
- Statement* final_loop = loop->IsForOfStatement()
- ? FinalizeForOfStatement(
- loop->AsForOfStatement(), RelocInfo::kNoPosition)
- : loop;
-
- for_scope->set_end_position(scanner()->location().end_pos);
- for_scope = for_scope->FinalizeBlockScope();
+ for_state.set_end_position(scanner()->location().end_pos);
+ Scope* for_scope = for_state.FinalizedBlockScope();
// Parsed for-in loop w/ variable declarations.
if (init_block != nullptr) {
init_block->statements()->Add(final_loop, zone());
@@ -3666,11 +3707,10 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
return final_loop;
}
} else {
+ bound_names_are_lexical =
+ IsLexicalVariableMode(parsing_result.descriptor.mode);
init = parsing_result.BuildInitializationBlock(
- IsLexicalVariableMode(parsing_result.descriptor.mode)
- ? &lexical_bindings
- : nullptr,
- CHECK_OK);
+ bound_names_are_lexical ? &bound_names : nullptr, CHECK_OK);
}
} else {
int lhs_beg_pos = peek_position();
@@ -3678,13 +3718,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
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;
+ bool is_for_each = CheckInOrOf(&mode, CHECK_OK);
bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
expression->IsObjectLiteral());
@@ -3705,6 +3740,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
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,16 +3756,10 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// 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);
+ Statement* final_loop = InitializeForEachStatement(
+ loop, expression, enumerable, body, each_keyword_position);
- Statement* final_loop = loop->IsForOfStatement()
- ? FinalizeForOfStatement(
- loop->AsForOfStatement(), RelocInfo::kNoPosition)
- : loop;
-
- for_scope->set_end_position(scanner()->location().end_pos);
- for_scope = for_scope->FinalizeBlockScope();
- DCHECK(for_scope == nullptr);
+ DCHECK_NULL(for_state.FinalizedBlockScope());
return final_loop;
} else {
@@ -3742,13 +3773,6 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
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;
@@ -3757,13 +3781,14 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// 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 (lexical_bindings.length() > 0) {
- inner_scope = NewScope(for_scope, BLOCK_SCOPE);
+ Scope* inner_scope = scope();
+ // TODO(verwaest): Allocate this through a ScopeState as well.
+ if (bound_names_are_lexical && bound_names.length() > 0) {
+ inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
inner_scope->set_start_position(scanner()->location().beg_pos);
}
{
- BlockState block_state(&scope_, inner_scope);
+ BlockState block_state(&scope_state_, inner_scope);
if (peek() != Token::SEMICOLON) {
cond = ParseExpression(true, CHECK_OK);
@@ -3780,15 +3805,14 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
}
Statement* result = NULL;
- if (lexical_bindings.length() > 0) {
- BlockState block_state(&scope_, for_scope);
+ if (bound_names_are_lexical && bound_names.length() > 0) {
result = DesugarLexicalBindingsInForStatement(
- inner_scope, parsing_result.descriptor.mode, &lexical_bindings, loop,
- init, cond, next, body, CHECK_OK);
- for_scope->set_end_position(scanner()->location().end_pos);
+ inner_scope, parsing_result.descriptor.mode, &bound_names, loop, init,
+ cond, next, body, CHECK_OK);
+ for_state.set_end_position(scanner()->location().end_pos);
} else {
- for_scope->set_end_position(scanner()->location().end_pos);
- for_scope = for_scope->FinalizeBlockScope();
+ for_state.set_end_position(scanner()->location().end_pos);
+ Scope* for_scope = for_state.FinalizedBlockScope();
if (for_scope) {
// Rewrite a for statement of the form
// for (const x = i; c; n) b
@@ -3808,8 +3832,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// }
// just in case b introduces a lexical binding some other way, e.g., if b
// is a FunctionDeclaration.
- Block* block =
- factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
+ Block* block = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
if (init != nullptr) {
block->statements()->Add(init, zone());
}
@@ -3882,16 +3905,9 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
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;
- }
-
+void Parser::ParseArrowFunctionFormalParameters(
+ ParserFormalParameters* parameters, Expression* expr, int end_pos,
+ bool* ok) {
// ArrowFunctionFormals ::
// Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail)
// Tail
@@ -3912,8 +3928,9 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
DCHECK_EQ(binop->op(), Token::COMMA);
Expression* left = binop->left();
Expression* right = binop->right();
- ParseArrowFunctionFormalParameters(parameters, left, params_loc, ok);
- if (!*ok) return;
+ int comma_pos = binop->position();
+ ParseArrowFunctionFormalParameters(parameters, left, comma_pos,
+ CHECK_OK_VOID);
// LHS of comma expression should be unparenthesized.
expr = right;
}
@@ -3931,31 +3948,63 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
}
Expression* initializer = nullptr;
- if (expr->IsVariableProxy()) {
- // When the formal parameter was originally seen, it was parsed as a
- // VariableProxy and recorded as unresolved in the scope. Here we undo that
- // parse-time side-effect for parameters that are single-names (not
- // patterns; for patterns that happens uniformly in
- // PatternRewriter::VisitVariableProxy).
- parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
- } else if (expr->IsAssignment()) {
+ if (expr->IsAssignment()) {
Assignment* assignment = expr->AsAssignment();
DCHECK(!assignment->is_compound());
initializer = assignment->value();
expr = assignment->target();
-
- // TODO(adamk): Only call this if necessary.
- RewriteParameterInitializerScope(parser_->stack_limit(), initializer,
- 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 Parser::DesugarAsyncFunctionBody(const AstRawString* function_name,
+ Scope* scope, ZoneList<Statement*>* body,
+ ExpressionClassifier* classifier,
+ FunctionKind kind,
+ FunctionBodyType 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 =
+ 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), kNoSourcePosition);
+ body->Add(factory()->NewExpressionStatement(init_generator_variable,
+ kNoSourcePosition),
+ zone());
+
+ Block* try_block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition);
+
+ ZoneList<Statement*>* inner_body = try_block->statements();
+
+ Expression* return_value = nullptr;
+ if (body_type == FunctionBodyType::kNormal) {
+ ParseStatementList(inner_body, Token::RBRACE, CHECK_OK_VOID);
+ return_value = factory()->NewUndefinedLiteral(kNoSourcePosition);
+ } else {
+ return_value =
+ ParseAssignmentExpression(accept_IN, classifier, CHECK_OK_VOID);
+ RewriteNonPattern(classifier, CHECK_OK_VOID);
+ }
+
+ 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 ::
@@ -3963,29 +4012,34 @@ DoExpression* Parser::ParseDoExpression(bool* ok) {
int pos = peek_position();
Expect(Token::DO, CHECK_OK);
- Variable* result =
- scope_->NewTemporary(ast_value_factory()->dot_result_string());
- Block* block = ParseBlock(nullptr, false, CHECK_OK);
+ Variable* result = NewTemporary(ast_value_factory()->dot_result_string());
+ Block* block = ParseBlock(nullptr, CHECK_OK);
DoExpression* expr = factory()->NewDoExpression(block, result, pos);
- if (!Rewriter::Rewrite(this, expr, ast_value_factory())) {
+ if (!Rewriter::Rewrite(this, GetClosureScope(), expr, ast_value_factory())) {
*ok = false;
return nullptr;
}
- block->set_scope(block->scope()->FinalizeBlockScope());
return expr;
}
-
-void ParserTraits::ParseArrowFunctionFormalParameterList(
+void ParserBaseTraits<Parser>::ParseArrowFunctionFormalParameterList(
ParserFormalParameters* parameters, Expression* expr,
- const Scanner::Location& params_loc,
- Scanner::Location* duplicate_loc, bool* ok) {
+ const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
+ const Scope::Snapshot& scope_snapshot, bool* ok) {
if (expr->IsEmptyParentheses()) return;
- ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
- if (!*ok) return;
+ delegate()->ParseArrowFunctionFormalParameters(
+ parameters, expr, params_loc.end_pos, CHECK_OK_VOID);
- Type::ExpressionClassifier classifier(parser_);
+ scope_snapshot.Reparent(parameters->scope);
+
+ if (parameters->Arity() > Code::kMaxArguments) {
+ ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
+ *ok = false;
+ return;
+ }
+
+ Type::ExpressionClassifier classifier(delegate());
if (!parameters->is_simple) {
classifier.RecordNonSimpleParameter();
}
@@ -3999,9 +4053,9 @@ void ParserTraits::ParseArrowFunctionFormalParameterList(
DCHECK_EQ(parameters->is_simple, parameters->scope->has_simple_parameters());
}
-
-void ParserTraits::ReindexLiterals(const ParserFormalParameters& parameters) {
- if (parser_->function_state_->materialized_literal_count() > 0) {
+void ParserBaseTraits<Parser>::ReindexLiterals(
+ const ParserFormalParameters& parameters) {
+ if (delegate()->function_state_->materialized_literal_count() > 0) {
AstLiteralReindexer reindexer;
for (const auto p : parameters.params) {
@@ -4010,7 +4064,7 @@ void ParserTraits::ReindexLiterals(const ParserFormalParameters& parameters) {
}
DCHECK(reindexer.count() <=
- parser_->function_state_->materialized_literal_count());
+ delegate()->function_state_->materialized_literal_count());
}
}
@@ -4029,8 +4083,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Setter ::
// '(' PropertySetParameterList ')' '{' FunctionBody '}'
- int pos = function_token_pos == RelocInfo::kNoPosition
- ? peek_position() : function_token_pos;
+ int pos = function_token_pos == kNoSourcePosition ? peek_position()
+ : function_token_pos;
bool is_generator = IsGeneratorFunction(kind);
@@ -4044,59 +4098,111 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
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);
- SetLanguageMode(scope, language_mode);
- ZoneList<Statement*>* body = NULL;
+ FunctionLiteral::EagerCompileHint eager_compile_hint =
+ function_state_->next_function_is_parenthesized()
+ ? FunctionLiteral::kShouldEagerCompile
+ : FunctionLiteral::kShouldLazyCompile;
+
+ // Determine if the function can be parsed lazily. Lazy parsing is
+ // different from lazy compilation; we need to parse more eagerly than we
+ // compile.
+
+ // We can only parse lazily if we also compile lazily. The heuristics for lazy
+ // compilation are:
+ // - It must not have been prohibited by the caller to Parse (some callers
+ // need a full AST).
+ // - The outer scope must allow lazy compilation of inner functions.
+ // - The function mustn't be a function expression with an open parenthesis
+ // before; we consider that a hint that the function will be called
+ // immediately, and it would be a waste of time to make it lazily
+ // compiled.
+ // These are all things we can know at this point, without looking at the
+ // function itself.
+
+ // In addition, we need to distinguish between these cases:
+ // (function foo() {
+ // bar = function() { return 1; }
+ // })();
+ // and
+ // (function foo() {
+ // var a = 1;
+ // bar = function() { return a; }
+ // })();
+
+ // Now foo will be parsed eagerly and compiled eagerly (optimization: assume
+ // parenthesis before the function means that it will be called
+ // immediately). The inner function *must* be parsed eagerly to resolve the
+ // possible reference to the variable in foo's scope. However, it's possible
+ // that it will be compiled lazily.
+
+ // To make this additional case work, both Parser and PreParser implement a
+ // logic where only top-level functions will be parsed lazily.
+ bool is_lazily_parsed = mode() == PARSE_LAZILY &&
+ this->scope()->AllowsLazyParsing() &&
+ !function_state_->next_function_is_parenthesized();
+
+ // Determine whether the function body can be discarded after parsing.
+ // The preconditions are:
+ // - Lazy compilation has to be enabled.
+ // - Neither V8 natives nor native function declarations can be allowed,
+ // since parsing one would retroactively force the function to be
+ // eagerly compiled.
+ // - The invoker of this parser can't depend on the AST being eagerly
+ // built (either because the function is about to be compiled, or
+ // because the AST is going to be inspected for some reason).
+ // - Because of the above, we can't be attempting to parse a
+ // 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 =
+ !is_lazily_parsed && FLAG_lazy && !allow_natives() &&
+ extension_ == NULL && allow_lazy() &&
+ function_type == FunctionLiteral::kDeclaration &&
+ eager_compile_hint != FunctionLiteral::kShouldEagerCompile &&
+ !(FLAG_validate_asm && scope()->IsAsmModule());
+
+ DeclarationScope* main_scope = nullptr;
+ if (use_temp_zone) {
+ // This Scope lives in the main Zone; we'll migrate data into it later.
+ main_scope = NewFunctionScope(kind);
+ }
+
+ ZoneList<Statement*>* body = nullptr;
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;
- // Parse function.
+
{
- AstNodeFactory function_factory(ast_value_factory());
- FunctionState function_state(&function_state_, &scope_, scope, kind,
- &function_factory);
- scope_->SetScopeName(function_name);
+ // Temporary zones can nest. When we migrate free variables (see below), we
+ // need to recreate them in the previous Zone.
+ AstNodeFactory previous_zone_ast_node_factory(ast_value_factory());
+ previous_zone_ast_node_factory.set_zone(zone());
+
+ // Open a new zone scope, 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. To be able
+ // to do scope analysis correctly after full parsing, we migrate needed
+ // information from scope into main_scope when the function has been parsed.
+ Zone temp_zone(zone()->allocator());
+ DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone);
+
+ DeclarationScope* scope = NewFunctionScope(kind);
+ SetLanguageMode(scope, language_mode);
+ if (!use_temp_zone) {
+ main_scope = scope;
+ } else {
+ DCHECK(main_scope->zone() != scope->zone());
+ }
+
+ FunctionState function_state(&function_state_, &scope_state_, scope, kind);
+#ifdef DEBUG
+ scope->SetScopeName(function_name);
+#endif
ExpressionClassifier formals_classifier(this, &duplicate_finder);
if (is_generator) {
@@ -4104,19 +4210,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// because it minimizes the work needed to suspend and resume an
// activation. The machine code produced for generators (by full-codegen)
// relies on this forced context allocation, but not in an essential way.
- scope_->ForceContextAllocation();
+ this->scope()->ForceContextAllocation();
// Calling a generator returns a generator object. That object is stored
// in a temporary variable, a definition that is used by "yield"
// expressions. This also marks the FunctionState as a generator.
- Variable* temp = scope_->NewTemporary(
- ast_value_factory()->dot_generator_object_string());
+ Variable* temp =
+ NewTemporary(ast_value_factory()->dot_generator_object_string());
function_state.set_generator_object_variable(temp);
}
Expect(Token::LPAREN, CHECK_OK);
int start_position = scanner()->location().beg_pos;
- scope_->set_start_position(start_position);
+ this->scope()->set_start_position(start_position);
ParserFormalParameters formals(scope);
ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
arity = formals.Arity();
@@ -4126,50 +4232,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
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).
if (formals.has_rest) arity--;
- // Determine if the function can be parsed lazily. Lazy parsing is different
- // from lazy compilation; we need to parse more eagerly than we compile.
-
- // We can only parse lazily if we also compile lazily. The heuristics for
- // lazy compilation are:
- // - It must not have been prohibited by the caller to Parse (some callers
- // need a full AST).
- // - The outer scope must allow lazy compilation of inner functions.
- // - The function mustn't be a function expression with an open parenthesis
- // before; we consider that a hint that the function will be called
- // immediately, and it would be a waste of time to make it lazily
- // compiled.
- // These are all things we can know at this point, without looking at the
- // function itself.
-
- // In addition, we need to distinguish between these cases:
- // (function foo() {
- // bar = function() { return 1; }
- // })();
- // and
- // (function foo() {
- // var a = 1;
- // bar = function() { return a; }
- // })();
-
- // Now foo will be parsed eagerly and compiled eagerly (optimization: assume
- // parenthesis before the function means that it will be called
- // immediately). The inner function *must* be parsed eagerly to resolve the
- // possible reference to the variable in foo's scope. However, it's possible
- // that it will be compiled lazily.
-
- // To make this additional case work, both Parser and PreParser implement a
- // 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.
-
// Eager or lazy parse?
// If is_lazily_parsed, we'll parse lazy. If we can set a bookmark, we'll
// pass it to SkipLazyFunctionBody, which may use it to abort lazy
@@ -4198,43 +4265,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
}
if (!is_lazily_parsed) {
- // Determine whether the function body can be discarded after parsing.
- // The preconditions are:
- // - Lazy compilation has to be enabled.
- // - Neither V8 natives nor native function declarations can be allowed,
- // since parsing one would retroactively force the function to be
- // eagerly compiled.
- // - The invoker of this parser can't depend on the AST being eagerly
- // built (either because the function is about to be compiled, or
- // because the AST is going to be inspected for some reason).
- // - Because of the above, we can't be attempting to parse a
- // FunctionExpression; even without enclosing parentheses it might be
- // immediately invoked.
- // - The function literal shouldn't be hinted to eagerly compile.
- bool use_temp_zone =
- FLAG_lazy && !allow_natives() && extension_ == NULL && allow_lazy() &&
- function_type == FunctionLiteral::kDeclaration &&
- eager_compile_hint != FunctionLiteral::kShouldEagerCompile;
- // 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.
- // For the purpose of scope analysis, some ZoneObjects allocated by the
- // factory must persist after the function body is thrown away and
- // temp_zone is deallocated. These objects are instead allocated in a
- // parser-persistent zone (see parser_zone_ in AstNodeFactory).
- {
- Zone temp_zone(zone()->allocator());
- AstNodeFactory::BodyScope inner(factory(), &temp_zone, use_temp_zone);
+ body = ParseEagerFunctionBody(function_name, pos, formals, kind,
+ function_type, CHECK_OK);
- body = ParseEagerFunctionBody(function_name, pos, formals, kind,
- function_type, CHECK_OK);
- }
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
if (use_temp_zone) {
// If the preconditions are correct the function body should never be
// accessed, but do this anyway for better behaviour if they're wrong.
- body = NULL;
+ body = nullptr;
}
}
@@ -4253,26 +4292,31 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (is_strict(language_mode)) {
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
CHECK_OK);
- }
- if (is_sloppy(language_mode) && allow_harmony_sloppy_function()) {
- InsertSloppyBlockFunctionVarBindings(scope, CHECK_OK);
+ CheckDecimalLiteralWithLeadingZero(use_counts_, scope->start_position(),
+ scope->end_position());
}
CheckConflictingVarDeclarations(scope, CHECK_OK);
if (body) {
// If body can be inspected, rewrite queued destructuring assignments
- ParserTraits::RewriteDestructuringAssignments();
+ RewriteDestructuringAssignments();
}
has_duplicate_parameters =
!formals_classifier.is_valid_formal_parameter_list_without_duplicates();
- }
+
+ if (use_temp_zone) {
+ DCHECK(main_scope != scope);
+ scope->AnalyzePartially(main_scope, &previous_zone_ast_node_factory);
+ }
+ } // DiscardableZoneScope goes out of scope.
FunctionLiteral::ParameterFlag duplicate_parameters =
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
: FunctionLiteral::kNoDuplicateParameters;
+ // Note that the FunctionLiteral needs to be created in the main Zone again.
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
- function_name, scope, body, materialized_literal_count,
+ function_name, main_scope, body, materialized_literal_count,
expected_property_count, arity, duplicate_parameters, function_type,
eager_compile_hint, kind, pos);
function_literal->set_function_token_position(function_token_pos);
@@ -4283,6 +4327,31 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
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(FunctionKind::kAsyncFunction,
+ &is_strict_reserved, CHECK_OK);
+ }
+ 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,
@@ -4291,6 +4360,8 @@ void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
if (produce_cached_parse_data()) CHECK(log_);
int function_block_pos = position();
+ DeclarationScope* scope = this->scope()->AsDeclarationScope();
+ DCHECK(scope->is_function_scope());
if (consume_cached_parse_data() && !cached_parse_data_->rejected()) {
// If we have cached data, we use it to skip parsing the function body. The
// data contains the information we need to construct the lazy function.
@@ -4302,17 +4373,14 @@ void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
if (entry.is_valid() && entry.end_pos() > function_block_pos) {
scanner()->SeekForward(entry.end_pos() - 1);
- scope_->set_end_position(entry.end_pos());
- Expect(Token::RBRACE, ok);
- if (!*ok) {
- return;
- }
- total_preparse_skipped_ += scope_->end_position() - function_block_pos;
+ scope->set_end_position(entry.end_pos());
+ Expect(Token::RBRACE, CHECK_OK_VOID);
+ total_preparse_skipped_ += scope->end_position() - function_block_pos;
*materialized_literal_count = entry.literal_count();
*expected_property_count = entry.property_count();
- SetLanguageMode(scope_, entry.language_mode());
- if (entry.uses_super_property()) scope_->RecordSuperPropertyUsage();
- if (entry.calls_eval()) scope_->RecordEvalCall();
+ SetLanguageMode(scope, entry.language_mode());
+ if (entry.uses_super_property()) scope->RecordSuperPropertyUsage();
+ if (entry.calls_eval()) scope->RecordEvalCall();
return;
}
cached_parse_data_->Reject();
@@ -4332,34 +4400,27 @@ void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
return;
}
if (logger.has_error()) {
- ParserTraits::ReportMessageAt(
- Scanner::Location(logger.start(), logger.end()), logger.message(),
- logger.argument_opt(), logger.error_type());
+ ReportMessageAt(Scanner::Location(logger.start(), logger.end()),
+ logger.message(), logger.argument_opt(),
+ logger.error_type());
*ok = false;
return;
}
- scope_->set_end_position(logger.end());
- Expect(Token::RBRACE, ok);
- if (!*ok) {
- return;
- }
- total_preparse_skipped_ += scope_->end_position() - function_block_pos;
+ scope->set_end_position(logger.end());
+ Expect(Token::RBRACE, CHECK_OK_VOID);
+ total_preparse_skipped_ += scope->end_position() - function_block_pos;
*materialized_literal_count = logger.literals();
*expected_property_count = logger.properties();
- SetLanguageMode(scope_, logger.language_mode());
- if (logger.uses_super_property()) {
- scope_->RecordSuperPropertyUsage();
- }
- if (logger.calls_eval()) {
- scope_->RecordEvalCall();
- }
+ SetLanguageMode(scope, logger.language_mode());
+ if (logger.uses_super_property()) scope->RecordSuperPropertyUsage();
+ if (logger.calls_eval()) scope->RecordEvalCall();
if (produce_cached_parse_data()) {
DCHECK(log_);
// Position right after terminal '}'.
int body_end = scanner()->location().end_pos;
log_->LogFunction(function_block_pos, body_end, *materialized_literal_count,
- *expected_property_count, scope_->language_mode(),
- scope_->uses_super_property(), scope_->calls_eval());
+ *expected_property_count, language_mode(),
+ scope->uses_super_property(), scope->calls_eval());
}
}
@@ -4369,49 +4430,50 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var) {
// throw /* type error kNonCoercible) */;
Expression* condition = factory()->NewBinaryOperation(
- Token::OR, factory()->NewCompareOperation(
- Token::EQ_STRICT, factory()->NewVariableProxy(var),
- factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
+ Token::OR,
factory()->NewCompareOperation(
Token::EQ_STRICT, factory()->NewVariableProxy(var),
- factory()->NewNullLiteral(RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
- RelocInfo::kNoPosition);
+ factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition),
+ factory()->NewCompareOperation(
+ Token::EQ_STRICT, factory()->NewVariableProxy(var),
+ factory()->NewNullLiteral(kNoSourcePosition), kNoSourcePosition),
+ kNoSourcePosition);
Expression* throw_type_error = this->NewThrowTypeError(
MessageTemplate::kNonCoercible, ast_value_factory()->empty_string(),
- RelocInfo::kNoPosition);
+ kNoSourcePosition);
IfStatement* if_statement = factory()->NewIfStatement(
- condition, factory()->NewExpressionStatement(throw_type_error,
- RelocInfo::kNoPosition),
- factory()->NewEmptyStatement(RelocInfo::kNoPosition),
- RelocInfo::kNoPosition);
+ condition,
+ factory()->NewExpressionStatement(throw_type_error, kNoSourcePosition),
+ factory()->NewEmptyStatement(kNoSourcePosition), kNoSourcePosition);
return if_statement;
}
-class InitializerRewriter : public AstExpressionVisitor {
+class InitializerRewriter final
+ : public AstTraversalVisitor<InitializerRewriter> {
public:
InitializerRewriter(uintptr_t stack_limit, Expression* root, Parser* parser,
Scope* scope)
- : AstExpressionVisitor(stack_limit, root),
+ : AstTraversalVisitor(stack_limit, root),
parser_(parser),
scope_(scope) {}
private:
- void VisitExpression(Expression* expr) override {
- RewritableExpression* to_rewrite = expr->AsRewritableExpression();
- if (to_rewrite == nullptr || to_rewrite->is_rewritten()) return;
+ // This is required so that the overriden Visit* methods can be
+ // called by the base class (template).
+ friend class AstTraversalVisitor<InitializerRewriter>;
+ // Just rewrite destructuring assignments wrapped in RewritableExpressions.
+ void VisitRewritableExpression(RewritableExpression* to_rewrite) {
+ if (to_rewrite->is_rewritten()) return;
Parser::PatternRewriter::RewriteDestructuringAssignment(parser_, to_rewrite,
scope_);
}
// Code in function literals does not need to be eagerly rewritten, it will be
// rewritten when scheduled.
- void VisitFunctionLiteral(FunctionLiteral* expr) override {}
+ void VisitFunctionLiteral(FunctionLiteral* expr) {}
- private:
Parser* parser_;
Scope* scope_;
};
@@ -4426,23 +4488,22 @@ void Parser::RewriteParameterInitializer(Expression* expr, Scope* scope) {
Block* Parser::BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok) {
DCHECK(!parameters.is_simple);
- DCHECK(scope_->is_function_scope());
- Block* init_block =
- factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+ DCHECK(scope()->is_function_scope());
+ Block* init_block = factory()->NewBlock(NULL, 1, true, kNoSourcePosition);
for (int i = 0; i < parameters.params.length(); ++i) {
auto parameter = parameters.params[i];
if (parameter.is_rest && parameter.pattern->IsVariableProxy()) break;
DeclarationDescriptor descriptor;
descriptor.declaration_kind = DeclarationDescriptor::PARAMETER;
descriptor.parser = this;
- descriptor.scope = scope_;
+ descriptor.scope = scope();
descriptor.hoist_scope = nullptr;
descriptor.mode = LET;
descriptor.declaration_pos = parameter.pattern->position();
// The position that will be used by the AssignmentExpression
// which copies from the temp parameter to the pattern.
//
- // TODO(adamk): Should this be RelocInfo::kNoPosition, since
+ // TODO(adamk): Should this be kNoSourcePosition, since
// it's just copying from a temp var to the real param var?
descriptor.initialization_pos = parameter.pattern->position();
// The initializer position which will end up in,
@@ -4454,43 +4515,44 @@ Block* Parser::BuildParameterInitializationBlock(
// IS_UNDEFINED($param) ? initializer : $param
// Ensure initializer is rewritten
- RewriteParameterInitializer(parameter.initializer, scope_);
+ RewriteParameterInitializer(parameter.initializer, scope());
auto condition = factory()->NewCompareOperation(
Token::EQ_STRICT,
factory()->NewVariableProxy(parameters.scope->parameter(i)),
- factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
- RelocInfo::kNoPosition);
+ factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
initial_value = factory()->NewConditional(
- condition, parameter.initializer, initial_value,
- RelocInfo::kNoPosition);
+ condition, parameter.initializer, initial_value, kNoSourcePosition);
descriptor.initialization_pos = parameter.initializer->position();
initializer_position = parameter.initializer_end_position;
}
- Scope* param_scope = scope_;
+ Scope* param_scope = scope();
Block* param_block = init_block;
- 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);
+ if (!parameter.is_simple() && scope()->calls_sloppy_eval()) {
+ param_scope = NewVarblockScope();
+ 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 = factory()->NewBlock(NULL, 8, true, kNoSourcePosition);
param_block->set_scope(param_scope);
- descriptor.hoist_scope = 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
+ ReparentParameterExpressionScope(stack_limit(), initial_value,
+ param_scope);
}
- {
- BlockState block_state(&scope_, param_scope);
- DeclarationParsingResult::Declaration decl(
- parameter.pattern, initializer_position, initial_value);
- PatternRewriter::DeclareAndInitializeVariables(param_block, &descriptor,
- &decl, nullptr, CHECK_OK);
- }
+ BlockState block_state(&scope_state_, param_scope);
+ DeclarationParsingResult::Declaration decl(
+ parameter.pattern, initializer_position, initial_value);
+ PatternRewriter::DeclareAndInitializeVariables(param_block, &descriptor,
+ &decl, nullptr, CHECK_OK);
- if (!parameter.is_simple() && scope_->calls_sloppy_eval()) {
- param_scope = param_scope->FinalizeBlockScope();
+ if (param_block != init_block) {
+ param_scope = block_state.FinalizedBlockScope();
if (param_scope != nullptr) {
CheckConflictingVarDeclarations(param_scope, CHECK_OK);
}
@@ -4500,6 +4562,54 @@ Block* Parser::BuildParameterInitializationBlock(
return init_block;
}
+Block* Parser::BuildRejectPromiseOnException(Block* block) {
+ // try { <block> } catch (error) { return Promise.reject(error); }
+ Block* try_block = block;
+ Scope* catch_scope = NewScope(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, kNoSourcePosition);
+
+ Expression* promise_reject = BuildPromiseReject(
+ factory()->NewVariableProxy(catch_variable), kNoSourcePosition);
+
+ ReturnStatement* return_promise_reject =
+ factory()->NewReturnStatement(promise_reject, kNoSourcePosition);
+ catch_block->statements()->Add(return_promise_reject, zone());
+ TryStatement* try_catch_statement = factory()->NewTryCatchStatement(
+ try_block, catch_scope, catch_variable, catch_block, kNoSourcePosition);
+
+ block = factory()->NewBlock(nullptr, 1, true, kNoSourcePosition);
+ 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(kNoSourcePosition),
+ 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,
@@ -4523,25 +4633,25 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
}
ZoneList<Statement*>* body = result;
- Scope* inner_scope = scope_;
+ DeclarationScope* function_scope = scope()->AsDeclarationScope();
+ DeclarationScope* inner_scope = function_scope;
Block* inner_block = nullptr;
if (!parameters.is_simple) {
- inner_scope = NewScope(scope_, BLOCK_SCOPE);
- inner_scope->set_is_declaration_scope();
+ inner_scope = NewVarblockScope();
inner_scope->set_start_position(scanner()->location().beg_pos);
- inner_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
+ inner_block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition);
inner_block->set_scope(inner_scope);
body = inner_block->statements();
}
{
- BlockState block_state(&scope_, inner_scope);
+ BlockState block_state(&scope_state_, inner_scope);
if (IsGeneratorFunction(kind)) {
// We produce:
//
// try { InitialYield; ...body...; return {value: undefined, done: true} }
- // finally { %GeneratorClose(generator) }
+ // finally { %_GeneratorClose(generator) }
//
// - InitialYield yields the actual generator object.
// - Any return statement inside the body will have its argument wrapped
@@ -4550,113 +4660,117 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
// Hence the finally clause.
Block* try_block =
- factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition);
+ factory()->NewBlock(nullptr, 3, false, kNoSourcePosition);
{
- 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(
- Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
+ Token::INIT, init_proxy, allocation, kNoSourcePosition);
VariableProxy* get_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
- Yield* yield =
- factory()->NewYield(get_proxy, assignment, RelocInfo::kNoPosition);
+ // The position of the yield is important for reporting the exception
+ // caused by calling the .throw method on a generator suspended at the
+ // initial yield (i.e. right after generator instantiation).
+ Yield* yield = factory()->NewYield(get_proxy, assignment,
+ scope()->start_position(),
+ Yield::kOnExceptionThrow);
try_block->statements()->Add(
- factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+ factory()->NewExpressionStatement(yield, kNoSourcePosition),
zone());
}
ParseStatementList(try_block->statements(), Token::RBRACE, CHECK_OK);
Statement* final_return = factory()->NewReturnStatement(
- BuildIteratorResult(nullptr, true), RelocInfo::kNoPosition);
+ BuildIteratorResult(nullptr, true), kNoSourcePosition);
try_block->statements()->Add(final_return, zone());
Block* finally_block =
- factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
+ factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(1, zone());
VariableProxy* call_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
args->Add(call_proxy, zone());
Expression* call = factory()->NewCallRuntime(
- Runtime::kGeneratorClose, args, RelocInfo::kNoPosition);
+ Runtime::kInlineGeneratorClose, args, kNoSourcePosition);
finally_block->statements()->Add(
- factory()->NewExpressionStatement(call, RelocInfo::kNoPosition),
- zone());
+ factory()->NewExpressionStatement(call, kNoSourcePosition), zone());
body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
- RelocInfo::kNoPosition),
+ kNoSourcePosition),
zone());
+ } else if (IsAsyncFunction(kind)) {
+ const bool accept_IN = true;
+ DesugarAsyncFunctionBody(function_name, inner_scope, body, nullptr, kind,
+ FunctionBodyType::kNormal, accept_IN, pos,
+ CHECK_OK);
} else {
ParseStatementList(body, Token::RBRACE, CHECK_OK);
}
if (IsSubclassConstructor(kind)) {
- body->Add(
- factory()->NewReturnStatement(
- this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
- zone());
+ body->Add(factory()->NewReturnStatement(
+ this->ThisExpression(kNoSourcePosition), kNoSourcePosition),
+ zone());
}
}
Expect(Token::RBRACE, CHECK_OK);
- scope_->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(scanner()->location().end_pos);
if (!parameters.is_simple) {
DCHECK_NOT_NULL(inner_scope);
+ DCHECK_EQ(function_scope, scope());
+ DCHECK_EQ(function_scope, inner_scope->outer_scope());
DCHECK_EQ(body, inner_block->statements());
- SetLanguageMode(scope_, inner_scope->language_mode());
+ SetLanguageMode(function_scope, inner_scope->language_mode());
Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK);
+
+ if (is_sloppy(inner_scope->language_mode())) {
+ InsertSloppyBlockFunctionVarBindings(inner_scope, function_scope,
+ CHECK_OK);
+ }
+
+ if (IsAsyncFunction(kind)) {
+ init_block = BuildRejectPromiseOnException(init_block);
+ }
+
DCHECK_NOT_NULL(init_block);
inner_scope->set_end_position(scanner()->location().end_pos);
- inner_scope = inner_scope->FinalizeBlockScope();
- if (inner_scope != nullptr) {
+ if (inner_scope->FinalizeBlockScope() != nullptr) {
CheckConflictingVarDeclarations(inner_scope, CHECK_OK);
InsertShadowingVarBindingInitializers(inner_block);
}
+ inner_scope = nullptr;
result->Add(init_block, zone());
result->Add(inner_block, zone());
+ } else {
+ DCHECK_EQ(inner_scope, function_scope);
+ if (is_sloppy(function_scope->language_mode())) {
+ InsertSloppyBlockFunctionVarBindings(function_scope, nullptr, CHECK_OK);
+ }
}
if (function_type == FunctionLiteral::kNamedExpression) {
// Now that we know the language mode, we can create the const assignment
// in the previously reserved spot.
- // NOTE: We create a proxy and resolve it here so that in the
- // future we can change the AST to only refer to VariableProxies
- // instead of Variables and Proxies as is the case now.
- VariableMode fvar_mode = is_strict(language_mode()) ? CONST : CONST_LEGACY;
- Variable* fvar = new (zone())
- Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
- kCreatedInitialized, kNotAssigned);
- VariableProxy* proxy = factory()->NewVariableProxy(fvar);
- VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
- proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
- scope_->DeclareFunctionVar(fvar_declaration);
-
+ DCHECK_EQ(function_scope, scope());
+ Variable* fvar = function_scope->DeclareFunctionVar(function_name);
VariableProxy* fproxy = factory()->NewVariableProxy(fvar);
result->Set(kFunctionNameAssignmentIndex,
factory()->NewExpressionStatement(
factory()->NewAssignment(Token::INIT, fproxy,
factory()->NewThisFunction(pos),
- RelocInfo::kNoPosition),
- RelocInfo::kNoPosition));
+ kNoSourcePosition),
+ kNoSourcePosition));
}
- // 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;
}
@@ -4668,7 +4782,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Start();
}
- TRACE_EVENT0("v8", "V8.PreParse");
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse");
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
@@ -4678,74 +4792,77 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
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_function_name);
+ SET_ALLOW(harmony_for_in);
SET_ALLOW(harmony_function_sent);
- SET_ALLOW(harmony_exponentiation_operator);
SET_ALLOW(harmony_restrictive_declarations);
+ SET_ALLOW(harmony_async_await);
+ SET_ALLOW(harmony_trailing_commas);
#undef SET_ALLOW
}
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
- language_mode(), function_state_->kind(), scope_->has_simple_parameters(),
- logger, bookmark);
+ language_mode(), function_state_->kind(),
+ scope()->AsDeclarationScope()->has_simple_parameters(), parsing_module_,
+ logger, bookmark, use_counts_);
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Stop();
}
return result;
}
-ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
- const AstRawString* name,
- Scanner::Location class_name_location,
- bool name_is_strict_reserved, int pos,
- bool* ok) {
+Expression* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
+ const AstRawString* name,
+ Scanner::Location class_name_location,
+ bool name_is_strict_reserved, int pos,
+ bool* ok) {
// All parts of a ClassDeclaration and ClassExpression are strict code.
if (name_is_strict_reserved) {
ReportMessageAt(class_name_location,
MessageTemplate::kUnexpectedStrictReserved);
*ok = false;
- return NULL;
+ return nullptr;
}
if (IsEvalOrArguments(name)) {
ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments);
*ok = false;
- return NULL;
+ return nullptr;
}
- Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
- BlockState block_state(&scope_, block_scope);
+ BlockState block_state(&scope_state_);
RaiseLanguageMode(STRICT);
- scope_->SetScopeName(name);
-
- VariableProxy* proxy = NULL;
- if (name != NULL) {
- proxy = NewUnresolved(name, CONST);
+#ifdef DEBUG
+ scope()->SetScopeName(name);
+#endif
+
+ VariableProxy* proxy = nullptr;
+ if (name != nullptr) {
+ proxy = NewUnresolved(name);
+ // TODO(verwaest): declare via block_state.
Declaration* declaration =
- factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+ factory()->NewVariableDeclaration(proxy, block_state.scope(), pos);
+ Declare(declaration, DeclarationDescriptor::NORMAL, CONST,
+ DefaultInitializationFlag(CONST), CHECK_OK);
}
- Expression* extends = NULL;
+ Expression* extends = nullptr;
if (Check(Token::EXTENDS)) {
- block_scope->set_start_position(scanner()->location().end_pos);
+ block_state.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,
ExpressionClassifier::ExpressionProductions);
}
} else {
- block_scope->set_start_position(scanner()->location().end_pos);
+ block_state.set_start_position(scanner()->location().end_pos);
}
ClassLiteralChecker checker(this);
ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone());
- FunctionLiteral* constructor = NULL;
+ FunctionLiteral* constructor = nullptr;
bool has_seen_constructor = false;
Expect(Token::LBRACE, CHECK_OK);
@@ -4755,13 +4872,12 @@ ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
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::kNormal, &is_computed_name,
&has_seen_constructor, &property_classifier, &property_name, CHECK_OK);
RewriteNonPattern(&property_classifier, CHECK_OK);
if (classifier != nullptr) {
@@ -4769,7 +4885,7 @@ ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
ExpressionClassifier::ExpressionProductions);
}
- if (has_seen_constructor && constructor == NULL) {
+ if (has_seen_constructor && constructor == nullptr) {
constructor = GetPropertyValue(property)->AsFunctionLiteral();
DCHECK_NOT_NULL(constructor);
constructor->set_raw_name(
@@ -4778,10 +4894,9 @@ ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
properties->Add(property, zone());
}
- if (fni_ != NULL) fni_->Infer();
+ if (fni_ != nullptr) fni_->Infer();
- if (allow_harmony_function_name() &&
- property_name != ast_value_factory()->constructor_string()) {
+ if (property_name != ast_value_factory()->constructor_string()) {
SetFunctionNameFromPropertyName(property, property_name);
}
}
@@ -4789,22 +4904,34 @@ ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
Expect(Token::RBRACE, CHECK_OK);
int end_pos = scanner()->location().end_pos;
- if (constructor == NULL) {
- constructor = DefaultConstructor(name, extends != NULL, block_scope, pos,
- end_pos, block_scope->language_mode());
+ if (constructor == nullptr) {
+ constructor = DefaultConstructor(name, has_extends, pos, end_pos,
+ block_state.language_mode());
}
// Note that we do not finalize this block scope because it is
// used as a sentinel value indicating an anonymous class.
- block_scope->set_end_position(end_pos);
+ block_state.set_end_position(end_pos);
- if (name != NULL) {
+ if (name != nullptr) {
DCHECK_NOT_NULL(proxy);
proxy->var()->set_initializer_position(end_pos);
}
- return factory()->NewClassLiteral(block_scope, proxy, extends, constructor,
- properties, pos, end_pos);
+ Block* do_block = factory()->NewBlock(nullptr, 1, false, pos);
+ Variable* result_var = NewTemporary(ast_value_factory()->empty_string());
+ do_block->set_scope(block_state.FinalizedBlockScope());
+ DoExpression* do_expr = factory()->NewDoExpression(do_block, result_var, pos);
+
+ ClassLiteral* class_literal = factory()->NewClassLiteral(
+ proxy, extends, constructor, properties, pos, end_pos);
+
+ do_block->statements()->Add(
+ factory()->NewExpressionStatement(class_literal, pos), zone());
+ do_expr->set_represented_function(constructor);
+ Rewriter::Rewrite(this, GetClosureScope(), do_expr, ast_value_factory());
+
+ return do_expr;
}
@@ -4827,7 +4954,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
if (extension_ != NULL) {
// The extension structures are only accessible while parsing the
// very first time not when reparsing because of lazy compilation.
- scope_->DeclarationScope()->ForceEagerCompilation();
+ GetClosureScope()->ForceEagerCompilation();
}
const Runtime::Function* function = Runtime::FunctionForName(name->string());
@@ -4865,7 +4992,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
// Check that the function is defined.
if (context_index == Context::kNotFound) {
- ParserTraits::ReportMessage(MessageTemplate::kNotDefined, name);
+ ReportMessage(MessageTemplate::kNotDefined, name);
*ok = false;
return NULL;
}
@@ -4885,11 +5012,11 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
// In ES6, conflicting variable bindings are early errors.
const AstRawString* name = decl->proxy()->raw_name();
int position = decl->proxy()->position();
- Scanner::Location location = position == RelocInfo::kNoPosition
- ? Scanner::Location::invalid()
- : Scanner::Location(position, position + 1);
- ParserTraits::ReportMessageAt(location, MessageTemplate::kVarRedeclaration,
- name);
+ Scanner::Location location =
+ position == kNoSourcePosition
+ ? Scanner::Location::invalid()
+ : Scanner::Location(position, position + 1);
+ ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
*ok = false;
}
}
@@ -4903,53 +5030,109 @@ void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) {
Scope* function_scope = inner_scope->outer_scope();
DCHECK(function_scope->is_function_scope());
ZoneList<Declaration*>* decls = inner_scope->declarations();
+ BlockState block_state(&scope_state_, inner_scope);
for (int i = 0; i < decls->length(); ++i) {
Declaration* decl = decls->at(i);
- if (decl->mode() != VAR || !decl->IsVariableDeclaration()) continue;
+ if (decl->proxy()->var()->mode() != VAR || !decl->IsVariableDeclaration()) {
+ continue;
+ }
const AstRawString* name = decl->proxy()->raw_name();
Variable* parameter = function_scope->LookupLocal(name);
if (parameter == nullptr) continue;
- VariableProxy* to = inner_scope->NewUnresolved(factory(), name);
+ VariableProxy* to = NewUnresolved(name);
VariableProxy* from = factory()->NewVariableProxy(parameter);
- Expression* assignment = factory()->NewAssignment(
- Token::ASSIGN, to, from, RelocInfo::kNoPosition);
- Statement* statement = factory()->NewExpressionStatement(
- assignment, RelocInfo::kNoPosition);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, to, from, kNoSourcePosition);
+ Statement* statement =
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
inner_block->statements()->InsertAt(0, statement, zone());
}
}
-
-void Parser::InsertSloppyBlockFunctionVarBindings(Scope* scope, bool* ok) {
+void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope,
+ Scope* complex_params_scope,
+ bool* ok) {
// For each variable which is used as a function declaration in a sloppy
// block,
- DCHECK(scope->is_declaration_scope());
SloppyBlockFunctionMap* map = scope->sloppy_block_function_map();
for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
AstRawString* name = static_cast<AstRawString*>(p->key);
- // If the variable wouldn't conflict with a lexical declaration,
- Variable* var = scope->LookupLocal(name);
- if (var == nullptr || !IsLexicalVariableMode(var->mode())) {
+
+ // If the variable wouldn't conflict with a lexical declaration
+ // or parameter,
+
+ // Check if there's a conflict with a parameter.
+ // This depends on the fact that functions always have a scope solely to
+ // hold complex parameters, and the names local to that scope are
+ // precisely the names of the parameters. IsDeclaredParameter(name) does
+ // not hold for names declared by complex parameters, nor are those
+ // bindings necessarily declared lexically, so we have to check for them
+ // explicitly. On the other hand, if there are not complex parameters,
+ // it is sufficient to just check IsDeclaredParameter.
+ if (complex_params_scope != nullptr) {
+ if (complex_params_scope->LookupLocal(name) != nullptr) {
+ continue;
+ }
+ } else {
+ if (scope->IsDeclaredParameter(name)) {
+ continue;
+ }
+ }
+
+ bool var_created = false;
+
+ // Write in assignments to var for each block-scoped function declaration
+ auto delegates = static_cast<SloppyBlockFunctionStatement*>(p->value);
+
+ DeclarationScope* decl_scope = scope;
+ while (decl_scope->is_eval_scope()) {
+ decl_scope = decl_scope->outer_scope()->GetDeclarationScope();
+ }
+ Scope* outer_scope = decl_scope->outer_scope();
+
+ for (SloppyBlockFunctionStatement* delegate = delegates;
+ delegate != nullptr; delegate = delegate->next()) {
+ // Check if there's a conflict with a lexical declaration
+ Scope* query_scope = delegate->scope()->outer_scope();
+ Variable* var = nullptr;
+ bool should_hoist = true;
+
+ // Note that we perform this loop for each delegate named 'name',
+ // which may duplicate work if those delegates share scopes.
+ // It is not sufficient to just do a Lookup on query_scope: for
+ // example, that does not prevent hoisting of the function in
+ // `{ let e; try {} catch (e) { function e(){} } }`
+ do {
+ var = query_scope->LookupLocal(name);
+ if (var != nullptr && IsLexicalVariableMode(var->mode())) {
+ should_hoist = false;
+ break;
+ }
+ query_scope = query_scope->outer_scope();
+ } while (query_scope != outer_scope);
+
+ if (!should_hoist) continue;
+
// Declare a var-style binding for the function in the outer scope
- VariableProxy* proxy = scope->NewUnresolved(factory(), name);
- Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, VAR, scope, RelocInfo::kNoPosition);
- Declare(declaration, DeclarationDescriptor::NORMAL, true, ok, scope);
- DCHECK(ok); // Based on the preceding check, this should not fail
- if (!ok) return;
-
- // Write in assignments to var for each block-scoped function declaration
- auto delegates = static_cast<SloppyBlockFunctionMap::Vector*>(p->value);
- for (SloppyBlockFunctionStatement* delegate : *delegates) {
- // Read from the local lexical scope and write to the function scope
- VariableProxy* to = scope->NewUnresolved(factory(), name);
- VariableProxy* from = delegate->scope()->NewUnresolved(factory(), name);
- Expression* assignment = factory()->NewAssignment(
- Token::ASSIGN, to, from, RelocInfo::kNoPosition);
- Statement* statement = factory()->NewExpressionStatement(
- assignment, RelocInfo::kNoPosition);
- delegate->set_statement(statement);
+ if (!var_created) {
+ var_created = true;
+ VariableProxy* proxy = scope->NewUnresolved(factory(), name);
+ Declaration* declaration =
+ factory()->NewVariableDeclaration(proxy, scope, kNoSourcePosition);
+ Declare(declaration, DeclarationDescriptor::NORMAL, VAR,
+ DefaultInitializationFlag(VAR), ok, scope);
+ DCHECK(ok); // Based on the preceding check, this should not fail
+ if (!ok) return;
}
+
+ // Read from the local lexical scope and write to the function scope
+ VariableProxy* to = scope->NewUnresolved(factory(), name);
+ VariableProxy* from = delegate->scope()->NewUnresolved(factory(), name);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, to, from, kNoSourcePosition);
+ Statement* statement =
+ factory()->NewExpressionStatement(assignment, kNoSourcePosition);
+ delegate->set_statement(statement);
}
}
}
@@ -4997,13 +5180,12 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) {
- if (scanner_.source_url()->length() > 0) {
- Handle<String> source_url = scanner_.source_url()->Internalize(isolate);
+ Handle<String> source_url = scanner_.SourceUrl(isolate);
+ if (!source_url.is_null()) {
script->set_source_url(*source_url);
}
- if (scanner_.source_mapping_url()->length() > 0) {
- Handle<String> source_mapping_url =
- scanner_.source_mapping_url()->Internalize(isolate);
+ Handle<String> source_mapping_url = scanner_.SourceMappingUrl(isolate);
+ if (!source_mapping_url.is_null()) {
script->set_source_mapping_url(*source_mapping_url);
}
}
@@ -5026,7 +5208,7 @@ void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) {
// Move statistics to Isolate.
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
- for (int i = 0; i < use_counts_[feature]; ++i) {
+ if (use_counts_[feature] > 0) {
isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
}
}
@@ -5093,24 +5275,38 @@ void Parser::ParseOnBackground(ParseInfo* info) {
DCHECK(info->literal() == NULL);
FunctionLiteral* result = NULL;
- fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
CompleteParserRecorder recorder;
if (produce_cached_parse_data()) log_ = &recorder;
- DCHECK(info->source_stream() != NULL);
- ExternalStreamingStream stream(info->source_stream(),
- info->source_stream_encoding());
- scanner_.Initialize(&stream);
+ std::unique_ptr<Utf16CharacterStream> stream;
+ Utf16CharacterStream* stream_ptr;
+ if (info->character_stream()) {
+ DCHECK(info->source_stream() == nullptr);
+ stream_ptr = info->character_stream();
+ } else {
+ DCHECK(info->character_stream() == nullptr);
+ stream.reset(new ExternalStreamingStream(info->source_stream(),
+ info->source_stream_encoding()));
+ stream_ptr = stream.get();
+ }
DCHECK(info->context().is_null() || info->context()->IsNativeContext());
+ DCHECK(original_scope_);
+
// When streaming, we don't know the length of the source until we have parsed
// it. The raw data can be UTF-8, so we wouldn't know the source length until
// we have decoded it anyway even if we knew the raw data length (which we
// don't). We work around this by storing all the scopes which need their end
// position set at the end of the script (the top scope and possible eval
// scopes) and set their end position after we know the script length.
- result = DoParseProgram(info);
+ if (info->is_lazy()) {
+ result = DoParseLazy(info, info->function_name(), stream_ptr);
+ } else {
+ fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
+ scanner_.Initialize(stream_ptr);
+ result = DoParseProgram(info);
+ }
info->set_literal(result);
@@ -5123,9 +5319,8 @@ void Parser::ParseOnBackground(ParseInfo* info) {
}
}
-
-ParserTraits::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) {
- return new (zone()) ParserTraits::TemplateLiteral(zone(), pos);
+Parser::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) {
+ return new (zone()) TemplateLiteral(zone(), pos);
}
@@ -5256,7 +5451,7 @@ ZoneList<v8::internal::Expression*>* Parser::PrepareSpreadArguments(
new (zone()) ZoneList<Expression*>(0, zone());
spread_list->Add(list->at(0)->AsSpread()->expression(), zone());
args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX,
- spread_list, RelocInfo::kNoPosition),
+ spread_list, kNoSourcePosition),
zone());
return args;
} else {
@@ -5280,7 +5475,7 @@ ZoneList<v8::internal::Expression*>* Parser::PrepareSpreadArguments(
}
int literal_index = function_state_->NextMaterializedLiteralIndex();
args->Add(factory()->NewArrayLiteral(unspread, literal_index,
- RelocInfo::kNoPosition),
+ kNoSourcePosition),
zone());
if (i == n) break;
@@ -5291,13 +5486,13 @@ ZoneList<v8::internal::Expression*>* Parser::PrepareSpreadArguments(
new (zone()) ZoneList<v8::internal::Expression*>(1, zone());
spread_list->Add(list->at(i++)->AsSpread()->expression(), zone());
args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX,
- spread_list, RelocInfo::kNoPosition),
+ spread_list, kNoSourcePosition),
zone());
}
list = new (zone()) ZoneList<v8::internal::Expression*>(1, zone());
list->Add(factory()->NewCallRuntime(Context::SPREAD_ARGUMENTS_INDEX, args,
- RelocInfo::kNoPosition),
+ kNoSourcePosition),
zone());
return list;
}
@@ -5324,19 +5519,17 @@ Expression* Parser::SpreadCall(Expression* function,
if (function->IsProperty()) {
// Method calls
if (function->AsProperty()->IsSuperAccess()) {
- Expression* home =
- ThisExpression(scope_, factory(), RelocInfo::kNoPosition);
+ Expression* home = ThisExpression(kNoSourcePosition);
args->InsertAt(0, function, zone());
args->InsertAt(1, home, zone());
} else {
- Variable* temp =
- scope_->NewTemporary(ast_value_factory()->empty_string());
+ Variable* temp = NewTemporary(ast_value_factory()->empty_string());
VariableProxy* obj = factory()->NewVariableProxy(temp);
Assignment* assign_obj = factory()->NewAssignment(
Token::ASSIGN, obj, function->AsProperty()->obj(),
- RelocInfo::kNoPosition);
+ kNoSourcePosition);
function = factory()->NewProperty(
- assign_obj, function->AsProperty()->key(), RelocInfo::kNoPosition);
+ assign_obj, function->AsProperty()->key(), kNoSourcePosition);
args->InsertAt(0, function, zone());
obj = factory()->NewVariableProxy(temp);
args->InsertAt(1, obj, zone());
@@ -5344,7 +5537,7 @@ Expression* Parser::SpreadCall(Expression* function,
} else {
// Non-method calls
args->InsertAt(0, function, zone());
- args->InsertAt(1, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+ args->InsertAt(1, factory()->NewUndefinedLiteral(kNoSourcePosition),
zone());
}
return factory()->NewCallRuntime(Context::REFLECT_APPLY_INDEX, args, pos);
@@ -5375,41 +5568,87 @@ void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) {
void Parser::RaiseLanguageMode(LanguageMode mode) {
- LanguageMode old = scope_->language_mode();
- SetLanguageMode(scope_, old > mode ? old : mode);
+ LanguageMode old = scope()->language_mode();
+ SetLanguageMode(scope(), old > mode ? old : mode);
}
-
-void ParserTraits::RewriteDestructuringAssignments() {
- parser_->RewriteDestructuringAssignments();
+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::RewriteExponentiation(Expression* left,
- Expression* right, int pos) {
- return parser_->RewriteExponentiation(left, right, pos);
+Expression* ParserBaseTraits<Parser>::ExpressionListToExpression(
+ ZoneList<Expression*>* args) {
+ AstNodeFactory* factory = delegate()->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;
}
-Expression* ParserTraits::RewriteAssignExponentiation(Expression* left,
- Expression* right,
- int pos) {
- return parser_->RewriteAssignExponentiation(left, right, pos);
-}
+Expression* Parser::RewriteAwaitExpression(Expression* value, int await_pos) {
+ // yield %AsyncFunctionAwait(.generator_object, <operand>)
+ Variable* generator_object_variable =
+ delegate()->function_state_->generator_object_variable();
-void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
- bool* ok) {
- parser_->RewriteNonPattern(classifier, ok);
-}
+ // If generator_object_variable is null,
+ if (!generator_object_variable) return value;
+
+ auto factory = delegate()->factory();
+ const int nopos = kNoSourcePosition;
+ Variable* temp_var =
+ delegate()->NewTemporary(delegate()->ast_value_factory()->empty_string());
+ VariableProxy* temp_proxy = factory->NewVariableProxy(temp_var);
+ Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
-Zone* ParserTraits::zone() const {
- return parser_->function_state_->scope()->zone();
+ // Wrap value evaluation to provide a break location.
+ Expression* value_assignment =
+ factory->NewAssignment(Token::ASSIGN, temp_proxy, value, nopos);
+ do_block->statements()->Add(
+ factory->NewExpressionStatement(value_assignment, value->position()),
+ zone());
+
+ ZoneList<Expression*>* async_function_await_args =
+ new (zone()) ZoneList<Expression*>(2, zone());
+ Expression* generator_object =
+ factory->NewVariableProxy(generator_object_variable);
+ async_function_await_args->Add(generator_object, zone());
+ async_function_await_args->Add(temp_proxy, zone());
+ Expression* async_function_await = delegate()->factory()->NewCallRuntime(
+ Context::ASYNC_FUNCTION_AWAIT_INDEX, async_function_await_args, nopos);
+ // Wrap await to provide a break location between value evaluation and yield.
+ Expression* await_assignment = factory->NewAssignment(
+ Token::ASSIGN, temp_proxy, async_function_await, nopos);
+ do_block->statements()->Add(
+ factory->NewExpressionStatement(await_assignment, await_pos), zone());
+ Expression* do_expr = factory->NewDoExpression(do_block, temp_var, nopos);
+
+ generator_object = factory->NewVariableProxy(generator_object_variable);
+ return factory->NewYield(generator_object, do_expr, nopos,
+ Yield::kOnExceptionRethrow);
}
+ZoneList<Expression*>* ParserBaseTraits<Parser>::GetNonPatternList() const {
+ return delegate()->function_state_->non_patterns_to_rewrite();
+}
-ZoneList<Expression*>* ParserTraits::GetNonPatternList() const {
- return parser_->function_state_->non_patterns_to_rewrite();
+ZoneList<typename ParserBaseTraits<Parser>::Type::ExpressionClassifier::Error>*
+ParserBaseTraits<Parser>::GetReportedErrorList() const {
+ return delegate()->function_state_->GetReportedErrorList();
}
+Zone* ParserBaseTraits<Parser>::zone() const { return delegate()->zone(); }
class NonPatternRewriter : public AstExpressionRewriter {
public:
@@ -5450,8 +5689,7 @@ class NonPatternRewriter : public AstExpressionRewriter {
void Parser::RewriteNonPattern(ExpressionClassifier* classifier, bool* ok) {
- ValidateExpression(classifier, ok);
- if (!*ok) return;
+ ValidateExpression(classifier, CHECK_OK_VOID);
auto non_patterns_to_rewrite = function_state_->non_patterns_to_rewrite();
int begin = classifier->GetNonPatternBegin();
int end = non_patterns_to_rewrite->length();
@@ -5488,7 +5726,7 @@ Expression* Parser::RewriteExponentiation(Expression* left, Expression* right,
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
args->Add(left, zone());
args->Add(right, zone());
- return factory()->NewCallRuntime(Context::MATH_POW_METHOD_INDEX, args, pos);
+ return factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos);
}
Expression* Parser::RewriteAssignExponentiation(Expression* left,
@@ -5499,34 +5737,33 @@ Expression* Parser::RewriteAssignExponentiation(Expression* left,
Expression* result;
DCHECK_NOT_NULL(lhs->raw_name());
- result =
- this->ExpressionFromIdentifier(lhs->raw_name(), lhs->position(),
- lhs->end_position(), scope_, factory());
+ result = this->ExpressionFromIdentifier(lhs->raw_name(), lhs->position(),
+ lhs->end_position());
args->Add(left, zone());
args->Add(right, zone());
Expression* call =
- factory()->NewCallRuntime(Context::MATH_POW_METHOD_INDEX, args, pos);
+ factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos);
return factory()->NewAssignment(Token::ASSIGN, result, call, pos);
} else if (left->IsProperty()) {
Property* prop = left->AsProperty();
- auto temp_obj = scope_->NewTemporary(ast_value_factory()->empty_string());
- auto temp_key = scope_->NewTemporary(ast_value_factory()->empty_string());
+ auto temp_obj = NewTemporary(ast_value_factory()->empty_string());
+ auto temp_key = NewTemporary(ast_value_factory()->empty_string());
Expression* assign_obj = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp_obj), prop->obj(),
- RelocInfo::kNoPosition);
+ kNoSourcePosition);
Expression* assign_key = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp_key), prop->key(),
- RelocInfo::kNoPosition);
+ kNoSourcePosition);
args->Add(factory()->NewProperty(factory()->NewVariableProxy(temp_obj),
factory()->NewVariableProxy(temp_key),
left->position()),
zone());
args->Add(right, zone());
Expression* call =
- factory()->NewCallRuntime(Context::MATH_POW_METHOD_INDEX, args, pos);
+ factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos);
Expression* target = factory()->NewProperty(
factory()->NewVariableProxy(temp_obj),
- factory()->NewVariableProxy(temp_key), RelocInfo::kNoPosition);
+ factory()->NewVariableProxy(temp_key), kNoSourcePosition);
Expression* assign =
factory()->NewAssignment(Token::ASSIGN, target, call, pos);
return factory()->NewBinaryOperation(
@@ -5553,18 +5790,15 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
// where $R, $i and $j are fresh temporary variables.
ZoneList<Expression*>::iterator s = lit->FirstSpread();
if (s == lit->EndValue()) return nullptr; // no spread, no rewriting...
- Variable* result =
- scope_->NewTemporary(ast_value_factory()->dot_result_string());
+ Variable* result = NewTemporary(ast_value_factory()->dot_result_string());
// NOTE: The value assigned to R is the whole original array literal,
// spreads included. This will be fixed before the rewritten AST is returned.
// $R = lit
- Expression* init_result =
- factory()->NewAssignment(Token::INIT, factory()->NewVariableProxy(result),
- lit, RelocInfo::kNoPosition);
- Block* do_block =
- factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
+ Expression* init_result = factory()->NewAssignment(
+ Token::INIT, factory()->NewVariableProxy(result), lit, kNoSourcePosition);
+ Block* do_block = factory()->NewBlock(nullptr, 16, false, kNoSourcePosition);
do_block->statements()->Add(
- factory()->NewExpressionStatement(init_result, RelocInfo::kNoPosition),
+ factory()->NewExpressionStatement(init_result, kNoSourcePosition),
zone());
// Traverse the array literal starting from the first spread.
while (s != lit->EndValue()) {
@@ -5573,20 +5807,36 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
if (spread == nullptr) {
// If the element is not a spread, we're adding a single:
// %AppendElement($R, value)
- ZoneList<Expression*>* append_element_args = NewExpressionList(2, zone());
- append_element_args->Add(factory()->NewVariableProxy(result), zone());
- append_element_args->Add(value, zone());
- do_block->statements()->Add(
- factory()->NewExpressionStatement(
- factory()->NewCallRuntime(Runtime::kAppendElement,
- append_element_args,
- RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
- zone());
+ // or, in case of a hole,
+ // ++($R.length)
+ if (!value->IsLiteral() ||
+ !value->AsLiteral()->raw_value()->IsTheHole()) {
+ ZoneList<Expression*>* append_element_args =
+ NewExpressionList(2, zone());
+ append_element_args->Add(factory()->NewVariableProxy(result), zone());
+ append_element_args->Add(value, zone());
+ do_block->statements()->Add(
+ factory()->NewExpressionStatement(
+ factory()->NewCallRuntime(Runtime::kAppendElement,
+ append_element_args,
+ kNoSourcePosition),
+ kNoSourcePosition),
+ zone());
+ } else {
+ Property* length_property = factory()->NewProperty(
+ factory()->NewVariableProxy(result),
+ factory()->NewStringLiteral(ast_value_factory()->length_string(),
+ kNoSourcePosition),
+ kNoSourcePosition);
+ CountOperation* count_op = factory()->NewCountOperation(
+ Token::INC, true /* prefix */, length_property, kNoSourcePosition);
+ do_block->statements()->Add(
+ factory()->NewExpressionStatement(count_op, kNoSourcePosition),
+ zone());
+ }
} else {
// If it's a spread, we're adding a for/of loop iterating through it.
- Variable* each =
- scope_->NewTemporary(ast_value_factory()->dot_for_string());
+ Variable* each = NewTemporary(ast_value_factory()->dot_for_string());
Expression* subject = spread->expression();
// %AppendElement($R, each)
Statement* append_body;
@@ -5597,16 +5847,16 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
append_element_args->Add(factory()->NewVariableProxy(each), zone());
append_body = factory()->NewExpressionStatement(
factory()->NewCallRuntime(Runtime::kAppendElement,
- append_element_args,
- RelocInfo::kNoPosition),
- RelocInfo::kNoPosition);
+ append_element_args, kNoSourcePosition),
+ kNoSourcePosition);
}
// for (each of spread) %AppendElement($R, each)
ForEachStatement* loop = factory()->NewForEachStatement(
- ForEachStatement::ITERATE, nullptr, RelocInfo::kNoPosition);
+ ForEachStatement::ITERATE, nullptr, kNoSourcePosition);
+ const bool finalize = false;
InitializeForOfStatement(loop->AsForOfStatement(),
factory()->NewVariableProxy(each), subject,
- append_body, spread->expression_position());
+ append_body, finalize);
do_block->statements()->Add(loop, zone());
}
}
@@ -5616,21 +5866,18 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
return factory()->NewDoExpression(do_block, result, lit->position());
}
-
-void ParserTraits::QueueDestructuringAssignmentForRewriting(Expression* expr) {
+void Parser::QueueDestructuringAssignmentForRewriting(Expression* expr) {
DCHECK(expr->IsRewritableExpression());
- parser_->function_state_->AddDestructuringAssignment(
- Parser::DestructuringAssignment(expr, parser_->scope_));
+ function_state_->AddDestructuringAssignment(
+ DestructuringAssignment(expr, delegate()->scope()));
}
-
-void ParserTraits::QueueNonPatternForRewriting(Expression* expr) {
+void Parser::QueueNonPatternForRewriting(Expression* expr, bool* ok) {
DCHECK(expr->IsRewritableExpression());
- parser_->function_state_->AddNonPatternForRewriting(expr);
+ function_state_->AddNonPatternForRewriting(expr, ok);
}
-
-void ParserTraits::SetFunctionNameFromPropertyName(
+void ParserBaseTraits<Parser>::SetFunctionNameFromPropertyName(
ObjectLiteralProperty* property, const AstRawString* name) {
Expression* value = property->value();
@@ -5646,46 +5893,38 @@ void ParserTraits::SetFunctionNameFromPropertyName(
if (is_getter || is_setter) {
DCHECK_NOT_NULL(name);
const AstRawString* prefix =
- is_getter ? parser_->ast_value_factory()->get_space_string()
- : parser_->ast_value_factory()->set_space_string();
+ is_getter ? delegate()->ast_value_factory()->get_space_string()
+ : delegate()->ast_value_factory()->set_space_string();
function->set_raw_name(
- parser_->ast_value_factory()->NewConsString(prefix, name));
+ delegate()->ast_value_factory()->NewConsString(prefix, name));
return;
}
}
- if (!value->IsAnonymousFunctionDefinition()) return;
- DCHECK_NOT_NULL(name);
-
// Ignore "__proto__" as a name when it's being used to set the [[Prototype]]
// of an object literal.
if (property->kind() == ObjectLiteralProperty::PROTOTYPE) return;
- if (function != nullptr) {
- function->set_raw_name(name);
- DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
- } else {
- DCHECK(value->IsClassLiteral());
- DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
- value->AsClassLiteral()->constructor()->set_raw_name(name);
- }
+ DCHECK(!value->IsAnonymousFunctionDefinition() ||
+ property->kind() == ObjectLiteralProperty::COMPUTED);
+ delegate()->SetFunctionName(value, name);
}
-
-void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
- Expression* identifier) {
- if (!value->IsAnonymousFunctionDefinition()) return;
+void ParserBaseTraits<Parser>::SetFunctionNameFromIdentifierRef(
+ Expression* value, Expression* identifier) {
if (!identifier->IsVariableProxy()) return;
+ delegate()->SetFunctionName(value, identifier->AsVariableProxy()->raw_name());
+}
- auto name = identifier->AsVariableProxy()->raw_name();
+void Parser::SetFunctionName(Expression* value, const AstRawString* name) {
DCHECK_NOT_NULL(name);
-
+ if (!value->IsAnonymousFunctionDefinition()) return;
auto function = value->AsFunctionLiteral();
if (function != nullptr) {
function->set_raw_name(name);
} else {
- DCHECK(value->IsClassLiteral());
- value->AsClassLiteral()->constructor()->set_raw_name(name);
+ DCHECK(value->IsDoExpression());
+ value->AsDoExpression()->represented_function()->set_raw_name(name);
}
}
@@ -5749,15 +5988,19 @@ void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
// }
// }
//
-// 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,607 +6009,431 @@ void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
// output = %_Call(iteratorReturn, iterator, input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
-
-Expression* ParserTraits::RewriteYieldStar(
- Expression* generator, Expression* iterable, 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();
-
+Expression* Parser::RewriteYieldStar(Expression* generator,
+ Expression* iterable, int pos) {
+ const int nopos = kNoSourcePosition;
// Forward definition for break/continue statements.
- WhileStatement* loop = factory->NewWhileStatement(nullptr, nopos);
-
+ WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
// let input = undefined;
- Variable* var_input = scope->NewTemporary(avfactory->empty_string());
+ Variable* var_input = NewTemporary(ast_value_factory()->empty_string());
Statement* initialize_input;
{
- Expression* input_proxy = factory->NewVariableProxy(var_input);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, input_proxy, factory->NewUndefinedLiteral(nopos), nopos);
- initialize_input = factory->NewExpressionStatement(assignment, nopos);
+ Expression* input_proxy = factory()->NewVariableProxy(var_input);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, input_proxy,
+ factory()->NewUndefinedLiteral(nopos), nopos);
+ initialize_input = factory()->NewExpressionStatement(assignment, nopos);
}
-
// let mode = kNext;
- Variable* var_mode = scope->NewTemporary(avfactory->empty_string());
+ Variable* var_mode = NewTemporary(ast_value_factory()->empty_string());
Statement* initialize_mode;
{
- Expression* mode_proxy = factory->NewVariableProxy(var_mode);
- Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* mode_proxy = factory()->NewVariableProxy(var_mode);
+ Expression* knext =
+ factory()->NewSmiLiteral(JSGeneratorObject::kNext, nopos);
Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
- initialize_mode = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+ initialize_mode = factory()->NewExpressionStatement(assignment, nopos);
}
-
// let output = undefined;
- Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+ Variable* var_output = NewTemporary(ast_value_factory()->empty_string());
Statement* initialize_output;
{
- Expression* output_proxy = factory->NewVariableProxy(var_output);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, output_proxy, factory->NewUndefinedLiteral(nopos),
- nopos);
- initialize_output = factory->NewExpressionStatement(assignment, nopos);
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, output_proxy,
+ factory()->NewUndefinedLiteral(nopos), nopos);
+ initialize_output = factory()->NewExpressionStatement(assignment, nopos);
}
-
// let iterator = iterable[Symbol.iterator];
- Variable* var_iterator = scope->NewTemporary(avfactory->empty_string());
+ Variable* var_iterator = NewTemporary(ast_value_factory()->empty_string());
Statement* get_iterator;
{
- Expression* iterator = GetIterator(iterable, factory, nopos);
- Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
- Expression* assignment = factory->NewAssignment(
+ Expression* iterator = GetIterator(iterable, factory(), nopos);
+ Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
+ Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, iterator_proxy, iterator, nopos);
- get_iterator = factory->NewExpressionStatement(assignment, nopos);
+ get_iterator = factory()->NewExpressionStatement(assignment, nopos);
}
-
// if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
Statement* validate_iterator;
{
Expression* is_receiver_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_iterator), zone);
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_iterator), zone());
is_receiver_call =
- factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
- Expression* call = NewThrowTypeError(
- MessageTemplate::kSymbolIteratorInvalid, avfactory->empty_string(),
- nopos);
- throw_call = factory->NewExpressionStatement(call, nopos);
+ Expression* call =
+ NewThrowTypeError(MessageTemplate::kSymbolIteratorInvalid,
+ ast_value_factory()->empty_string(), nopos);
+ throw_call = factory()->NewExpressionStatement(call, nopos);
}
- validate_iterator = factory->NewIfStatement(
- is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ validate_iterator = factory()->NewIfStatement(
+ is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
+ nopos);
}
-
// output = iterator.next(input);
Statement* call_next;
{
- Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
Expression* literal =
- factory->NewStringLiteral(avfactory->next_string(), nopos);
+ factory()->NewStringLiteral(ast_value_factory()->next_string(), nopos);
Expression* next_property =
- factory->NewProperty(iterator_proxy, literal, nopos);
- Expression* input_proxy = factory->NewVariableProxy(var_input);
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(input_proxy, zone);
- Expression* call = factory->NewCall(next_property, args, nopos);
- Expression* output_proxy = factory->NewVariableProxy(var_output);
+ factory()->NewProperty(iterator_proxy, literal, nopos);
+ Expression* input_proxy = factory()->NewVariableProxy(var_input);
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(input_proxy, zone());
+ Expression* call = factory()->NewCall(next_property, args, nopos);
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
- call_next = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
+ call_next = factory()->NewExpressionStatement(assignment, nopos);
}
-
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
Statement* validate_next_output;
{
Expression* is_receiver_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
is_receiver_call =
- factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
- Expression* call = factory->NewCallRuntime(
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
+ Expression* call = factory()->NewCallRuntime(
Runtime::kThrowIteratorResultNotAnObject, args, nopos);
- throw_call = factory->NewExpressionStatement(call, nopos);
+ throw_call = factory()->NewExpressionStatement(call, nopos);
}
- validate_next_output = factory->NewIfStatement(
- is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ validate_next_output = factory()->NewIfStatement(
+ is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
+ nopos);
}
-
// let iteratorThrow = iterator.throw;
- Variable* var_throw = scope->NewTemporary(avfactory->empty_string());
+ Variable* var_throw = NewTemporary(ast_value_factory()->empty_string());
Statement* get_throw;
{
- Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+ Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
Expression* literal =
- factory->NewStringLiteral(avfactory->throw_string(), nopos);
+ factory()->NewStringLiteral(ast_value_factory()->throw_string(), nopos);
Expression* property =
- factory->NewProperty(iterator_proxy, literal, nopos);
- Expression* throw_proxy = factory->NewVariableProxy(var_throw);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, throw_proxy, property, nopos);
- get_throw = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewProperty(iterator_proxy, literal, nopos);
+ Expression* throw_proxy = factory()->NewVariableProxy(var_throw);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, throw_proxy, property, nopos);
+ get_throw = factory()->NewExpressionStatement(assignment, nopos);
}
-
// if (IS_NULL_OR_UNDEFINED(iteratorThrow) {
// IteratorClose(iterator);
// throw MakeTypeError(kThrowMethodMissing);
// }
Statement* check_throw;
{
- Expression* condition = factory->NewCompareOperation(
- Token::EQ, factory->NewVariableProxy(var_throw),
- factory->NewNullLiteral(nopos), nopos);
-
- Expression* call = NewThrowTypeError(
- MessageTemplate::kThrowMethodMissing,
- avfactory->empty_string(), nopos);
- Statement* throw_call = factory->NewExpressionStatement(call, nopos);
+ Expression* condition = factory()->NewCompareOperation(
+ Token::EQ, factory()->NewVariableProxy(var_throw),
+ factory()->NewNullLiteral(nopos), nopos);
+ Expression* call =
+ NewThrowTypeError(MessageTemplate::kThrowMethodMissing,
+ ast_value_factory()->empty_string(), nopos);
+ 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);
- then->statements()->Add(throw_call, zone);
- check_throw = factory->NewIfStatement(
- condition, then, factory->NewEmptyStatement(nopos), nopos);
+ Block* then = factory()->NewBlock(nullptr, 4 + 1, false, nopos);
+ 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);
}
-
// output = %_Call(iteratorThrow, iterator, input);
Statement* call_throw;
{
- auto args = new (zone) ZoneList<Expression*>(3, zone);
- args->Add(factory->NewVariableProxy(var_throw), zone);
- args->Add(factory->NewVariableProxy(var_iterator), zone);
- args->Add(factory->NewVariableProxy(var_input), zone);
+ auto args = new (zone()) ZoneList<Expression*>(3, zone());
+ args->Add(factory()->NewVariableProxy(var_throw), zone());
+ args->Add(factory()->NewVariableProxy(var_iterator), zone());
+ args->Add(factory()->NewVariableProxy(var_input), zone());
Expression* call =
- factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
- call_throw = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* assignment = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(var_output), call, nopos);
+ call_throw = factory()->NewExpressionStatement(assignment, nopos);
}
-
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
Statement* validate_throw_output;
{
Expression* is_receiver_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
is_receiver_call =
- factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
- Expression* call = factory->NewCallRuntime(
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
+ Expression* call = factory()->NewCallRuntime(
Runtime::kThrowIteratorResultNotAnObject, args, nopos);
- throw_call = factory->NewExpressionStatement(call, nopos);
+ throw_call = factory()->NewExpressionStatement(call, nopos);
}
- validate_throw_output = factory->NewIfStatement(
- is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ validate_throw_output = factory()->NewIfStatement(
+ is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
+ nopos);
}
-
// if (output.done) break;
Statement* if_done;
{
- Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* literal =
- factory->NewStringLiteral(avfactory->done_string(), nopos);
- Expression* property = factory->NewProperty(output_proxy, literal, nopos);
- BreakStatement* break_loop = factory->NewBreakStatement(loop, nopos);
- if_done = factory->NewIfStatement(
- property, break_loop, factory->NewEmptyStatement(nopos), nopos);
+ factory()->NewStringLiteral(ast_value_factory()->done_string(), nopos);
+ Expression* property = factory()->NewProperty(output_proxy, literal, nopos);
+ BreakStatement* break_loop = factory()->NewBreakStatement(loop, nopos);
+ if_done = factory()->NewIfStatement(
+ property, break_loop, factory()->NewEmptyStatement(nopos), nopos);
}
// mode = kReturn;
Statement* set_mode_return;
{
- Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ 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);
+ factory()->NewAssignment(Token::ASSIGN, mode_proxy, kreturn, nopos);
+ set_mode_return = factory()->NewExpressionStatement(assignment, nopos);
}
// Yield(output);
Statement* yield_output;
{
- Expression* output_proxy = factory->NewVariableProxy(var_output);
- Yield* yield = factory->NewYield(generator, output_proxy, nopos);
- yield_output = factory->NewExpressionStatement(yield, nopos);
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
+ Yield* yield = factory()->NewYield(generator, output_proxy, nopos,
+ Yield::kOnExceptionThrow);
+ yield_output = factory()->NewExpressionStatement(yield, nopos);
}
-
// mode = kNext;
Statement* set_mode_next;
{
- Expression* mode_proxy = factory->NewVariableProxy(var_mode);
- Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ Expression* mode_proxy = factory()->NewVariableProxy(var_mode);
+ Expression* knext =
+ factory()->NewSmiLiteral(JSGeneratorObject::kNext, nopos);
Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
- set_mode_next = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+ set_mode_next = factory()->NewExpressionStatement(assignment, nopos);
}
-
// mode = kThrow;
Statement* set_mode_throw;
{
- Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+ 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);
+ factory()->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos);
+ set_mode_throw = factory()->NewExpressionStatement(assignment, nopos);
}
-
// input = function.sent;
Statement* get_input;
{
- Expression* function_sent = FunctionSentExpression(scope, factory, nopos);
- Expression* input_proxy = factory->NewVariableProxy(var_input);
- Expression* assignment = factory->NewAssignment(
+ Expression* function_sent = FunctionSentExpression(factory(), nopos);
+ Expression* input_proxy = factory()->NewVariableProxy(var_input);
+ Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, input_proxy, function_sent, nopos);
- get_input = factory->NewExpressionStatement(assignment, nopos);
+ get_input = factory()->NewExpressionStatement(assignment, nopos);
}
+ // 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);
- // output.value;
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
+ Expression* literal =
+ factory()->NewStringLiteral(ast_value_factory()->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);
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* literal =
- factory->NewStringLiteral(avfactory->value_string(), nopos);
- Expression* property = factory->NewProperty(output_proxy, literal, nopos);
- get_value = factory->NewExpressionStatement(property, nopos);
+ factory()->NewStringLiteral(ast_value_factory()->value_string(), nopos);
+ Expression* property = factory()->NewProperty(output_proxy, literal, nopos);
+ get_value = factory()->NewExpressionStatement(property, nopos);
}
-
// Now put things together.
-
// try { ... } catch(e) { ... }
Statement* try_catch;
{
- Block* try_block = factory->NewBlock(nullptr, 2, false, nopos);
- try_block->statements()->Add(yield_output, zone);
- try_block->statements()->Add(set_mode_next, zone);
+ Block* try_block = factory()->NewBlock(nullptr, 2, false, nopos);
+ try_block->statements()->Add(yield_output, zone());
+ try_block->statements()->Add(set_mode_next, zone());
- Block* catch_block = factory->NewBlock(nullptr, 1, false, nopos);
- catch_block->statements()->Add(set_mode_throw, zone);
+ Block* catch_block = factory()->NewBlock(nullptr, 1, false, nopos);
+ catch_block->statements()->Add(set_mode_throw, zone());
- Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
- const AstRawString* name = avfactory->dot_catch_string();
+ Scope* catch_scope = NewScope(CATCH_SCOPE);
+ catch_scope->set_is_hidden();
+ const AstRawString* name = ast_value_factory()->dot_catch_string();
Variable* catch_variable =
catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
Variable::NORMAL);
- try_catch = factory->NewTryCatchStatement(
+ try_catch = factory()->NewTryCatchStatementForDesugaring(
try_block, catch_scope, catch_variable, catch_block, nopos);
}
-
// try { ... } finally { ... }
Statement* try_finally;
{
- Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
- try_block->statements()->Add(try_catch, zone);
+ Block* try_block = factory()->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(try_catch, zone());
- Block* finally = factory->NewBlock(nullptr, 2, false, nopos);
- finally->statements()->Add(get_input, zone);
- finally->statements()->Add(
- factory->NewContinueStatement(loop, nopos), zone);
+ Block* finally = factory()->NewBlock(nullptr, 2, false, nopos);
+ finally->statements()->Add(get_input, zone());
+ finally->statements()->Add(factory()->NewContinueStatement(loop, nopos),
+ zone());
- try_finally = factory->NewTryFinallyStatement(try_block, finally, nopos);
+ try_finally = factory()->NewTryFinallyStatement(try_block, finally, nopos);
}
-
// switch (mode) { ... }
- SwitchStatement* switch_mode = factory->NewSwitchStatement(nullptr, nopos);
+ SwitchStatement* switch_mode = factory()->NewSwitchStatement(nullptr, nopos);
{
- auto case_next = new (zone) ZoneList<Statement*>(3, zone);
- case_next->Add(call_next, zone);
- case_next->Add(validate_next_output, zone);
- 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);
- case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
-
- auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
- case_throw->Add(get_throw, zone);
- case_throw->Add(check_throw, zone);
- case_throw->Add(call_throw, zone);
- case_throw->Add(validate_throw_output, zone);
- case_throw->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
-
- auto cases = new (zone) ZoneList<CaseClause*>(3, zone);
- Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+ auto case_next = new (zone()) ZoneList<Statement*>(3, zone());
+ case_next->Add(call_next, zone());
+ case_next->Add(validate_next_output, zone());
+ case_next->Add(factory()->NewBreakStatement(switch_mode, nopos), zone());
+
+ auto case_return = new (zone()) ZoneList<Statement*>(5, zone());
+ 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());
+ case_throw->Add(get_throw, zone());
+ case_throw->Add(check_throw, zone());
+ case_throw->Add(call_throw, zone());
+ case_throw->Add(validate_throw_output, zone());
+ case_throw->Add(factory()->NewBreakStatement(switch_mode, nopos), zone());
+
+ auto cases = new (zone()) ZoneList<CaseClause*>(3, zone());
+ 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);
- 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);
+ 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());
- switch_mode->Initialize(factory->NewVariableProxy(var_mode), cases);
+ switch_mode->Initialize(factory()->NewVariableProxy(var_mode), cases);
}
-
// while (true) { ... }
// Already defined earlier: WhileStatement* loop = ...
{
- Block* loop_body = factory->NewBlock(nullptr, 4, false, nopos);
- loop_body->statements()->Add(switch_mode, zone);
- loop_body->statements()->Add(if_done, zone);
- loop_body->statements()->Add(set_mode_return, zone);
- loop_body->statements()->Add(try_finally, zone);
+ Block* loop_body = factory()->NewBlock(nullptr, 4, false, nopos);
+ loop_body->statements()->Add(switch_mode, zone());
+ loop_body->statements()->Add(if_done, zone());
+ loop_body->statements()->Add(set_mode_return, zone());
+ loop_body->statements()->Add(try_finally, zone());
- loop->Initialize(factory->NewBooleanLiteral(true, nopos), loop_body);
+ loop->Initialize(factory()->NewBooleanLiteral(true, nopos), loop_body);
}
-
// do { ... }
DoExpression* yield_star;
{
// 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);
- 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);
+ 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);
- do_block->statements()->Add(get_value, zone);
+ Block* do_block = factory()->NewBlock(nullptr, 2, false, nopos);
+ do_block->statements()->Add(do_block_, zone());
+ do_block->statements()->Add(get_value, zone());
- Variable* dot_result = scope->NewTemporary(avfactory->dot_result_string());
- yield_star = factory->NewDoExpression(do_block, dot_result, nopos);
- Rewriter::Rewrite(parser_, yield_star, avfactory);
+ Variable* dot_result =
+ NewTemporary(ast_value_factory()->dot_result_string());
+ yield_star = factory()->NewDoExpression(do_block, dot_result, nopos);
+ Rewriter::Rewrite(this, GetClosureScope(), yield_star, ast_value_factory());
}
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();
- auto avfactory = parser_->ast_value_factory();
- const int nopos = RelocInfo::kNoPosition;
+Statement* Parser::CheckCallable(Variable* var, Expression* error, int pos) {
+ const int nopos = kNoSourcePosition;
Statement* validate_var;
{
- Expression* type_of = factory->NewUnaryOperation(
- Token::TYPEOF, factory->NewVariableProxy(var), nopos);
- Expression* function_literal =
- factory->NewStringLiteral(avfactory->function_string(), nopos);
- Expression* condition = factory->NewCompareOperation(
+ Expression* type_of = factory()->NewUnaryOperation(
+ Token::TYPEOF, factory()->NewVariableProxy(var), nopos);
+ Expression* function_literal = factory()->NewStringLiteral(
+ ast_value_factory()->function_string(), nopos);
+ Expression* condition = factory()->NewCompareOperation(
Token::EQ_STRICT, type_of, function_literal, nopos);
- Statement* throw_call = factory->NewExpressionStatement(error, pos);
+ Statement* throw_call = factory()->NewExpressionStatement(error, pos);
- validate_var = factory->NewIfStatement(
- condition, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ validate_var = factory()->NewIfStatement(
+ condition, factory()->NewEmptyStatement(nopos), throw_call, nopos);
}
return validate_var;
}
-void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
- Variable* iterator,
- Maybe<Variable*> input,
- Variable* var_output) {
+void Parser::BuildIteratorClose(ZoneList<Statement*>* statements,
+ Variable* iterator, Variable* input,
+ Variable* var_output) {
//
// This function adds four statements to [statements], corresponding to the
// following code:
@@ -6378,33 +6445,22 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
// output = %_Call(iteratorReturn, iterator, input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
//
- // When the input variable is not given, the return statement becomes
- // return {value: undefined, done: true};
- // and %_Call has only two arguments:
- // output = %_Call(iteratorReturn, iterator);
- //
- // 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();
- auto avfactory = parser_->ast_value_factory();
- auto zone = parser_->zone();
+ const int nopos = kNoSourcePosition;
// let iteratorReturn = iterator.return;
Variable* var_return = var_output; // Reusing the output variable.
Statement* get_return;
{
- Expression* iterator_proxy = factory->NewVariableProxy(iterator);
- Expression* literal =
- factory->NewStringLiteral(avfactory->return_string(), nopos);
+ Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
+ Expression* literal = factory()->NewStringLiteral(
+ ast_value_factory()->return_string(), nopos);
Expression* property =
- factory->NewProperty(iterator_proxy, literal, nopos);
- Expression* return_proxy = factory->NewVariableProxy(var_return);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, return_proxy, property, nopos);
- get_return = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewProperty(iterator_proxy, literal, nopos);
+ Expression* return_proxy = factory()->NewVariableProxy(var_return);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, return_proxy, property, nopos);
+ get_return = factory()->NewExpressionStatement(assignment, nopos);
}
// if (IS_NULL_OR_UNDEFINED(iteratorReturn) {
@@ -6412,38 +6468,33 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
// }
Statement* check_return;
{
- Expression* condition = factory->NewCompareOperation(
- Token::EQ, factory->NewVariableProxy(var_return),
- factory->NewNullLiteral(nopos), nopos);
+ 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(BuildIteratorResult(value, true), nopos);
+ factory()->NewReturnStatement(BuildIteratorResult(value, true), nopos);
- check_return = factory->NewIfStatement(
- condition, return_input, factory->NewEmptyStatement(nopos), nopos);
+ check_return = factory()->NewIfStatement(
+ condition, return_input, factory()->NewEmptyStatement(nopos), nopos);
}
// 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);
- }
+ auto args = new (zone()) ZoneList<Expression*>(3, zone());
+ args->Add(factory()->NewVariableProxy(var_return), zone());
+ args->Add(factory()->NewVariableProxy(iterator), zone());
+ args->Add(factory()->NewVariableProxy(input), zone());
Expression* call =
- factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
- Expression* output_proxy = factory->NewVariableProxy(var_output);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, output_proxy, call, nopos);
- call_return = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
+ call_return = factory()->NewExpressionStatement(assignment, nopos);
}
// if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
@@ -6451,36 +6502,35 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
{
Expression* is_receiver_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
is_receiver_call =
- factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
- Expression* call = factory->NewCallRuntime(
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
+ Expression* call = factory()->NewCallRuntime(
Runtime::kThrowIteratorResultNotAnObject, args, nopos);
- throw_call = factory->NewExpressionStatement(call, nopos);
+ throw_call = factory()->NewExpressionStatement(call, nopos);
}
- validate_output = factory->NewIfStatement(
- is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ validate_output = factory()->NewIfStatement(
+ is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
+ nopos);
}
- statements->Add(get_return, zone);
- statements->Add(check_return, zone);
- statements->Add(call_return, zone);
- statements->Add(validate_output, zone);
+ statements->Add(get_return, zone());
+ statements->Add(check_return, zone());
+ statements->Add(call_return, zone());
+ statements->Add(validate_output, zone());
}
-void ParserTraits::FinalizeIteratorUse(Variable* completion,
- Expression* condition, Variable* iter,
- Block* iterator_use, Block* target) {
- if (!FLAG_harmony_iterator_close) return;
-
+void Parser::FinalizeIteratorUse(Variable* completion, Expression* condition,
+ Variable* iter, Block* iterator_use,
+ Block* target) {
//
// This function adds two statements to [target], corresponding to the
// following code:
@@ -6500,36 +6550,33 @@ void ParserTraits::FinalizeIteratorUse(Variable* completion,
// }
//
- const int nopos = RelocInfo::kNoPosition;
- auto factory = parser_->factory();
- auto avfactory = parser_->ast_value_factory();
- auto scope = parser_->scope_;
- auto zone = parser_->zone();
+ const int nopos = kNoSourcePosition;
// completion = kNormalCompletion;
Statement* initialize_completion;
{
- Expression* proxy = factory->NewVariableProxy(completion);
- Expression* assignment = factory->NewAssignment(
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, proxy,
- factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
- initialize_completion = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
+ initialize_completion =
+ factory()->NewExpressionStatement(assignment, nopos);
}
// if (completion === kAbruptCompletion) completion = kThrowCompletion;
Statement* set_completion_throw;
{
- Expression* condition = factory->NewCompareOperation(
- Token::EQ_STRICT, factory->NewVariableProxy(completion),
- factory->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
+ Expression* condition = factory()->NewCompareOperation(
+ Token::EQ_STRICT, factory()->NewVariableProxy(completion),
+ factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
- Expression* proxy = factory->NewVariableProxy(completion);
- Expression* assignment = factory->NewAssignment(
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, proxy,
- factory->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos);
- Statement* statement = factory->NewExpressionStatement(assignment, nopos);
- set_completion_throw = factory->NewIfStatement(
- condition, statement, factory->NewEmptyStatement(nopos), nopos);
+ factory()->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos);
+ Statement* statement = factory()->NewExpressionStatement(assignment, nopos);
+ set_completion_throw = factory()->NewIfStatement(
+ condition, statement, factory()->NewEmptyStatement(nopos), nopos);
}
// if (condition) {
@@ -6537,16 +6584,16 @@ void ParserTraits::FinalizeIteratorUse(Variable* completion,
// }
Block* maybe_close;
{
- Block* block = factory->NewBlock(nullptr, 2, true, nopos);
- parser_->BuildIteratorCloseForCompletion(block->statements(), iter,
- completion);
+ Block* block = factory()->NewBlock(nullptr, 2, true, nopos);
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ BuildIteratorCloseForCompletion(block->statements(), iter, proxy);
DCHECK(block->statements()->length() == 2);
- maybe_close = factory->NewBlock(nullptr, 1, true, nopos);
+ maybe_close = factory()->NewBlock(nullptr, 1, true, nopos);
maybe_close->statements()->Add(
- factory->NewIfStatement(condition, block,
- factory->NewEmptyStatement(nopos), nopos),
- zone);
+ factory()->NewIfStatement(condition, block,
+ factory()->NewEmptyStatement(nopos), nopos),
+ zone());
}
// try { #try_block }
@@ -6556,10 +6603,11 @@ void ParserTraits::FinalizeIteratorUse(Variable* completion,
// }
Statement* try_catch;
{
- Scope* catch_scope = parser_->NewScope(scope, CATCH_SCOPE);
+ Scope* catch_scope = NewScopeWithParent(scope(), CATCH_SCOPE);
Variable* catch_variable =
- catch_scope->DeclareLocal(avfactory->dot_catch_string(), VAR,
+ catch_scope->DeclareLocal(ast_value_factory()->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
@@ -6567,37 +6615,37 @@ void ParserTraits::FinalizeIteratorUse(Variable* completion,
// TryCatchStatementForReThrow below (which does not clear the pending
// message), rather than a TryCatchStatement.
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(catch_variable), zone);
- rethrow = factory->NewExpressionStatement(
- factory->NewCallRuntime(Runtime::kReThrow, args, nopos), nopos);
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(catch_variable), zone());
+ rethrow = factory()->NewExpressionStatement(
+ factory()->NewCallRuntime(Runtime::kReThrow, args, nopos), nopos);
}
- Block* catch_block = factory->NewBlock(nullptr, 2, false, nopos);
- catch_block->statements()->Add(set_completion_throw, zone);
- catch_block->statements()->Add(rethrow, zone);
+ Block* catch_block = factory()->NewBlock(nullptr, 2, false, nopos);
+ catch_block->statements()->Add(set_completion_throw, zone());
+ catch_block->statements()->Add(rethrow, zone());
- try_catch = factory->NewTryCatchStatementForReThrow(
+ try_catch = factory()->NewTryCatchStatementForReThrow(
iterator_use, catch_scope, catch_variable, catch_block, nopos);
}
// try { #try_catch } finally { #maybe_close }
Statement* try_finally;
{
- Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
- try_block->statements()->Add(try_catch, zone);
+ Block* try_block = factory()->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(try_catch, zone());
try_finally =
- factory->NewTryFinallyStatement(try_block, maybe_close, nopos);
+ factory()->NewTryFinallyStatement(try_block, maybe_close, nopos);
}
- target->statements()->Add(initialize_completion, zone);
- target->statements()->Add(try_finally, zone);
+ target->statements()->Add(initialize_completion, zone());
+ target->statements()->Add(try_finally, zone());
}
-void ParserTraits::BuildIteratorCloseForCompletion(
- ZoneList<Statement*>* statements, Variable* iterator,
- Variable* completion) {
+void Parser::BuildIteratorCloseForCompletion(ZoneList<Statement*>* statements,
+ Variable* iterator,
+ Expression* completion) {
//
// This function adds two statements to [statements], corresponding to the
// following code:
@@ -6618,26 +6666,20 @@ void ParserTraits::BuildIteratorCloseForCompletion(
// }
//
- const int nopos = RelocInfo::kNoPosition;
- auto factory = parser_->factory();
- auto avfactory = parser_->ast_value_factory();
- auto scope = parser_->scope_;
- auto zone = parser_->zone();
-
-
+ const int nopos = kNoSourcePosition;
// let iteratorReturn = iterator.return;
- Variable* var_return = scope->NewTemporary(avfactory->empty_string());
+ Variable* var_return = NewTemporary(ast_value_factory()->empty_string());
Statement* get_return;
{
- Expression* iterator_proxy = factory->NewVariableProxy(iterator);
- Expression* literal =
- factory->NewStringLiteral(avfactory->return_string(), nopos);
+ Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
+ Expression* literal = factory()->NewStringLiteral(
+ ast_value_factory()->return_string(), nopos);
Expression* property =
- factory->NewProperty(iterator_proxy, literal, nopos);
- Expression* return_proxy = factory->NewVariableProxy(var_return);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, return_proxy, property, nopos);
- get_return = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewProperty(iterator_proxy, literal, nopos);
+ Expression* return_proxy = factory()->NewVariableProxy(var_return);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, return_proxy, property, nopos);
+ get_return = factory()->NewExpressionStatement(assignment, nopos);
}
// if (!IS_CALLABLE(iteratorReturn)) {
@@ -6645,34 +6687,35 @@ void ParserTraits::BuildIteratorCloseForCompletion(
// }
Statement* check_return_callable;
{
- Expression* throw_expr = NewThrowTypeError(
- MessageTemplate::kReturnMethodNotCallable,
- avfactory->empty_string(), nopos);
+ Expression* throw_expr =
+ NewThrowTypeError(MessageTemplate::kReturnMethodNotCallable,
+ ast_value_factory()->empty_string(), nopos);
check_return_callable = CheckCallable(var_return, throw_expr, nopos);
}
// try { %_Call(iteratorReturn, iterator) } catch (_) { }
Statement* try_call_return;
{
- auto args = new (zone) ZoneList<Expression*>(2, zone);
- args->Add(factory->NewVariableProxy(var_return), zone);
- args->Add(factory->NewVariableProxy(iterator), zone);
+ auto args = new (zone()) ZoneList<Expression*>(2, zone());
+ args->Add(factory()->NewVariableProxy(var_return), zone());
+ args->Add(factory()->NewVariableProxy(iterator), zone());
Expression* call =
- factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
- Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
- try_block->statements()->Add(factory->NewExpressionStatement(call, nopos),
- zone);
+ Block* try_block = factory()->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(factory()->NewExpressionStatement(call, nopos),
+ zone());
- Block* catch_block = factory->NewBlock(nullptr, 0, false, nopos);
+ Block* catch_block = factory()->NewBlock(nullptr, 0, false, nopos);
- Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
- Variable* catch_variable = catch_scope->DeclareLocal(
- avfactory->dot_catch_string(), VAR, kCreatedInitialized,
- Variable::NORMAL);
+ Scope* catch_scope = NewScope(CATCH_SCOPE);
+ Variable* catch_variable =
+ catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), VAR,
+ kCreatedInitialized, Variable::NORMAL);
+ catch_scope->set_is_hidden();
- try_call_return = factory->NewTryCatchStatement(
+ try_call_return = factory()->NewTryCatchStatement(
try_block, catch_scope, catch_variable, catch_block, nopos);
}
@@ -6682,44 +6725,45 @@ void ParserTraits::BuildIteratorCloseForCompletion(
// }
Block* validate_return;
{
- Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+ Variable* var_output = NewTemporary(ast_value_factory()->empty_string());
Statement* call_return;
{
- auto args = new (zone) ZoneList<Expression*>(2, zone);
- args->Add(factory->NewVariableProxy(var_return), zone);
- args->Add(factory->NewVariableProxy(iterator), zone);
+ auto args = new (zone()) ZoneList<Expression*>(2, zone());
+ args->Add(factory()->NewVariableProxy(var_return), zone());
+ args->Add(factory()->NewVariableProxy(iterator), zone());
Expression* call =
- factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
- Expression* output_proxy = factory->NewVariableProxy(var_output);
+ Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* assignment =
- factory->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
- call_return = factory->NewExpressionStatement(assignment, nopos);
+ factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
+ call_return = factory()->NewExpressionStatement(assignment, nopos);
}
Expression* is_receiver_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
is_receiver_call =
- factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+ factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
- auto args = new (zone) ZoneList<Expression*>(1, zone);
- args->Add(factory->NewVariableProxy(var_output), zone);
- Expression* call = factory->NewCallRuntime(
+ auto args = new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(factory()->NewVariableProxy(var_output), zone());
+ Expression* call = factory()->NewCallRuntime(
Runtime::kThrowIteratorResultNotAnObject, args, nopos);
- throw_call = factory->NewExpressionStatement(call, nopos);
+ throw_call = factory()->NewExpressionStatement(call, nopos);
}
- Statement* check_return = factory->NewIfStatement(
- is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+ Statement* check_return = factory()->NewIfStatement(
+ is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
+ nopos);
- validate_return = factory->NewBlock(nullptr, 2, false, nopos);
- validate_return->statements()->Add(call_return, zone);
- validate_return->statements()->Add(check_return, zone);
+ validate_return = factory()->NewBlock(nullptr, 2, false, nopos);
+ validate_return->statements()->Add(call_return, zone());
+ validate_return->statements()->Add(check_return, zone());
}
// if (completion === kThrowCompletion) {
@@ -6730,44 +6774,40 @@ void ParserTraits::BuildIteratorCloseForCompletion(
// }
Statement* call_return_carefully;
{
- Expression* condition = factory->NewCompareOperation(
- Token::EQ_STRICT, factory->NewVariableProxy(completion),
- factory->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos);
+ Expression* condition = factory()->NewCompareOperation(
+ Token::EQ_STRICT, completion,
+ factory()->NewSmiLiteral(Parser::kThrowCompletion, nopos), nopos);
- Block* then_block = factory->NewBlock(nullptr, 2, false, nopos);
- then_block->statements()->Add(check_return_callable, zone);
- then_block->statements()->Add(try_call_return, zone);
+ Block* then_block = factory()->NewBlock(nullptr, 2, false, nopos);
+ then_block->statements()->Add(check_return_callable, zone());
+ then_block->statements()->Add(try_call_return, zone());
- call_return_carefully =
- factory->NewIfStatement(condition, then_block, validate_return, nopos);
+ call_return_carefully = factory()->NewIfStatement(condition, then_block,
+ validate_return, nopos);
}
// if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { ... }
Statement* maybe_call_return;
{
- Expression* condition = factory->NewCompareOperation(
- Token::EQ, factory->NewVariableProxy(var_return),
- factory->NewNullLiteral(nopos), nopos);
+ Expression* condition = factory()->NewCompareOperation(
+ Token::EQ, factory()->NewVariableProxy(var_return),
+ factory()->NewNullLiteral(nopos), nopos);
- maybe_call_return =
- factory->NewIfStatement(condition, factory->NewEmptyStatement(nopos),
- call_return_carefully, nopos);
+ maybe_call_return = factory()->NewIfStatement(
+ condition, factory()->NewEmptyStatement(nopos), call_return_carefully,
+ nopos);
}
-
- statements->Add(get_return, zone);
- statements->Add(maybe_call_return, zone);
+ statements->Add(get_return, zone());
+ statements->Add(maybe_call_return, zone());
}
-
-Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
- if (!FLAG_harmony_iterator_close) return loop;
-
+Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop,
+ Variable* var_completion, int pos) {
//
// This function replaces the loop with the following wrapping:
//
- // let each;
- // let completion = kNormalCompletion;
+ // completion = kNormalCompletion;
// try {
// try {
// #loop;
@@ -6781,120 +6821,48 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
// }
// }
//
- // where the loop's body is wrapped as follows:
+ // Note that the loop's body and its assign_each already contain appropriate
+ // assignments to completion (see InitializeForOfStatement).
//
- // {
- // #loop-body
- // {{completion = kNormalCompletion;}}
- // }
- //
- // and the loop's assign_each is wrapped as follows
- //
- // do {
- // {{completion = kAbruptCompletion;}}
- // #assign-each
- // }
- //
-
- const int nopos = RelocInfo::kNoPosition;
- auto factory = parser_->factory();
- auto avfactory = parser_->ast_value_factory();
- auto scope = parser_->scope_;
- auto zone = parser_->zone();
- Variable* var_completion = scope->NewTemporary(avfactory->empty_string());
-
- // let each;
- Variable* var_each = scope->NewTemporary(avfactory->empty_string());
- Statement* initialize_each;
- {
- Expression* proxy = factory->NewVariableProxy(var_each);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, proxy,
- factory->NewUndefinedLiteral(nopos), nopos);
- initialize_each =
- factory->NewExpressionStatement(assignment, nopos);
- }
+ const int nopos = kNoSourcePosition;
// !(completion === kNormalCompletion || IS_UNDEFINED(#iterator))
Expression* closing_condition;
{
- Expression* lhs = factory->NewCompareOperation(
- Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
- factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
- Expression* rhs = factory->NewCompareOperation(
- Token::EQ_STRICT, factory->NewVariableProxy(loop->iterator()),
- factory->NewUndefinedLiteral(nopos), nopos);
- closing_condition = factory->NewUnaryOperation(
- Token::NOT, factory->NewBinaryOperation(Token::OR, lhs, rhs, nopos),
+ Expression* lhs = factory()->NewCompareOperation(
+ Token::EQ_STRICT, factory()->NewVariableProxy(var_completion),
+ factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
+ Expression* rhs = factory()->NewCompareOperation(
+ Token::EQ_STRICT, factory()->NewVariableProxy(loop->iterator()),
+ factory()->NewUndefinedLiteral(nopos), nopos);
+ closing_condition = factory()->NewUnaryOperation(
+ Token::NOT, factory()->NewBinaryOperation(Token::OR, lhs, rhs, nopos),
nopos);
}
- // {{completion = kNormalCompletion;}}
- Statement* set_completion_normal;
- {
- Expression* proxy = factory->NewVariableProxy(var_completion);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, proxy,
- factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
-
- Block* block = factory->NewBlock(nullptr, 1, true, nopos);
- block->statements()->Add(
- factory->NewExpressionStatement(assignment, nopos), zone);
- set_completion_normal = block;
- }
-
- // {{completion = kAbruptCompletion;}}
- Statement* set_completion_abrupt;
- {
- Expression* proxy = factory->NewVariableProxy(var_completion);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, proxy,
- factory->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
-
- Block* block = factory->NewBlock(nullptr, 1, true, nopos);
- block->statements()->Add(factory->NewExpressionStatement(assignment, nopos),
- zone);
- set_completion_abrupt = block;
- }
-
- // { #loop-body; #set_completion_normal }
- Block* new_body = factory->NewBlock(nullptr, 2, false, nopos);
+ Block* final_loop = factory()->NewBlock(nullptr, 2, false, nopos);
{
- new_body->statements()->Add(loop->body(), zone);
- new_body->statements()->Add(set_completion_normal, zone);
- }
-
- // { #set_completion_abrupt; #assign-each }
- Block* new_assign_each = factory->NewBlock(nullptr, 2, false, nopos);
- {
- new_assign_each->statements()->Add(set_completion_abrupt, zone);
- new_assign_each->statements()->Add(
- factory->NewExpressionStatement(loop->assign_each(), nopos), zone);
- }
-
- // Now put things together.
-
- loop->set_body(new_body);
- loop->set_assign_each(
- factory->NewDoExpression(new_assign_each, var_each, nopos));
-
- Statement* final_loop;
- {
- Block* target = factory->NewBlock(nullptr, 3, false, nopos);
- target->statements()->Add(initialize_each, zone);
-
- Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
- try_block->statements()->Add(loop, zone);
+ Block* try_block = factory()->NewBlock(nullptr, 1, false, nopos);
+ try_block->statements()->Add(loop, zone());
FinalizeIteratorUse(var_completion, closing_condition, loop->iterator(),
- try_block, target);
- final_loop = target;
+ try_block, final_loop);
}
return final_loop;
}
+#ifdef DEBUG
+void Parser::Print(AstNode* node) {
+ ast_value_factory()->Internalize(Isolate::Current());
+ node->Print(Isolate::Current());
+}
+#endif // DEBUG
+
+#undef CHECK_OK
+#undef CHECK_OK_VOID
+#undef CHECK_FAILED
} // namespace internal
} // namespace v8