2015-05-11 16:28:28 +00:00
|
|
|
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/ast.h"
|
2015-05-18 08:34:05 +00:00
|
|
|
#include "src/messages.h"
|
2015-05-11 16:28:28 +00:00
|
|
|
#include "src/parser.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
|
2015-05-15 09:56:31 +00:00
|
|
|
void Parser::PatternRewriter::DeclareAndInitializeVariables(
|
|
|
|
Block* block, const DeclarationDescriptor* declaration_descriptor,
|
|
|
|
const DeclarationParsingResult::Declaration* declaration,
|
|
|
|
ZoneList<const AstRawString*>* names, bool* ok) {
|
|
|
|
PatternRewriter rewriter;
|
2015-05-11 16:28:28 +00:00
|
|
|
|
2015-05-15 09:56:31 +00:00
|
|
|
rewriter.pattern_ = declaration->pattern;
|
|
|
|
rewriter.initializer_position_ = declaration->initializer_position;
|
|
|
|
rewriter.block_ = block;
|
|
|
|
rewriter.descriptor_ = declaration_descriptor;
|
|
|
|
rewriter.names_ = names;
|
|
|
|
rewriter.ok_ = ok;
|
2015-05-11 16:28:28 +00:00
|
|
|
|
2015-05-15 09:56:31 +00:00
|
|
|
rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
|
|
|
Expression* value = current_value_;
|
2015-09-30 20:22:23 +00:00
|
|
|
descriptor_->scope->RemoveUnresolved(pattern);
|
2015-05-11 16:28:28 +00:00
|
|
|
|
|
|
|
// Declare variable.
|
|
|
|
// Note that we *always* must treat the initial value via a separate init
|
|
|
|
// assignment for variables and constants because the value must be assigned
|
|
|
|
// when the variable is encountered in the source. But the variable/constant
|
|
|
|
// is declared (and set to 'undefined') upon entering the function within
|
|
|
|
// which the variable or constant is declared. Only function variables have
|
|
|
|
// an initial value in the declaration (because they are initialized upon
|
|
|
|
// entering the function).
|
|
|
|
//
|
|
|
|
// If we have a legacy const declaration, in an inner scope, the proxy
|
|
|
|
// is always bound to the declared variable (independent of possibly
|
|
|
|
// surrounding 'with' statements).
|
|
|
|
// For let/const declarations in harmony mode, we can also immediately
|
|
|
|
// pre-resolve the proxy because it resides in the same scope as the
|
|
|
|
// declaration.
|
2015-05-15 09:56:31 +00:00
|
|
|
Parser* parser = descriptor_->parser;
|
2015-05-11 16:28:28 +00:00
|
|
|
const AstRawString* name = pattern->raw_name();
|
2015-05-15 09:56:31 +00:00
|
|
|
VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode);
|
2015-05-11 16:28:28 +00:00
|
|
|
Declaration* declaration = factory()->NewVariableDeclaration(
|
2015-05-21 17:47:07 +00:00
|
|
|
proxy, descriptor_->mode, descriptor_->scope,
|
|
|
|
descriptor_->declaration_pos);
|
2015-06-22 14:15:53 +00:00
|
|
|
Variable* var = parser->Declare(declaration, descriptor_->declaration_kind,
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
descriptor_->mode != VAR, ok_,
|
|
|
|
descriptor_->hoist_scope);
|
2015-05-11 16:28:28 +00:00
|
|
|
if (!*ok_) return;
|
|
|
|
DCHECK_NOT_NULL(var);
|
|
|
|
DCHECK(!proxy->is_resolved() || proxy->var() == var);
|
2015-05-15 09:56:31 +00:00
|
|
|
var->set_initializer_position(initializer_position_);
|
|
|
|
|
|
|
|
DCHECK(initializer_position_ != RelocInfo::kNoPosition);
|
|
|
|
|
|
|
|
if (descriptor_->declaration_scope->num_var_or_const() >
|
|
|
|
kMaxNumFunctionLocals) {
|
2015-05-18 08:34:05 +00:00
|
|
|
parser->ReportMessage(MessageTemplate::kTooManyVariables);
|
2015-05-11 16:28:28 +00:00
|
|
|
*ok_ = false;
|
|
|
|
return;
|
|
|
|
}
|
2015-05-15 09:56:31 +00:00
|
|
|
if (names_) {
|
|
|
|
names_->Add(name, zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize variables if needed. A
|
|
|
|
// declaration of the form:
|
|
|
|
//
|
|
|
|
// var v = x;
|
|
|
|
//
|
|
|
|
// is syntactic sugar for:
|
|
|
|
//
|
|
|
|
// var v; v = x;
|
|
|
|
//
|
|
|
|
// In particular, we need to re-lookup 'v' (in scope_, not
|
|
|
|
// declaration_scope) as it may be a different 'v' than the 'v' in the
|
|
|
|
// declaration (e.g., if we are inside a 'with' statement or 'catch'
|
|
|
|
// block).
|
|
|
|
//
|
|
|
|
// However, note that const declarations are different! A const
|
|
|
|
// declaration of the form:
|
|
|
|
//
|
|
|
|
// const c = x;
|
|
|
|
//
|
|
|
|
// is *not* syntactic sugar for:
|
|
|
|
//
|
|
|
|
// const c; c = x;
|
|
|
|
//
|
|
|
|
// The "variable" c initialized to x is the same as the declared
|
|
|
|
// one - there is no re-lookup (see the last parameter of the
|
|
|
|
// Declare() call above).
|
2015-05-15 09:56:31 +00:00
|
|
|
Scope* initialization_scope = descriptor_->is_const
|
|
|
|
? descriptor_->declaration_scope
|
|
|
|
: descriptor_->scope;
|
2015-05-11 16:28:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Global variable declarations must be compiled in a specific
|
|
|
|
// way. When the script containing the global variable declaration
|
|
|
|
// is entered, the global variable must be declared, so that if it
|
|
|
|
// doesn't exist (on the global object itself, see ES5 errata) it
|
|
|
|
// gets created with an initial undefined value. This is handled
|
|
|
|
// by the declarations part of the function representing the
|
|
|
|
// top-level global code; see Runtime::DeclareGlobalVariable. If
|
|
|
|
// it already exists (in the object or in a prototype), it is
|
|
|
|
// *not* touched until the variable declaration statement is
|
|
|
|
// executed.
|
|
|
|
//
|
|
|
|
// Executing the variable declaration statement will always
|
|
|
|
// guarantee to give the global object an own property.
|
|
|
|
// This way, global variable declarations can shadow
|
|
|
|
// properties in the prototype chain, but only after the variable
|
|
|
|
// declaration statement has been executed. This is important in
|
|
|
|
// browsers where the global object (window) has lots of
|
|
|
|
// properties defined in prototype objects.
|
|
|
|
if (initialization_scope->is_script_scope() &&
|
2015-05-15 09:56:31 +00:00
|
|
|
!IsLexicalVariableMode(descriptor_->mode)) {
|
2015-05-11 16:28:28 +00:00
|
|
|
// Compute the arguments for the runtime
|
|
|
|
// call.test-parsing/InitializedDeclarationsInStrictForOfError
|
|
|
|
ZoneList<Expression*>* arguments =
|
|
|
|
new (zone()) ZoneList<Expression*>(3, zone());
|
|
|
|
// We have at least 1 parameter.
|
2015-05-21 17:47:07 +00:00
|
|
|
arguments->Add(
|
|
|
|
factory()->NewStringLiteral(name, descriptor_->declaration_pos),
|
|
|
|
zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
CallRuntime* initialize;
|
|
|
|
|
2015-05-15 09:56:31 +00:00
|
|
|
if (descriptor_->is_const) {
|
2015-05-11 16:28:28 +00:00
|
|
|
arguments->Add(value, zone());
|
|
|
|
value = NULL; // zap the value to avoid the unnecessary assignment
|
|
|
|
|
|
|
|
// Construct the call to Runtime_InitializeConstGlobal
|
|
|
|
// and add it to the initialization statement block.
|
|
|
|
// Note that the function does different things depending on
|
|
|
|
// the number of arguments (1 or 2).
|
2015-08-26 11:16:38 +00:00
|
|
|
initialize =
|
|
|
|
factory()->NewCallRuntime(Runtime::kInitializeConstGlobal, arguments,
|
|
|
|
descriptor_->initialization_pos);
|
2015-05-11 16:28:28 +00:00
|
|
|
} else {
|
|
|
|
// Add language mode.
|
|
|
|
// We may want to pass singleton to avoid Literal allocations.
|
|
|
|
LanguageMode language_mode = initialization_scope->language_mode();
|
2015-05-21 17:47:07 +00:00
|
|
|
arguments->Add(factory()->NewNumberLiteral(language_mode,
|
|
|
|
descriptor_->declaration_pos),
|
|
|
|
zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
|
|
|
|
// Be careful not to assign a value to the global variable if
|
|
|
|
// we're in a with. The initialization value should not
|
|
|
|
// necessarily be stored in the global object in that case,
|
|
|
|
// which is why we need to generate a separate assignment node.
|
|
|
|
if (value != NULL && !inside_with()) {
|
|
|
|
arguments->Add(value, zone());
|
|
|
|
value = NULL; // zap the value to avoid the unnecessary assignment
|
|
|
|
// Construct the call to Runtime_InitializeVarGlobal
|
|
|
|
// and add it to the initialization statement block.
|
2015-08-26 11:16:38 +00:00
|
|
|
initialize =
|
|
|
|
factory()->NewCallRuntime(Runtime::kInitializeVarGlobal, arguments,
|
|
|
|
descriptor_->declaration_pos);
|
2015-05-11 16:28:28 +00:00
|
|
|
} else {
|
|
|
|
initialize = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (initialize != NULL) {
|
2015-05-15 09:56:31 +00:00
|
|
|
block_->AddStatement(
|
2015-05-11 16:28:28 +00:00
|
|
|
factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
|
|
|
|
zone());
|
|
|
|
}
|
2015-05-15 09:56:31 +00:00
|
|
|
} else if (value != nullptr && (descriptor_->needs_init ||
|
|
|
|
IsLexicalVariableMode(descriptor_->mode))) {
|
2015-05-11 16:28:28 +00:00
|
|
|
// Constant initializations always assign to the declared constant which
|
|
|
|
// is always at the function scope level. This is only relevant for
|
|
|
|
// dynamically looked-up variables and constants (the
|
|
|
|
// start context for constant lookups is always the function context,
|
|
|
|
// while it is the top context for var declared variables). Sigh...
|
|
|
|
// For 'let' and 'const' declared variables in harmony mode the
|
|
|
|
// initialization also always assigns to the declared variable.
|
|
|
|
DCHECK_NOT_NULL(proxy);
|
|
|
|
DCHECK_NOT_NULL(proxy->var());
|
|
|
|
DCHECK_NOT_NULL(value);
|
2015-05-15 09:56:31 +00:00
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2015-05-21 17:47:07 +00:00
|
|
|
descriptor_->init_op, proxy, value, descriptor_->initialization_pos);
|
2015-05-15 09:56:31 +00:00
|
|
|
block_->AddStatement(
|
2015-05-11 16:28:28 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
|
|
|
|
zone());
|
|
|
|
value = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add an assignment node to the initialization statement block if we still
|
|
|
|
// have a pending initialization value.
|
|
|
|
if (value != NULL) {
|
2015-05-15 09:56:31 +00:00
|
|
|
DCHECK(descriptor_->mode == VAR);
|
2015-05-11 16:28:28 +00:00
|
|
|
// 'var' initializations are simply assignments (with all the consequences
|
|
|
|
// if they are inside a 'with' statement - they may change a 'with' object
|
|
|
|
// property).
|
|
|
|
VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
|
2015-05-15 09:56:31 +00:00
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
2015-05-21 17:47:07 +00:00
|
|
|
descriptor_->init_op, proxy, value, descriptor_->initialization_pos);
|
2015-05-15 09:56:31 +00:00
|
|
|
block_->AddStatement(
|
2015-05-11 16:28:28 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
|
|
|
|
zone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:29:50 +00:00
|
|
|
Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
|
2015-07-23 13:51:27 +00:00
|
|
|
auto temp = descriptor_->parser->scope_->NewTemporary(
|
|
|
|
ast_value_factory()->empty_string());
|
2015-05-20 08:08:26 +00:00
|
|
|
if (value != nullptr) {
|
|
|
|
auto assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(temp), value,
|
|
|
|
RelocInfo::kNoPosition);
|
2015-05-18 20:15:08 +00:00
|
|
|
|
2015-05-20 08:08:26 +00:00
|
|
|
block_->AddStatement(
|
|
|
|
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
|
|
|
|
zone());
|
|
|
|
}
|
2015-05-19 14:29:50 +00:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2015-05-18 20:15:08 +00:00
|
|
|
|
2015-05-19 14:29:50 +00:00
|
|
|
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
|
|
|
|
auto temp = CreateTempVar(current_value_);
|
2015-05-19 16:27:21 +00:00
|
|
|
|
|
|
|
block_->AddStatement(descriptor_->parser->BuildAssertIsCoercible(temp),
|
|
|
|
zone());
|
2015-05-18 20:15:08 +00:00
|
|
|
|
2015-05-11 16:28:28 +00:00
|
|
|
for (ObjectLiteralProperty* property : *pattern->properties()) {
|
|
|
|
RecurseIntoSubpattern(
|
|
|
|
property->value(),
|
|
|
|
factory()->NewProperty(factory()->NewVariableProxy(temp),
|
|
|
|
property->key(), RelocInfo::kNoPosition));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
|
2015-05-20 08:08:26 +00:00
|
|
|
auto iterator = CreateTempVar(
|
|
|
|
descriptor_->parser->GetIterator(current_value_, factory()));
|
|
|
|
auto done = CreateTempVar(
|
|
|
|
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
|
|
|
|
auto result = CreateTempVar();
|
|
|
|
auto v = CreateTempVar();
|
2015-05-20 15:05:58 +00:00
|
|
|
|
|
|
|
Spread* spread = nullptr;
|
2015-05-20 08:08:26 +00:00
|
|
|
for (Expression* value : *node->values()) {
|
2015-05-20 15:05:58 +00:00
|
|
|
if (value->IsSpread()) {
|
|
|
|
spread = value->AsSpread();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-05-20 08:08:26 +00:00
|
|
|
// if (!done) {
|
|
|
|
// result = IteratorNext(iterator);
|
|
|
|
// v = (done = result.done) ? undefined : result.value;
|
|
|
|
// }
|
|
|
|
auto next_block =
|
|
|
|
factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
|
|
|
|
next_block->AddStatement(factory()->NewExpressionStatement(
|
|
|
|
descriptor_->parser->BuildIteratorNextResult(
|
|
|
|
factory()->NewVariableProxy(iterator),
|
|
|
|
result, RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
zone());
|
|
|
|
|
|
|
|
auto assign_to_done = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(ast_value_factory()->done_string(),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
auto next_value = factory()->NewConditional(
|
|
|
|
assign_to_done, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
|
|
|
|
factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(ast_value_factory()->value_string(),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
next_block->AddStatement(
|
|
|
|
factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(Token::ASSIGN,
|
|
|
|
factory()->NewVariableProxy(v), next_value,
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
zone());
|
|
|
|
|
|
|
|
auto if_statement = factory()->NewIfStatement(
|
|
|
|
factory()->NewUnaryOperation(Token::NOT,
|
|
|
|
factory()->NewVariableProxy(done),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
block_->AddStatement(if_statement, zone());
|
|
|
|
|
|
|
|
if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
|
|
|
|
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
|
|
|
|
}
|
|
|
|
}
|
2015-05-20 15:05:58 +00:00
|
|
|
|
|
|
|
if (spread != nullptr) {
|
|
|
|
// array = [];
|
2015-08-26 11:16:38 +00:00
|
|
|
// if (!done) %concat_iterable_to_array(array, iterator);
|
2015-05-20 15:05:58 +00:00
|
|
|
auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
|
|
|
|
auto array = CreateTempVar(factory()->NewArrayLiteral(
|
|
|
|
empty_exprs,
|
|
|
|
// Reuse pattern's literal index - it is unused since there is no
|
|
|
|
// actual literal allocated.
|
|
|
|
node->literal_index(), is_strong(descriptor_->parser->language_mode()),
|
|
|
|
RelocInfo::kNoPosition));
|
|
|
|
|
|
|
|
auto arguments = new (zone()) ZoneList<Expression*>(2, zone());
|
|
|
|
arguments->Add(factory()->NewVariableProxy(array), zone());
|
|
|
|
arguments->Add(factory()->NewVariableProxy(iterator), zone());
|
2015-08-26 11:16:38 +00:00
|
|
|
auto spread_into_array_call =
|
|
|
|
factory()->NewCallRuntime(Context::CONCAT_ITERABLE_TO_ARRAY_INDEX,
|
|
|
|
arguments, RelocInfo::kNoPosition);
|
2015-05-20 15:05:58 +00:00
|
|
|
|
|
|
|
auto if_statement = factory()->NewIfStatement(
|
|
|
|
factory()->NewUnaryOperation(Token::NOT,
|
|
|
|
factory()->NewVariableProxy(done),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
factory()->NewExpressionStatement(spread_into_array_call,
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
factory()->NewEmptyStatement(RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
block_->AddStatement(if_statement, zone());
|
|
|
|
|
|
|
|
|
|
|
|
RecurseIntoSubpattern(spread->expression(),
|
|
|
|
factory()->NewVariableProxy(array));
|
|
|
|
}
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
|
2015-05-19 14:29:50 +00:00
|
|
|
// let {<pattern> = <init>} = <value>
|
|
|
|
// becomes
|
|
|
|
// temp = <value>;
|
|
|
|
// <pattern> = temp === undefined ? <init> : temp;
|
|
|
|
DCHECK(node->op() == Token::ASSIGN);
|
|
|
|
auto temp = CreateTempVar(current_value_);
|
|
|
|
Expression* is_undefined = factory()->NewCompareOperation(
|
|
|
|
Token::EQ_STRICT, factory()->NewVariableProxy(temp),
|
|
|
|
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
Expression* value = factory()->NewConditional(
|
|
|
|
is_undefined, node->value(), factory()->NewVariableProxy(temp),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
RecurseIntoSubpattern(node->target(), value);
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =============== UNREACHABLE =============================
|
|
|
|
|
|
|
|
void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
|
|
|
|
|
|
|
|
#define NOT_A_PATTERN(Node) \
|
|
|
|
void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
|
|
|
|
UNREACHABLE(); \
|
|
|
|
}
|
|
|
|
|
|
|
|
NOT_A_PATTERN(BinaryOperation)
|
|
|
|
NOT_A_PATTERN(Block)
|
|
|
|
NOT_A_PATTERN(BreakStatement)
|
|
|
|
NOT_A_PATTERN(Call)
|
|
|
|
NOT_A_PATTERN(CallNew)
|
|
|
|
NOT_A_PATTERN(CallRuntime)
|
|
|
|
NOT_A_PATTERN(CaseClause)
|
|
|
|
NOT_A_PATTERN(ClassLiteral)
|
|
|
|
NOT_A_PATTERN(CompareOperation)
|
|
|
|
NOT_A_PATTERN(Conditional)
|
|
|
|
NOT_A_PATTERN(ContinueStatement)
|
|
|
|
NOT_A_PATTERN(CountOperation)
|
|
|
|
NOT_A_PATTERN(DebuggerStatement)
|
|
|
|
NOT_A_PATTERN(DoWhileStatement)
|
|
|
|
NOT_A_PATTERN(EmptyStatement)
|
2015-09-30 20:22:23 +00:00
|
|
|
NOT_A_PATTERN(EmptyParentheses)
|
2015-05-11 16:28:28 +00:00
|
|
|
NOT_A_PATTERN(ExportDeclaration)
|
|
|
|
NOT_A_PATTERN(ExpressionStatement)
|
|
|
|
NOT_A_PATTERN(ForInStatement)
|
|
|
|
NOT_A_PATTERN(ForOfStatement)
|
|
|
|
NOT_A_PATTERN(ForStatement)
|
|
|
|
NOT_A_PATTERN(FunctionDeclaration)
|
|
|
|
NOT_A_PATTERN(FunctionLiteral)
|
|
|
|
NOT_A_PATTERN(IfStatement)
|
|
|
|
NOT_A_PATTERN(ImportDeclaration)
|
|
|
|
NOT_A_PATTERN(Literal)
|
|
|
|
NOT_A_PATTERN(NativeFunctionLiteral)
|
|
|
|
NOT_A_PATTERN(Property)
|
|
|
|
NOT_A_PATTERN(RegExpLiteral)
|
|
|
|
NOT_A_PATTERN(ReturnStatement)
|
2015-09-30 20:22:23 +00:00
|
|
|
NOT_A_PATTERN(SloppyBlockFunctionStatement)
|
|
|
|
NOT_A_PATTERN(Spread)
|
2015-06-02 22:04:25 +00:00
|
|
|
NOT_A_PATTERN(SuperPropertyReference)
|
|
|
|
NOT_A_PATTERN(SuperCallReference)
|
2015-05-11 16:28:28 +00:00
|
|
|
NOT_A_PATTERN(SwitchStatement)
|
|
|
|
NOT_A_PATTERN(ThisFunction)
|
|
|
|
NOT_A_PATTERN(Throw)
|
|
|
|
NOT_A_PATTERN(TryCatchStatement)
|
|
|
|
NOT_A_PATTERN(TryFinallyStatement)
|
|
|
|
NOT_A_PATTERN(UnaryOperation)
|
|
|
|
NOT_A_PATTERN(VariableDeclaration)
|
|
|
|
NOT_A_PATTERN(WhileStatement)
|
|
|
|
NOT_A_PATTERN(WithStatement)
|
|
|
|
NOT_A_PATTERN(Yield)
|
|
|
|
|
|
|
|
#undef NOT_A_PATTERN
|
2015-06-01 22:46:54 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|