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

Side by Side Diff: src/parser.cc

Issue 1130623004: [destructuring] Implement basic binding destructuring infrastructure (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: CR feedback 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 unified diff | Download patch
« no previous file with comments | « src/parser.h ('k') | src/pattern-rewriter.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/api.h" 7 #include "src/api.h"
8 #include "src/ast.h" 8 #include "src/ast.h"
9 #include "src/bailout-reason.h" 9 #include "src/bailout-reason.h"
10 #include "src/base/platform/platform.h" 10 #include "src/base/platform/platform.h"
11 #include "src/bootstrapper.h" 11 #include "src/bootstrapper.h"
12 #include "src/char-predicates-inl.h" 12 #include "src/char-predicates-inl.h"
13 #include "src/codegen.h" 13 #include "src/codegen.h"
14 #include "src/compiler.h" 14 #include "src/compiler.h"
15 #include "src/messages.h" 15 #include "src/messages.h"
16 #include "src/parser.h" 16 #include "src/parser.h"
17 #include "src/pattern-rewriter.h"
17 #include "src/preparser.h" 18 #include "src/preparser.h"
18 #include "src/runtime/runtime.h" 19 #include "src/runtime/runtime.h"
19 #include "src/scanner-character-streams.h" 20 #include "src/scanner-character-streams.h"
20 #include "src/scopeinfo.h" 21 #include "src/scopeinfo.h"
21 #include "src/string-stream.h" 22 #include "src/string-stream.h"
22 23
23 namespace v8 { 24 namespace v8 {
24 namespace internal { 25 namespace internal {
25 26
26 ScriptData::ScriptData(const byte* data, int length) 27 ScriptData::ScriptData(const byte* data, int length)
(...skipping 2277 matching lines...) Expand 10 before | Expand all | Expand 10 after
2304 // 2305 //
2305 // ConstDeclaration :: 2306 // ConstDeclaration ::
2306 // const ConstBinding (',' ConstBinding)* ';' 2307 // const ConstBinding (',' ConstBinding)* ';'
2307 // ConstBinding :: 2308 // ConstBinding ::
2308 // Identifier '=' AssignmentExpression 2309 // Identifier '=' AssignmentExpression
2309 // 2310 //
2310 // TODO(ES6): 2311 // TODO(ES6):
2311 // ConstBinding :: 2312 // ConstBinding ::
2312 // BindingPattern '=' AssignmentExpression 2313 // BindingPattern '=' AssignmentExpression
2313 2314
2314 int pos = peek_position(); 2315 PatternRewriter::DeclarationDescriptor decl;
2315 VariableMode mode = VAR; 2316 decl.parser = this;
2317 decl.pos = peek_position();
2318 decl.mode = VAR;
2316 // True if the binding needs initialization. 'let' and 'const' declared 2319 // True if the binding needs initialization. 'let' and 'const' declared
2317 // bindings are created uninitialized by their declaration nodes and 2320 // bindings are created uninitialized by their declaration nodes and
2318 // need initialization. 'var' declared bindings are always initialized 2321 // need initialization. 'var' declared bindings are always initialized
2319 // immediately by their declaration nodes. 2322 // immediately by their declaration nodes.
2320 bool needs_init = false; 2323 decl.needs_init = false;
2321 bool is_const = false; 2324 decl.is_const = false;
2322 Token::Value init_op = Token::INIT_VAR; 2325 decl.init_op = Token::INIT_VAR;
2326 decl.names = names;
2323 if (peek() == Token::VAR) { 2327 if (peek() == Token::VAR) {
2324 if (is_strong(language_mode())) { 2328 if (is_strong(language_mode())) {
2325 Scanner::Location location = scanner()->peek_location(); 2329 Scanner::Location location = scanner()->peek_location();
2326 ReportMessageAt(location, "strong_var"); 2330 ReportMessageAt(location, "strong_var");
2327 *ok = false; 2331 *ok = false;
2328 return NULL; 2332 return NULL;
2329 } 2333 }
2330 Consume(Token::VAR); 2334 Consume(Token::VAR);
2331 } else if (peek() == Token::CONST) { 2335 } else if (peek() == Token::CONST) {
2332 Consume(Token::CONST); 2336 Consume(Token::CONST);
2333 if (is_sloppy(language_mode())) { 2337 if (is_sloppy(language_mode())) {
2334 mode = CONST_LEGACY; 2338 decl.mode = CONST_LEGACY;
2335 init_op = Token::INIT_CONST_LEGACY; 2339 decl.init_op = Token::INIT_CONST_LEGACY;
2336 ++use_counts_[v8::Isolate::kLegacyConst]; 2340 ++use_counts_[v8::Isolate::kLegacyConst];
2337 } else { 2341 } else {
2338 DCHECK(var_context != kStatement); 2342 DCHECK(var_context != kStatement);
2339 mode = CONST; 2343 decl.mode = CONST;
2340 init_op = Token::INIT_CONST; 2344 decl.init_op = Token::INIT_CONST;
2341 } 2345 }
2342 is_const = true; 2346 decl.is_const = true;
2343 needs_init = true; 2347 decl.needs_init = true;
2344 } else if (peek() == Token::LET && is_strict(language_mode())) { 2348 } else if (peek() == Token::LET && is_strict(language_mode())) {
2345 Consume(Token::LET); 2349 Consume(Token::LET);
2346 DCHECK(var_context != kStatement); 2350 DCHECK(var_context != kStatement);
2347 mode = LET; 2351 decl.mode = LET;
2348 needs_init = true; 2352 decl.needs_init = true;
2349 init_op = Token::INIT_LET; 2353 decl.init_op = Token::INIT_LET;
2350 } else { 2354 } else {
2351 UNREACHABLE(); // by current callers 2355 UNREACHABLE(); // by current callers
2352 } 2356 }
2353 2357
2354 Scope* declaration_scope = DeclarationScope(mode); 2358 decl.declaration_scope = DeclarationScope(decl.mode);
2359 decl.scope = scope_;
2360
2355 2361
2356 // The scope of a var/const declared variable anywhere inside a function 2362 // The scope of a var/const declared variable anywhere inside a function
2357 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can 2363 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
2358 // transform a source-level var/const declaration into a (Function) 2364 // transform a source-level var/const declaration into a (Function)
2359 // Scope declaration, and rewrite the source-level initialization into an 2365 // Scope declaration, and rewrite the source-level initialization into an
2360 // assignment statement. We use a block to collect multiple assignments. 2366 // assignment statement. We use a block to collect multiple assignments.
2361 // 2367 //
2362 // We mark the block as initializer block because we don't want the 2368 // We mark the block as initializer block because we don't want the
2363 // rewriter to add a '.result' assignment to such a block (to get compliant 2369 // rewriter to add a '.result' assignment to such a block (to get compliant
2364 // behavior for code such as print(eval('var x = 7')), and for cosmetic 2370 // behavior for code such as print(eval('var x = 7')), and for cosmetic
2365 // reasons when pretty-printing. Also, unless an assignment (initialization) 2371 // reasons when pretty-printing. Also, unless an assignment (initialization)
2366 // is inside an initializer block, it is ignored. 2372 // is inside an initializer block, it is ignored.
2367 // 2373 //
2368 // Create new block with one expected declaration. 2374 // Create new block with one expected declaration.
2369 Block* block = factory()->NewBlock(NULL, 1, true, pos); 2375 decl.block = factory()->NewBlock(NULL, 1, true, decl.pos);
2370 int nvars = 0; // the number of variables declared 2376 int nvars = 0; // the number of variables declared
2377 decl.nvars = &nvars;
2371 int bindings_start = peek_position(); 2378 int bindings_start = peek_position();
2372 const AstRawString* name = NULL;
2373 const AstRawString* first_name = NULL; 2379 const AstRawString* first_name = NULL;
2374 bool is_for_iteration_variable; 2380 bool is_for_iteration_variable;
2375 do { 2381 do {
2376 if (fni_ != NULL) fni_->Enter(); 2382 if (fni_ != NULL) fni_->Enter();
2377 2383
2378 // Parse variable name. 2384 // Parse variable name.
2379 if (nvars > 0) Consume(Token::COMMA); 2385 if (nvars > 0) Consume(Token::COMMA);
2380 2386
2387 PatternRewriter pattern_rewriter;
2381 { 2388 {
2382 ExpressionClassifier pattern_classifier; 2389 ExpressionClassifier pattern_classifier;
2383 Token::Value next = peek(); 2390 Token::Value next = peek();
2384 Expression* pattern = 2391 Expression* pattern =
2385 ParsePrimaryExpression(&pattern_classifier, CHECK_OK); 2392 ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
2386 ValidateBindingPattern(&pattern_classifier, CHECK_OK); 2393 ValidateBindingPattern(&pattern_classifier, CHECK_OK);
2387 if (pattern->IsVariableProxy() && 2394 pattern_rewriter = PatternRewriter(&decl, pattern);
2388 pattern->AsVariableProxy()->IsValidReferenceExpression()) { 2395 if (!allow_harmony_destructuring() &&
2389 scope_->RemoveUnresolved(pattern->AsVariableProxy()); 2396 !pattern_rewriter.IsSingleVariableBinding()) {
2390 name = pattern->AsVariableProxy()->raw_name();
2391 } else if (allow_harmony_destructuring()) {
2392 // TODO(dslomov): really destructure.
2393 name = ast_value_factory()->GetOneByteString(".temp.variable");
2394 } else {
2395 ReportUnexpectedToken(next); 2397 ReportUnexpectedToken(next);
2396 *ok = false; 2398 *ok = false;
2397 return nullptr; 2399 return nullptr;
2398 } 2400 }
2401
2402 // TODO(dslomov): unify
2399 } 2403 }
2400 2404
2401 if (!first_name) first_name = name;
2402 Scanner::Location variable_loc = scanner()->location(); 2405 Scanner::Location variable_loc = scanner()->location();
2403 if (fni_ != NULL) fni_->PushVariableName(name); 2406 const bool single_name = pattern_rewriter.IsSingleVariableBinding();
2407 if (single_name) {
2408 if (!first_name) first_name = pattern_rewriter.SingleName();
2409 if (fni_ != NULL) fni_->PushVariableName(pattern_rewriter.SingleName());
2410 }
2404 2411
2405 // Declare variable.
2406 // Note that we *always* must treat the initial value via a separate init
2407 // assignment for variables and constants because the value must be assigned
2408 // when the variable is encountered in the source. But the variable/constant
2409 // is declared (and set to 'undefined') upon entering the function within
2410 // which the variable or constant is declared. Only function variables have
2411 // an initial value in the declaration (because they are initialized upon
2412 // entering the function).
2413 //
2414 // If we have a const declaration, in an inner scope, the proxy is always
2415 // bound to the declared variable (independent of possibly surrounding with
2416 // statements).
2417 // For let/const declarations in harmony mode, we can also immediately
2418 // pre-resolve the proxy because it resides in the same scope as the
2419 // declaration.
2420 is_for_iteration_variable = 2412 is_for_iteration_variable =
2421 var_context == kForStatement && 2413 var_context == kForStatement &&
2422 (peek() == Token::IN || PeekContextualKeyword(CStrVector("of"))); 2414 (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
2423 if (is_for_iteration_variable && mode == CONST) { 2415 if (is_for_iteration_variable && decl.mode == CONST) {
2424 needs_init = false; 2416 decl.needs_init = false;
2425 } 2417 }
2418 decl.initialization_scope =
rossberg 2015/05/11 13:18:29 Is there a reason why this can't be local to the r
Dmitry Lomov (no reviews) 2015/05/11 13:57:19 Done.
2419 decl.is_const ? decl.declaration_scope : decl.scope;
2426 2420
2427 VariableProxy* proxy = NewUnresolved(name, mode);
2428 Declaration* declaration =
2429 factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
2430 Variable* var = Declare(declaration, mode != VAR, CHECK_OK);
2431 DCHECK_NOT_NULL(var);
2432 DCHECK(!proxy->is_resolved() || proxy->var() == var);
2433 nvars++;
2434 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
2435 ReportMessage("too_many_variables");
2436 *ok = false;
2437 return NULL;
2438 }
2439 if (names) names->Add(name, zone());
2440
2441 // Parse initialization expression if present and/or needed. A
2442 // declaration of the form:
2443 //
2444 // var v = x;
2445 //
2446 // is syntactic sugar for:
2447 //
2448 // var v; v = x;
2449 //
2450 // In particular, we need to re-lookup 'v' (in scope_, not
2451 // declaration_scope) as it may be a different 'v' than the 'v' in the
2452 // declaration (e.g., if we are inside a 'with' statement or 'catch'
2453 // block).
2454 //
2455 // However, note that const declarations are different! A const
2456 // declaration of the form:
2457 //
2458 // const c = x;
2459 //
2460 // is *not* syntactic sugar for:
2461 //
2462 // const c; c = x;
2463 //
2464 // The "variable" c initialized to x is the same as the declared
2465 // one - there is no re-lookup (see the last parameter of the
2466 // Declare() call above).
2467
2468 Scope* initialization_scope = is_const ? declaration_scope : scope_;
2469 Expression* value = NULL; 2421 Expression* value = NULL;
2470 int pos = -1; 2422 decl.pos = -1;
2423 decl.initializer_position = -1;
2471 // Harmony consts have non-optional initializers. 2424 // Harmony consts have non-optional initializers.
2472 if (peek() == Token::ASSIGN || 2425 if (peek() == Token::ASSIGN ||
2473 (mode == CONST && !is_for_iteration_variable)) { 2426 (decl.mode == CONST && !is_for_iteration_variable)) {
2474 Expect(Token::ASSIGN, CHECK_OK); 2427 Expect(Token::ASSIGN, CHECK_OK);
2475 pos = position(); 2428 decl.pos = position();
2476 ExpressionClassifier classifier; 2429 ExpressionClassifier classifier;
2477 value = ParseAssignmentExpression(var_context != kForStatement, 2430 value = ParseAssignmentExpression(var_context != kForStatement,
2478 &classifier, CHECK_OK); 2431 &classifier, CHECK_OK);
2479 ValidateExpression(&classifier, CHECK_OK); 2432 ValidateExpression(&classifier, CHECK_OK);
2480 variable_loc.end_pos = scanner()->location().end_pos; 2433 variable_loc.end_pos = scanner()->location().end_pos;
2481 2434
2482 if (first_initializer_loc && !first_initializer_loc->IsValid()) { 2435 if (first_initializer_loc && !first_initializer_loc->IsValid()) {
2483 *first_initializer_loc = variable_loc; 2436 *first_initializer_loc = variable_loc;
2484 } 2437 }
2485 2438
2486 // Don't infer if it is "a = function(){...}();"-like expression. 2439 // Don't infer if it is "a = function(){...}();"-like expression.
2487 if (fni_ != NULL && 2440 if (single_name) {
2488 value->AsCall() == NULL && 2441 if (fni_ != NULL && value->AsCall() == NULL &&
2489 value->AsCallNew() == NULL) { 2442 value->AsCallNew() == NULL) {
2490 fni_->Infer(); 2443 fni_->Infer();
2491 } else { 2444 } else {
2492 fni_->RemoveLastFunction(); 2445 fni_->RemoveLastFunction();
2446 }
2493 } 2447 }
2494 // End position of the initializer is after the assignment expression. 2448 // End position of the initializer is after the assignment expression.
2495 var->set_initializer_position(scanner()->location().end_pos); 2449 decl.initializer_position = scanner()->location().end_pos;
2496 } else { 2450 } else {
2497 // End position of the initializer is after the variable. 2451 // End position of the initializer is after the variable.
2498 var->set_initializer_position(position()); 2452 decl.initializer_position = position();
2499 } 2453 }
2500 2454
2501 // Make sure that 'const x' and 'let x' initialize 'x' to undefined. 2455 // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
2502 if (value == NULL && needs_init) { 2456 if (value == NULL && decl.needs_init) {
2503 value = GetLiteralUndefined(position()); 2457 value = GetLiteralUndefined(position());
2504 } 2458 }
2505 2459
2506 // Global variable declarations must be compiled in a specific 2460 pattern_rewriter.DeclareAndInitializeVariables(value, CHECK_OK);
2507 // way. When the script containing the global variable declaration
2508 // is entered, the global variable must be declared, so that if it
2509 // doesn't exist (on the global object itself, see ES5 errata) it
2510 // gets created with an initial undefined value. This is handled
2511 // by the declarations part of the function representing the
2512 // top-level global code; see Runtime::DeclareGlobalVariable. If
2513 // it already exists (in the object or in a prototype), it is
2514 // *not* touched until the variable declaration statement is
2515 // executed.
2516 //
2517 // Executing the variable declaration statement will always
2518 // guarantee to give the global object an own property.
2519 // This way, global variable declarations can shadow
2520 // properties in the prototype chain, but only after the variable
2521 // declaration statement has been executed. This is important in
2522 // browsers where the global object (window) has lots of
2523 // properties defined in prototype objects.
2524 if (initialization_scope->is_script_scope() &&
2525 !IsLexicalVariableMode(mode)) {
2526 // Compute the arguments for the runtime call.
2527 ZoneList<Expression*>* arguments =
2528 new(zone()) ZoneList<Expression*>(3, zone());
2529 // We have at least 1 parameter.
2530 arguments->Add(factory()->NewStringLiteral(name, pos), zone());
2531 CallRuntime* initialize;
2532 2461
2533 if (is_const) { 2462 if (single_name && fni_ != NULL) fni_->Leave();
2534 arguments->Add(value, zone());
2535 value = NULL; // zap the value to avoid the unnecessary assignment
2536
2537 // Construct the call to Runtime_InitializeConstGlobal
2538 // and add it to the initialization statement block.
2539 // Note that the function does different things depending on
2540 // the number of arguments (1 or 2).
2541 initialize = factory()->NewCallRuntime(
2542 ast_value_factory()->initialize_const_global_string(),
2543 Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
2544 pos);
2545 } else {
2546 // Add language mode.
2547 // We may want to pass singleton to avoid Literal allocations.
2548 LanguageMode language_mode = initialization_scope->language_mode();
2549 arguments->Add(factory()->NewNumberLiteral(language_mode, pos), zone());
2550
2551 // Be careful not to assign a value to the global variable if
2552 // we're in a with. The initialization value should not
2553 // necessarily be stored in the global object in that case,
2554 // which is why we need to generate a separate assignment node.
2555 if (value != NULL && !inside_with()) {
2556 arguments->Add(value, zone());
2557 value = NULL; // zap the value to avoid the unnecessary assignment
2558 // Construct the call to Runtime_InitializeVarGlobal
2559 // and add it to the initialization statement block.
2560 initialize = factory()->NewCallRuntime(
2561 ast_value_factory()->initialize_var_global_string(),
2562 Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
2563 pos);
2564 } else {
2565 initialize = NULL;
2566 }
2567 }
2568
2569 if (initialize != NULL) {
2570 block->AddStatement(factory()->NewExpressionStatement(
2571 initialize, RelocInfo::kNoPosition),
2572 zone());
2573 }
2574 } else if (needs_init) {
2575 // Constant initializations always assign to the declared constant which
2576 // is always at the function scope level. This is only relevant for
2577 // dynamically looked-up variables and constants (the start context for
2578 // constant lookups is always the function context, while it is the top
2579 // context for var declared variables). Sigh...
2580 // For 'let' and 'const' declared variables in harmony mode the
2581 // initialization also always assigns to the declared variable.
2582 DCHECK(proxy != NULL);
2583 DCHECK(proxy->var() != NULL);
2584 DCHECK(value != NULL);
2585 Assignment* assignment =
2586 factory()->NewAssignment(init_op, proxy, value, pos);
2587 block->AddStatement(
2588 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
2589 zone());
2590 value = NULL;
2591 }
2592
2593 // Add an assignment node to the initialization statement block if we still
2594 // have a pending initialization value.
2595 if (value != NULL) {
2596 DCHECK(mode == VAR);
2597 // 'var' initializations are simply assignments (with all the consequences
2598 // if they are inside a 'with' statement - they may change a 'with' object
2599 // property).
2600 VariableProxy* proxy =
2601 initialization_scope->NewUnresolved(factory(), name);
2602 Assignment* assignment =
2603 factory()->NewAssignment(init_op, proxy, value, pos);
2604 block->AddStatement(
2605 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
2606 zone());
2607 }
2608
2609 if (fni_ != NULL) fni_->Leave();
2610 } while (peek() == Token::COMMA); 2463 } while (peek() == Token::COMMA);
2611 2464
2612 if (bindings_loc) { 2465 if (bindings_loc) {
2613 *bindings_loc = 2466 *bindings_loc =
2614 Scanner::Location(bindings_start, scanner()->location().end_pos); 2467 Scanner::Location(bindings_start, scanner()->location().end_pos);
2615 } 2468 }
2616 2469
2617 if (num_decl) *num_decl = nvars; 2470 if (num_decl) *num_decl = nvars;
2618 *out = first_name; 2471 *out = first_name;
2619 2472
2620 return block; 2473 return decl.block;
2621 } 2474 }
2622 2475
2623 2476
2624 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, 2477 static bool ContainsLabel(ZoneList<const AstRawString*>* labels,
2625 const AstRawString* label) { 2478 const AstRawString* label) {
2626 DCHECK(label != NULL); 2479 DCHECK(label != NULL);
2627 if (labels != NULL) { 2480 if (labels != NULL) {
2628 for (int i = labels->length(); i-- > 0; ) { 2481 for (int i = labels->length(); i-- > 0; ) {
2629 if (labels->at(i) == label) { 2482 if (labels->at(i) == label) {
2630 return true; 2483 return true;
(...skipping 3289 matching lines...) Expand 10 before | Expand all | Expand 10 after
5920 5773
5921 Expression* Parser::SpreadCallNew(Expression* function, 5774 Expression* Parser::SpreadCallNew(Expression* function,
5922 ZoneList<v8::internal::Expression*>* args, 5775 ZoneList<v8::internal::Expression*>* args,
5923 int pos) { 5776 int pos) {
5924 args->InsertAt(0, function, zone()); 5777 args->InsertAt(0, function, zone());
5925 5778
5926 return factory()->NewCallRuntime( 5779 return factory()->NewCallRuntime(
5927 ast_value_factory()->reflect_construct_string(), NULL, args, pos); 5780 ast_value_factory()->reflect_construct_string(), NULL, args, pos);
5928 } 5781 }
5929 } } // namespace v8::internal 5782 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/parser.h ('k') | src/pattern-rewriter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698