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.
|
|
|
|
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/ast/ast.h"
|
2015-05-18 08:34:05 +00:00
|
|
|
#include "src/messages.h"
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/parsing/parameter-initializer-rewriter.h"
|
|
|
|
#include "src/parsing/parser.h"
|
2015-05-11 16:28:28 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2016-03-08 09:35:11 +00:00
|
|
|
DCHECK(block->ignore_completion_value());
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
rewriter.scope_ = declaration_descriptor->scope;
|
|
|
|
rewriter.parser_ = declaration_descriptor->parser;
|
|
|
|
rewriter.context_ = BINDING;
|
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-12-22 13:28:34 +00:00
|
|
|
rewriter.recursion_level_ = 0;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::RewriteDestructuringAssignment(
|
2016-02-19 15:58:57 +00:00
|
|
|
Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
|
2015-12-04 17:20:10 +00:00
|
|
|
PatternRewriter rewriter;
|
|
|
|
|
|
|
|
DCHECK(!to_rewrite->is_rewritten());
|
|
|
|
|
2015-12-11 19:38:57 +00:00
|
|
|
bool ok = true;
|
2015-12-04 17:20:10 +00:00
|
|
|
rewriter.scope_ = scope;
|
|
|
|
rewriter.parser_ = parser;
|
|
|
|
rewriter.context_ = ASSIGNMENT;
|
|
|
|
rewriter.pattern_ = to_rewrite;
|
|
|
|
rewriter.block_ = nullptr;
|
|
|
|
rewriter.descriptor_ = nullptr;
|
|
|
|
rewriter.names_ = nullptr;
|
2015-12-11 19:38:57 +00:00
|
|
|
rewriter.ok_ = &ok;
|
2015-12-22 13:28:34 +00:00
|
|
|
rewriter.recursion_level_ = 0;
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
rewriter.RecurseIntoSubpattern(rewriter.pattern_, nullptr);
|
2015-12-11 19:38:57 +00:00
|
|
|
DCHECK(ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Expression* Parser::PatternRewriter::RewriteDestructuringAssignment(
|
|
|
|
Parser* parser, Assignment* assignment, Scope* scope) {
|
|
|
|
DCHECK_NOT_NULL(assignment);
|
|
|
|
DCHECK_EQ(Token::ASSIGN, assignment->op());
|
2016-02-19 15:58:57 +00:00
|
|
|
auto to_rewrite = parser->factory()->NewRewritableExpression(assignment);
|
2015-12-11 19:38:57 +00:00
|
|
|
RewriteDestructuringAssignment(parser, to_rewrite, scope);
|
|
|
|
return to_rewrite->expression();
|
2015-12-04 17:20:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Parser::PatternRewriter::IsAssignmentContext(PatternContext c) const {
|
|
|
|
return c == ASSIGNMENT || c == ASSIGNMENT_INITIALIZER;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Parser::PatternRewriter::IsBindingContext(PatternContext c) const {
|
|
|
|
return c == BINDING || c == INITIALIZER;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Parser::PatternRewriter::PatternContext
|
|
|
|
Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) {
|
|
|
|
PatternContext old_context = context();
|
2016-04-07 13:25:24 +00:00
|
|
|
// AssignmentExpressions may occur in the Initializer position of a
|
|
|
|
// SingleNameBinding. Such expressions should not prompt a change in the
|
|
|
|
// pattern's context.
|
|
|
|
if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN &&
|
|
|
|
!IsInitializerContext()) {
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(ASSIGNMENT);
|
|
|
|
}
|
|
|
|
return old_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Parser::PatternRewriter::PatternContext
|
|
|
|
Parser::PatternRewriter::SetInitializerContextIfNeeded(Expression* node) {
|
|
|
|
// Set appropriate initializer context for BindingElement and
|
|
|
|
// AssignmentElement nodes
|
|
|
|
PatternContext old_context = context();
|
|
|
|
bool is_destructuring_assignment =
|
2016-02-19 15:58:57 +00:00
|
|
|
node->IsRewritableExpression() &&
|
|
|
|
!node->AsRewritableExpression()->is_rewritten();
|
2015-12-04 17:20:10 +00:00
|
|
|
bool is_assignment =
|
|
|
|
node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN;
|
|
|
|
if (is_destructuring_assignment || is_assignment) {
|
|
|
|
switch (old_context) {
|
|
|
|
case BINDING:
|
|
|
|
set_context(INITIALIZER);
|
|
|
|
break;
|
|
|
|
case ASSIGNMENT:
|
|
|
|
set_context(ASSIGNMENT_INITIALIZER);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return old_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-11 16:28:28 +00:00
|
|
|
void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
|
|
|
Expression* value = current_value_;
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
if (IsAssignmentContext()) {
|
|
|
|
// In an assignment context, simply perform the assignment
|
|
|
|
Assignment* assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, pattern, value, pattern->position());
|
|
|
|
block_->statements()->Add(
|
2015-12-22 08:20:47 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, pattern->position()),
|
2015-12-04 17:20:10 +00:00
|
|
|
zone());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
const AstRawString* name = pattern->raw_name();
|
2015-12-04 17:20:10 +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-12-04 17:20:10 +00:00
|
|
|
Variable* var =
|
|
|
|
parser_->Declare(declaration, descriptor_->declaration_kind,
|
|
|
|
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);
|
|
|
|
|
2015-12-02 23:57:27 +00:00
|
|
|
Scope* declaration_scope = IsLexicalVariableMode(descriptor_->mode)
|
|
|
|
? descriptor_->scope
|
|
|
|
: descriptor_->scope->DeclarationScope();
|
|
|
|
if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
|
2015-12-04 17:20:10 +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-12-02 23:57:27 +00:00
|
|
|
Scope* initialization_scope = IsImmutableVariableMode(descriptor_->mode)
|
|
|
|
? declaration_scope
|
2015-05-15 09:56:31 +00:00
|
|
|
: 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-12-02 23:57:27 +00:00
|
|
|
if (IsImmutableVariableMode(descriptor_->mode)) {
|
2015-05-11 16:28:28 +00:00
|
|
|
arguments->Add(value, zone());
|
|
|
|
// 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).
|
2016-03-07 13:39:49 +00:00
|
|
|
initialize = factory()->NewCallRuntime(Runtime::kInitializeConstGlobal,
|
|
|
|
arguments, value->position());
|
|
|
|
value = NULL; // zap the value to avoid the unnecessary assignment
|
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();
|
2016-03-07 13:39:49 +00:00
|
|
|
arguments->Add(
|
|
|
|
factory()->NewNumberLiteral(language_mode, RelocInfo::kNoPosition),
|
|
|
|
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.
|
2015-10-27 00:47:40 +00:00
|
|
|
if (value != NULL && !descriptor_->scope->inside_with()) {
|
2015-05-11 16:28:28 +00:00
|
|
|
arguments->Add(value, zone());
|
|
|
|
// Construct the call to Runtime_InitializeVarGlobal
|
|
|
|
// and add it to the initialization statement block.
|
2016-03-07 13:39:49 +00:00
|
|
|
initialize = factory()->NewCallRuntime(Runtime::kInitializeVarGlobal,
|
|
|
|
arguments, value->position());
|
|
|
|
value = NULL; // zap the value to avoid the unnecessary assignment
|
2015-05-11 16:28:28 +00:00
|
|
|
} else {
|
|
|
|
initialize = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (initialize != NULL) {
|
2015-10-01 13:59:36 +00:00
|
|
|
block_->statements()->Add(
|
2016-03-01 12:47:27 +00:00
|
|
|
factory()->NewExpressionStatement(initialize, initialize->position()),
|
2015-05-11 16:28:28 +00:00
|
|
|
zone());
|
|
|
|
}
|
2016-04-14 01:00:22 +00:00
|
|
|
} else if (value != nullptr && IsLexicalVariableMode(descriptor_->mode)) {
|
|
|
|
// For 'let' and 'const' declared variables the initialization always
|
|
|
|
// assigns to the declared variable.
|
2015-05-11 16:28:28 +00:00
|
|
|
DCHECK_NOT_NULL(proxy);
|
|
|
|
DCHECK_NOT_NULL(proxy->var());
|
|
|
|
DCHECK_NOT_NULL(value);
|
2015-12-22 13:28:34 +00:00
|
|
|
// Add break location for destructured sub-pattern.
|
2016-03-07 13:39:49 +00:00
|
|
|
int pos = IsSubPattern() ? pattern->position() : value->position();
|
2015-12-22 13:28:34 +00:00
|
|
|
Assignment* assignment =
|
|
|
|
factory()->NewAssignment(Token::INIT, proxy, value, pos);
|
2015-10-01 13:59:36 +00:00
|
|
|
block_->statements()->Add(
|
2015-12-22 13:28:34 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, pos), zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
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-12-22 13:28:34 +00:00
|
|
|
// Add break location for destructured sub-pattern.
|
2016-03-07 13:39:49 +00:00
|
|
|
int pos = IsSubPattern() ? pattern->position() : value->position();
|
2015-12-22 13:28:34 +00:00
|
|
|
Assignment* assignment =
|
|
|
|
factory()->NewAssignment(Token::INIT, proxy, value, pos);
|
2015-10-01 13:59:36 +00:00
|
|
|
block_->statements()->Add(
|
2015-12-22 13:28:34 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, pos), zone());
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:29:50 +00:00
|
|
|
Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
|
2015-12-04 17:20:10 +00:00
|
|
|
auto temp = 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-10-01 13:59:36 +00:00
|
|
|
block_->statements()->Add(
|
2015-05-20 08:08:26 +00:00
|
|
|
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
|
|
|
|
zone());
|
|
|
|
}
|
2015-05-19 14:29:50 +00:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2015-05-18 20:15:08 +00:00
|
|
|
|
2016-02-19 15:58:57 +00:00
|
|
|
void Parser::PatternRewriter::VisitRewritableExpression(
|
|
|
|
RewritableExpression* node) {
|
|
|
|
// If this is not a destructuring assignment...
|
|
|
|
if (!IsAssignmentContext() || !node->expression()->IsAssignment()) {
|
|
|
|
// Mark the node as rewritten to prevent redundant rewriting, and
|
2015-12-04 17:20:10 +00:00
|
|
|
// perform BindingPattern rewriting
|
|
|
|
DCHECK(!node->is_rewritten());
|
|
|
|
node->Rewrite(node->expression());
|
|
|
|
return node->expression()->Accept(this);
|
|
|
|
}
|
2015-05-19 16:27:21 +00:00
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
if (node->is_rewritten()) return;
|
|
|
|
DCHECK(IsAssignmentContext());
|
|
|
|
Assignment* assign = node->expression()->AsAssignment();
|
|
|
|
DCHECK_NOT_NULL(assign);
|
|
|
|
DCHECK_EQ(Token::ASSIGN, assign->op());
|
|
|
|
|
|
|
|
auto initializer = assign->value();
|
|
|
|
auto value = initializer;
|
|
|
|
|
|
|
|
if (IsInitializerContext()) {
|
|
|
|
// let {<pattern> = <init>} = <value>
|
|
|
|
// becomes
|
|
|
|
// temp = <value>;
|
|
|
|
// <pattern> = temp === undefined ? <init> : temp;
|
|
|
|
auto temp_var = CreateTempVar(current_value_);
|
|
|
|
Expression* is_undefined = factory()->NewCompareOperation(
|
|
|
|
Token::EQ_STRICT, factory()->NewVariableProxy(temp_var),
|
|
|
|
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
value = factory()->NewConditional(is_undefined, initializer,
|
|
|
|
factory()->NewVariableProxy(temp_var),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
|
|
|
|
int pos = assign->position();
|
|
|
|
Block* old_block = block_;
|
2016-03-08 09:35:11 +00:00
|
|
|
block_ = factory()->NewBlock(nullptr, 8, true, pos);
|
2015-12-04 17:20:10 +00:00
|
|
|
Variable* temp = nullptr;
|
|
|
|
Expression* pattern = assign->target();
|
|
|
|
Expression* old_value = current_value_;
|
|
|
|
current_value_ = value;
|
|
|
|
if (pattern->IsObjectLiteral()) {
|
|
|
|
VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
|
|
|
|
} else {
|
|
|
|
DCHECK(pattern->IsArrayLiteral());
|
|
|
|
VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
|
|
|
|
}
|
|
|
|
DCHECK_NOT_NULL(temp);
|
|
|
|
current_value_ = old_value;
|
|
|
|
Expression* expr = factory()->NewDoExpression(block_, temp, pos);
|
|
|
|
node->Rewrite(expr);
|
|
|
|
block_ = old_block;
|
|
|
|
if (block_) {
|
|
|
|
block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
|
|
|
|
zone());
|
|
|
|
}
|
|
|
|
return set_context(old_context);
|
|
|
|
}
|
|
|
|
|
2016-06-23 20:47:00 +00:00
|
|
|
// Two cases for scope rewriting the scope of default parameters:
|
|
|
|
// - Eagerly parsed arrow functions are initially parsed as having
|
|
|
|
// expressions in the enclosing scope, but when the arrow is encountered,
|
|
|
|
// need to be in the scope of the function.
|
|
|
|
// - When an extra declaration scope needs to be inserted to account for
|
|
|
|
// a sloppy eval in a default parameter or function body, the expressions
|
|
|
|
// needs to be in that new inner scope which was added after initial
|
|
|
|
// parsing.
|
|
|
|
// Each of these cases can be handled by rewriting the contents of the
|
|
|
|
// expression to the current scope. The source scope is typically the outer
|
|
|
|
// scope when one case occurs; when both cases occur, both scopes need to
|
|
|
|
// be included as the outer scope. (Both rewritings still need to be done
|
|
|
|
// to account for lazily parsed arrow functions which hit the second case.)
|
|
|
|
// TODO(littledan): Remove the outer_scope parameter of
|
|
|
|
// RewriteParameterInitializerScope
|
|
|
|
void Parser::PatternRewriter::RewriteParameterScopes(Expression* expr) {
|
|
|
|
if (!IsBindingContext()) return;
|
|
|
|
if (descriptor_->declaration_kind != DeclarationDescriptor::PARAMETER) return;
|
|
|
|
if (!scope()->is_arrow_scope() && !scope()->is_block_scope()) return;
|
|
|
|
|
|
|
|
// Either this scope is an arrow scope or a declaration block scope.
|
|
|
|
DCHECK(scope()->is_declaration_scope());
|
|
|
|
|
|
|
|
if (scope()->outer_scope()->is_arrow_scope() && scope()->is_block_scope()) {
|
|
|
|
RewriteParameterInitializerScope(parser_->stack_limit(), expr,
|
|
|
|
scope()->outer_scope()->outer_scope(),
|
|
|
|
scope());
|
|
|
|
}
|
|
|
|
RewriteParameterInitializerScope(parser_->stack_limit(), expr,
|
|
|
|
scope()->outer_scope(), scope());
|
|
|
|
}
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
|
|
|
|
Variable** temp_var) {
|
|
|
|
auto temp = *temp_var = CreateTempVar(current_value_);
|
|
|
|
|
|
|
|
block_->statements()->Add(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()) {
|
2015-12-04 17:20:10 +00:00
|
|
|
PatternContext context = SetInitializerContextIfNeeded(property->value());
|
2016-06-23 20:47:00 +00:00
|
|
|
|
|
|
|
// Computed property names contain expressions which might require
|
|
|
|
// scope rewriting.
|
|
|
|
if (!property->key()->IsLiteral()) RewriteParameterScopes(property->key());
|
|
|
|
|
2015-05-11 16:28:28 +00:00
|
|
|
RecurseIntoSubpattern(
|
|
|
|
property->value(),
|
|
|
|
factory()->NewProperty(factory()->NewVariableProxy(temp),
|
|
|
|
property->key(), RelocInfo::kNoPosition));
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(context);
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
|
|
|
|
Variable* temp_var = nullptr;
|
|
|
|
VisitObjectLiteral(node, &temp_var);
|
|
|
|
}
|
|
|
|
|
2015-10-06 17:01:10 +00:00
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
|
|
|
|
Variable** temp_var) {
|
2016-03-10 09:33:29 +00:00
|
|
|
DCHECK(block_->ignore_completion_value());
|
2015-12-04 17:20:10 +00:00
|
|
|
|
2016-03-10 09:33:29 +00:00
|
|
|
auto temp = *temp_var = CreateTempVar(current_value_);
|
2015-12-04 17:20:10 +00:00
|
|
|
auto iterator = CreateTempVar(parser_->GetIterator(
|
2015-12-02 18:36:39 +00:00
|
|
|
factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition));
|
2015-05-20 08:08:26 +00:00
|
|
|
auto done = CreateTempVar(
|
|
|
|
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
|
|
|
|
auto result = CreateTempVar();
|
|
|
|
auto v = CreateTempVar();
|
2016-03-10 09:33:29 +00:00
|
|
|
auto completion = CreateTempVar();
|
|
|
|
auto nopos = RelocInfo::kNoPosition;
|
|
|
|
|
|
|
|
// For the purpose of iterator finalization, we temporarily set block_ to a
|
|
|
|
// new block. In the main body of this function, we write to block_ (both
|
|
|
|
// explicitly and implicitly via recursion). At the end of the function, we
|
|
|
|
// wrap this new block in a try-finally statement, restore block_ to its
|
|
|
|
// original value, and add the try-finally statement to block_.
|
|
|
|
auto target = block_;
|
|
|
|
if (FLAG_harmony_iterator_close) {
|
|
|
|
block_ = factory()->NewBlock(nullptr, 8, true, nopos);
|
|
|
|
}
|
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-12-04 17:20:10 +00:00
|
|
|
PatternContext context = SetInitializerContextIfNeeded(value);
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2015-05-20 08:08:26 +00:00
|
|
|
// if (!done) {
|
2016-03-10 09:33:29 +00:00
|
|
|
// done = true; // If .next, .done or .value throws, don't close.
|
2015-05-20 08:08:26 +00:00
|
|
|
// result = IteratorNext(iterator);
|
2016-03-10 19:11:02 +00:00
|
|
|
// if (result.done) {
|
|
|
|
// v = undefined;
|
|
|
|
// } else {
|
|
|
|
// v = result.value;
|
|
|
|
// done = false;
|
|
|
|
// }
|
2015-05-20 08:08:26 +00:00
|
|
|
// }
|
2016-03-10 19:11:02 +00:00
|
|
|
Statement* if_not_done;
|
2016-03-10 09:33:29 +00:00
|
|
|
{
|
2016-03-10 19:11:02 +00:00
|
|
|
auto result_done = factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(ast_value_factory()->done_string(),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
|
|
|
|
auto assign_undefined = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(v),
|
|
|
|
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
|
|
|
|
auto assign_value = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(v),
|
|
|
|
factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(ast_value_factory()->value_string(),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
|
|
|
|
auto unset_done = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
|
|
|
|
auto inner_else =
|
|
|
|
factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
|
|
|
|
inner_else->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(assign_value, nopos), zone());
|
|
|
|
inner_else->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(unset_done, nopos), zone());
|
|
|
|
|
|
|
|
auto inner_if = factory()->NewIfStatement(
|
|
|
|
result_done,
|
|
|
|
factory()->NewExpressionStatement(assign_undefined, nopos),
|
|
|
|
inner_else, nopos);
|
|
|
|
|
2016-03-10 09:33:29 +00:00
|
|
|
auto next_block =
|
|
|
|
factory()->NewBlock(nullptr, 3, true, RelocInfo::kNoPosition);
|
|
|
|
next_block->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewBooleanLiteral(true, nopos), nopos),
|
|
|
|
nopos),
|
|
|
|
zone());
|
|
|
|
next_block->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(
|
|
|
|
parser_->BuildIteratorNextResult(
|
|
|
|
factory()->NewVariableProxy(iterator), result,
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
zone());
|
2016-03-10 19:11:02 +00:00
|
|
|
next_block->statements()->Add(inner_if, zone());
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-03-10 19:11:02 +00:00
|
|
|
if_not_done = factory()->NewIfStatement(
|
2016-03-10 09:33:29 +00:00
|
|
|
factory()->NewUnaryOperation(Token::NOT,
|
|
|
|
factory()->NewVariableProxy(done),
|
|
|
|
RelocInfo::kNoPosition),
|
|
|
|
next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
}
|
2016-03-10 19:11:02 +00:00
|
|
|
block_->statements()->Add(if_not_done, zone());
|
2015-05-20 08:08:26 +00:00
|
|
|
|
|
|
|
if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
|
2016-03-10 09:33:29 +00:00
|
|
|
if (FLAG_harmony_iterator_close) {
|
|
|
|
// completion = kAbruptCompletion;
|
|
|
|
Expression* proxy = factory()->NewVariableProxy(completion);
|
|
|
|
Expression* assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, proxy,
|
|
|
|
factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
|
|
|
|
block_->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(assignment, nopos), zone());
|
|
|
|
}
|
|
|
|
|
2015-05-20 08:08:26 +00:00
|
|
|
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
|
2016-03-10 09:33:29 +00:00
|
|
|
|
|
|
|
if (FLAG_harmony_iterator_close) {
|
|
|
|
// completion = kNormalCompletion;
|
|
|
|
Expression* proxy = factory()->NewVariableProxy(completion);
|
|
|
|
Expression* assignment = factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, proxy,
|
|
|
|
factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
|
|
|
|
block_->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(assignment, nopos), zone());
|
|
|
|
}
|
2015-05-20 08:08:26 +00:00
|
|
|
}
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(context);
|
2015-05-20 08:08:26 +00:00
|
|
|
}
|
2015-05-20 15:05:58 +00:00
|
|
|
|
|
|
|
if (spread != nullptr) {
|
2016-03-10 09:33:29 +00:00
|
|
|
// A spread can only occur as the last component. It is not handled by
|
|
|
|
// RecurseIntoSubpattern above.
|
|
|
|
|
|
|
|
// let array = [];
|
2016-04-05 08:56:07 +00:00
|
|
|
// while (!done) {
|
2016-04-28 09:59:53 +00:00
|
|
|
// done = true; // If .next, .done or .value throws, don't close.
|
2016-04-05 08:56:07 +00:00
|
|
|
// result = IteratorNext(iterator);
|
2016-04-28 09:59:53 +00:00
|
|
|
// if (!result.done) {
|
2016-04-05 08:56:07 +00:00
|
|
|
// %AppendElement(array, result.value);
|
2016-04-28 09:59:53 +00:00
|
|
|
// done = false;
|
2016-04-05 08:56:07 +00:00
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// let array = [];
|
|
|
|
Variable* array;
|
|
|
|
{
|
|
|
|
auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
|
|
|
|
array = CreateTempVar(factory()->NewArrayLiteral(
|
|
|
|
empty_exprs,
|
|
|
|
// Reuse pattern's literal index - it is unused since there is no
|
|
|
|
// actual literal allocated.
|
|
|
|
node->literal_index(), RelocInfo::kNoPosition));
|
|
|
|
}
|
|
|
|
|
2016-03-10 09:33:29 +00:00
|
|
|
// done = true;
|
2016-04-05 08:56:07 +00:00
|
|
|
Statement* set_done = factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewBooleanLiteral(true, nopos), nopos),
|
|
|
|
nopos);
|
|
|
|
|
2016-04-28 09:59:53 +00:00
|
|
|
// result = IteratorNext(iterator);
|
|
|
|
Statement* get_next = factory()->NewExpressionStatement(
|
|
|
|
parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
|
|
|
|
result, nopos),
|
|
|
|
nopos);
|
|
|
|
|
2016-04-05 08:56:07 +00:00
|
|
|
// %AppendElement(array, result.value);
|
|
|
|
Statement* append_element;
|
|
|
|
{
|
|
|
|
auto args = new (zone()) ZoneList<Expression*>(2, zone());
|
|
|
|
args->Add(factory()->NewVariableProxy(array), zone());
|
|
|
|
args->Add(factory()->NewProperty(
|
|
|
|
factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(
|
|
|
|
ast_value_factory()->value_string(), nopos),
|
|
|
|
nopos),
|
|
|
|
zone());
|
|
|
|
append_element = factory()->NewExpressionStatement(
|
|
|
|
factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
|
|
|
|
nopos);
|
|
|
|
}
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-04-28 09:59:53 +00:00
|
|
|
// done = false;
|
|
|
|
Statement* unset_done = factory()->NewExpressionStatement(
|
|
|
|
factory()->NewAssignment(
|
|
|
|
Token::ASSIGN, factory()->NewVariableProxy(done),
|
|
|
|
factory()->NewBooleanLiteral(false, nopos), nopos),
|
|
|
|
nopos);
|
|
|
|
|
|
|
|
// if (!result.done) { #append_element; #unset_done }
|
|
|
|
Statement* maybe_append_and_unset_done;
|
2016-04-05 08:56:07 +00:00
|
|
|
{
|
|
|
|
Expression* result_done =
|
|
|
|
factory()->NewProperty(factory()->NewVariableProxy(result),
|
|
|
|
factory()->NewStringLiteral(
|
|
|
|
ast_value_factory()->done_string(), nopos),
|
|
|
|
nopos);
|
2016-04-28 09:59:53 +00:00
|
|
|
|
|
|
|
Block* then = factory()->NewBlock(nullptr, 2, true, nopos);
|
|
|
|
then->statements()->Add(append_element, zone());
|
|
|
|
then->statements()->Add(unset_done, zone());
|
|
|
|
|
|
|
|
maybe_append_and_unset_done = factory()->NewIfStatement(
|
|
|
|
factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
|
|
|
|
factory()->NewEmptyStatement(nopos), nopos);
|
2016-04-05 08:56:07 +00:00
|
|
|
}
|
2015-05-20 15:05:58 +00:00
|
|
|
|
2016-04-05 08:56:07 +00:00
|
|
|
// while (!done) {
|
2016-04-28 09:59:53 +00:00
|
|
|
// #set_done;
|
2016-04-05 08:56:07 +00:00
|
|
|
// #get_next;
|
2016-04-28 09:59:53 +00:00
|
|
|
// #maybe_append_and_unset_done;
|
2016-04-05 08:56:07 +00:00
|
|
|
// }
|
|
|
|
WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
|
|
|
|
{
|
|
|
|
Expression* condition = factory()->NewUnaryOperation(
|
|
|
|
Token::NOT, factory()->NewVariableProxy(done), nopos);
|
2016-04-28 09:59:53 +00:00
|
|
|
Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
|
|
|
|
body->statements()->Add(set_done, zone());
|
2016-04-05 08:56:07 +00:00
|
|
|
body->statements()->Add(get_next, zone());
|
2016-04-28 09:59:53 +00:00
|
|
|
body->statements()->Add(maybe_append_and_unset_done, zone());
|
2016-04-05 08:56:07 +00:00
|
|
|
loop->Initialize(condition, body);
|
|
|
|
}
|
2016-03-10 09:33:29 +00:00
|
|
|
|
2016-04-05 08:56:07 +00:00
|
|
|
block_->statements()->Add(loop, zone());
|
2015-05-20 15:05:58 +00:00
|
|
|
RecurseIntoSubpattern(spread->expression(),
|
|
|
|
factory()->NewVariableProxy(array));
|
|
|
|
}
|
2016-03-10 09:33:29 +00:00
|
|
|
|
|
|
|
if (FLAG_harmony_iterator_close) {
|
|
|
|
Expression* closing_condition = factory()->NewUnaryOperation(
|
|
|
|
Token::NOT, factory()->NewVariableProxy(done), nopos);
|
|
|
|
parser_->FinalizeIteratorUse(completion, closing_condition, iterator,
|
|
|
|
block_, target);
|
|
|
|
block_ = target;
|
|
|
|
}
|
2015-05-11 16:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-04 17:20:10 +00:00
|
|
|
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
|
|
|
|
Variable* temp_var = nullptr;
|
|
|
|
VisitArrayLiteral(node, &temp_var);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
2015-12-04 17:20:10 +00:00
|
|
|
DCHECK_EQ(Token::ASSIGN, node->op());
|
|
|
|
|
|
|
|
auto initializer = node->value();
|
|
|
|
auto value = initializer;
|
2015-05-19 14:29:50 +00:00
|
|
|
auto temp = CreateTempVar(current_value_);
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
if (IsInitializerContext()) {
|
|
|
|
Expression* is_undefined = factory()->NewCompareOperation(
|
|
|
|
Token::EQ_STRICT, factory()->NewVariableProxy(temp),
|
|
|
|
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
|
|
|
|
RelocInfo::kNoPosition);
|
|
|
|
value = factory()->NewConditional(is_undefined, initializer,
|
|
|
|
factory()->NewVariableProxy(temp),
|
|
|
|
RelocInfo::kNoPosition);
|
2015-10-21 12:04:10 +00:00
|
|
|
}
|
2015-12-04 17:20:10 +00:00
|
|
|
|
2016-06-23 20:47:00 +00:00
|
|
|
// Initializer may have been parsed in the wrong scope.
|
|
|
|
RewriteParameterScopes(initializer);
|
2015-12-04 17:20:10 +00:00
|
|
|
|
|
|
|
PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
|
2015-05-19 14:29:50 +00:00
|
|
|
RecurseIntoSubpattern(node->target(), value);
|
2015-12-04 17:20:10 +00:00
|
|
|
set_context(old_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =============== AssignmentPattern only ==================
|
|
|
|
|
|
|
|
void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
|
|
|
|
DCHECK(IsAssignmentContext());
|
|
|
|
auto value = current_value_;
|
|
|
|
|
|
|
|
Assignment* assignment =
|
|
|
|
factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
|
|
|
|
|
|
|
|
block_->statements()->Add(
|
|
|
|
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
|
|
|
|
zone());
|
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)
|
2015-10-21 02:55:47 +00:00
|
|
|
NOT_A_PATTERN(DoExpression)
|
2015-05-11 16:28:28 +00:00
|
|
|
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(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
|