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

Side by Side Diff: src/parser.cc

Issue 7837028: Let bound iteration variables in for-loops (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebased. Created 9 years, 2 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1613 matching lines...) Expand 10 before | Expand all | Expand 10 after
1624 } 1624 }
1625 1625
1626 1626
1627 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, 1627 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
1628 bool* ok) { 1628 bool* ok) {
1629 // VariableStatement :: 1629 // VariableStatement ::
1630 // VariableDeclarations ';' 1630 // VariableDeclarations ';'
1631 1631
1632 Handle<String> ignore; 1632 Handle<String> ignore;
1633 Block* result = ParseVariableDeclarations(var_context, 1633 Block* result = ParseVariableDeclarations(var_context,
1634 NULL,
1634 &ignore, 1635 &ignore,
1635 CHECK_OK); 1636 CHECK_OK);
1636 ExpectSemicolon(CHECK_OK); 1637 ExpectSemicolon(CHECK_OK);
1637 return result; 1638 return result;
1638 } 1639 }
1639 1640
1640 1641
1641 bool Parser::IsEvalOrArguments(Handle<String> string) { 1642 bool Parser::IsEvalOrArguments(Handle<String> string) {
1642 return string.is_identical_to(isolate()->factory()->eval_symbol()) || 1643 return string.is_identical_to(isolate()->factory()->eval_symbol()) ||
1643 string.is_identical_to(isolate()->factory()->arguments_symbol()); 1644 string.is_identical_to(isolate()->factory()->arguments_symbol());
1644 } 1645 }
1645 1646
1646 1647
1647 // If the variable declaration declares exactly one non-const 1648 // If the variable declaration declares exactly one non-const
1648 // variable, then *var is set to that variable. In all other cases, 1649 // variable, then *var is set to that variable. In all other cases,
1649 // *var is untouched; in particular, it is the caller's responsibility 1650 // *var is untouched; in particular, it is the caller's responsibility
1650 // to initialize it properly. This mechanism is used for the parsing 1651 // to initialize it properly. This mechanism is used for the parsing
1651 // of 'for-in' loops. 1652 // of 'for-in' loops.
1652 Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, 1653 Block* Parser::ParseVariableDeclarations(
1653 Handle<String>* out, 1654 VariableDeclarationContext var_context,
1654 bool* ok) { 1655 VariableDeclarationProperties* decl_props,
1656 Handle<String>* out,
1657 bool* ok) {
1655 // VariableDeclarations :: 1658 // VariableDeclarations ::
1656 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] 1659 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
1657 1660
1658 VariableMode mode = VAR; 1661 VariableMode mode = VAR;
1659 // True if the binding needs initialization. 'let' and 'const' declared 1662 // True if the binding needs initialization. 'let' and 'const' declared
1660 // bindings are created uninitialized by their declaration nodes and 1663 // bindings are created uninitialized by their declaration nodes and
1661 // need initialization. 'var' declared bindings are always initialized 1664 // need initialization. 'var' declared bindings are always initialized
1662 // immediately by their declaration nodes. 1665 // immediately by their declaration nodes.
1663 bool needs_init = false; 1666 bool needs_init = false;
1664 bool is_const = false; 1667 bool is_const = false;
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
1782 position = scanner().location().beg_pos; 1785 position = scanner().location().beg_pos;
1783 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK); 1786 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
1784 // Don't infer if it is "a = function(){...}();"-like expression. 1787 // Don't infer if it is "a = function(){...}();"-like expression.
1785 if (fni_ != NULL && 1788 if (fni_ != NULL &&
1786 value->AsCall() == NULL && 1789 value->AsCall() == NULL &&
1787 value->AsCallNew() == NULL) { 1790 value->AsCallNew() == NULL) {
1788 fni_->Infer(); 1791 fni_->Infer();
1789 } else { 1792 } else {
1790 fni_->RemoveLastFunction(); 1793 fni_->RemoveLastFunction();
1791 } 1794 }
1795 if (decl_props != NULL) *decl_props = kHasInitializers;
1792 } 1796 }
1793 1797
1794 // Make sure that 'const x' and 'let x' initialize 'x' to undefined. 1798 // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
1795 if (value == NULL && needs_init) { 1799 if (value == NULL && needs_init) {
1796 value = GetLiteralUndefined(); 1800 value = GetLiteralUndefined();
1797 } 1801 }
1798 1802
1799 // Global variable declarations must be compiled in a specific 1803 // Global variable declarations must be compiled in a specific
1800 // way. When the script containing the global variable declaration 1804 // way. When the script containing the global variable declaration
1801 // is entered, the global variable must be declared, so that if it 1805 // is entered, the global variable must be declared, so that if it
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after
2362 return loop; 2366 return loop;
2363 } 2367 }
2364 2368
2365 2369
2366 Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { 2370 Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
2367 // ForStatement :: 2371 // ForStatement ::
2368 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement 2372 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
2369 2373
2370 Statement* init = NULL; 2374 Statement* init = NULL;
2371 2375
2376 // Create an in-between scope for let-bound iteration variables.
2377 Scope* saved_scope = top_scope_;
2378 Scope* for_scope = NewScope(top_scope_, Scope::BLOCK_SCOPE);
2379 if (top_scope_->is_strict_mode()) {
2380 for_scope->EnableStrictMode();
2381 }
2382 top_scope_ = for_scope;
2383
2372 Expect(Token::FOR, CHECK_OK); 2384 Expect(Token::FOR, CHECK_OK);
2373 Expect(Token::LPAREN, CHECK_OK); 2385 Expect(Token::LPAREN, CHECK_OK);
2374 if (peek() != Token::SEMICOLON) { 2386 if (peek() != Token::SEMICOLON) {
2375 if (peek() == Token::VAR || peek() == Token::CONST) { 2387 if (peek() == Token::VAR || peek() == Token::CONST) {
2376 Handle<String> name; 2388 Handle<String> name;
2377 Block* variable_statement = 2389 Block* variable_statement =
2378 ParseVariableDeclarations(kForStatement, &name, CHECK_OK); 2390 ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK);
2379 2391
2380 if (peek() == Token::IN && !name.is_null()) { 2392 if (peek() == Token::IN && !name.is_null()) {
2381 VariableProxy* each = top_scope_->NewUnresolved(name); 2393 VariableProxy* each = top_scope_->NewUnresolved(name);
2382 ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); 2394 ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
2383 Target target(&this->target_stack_, loop); 2395 Target target(&this->target_stack_, loop);
2384 2396
2385 Expect(Token::IN, CHECK_OK); 2397 Expect(Token::IN, CHECK_OK);
2386 Expression* enumerable = ParseExpression(true, CHECK_OK); 2398 Expression* enumerable = ParseExpression(true, CHECK_OK);
2387 Expect(Token::RPAREN, CHECK_OK); 2399 Expect(Token::RPAREN, CHECK_OK);
2388 2400
2389 Statement* body = ParseStatement(NULL, CHECK_OK); 2401 Statement* body = ParseStatement(NULL, CHECK_OK);
2390 loop->Initialize(each, enumerable, body); 2402 loop->Initialize(each, enumerable, body);
2391 Block* result = new(zone()) Block(isolate(), NULL, 2, false); 2403 Block* result = new(zone()) Block(isolate(), NULL, 2, false);
2392 result->AddStatement(variable_statement); 2404 result->AddStatement(variable_statement);
2393 result->AddStatement(loop); 2405 result->AddStatement(loop);
2406 top_scope_ = saved_scope;
2407 for_scope = for_scope->FinalizeBlockScope();
2408 ASSERT(for_scope == NULL);
2394 // Parsed for-in loop w/ variable/const declaration. 2409 // Parsed for-in loop w/ variable/const declaration.
2395 return result; 2410 return result;
2396 } else { 2411 } else {
2397 init = variable_statement; 2412 init = variable_statement;
2398 } 2413 }
2414 } else if (peek() == Token::LET) {
2415 Handle<String> name;
2416 VariableDeclarationProperties decl_props = kHasNoInitializers;
2417 Block* variable_statement =
2418 ParseVariableDeclarations(kForStatement,
2419 &decl_props,
2420 &name,
2421 CHECK_OK);
2422 bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
2423 if (peek() == Token::IN && accept_IN) {
2424 // Rewrite a for-in statement of the form
2425 //
2426 // for (let x in e) b
2427 //
2428 // into
2429 //
2430 // <let x' be a temporary variable>
2431 // for (x' in e) {
2432 // let x;
2433 // x = x';
2434 // b;
2435 // }
2399 2436
2437 // TODO(keuchel): move temporary variable to block scope
Lasse Reichstein 2011/10/17 11:49:40 What does this mean? Is the current code not corre
Steven 2011/10/17 12:18:29 This is an optimization. TEMPORARY variables are a
2438 Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
2439 VariableProxy* temp_proxy = new(zone()) VariableProxy(isolate(), temp);
2440 VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
2441 ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
2442 Target target(&this->target_stack_, loop);
2443
2444 Expect(Token::IN, CHECK_OK);
2445 Expression* enumerable = ParseExpression(true, CHECK_OK);
2446 Expect(Token::RPAREN, CHECK_OK);
2447
2448 Statement* body = ParseStatement(NULL, CHECK_OK);
2449 Block* body_block = new(zone()) Block(isolate(), NULL, 3, false);
2450 Assignment* assignment = new(zone()) Assignment(isolate(),
2451 Token::ASSIGN,
2452 each,
2453 temp_proxy,
2454 RelocInfo::kNoPosition);
2455 Statement* assignment_statement =
2456 new(zone()) ExpressionStatement(assignment);
2457 body_block->AddStatement(variable_statement);
2458 body_block->AddStatement(assignment_statement);
2459 body_block->AddStatement(body);
2460 loop->Initialize(temp_proxy, enumerable, body_block);
2461 top_scope_ = saved_scope;
2462 for_scope = for_scope->FinalizeBlockScope();
2463 body_block->set_block_scope(for_scope);
2464 // Parsed for-in loop w/ let declaration.
2465 return loop;
2466
2467 } else {
2468 init = variable_statement;
2469 }
2400 } else { 2470 } else {
2401 Expression* expression = ParseExpression(false, CHECK_OK); 2471 Expression* expression = ParseExpression(false, CHECK_OK);
2402 if (peek() == Token::IN) { 2472 if (peek() == Token::IN) {
2403 // Signal a reference error if the expression is an invalid 2473 // Signal a reference error if the expression is an invalid
2404 // left-hand side expression. We could report this as a syntax 2474 // left-hand side expression. We could report this as a syntax
2405 // error here but for compatibility with JSC we choose to report 2475 // error here but for compatibility with JSC we choose to report
2406 // the error at runtime. 2476 // the error at runtime.
2407 if (expression == NULL || !expression->IsValidLeftHandSide()) { 2477 if (expression == NULL || !expression->IsValidLeftHandSide()) {
2408 Handle<String> type = 2478 Handle<String> type =
2409 isolate()->factory()->invalid_lhs_in_for_in_symbol(); 2479 isolate()->factory()->invalid_lhs_in_for_in_symbol();
2410 expression = NewThrowReferenceError(type); 2480 expression = NewThrowReferenceError(type);
2411 } 2481 }
2412 ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); 2482 ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
2413 Target target(&this->target_stack_, loop); 2483 Target target(&this->target_stack_, loop);
2414 2484
2415 Expect(Token::IN, CHECK_OK); 2485 Expect(Token::IN, CHECK_OK);
2416 Expression* enumerable = ParseExpression(true, CHECK_OK); 2486 Expression* enumerable = ParseExpression(true, CHECK_OK);
2417 Expect(Token::RPAREN, CHECK_OK); 2487 Expect(Token::RPAREN, CHECK_OK);
2418 2488
2419 Statement* body = ParseStatement(NULL, CHECK_OK); 2489 Statement* body = ParseStatement(NULL, CHECK_OK);
2420 if (loop) loop->Initialize(expression, enumerable, body); 2490 if (loop) loop->Initialize(expression, enumerable, body);
2491 top_scope_ = saved_scope;
2492 for_scope = for_scope->FinalizeBlockScope();
2493 ASSERT(for_scope == NULL);
2421 // Parsed for-in loop. 2494 // Parsed for-in loop.
2422 return loop; 2495 return loop;
2423 2496
2424 } else { 2497 } else {
2425 init = new(zone()) ExpressionStatement(expression); 2498 init = new(zone()) ExpressionStatement(expression);
2426 } 2499 }
2427 } 2500 }
2428 } 2501 }
2429 2502
2430 // Standard 'for' loop 2503 // Standard 'for' loop
(...skipping 10 matching lines...) Expand all
2441 Expect(Token::SEMICOLON, CHECK_OK); 2514 Expect(Token::SEMICOLON, CHECK_OK);
2442 2515
2443 Statement* next = NULL; 2516 Statement* next = NULL;
2444 if (peek() != Token::RPAREN) { 2517 if (peek() != Token::RPAREN) {
2445 Expression* exp = ParseExpression(true, CHECK_OK); 2518 Expression* exp = ParseExpression(true, CHECK_OK);
2446 next = new(zone()) ExpressionStatement(exp); 2519 next = new(zone()) ExpressionStatement(exp);
2447 } 2520 }
2448 Expect(Token::RPAREN, CHECK_OK); 2521 Expect(Token::RPAREN, CHECK_OK);
2449 2522
2450 Statement* body = ParseStatement(NULL, CHECK_OK); 2523 Statement* body = ParseStatement(NULL, CHECK_OK);
2451 if (loop) loop->Initialize(init, cond, next, body); 2524 top_scope_ = saved_scope;
2452 return loop; 2525 for_scope = for_scope->FinalizeBlockScope();
2526 if (for_scope != NULL) {
2527 // Rewrite a for statement of the form
2528 //
2529 // for (let x = i; c; n) b
2530 //
2531 // into
2532 //
2533 // {
2534 // let x = i;
2535 // for (; c; n) b
2536 // }
2537 ASSERT(init != NULL);
2538 Block* result = new(zone()) Block(isolate(), NULL, 2, false);
2539 result->AddStatement(init);
2540 result->AddStatement(loop);
2541 result->set_block_scope(for_scope);
2542 if (loop) loop->Initialize(NULL, cond, next, body);
2543 return result;
2544 } else {
2545 if (loop) loop->Initialize(init, cond, next, body);
2546 return loop;
2547 }
2453 } 2548 }
2454 2549
2455 2550
2456 // Precedence = 1 2551 // Precedence = 1
2457 Expression* Parser::ParseExpression(bool accept_IN, bool* ok) { 2552 Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
2458 // Expression :: 2553 // Expression ::
2459 // AssignmentExpression 2554 // AssignmentExpression
2460 // Expression ',' AssignmentExpression 2555 // Expression ',' AssignmentExpression
2461 2556
2462 Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK); 2557 Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
(...skipping 2767 matching lines...) Expand 10 before | Expand all | Expand 10 after
5230 result = parser.ParseProgram(source, 5325 result = parser.ParseProgram(source,
5231 info->is_global(), 5326 info->is_global(),
5232 info->StrictMode()); 5327 info->StrictMode());
5233 } 5328 }
5234 } 5329 }
5235 info->SetFunction(result); 5330 info->SetFunction(result);
5236 return (result != NULL); 5331 return (result != NULL);
5237 } 5332 }
5238 5333
5239 } } // namespace v8::internal 5334 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | test/mjsunit/harmony/block-for.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698