Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Unified Diff: src/pattern-matcher.cc

Issue 1130623004: [destructuring] Implement basic binding destructuring infrastructure (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/pattern-matcher.cc
diff --git a/src/pattern-matcher.cc b/src/pattern-matcher.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4bd815496897191c27a9438bf0fe703abff42278
--- /dev/null
+++ b/src/pattern-matcher.cc
@@ -0,0 +1,409 @@
+// 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"
+#include "src/parser.h"
+
+namespace v8 {
+
arv (Not doing code reviews) 2015/05/08 19:09:49 Can I has .h file?
+namespace internal {
+
+
+bool Parser::PatternMatcher::IsSingleVariableBinding() const {
+ return pattern_->IsVariableProxy();
+}
+
+
+const AstRawString* Parser::PatternMatcher::SingleName() const {
+ DCHECK(IsSingleVariableBinding());
+ return pattern_->AsVariableProxy()->raw_name();
+}
+
+
+void Parser::PatternMatcher::DeclareAndInitializeVariables(Expression* value,
+ bool* ok) {
+ ok_ = ok;
+ RecurseIntoSubpattern(pattern_, value);
+}
+
+
+void Parser::PatternMatcher::VisitVariableProxy(VariableProxy* pattern) {
+ Expression* value = current_value_;
+ decl_->scope->RemoveUnresolved(pattern->AsVariableProxy());
+
+ // 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 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.
+ Parser* parser = decl_->parser;
+ const AstRawString* name = pattern->raw_name();
+ VariableProxy* proxy = parser->NewUnresolved(name, decl_->mode);
+ Declaration* declaration = factory()->NewVariableDeclaration(
+ proxy, decl_->mode, decl_->scope, decl_->pos);
+ Variable* var = parser->Declare(declaration, decl_->mode != VAR, ok_);
+ if (!*ok_) return;
+ DCHECK_NOT_NULL(var);
+ DCHECK(!proxy->is_resolved() || proxy->var() == var);
+ var->set_initializer_position(decl_->initializer_position);
+ (*decl_->nvars)++;
+ if (decl_->declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
+ parser->ReportMessage("too_many_variables");
+ *ok_ = false;
+ return;
+ }
+ if (decl_->names) {
+ decl_->names->Add(name, zone());
+ }
+
+
+ // 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 (decl_->initialization_scope()->is_script_scope() &&
+ !IsLexicalVariableMode(decl_->mode)) {
+ // 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.
+ arguments->Add(factory()->NewStringLiteral(name, decl_->pos), zone());
+ CallRuntime* initialize;
+
+ if (decl_->is_const) {
+ 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).
+ initialize = factory()->NewCallRuntime(
+ ast_value_factory()->initialize_const_global_string(),
+ Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
+ decl_->pos);
+ } else {
+ // Add language mode.
+ // We may want to pass singleton to avoid Literal allocations.
+ LanguageMode language_mode =
+ decl_->initialization_scope()->language_mode();
+ arguments->Add(factory()->NewNumberLiteral(language_mode, decl_->pos),
+ zone());
+
+ // 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 && !decl_->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.
+ initialize = factory()->NewCallRuntime(
+ ast_value_factory()->initialize_var_global_string(),
+ Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
+ decl_->pos);
+ } else {
+ initialize = NULL;
+ }
+ }
+
+ if (initialize != NULL) {
+ decl_->block->AddStatement(
+ factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
+ zone());
+ }
+ } else if (decl_->needs_init) {
+ // 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
+ // stest-parsing/InitializedDeclarationsInStrictForOfError tart context for
arv (Not doing code reviews) 2015/05/08 19:09:49 typo
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 Done.
+ // 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(proxy != NULL);
arv (Not doing code reviews) 2015/05/08 19:09:49 DCHECK_NOT_NULL
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 Done.
+ DCHECK(proxy->var() != NULL);
+ DCHECK(value != NULL);
+ Assignment* assignment =
+ factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos);
+ decl_->block->AddStatement(
+ 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) {
+ DCHECK(decl_->mode == VAR);
+ // '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 =
+ decl_->initialization_scope()->NewUnresolved(factory(), name);
+ Assignment* assignment =
+ factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos);
+ decl_->block->AddStatement(
+ factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
+ zone());
+ }
+}
+
+
+void Parser::PatternMatcher::VisitObjectLiteral(ObjectLiteral* pattern) {
+ auto temp = decl_->declaration_scope->NewTemporary(
+ ast_value_factory()->empty_string());
+ auto assignment =
+ factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp),
+ current_value_, RelocInfo::kNoPosition);
+ decl_->block->AddStatement(
+ factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
+ zone());
+ auto properties = pattern->properties();
+ for (auto i = properties->begin(); i != properties->end(); i++) {
arv (Not doing code reviews) 2015/05/08 19:09:49 Can we do? for (auto property : properties) {
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 Done.
+ ObjectLiteralProperty* property = *i;
+
+ RecurseIntoSubpattern(
+ property->value(),
+ factory()->NewProperty(factory()->NewVariableProxy(temp),
+ property->key(), RelocInfo::kNoPosition));
arv (Not doing code reviews) 2015/05/08 19:09:49 TODO(dslomov): Computed property names
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 Done.
+ }
+}
+
+
+void Parser::PatternMatcher::VisitArrayLiteral(ArrayLiteral* node) {
+ // TODO(dslomov): implement.
+}
+
+
+// =============== UNREACHABLE =============================
+void Parser::PatternMatcher::VisitProperty(Property* node) { UNREACHABLE(); }
arv (Not doing code reviews) 2015/05/08 19:09:49 This is only unreachable in binding patterns: var
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 I am not dealing with assignment patterns yet. As
+
+
+void Parser::PatternMatcher::Visit(AstNode* node) { UNREACHABLE(); }
+
+
+void Parser::PatternMatcher::VisitVariableDeclaration(
+ VariableDeclaration* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitExportDeclaration(ExportDeclaration* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitEmptyStatement(EmptyStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitContinueStatement(ContinueStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitBreakStatement(BreakStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitDebuggerStatement(DebuggerStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitNativeFunctionLiteral(
+ NativeFunctionLiteral* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitLiteral(Literal* node) { UNREACHABLE(); }
+
+
+void Parser::PatternMatcher::VisitRegExpLiteral(RegExpLiteral* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitThisFunction(ThisFunction* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitSuperReference(
+ v8::internal::SuperReference* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitImportDeclaration(ImportDeclaration* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitExpressionStatement(
+ ExpressionStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitReturnStatement(ReturnStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitYield(Yield* node) { UNREACHABLE(); }
+
+
+void Parser::PatternMatcher::VisitThrow(Throw* node) { UNREACHABLE(); }
+
+
+void Parser::PatternMatcher::VisitUnaryOperation(UnaryOperation* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitCountOperation(CountOperation* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitBlock(Block* node) { UNREACHABLE(); }
+
+
+void Parser::PatternMatcher::VisitFunctionDeclaration(
+ FunctionDeclaration* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitCallRuntime(CallRuntime* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitWithStatement(WithStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitDoWhileStatement(DoWhileStatement* node) {
arv (Not doing code reviews) 2015/05/08 19:09:49 Maybe a macro for all of these?
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 Done.
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitWhileStatement(WhileStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitTryCatchStatement(TryCatchStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitTryFinallyStatement(
+ TryFinallyStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitAssignment(Assignment* node) {
arv (Not doing code reviews) 2015/05/08 19:09:49 TODO(dslomov): Implement var {x: y = 42} = {}; as
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 Done.
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitBinaryOperation(BinaryOperation* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitCompareOperation(CompareOperation* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitSpread(Spread* node) { UNREACHABLE(); }
arv (Not doing code reviews) 2015/05/08 19:09:48 TODO(dslomov): Implement var [...xs] = []
Dmitry Lomov (no reviews) 2015/05/11 11:07:28 Done.
+
+
+void Parser::PatternMatcher::VisitForInStatement(ForInStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitForOfStatement(ForOfStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitConditional(Conditional* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitIfStatement(IfStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitSwitchStatement(SwitchStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitCaseClause(CaseClause* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitForStatement(ForStatement* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitClassLiteral(ClassLiteral* node) {
+ UNREACHABLE();
+}
+
+
+void Parser::PatternMatcher::VisitCall(Call* node) { UNREACHABLE(); }
+
+
+void Parser::PatternMatcher::VisitCallNew(CallNew* node) { UNREACHABLE(); }
+
+
+void Parser::PatternMatcher::VisitFunctionLiteral(FunctionLiteral* node) {
+ UNREACHABLE();
+}
+}
+} // namespace v8::internal

Powered by Google App Engine
This is Rietveld 408576698