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

Side by Side Diff: src/parser.cc

Issue 292743009: Make let variables fresh in each iteration of a for-loop. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 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 | Annotate | Revision Log
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 "v8.h" 5 #include "v8.h"
6 6
7 #include "api.h" 7 #include "api.h"
8 #include "ast.h" 8 #include "ast.h"
9 #include "bootstrapper.h" 9 #include "bootstrapper.h"
10 #include "char-predicates-inl.h" 10 #include "char-predicates-inl.h"
(...skipping 2819 matching lines...) Expand 10 before | Expand all | Expand 10 after
2830 } 2830 }
2831 2831
2832 for_of->Initialize(each, subject, body, 2832 for_of->Initialize(each, subject, body,
2833 assign_iterator, next_result, result_done, assign_each); 2833 assign_iterator, next_result, result_done, assign_each);
2834 } else { 2834 } else {
2835 stmt->Initialize(each, subject, body); 2835 stmt->Initialize(each, subject, body);
2836 } 2836 }
2837 } 2837 }
2838 2838
2839 2839
2840 Statement* Parser::Assign(Token::Value op,
2841 VariableProxy* dst,
2842 Expression* src,
2843 int pos) {
2844 Assignment* x = factory()->NewAssignment(op, dst, src, pos);
2845 return factory()->NewExpressionStatement(x, pos);
2846 }
2847
2848
2849 Variable* Parser::Temporary(Handle<String> name) {
2850 return scope_->DeclarationScope()->NewTemporary(name);
2851 }
2852
2853 Statement* Parser::DesugarLetBindingsInForStatement(
2854 Scope* inner_scope, ZoneStringList* names, ForStatement* loop,
2855 Statement* init, Expression* cond, Statement* next, bool* ok) {
2856 // ES6 13.6.3.4 specifies that on each loop iteration the let variables are
2857 // copied into a new environment. After copying, the "next" statement of the
2858 // loop is executed to update the loop variables. The the loop condition is
rossberg 2014/05/22 12:55:44 Nit: "The the"
ulan 2014/05/23 14:29:03 Done.
2859 // checked and the loop body is executed.
2860 //
2861 // We rewrite a for statement of the form
2862 //
2863 // for (let x = i; cond; next) body
2864 //
2865 // into
2866 //
2867 // {
2868 // let x = i;
2869 // temp_x = x;
2870 // flag = 1;
2871 // for (;;) {
2872 // let x = temp_x;
2873 // if (flag == 1) {
2874 // flag = 0;
2875 // } else {
2876 // next;
2877 // }
2878 // if (cond) {
2879 // <empty>
2880 // } else {
2881 // break;
2882 // }
2883 // b
2884 // temp_x = x;
2885 // }
2886 // }
rossberg 2014/05/22 12:55:44 So, eventually, there should be a comment here alo
ulan 2014/05/23 14:29:03 As discussed offline, only lets and consts are all
2887
2888 ASSERT(names->length() > 0);
2889 Scope* for_scope = scope_;
2890 ZoneList<Variable*> temps(names->length(), zone());
2891
2892 Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false,
2893 RelocInfo::kNoPosition);
2894 outer_block->AddStatement(init, zone());
2895
2896 Handle<String> temp_name = isolate()->factory()->dot_for_string();
2897 Handle<Smi> smi0 = handle(Smi::FromInt(0), isolate());
2898 Handle<Smi> smi1 = handle(Smi::FromInt(1), isolate());
2899
2900
2901 // For each let variable x:
2902 // make statement: temp_x = x.
2903 for (int i = 0; i < names->length(); i++) {
2904 VariableProxy* proxy =
2905 NewUnresolved(names->at(i), LET, Interface::NewValue());
2906 Variable* temp = Temporary(temp_name);
2907 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
2908 Statement* assignment = Assign(Token::ASSIGN, temp_proxy, proxy);
2909 outer_block->AddStatement(assignment, zone());
2910 temps.Add(temp, zone());
2911 }
2912
2913 Variable* flag = Temporary(temp_name);
2914 // Make statement: flag = 1.
2915 {
2916 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
2917 Expression* const1 = factory()->NewLiteral(smi1, RelocInfo::kNoPosition);
2918 Statement* assignment = Assign(Token::ASSIGN, flag_proxy, const1);
2919 outer_block->AddStatement(assignment, zone());
2920 }
2921
2922 outer_block->AddStatement(loop, zone());
2923 outer_block->set_scope(for_scope);
2924 scope_ = inner_scope;
2925
2926 Statement* body = ParseStatement(NULL, CHECK_OK);
rossberg 2014/05/22 12:55:44 It's somewhat inappropriate to do actual parsing i
ulan 2014/05/23 14:29:03 Done.
2927
2928 Block* inner_block = factory()->NewBlock(NULL, 2 * names->length() + 3,
2929 false, RelocInfo::kNoPosition);
2930 int pos = scanner()->location().beg_pos;
2931 ZoneList<Variable*> inner_vars(names->length(), zone());
2932
2933 // For each let variable x:
2934 // make statement: let x = temp_x.
2935 for (int i = 0; i < names->length(); i++) {
2936 VariableProxy* proxy =
2937 NewUnresolved(names->at(i), LET, Interface::NewValue());
2938 Declaration* declaration =
2939 factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
2940 Declare(declaration, true, CHECK_OK);
2941 inner_vars.Add(declaration->proxy()->var(), zone());
2942 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
2943 Statement* statement = Assign(Token::INIT_LET, proxy, temp_proxy, pos);
2944 proxy->var()->set_initializer_position(pos);
2945 inner_block->AddStatement(statement, zone());
2946 }
2947
2948 // Make statement: if (flag == 1) { flag = 0; } else { next; }.
2949 {
2950 Expression* compare = NULL;
2951 // Make compare expresion: flag == 1.
2952 {
2953 Expression* const1 = factory()->NewLiteral(smi1, RelocInfo::kNoPosition);
2954 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
2955 compare = factory()->NewCompareOperation(
2956 Token::EQ, flag_proxy, const1, RelocInfo::kNoPosition);
2957 }
2958 Statement* clear_flag = NULL;
2959 // Make statement: flag = 0.
2960 {
2961 VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
2962 Expression* const0 = factory()->NewLiteral(smi0, RelocInfo::kNoPosition);
2963 clear_flag = Assign(Token::ASSIGN, flag_proxy, const0);
2964 }
2965 Statement* clear_flag_or_next = factory()->NewIfStatement(
2966 compare, clear_flag, next, RelocInfo::kNoPosition);
2967 inner_block->AddStatement(clear_flag_or_next, zone());
2968 }
2969
2970
2971 // Make statement: if (cond) { } else { break; }.
2972 {
2973 Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
2974 BreakableStatement* t = LookupBreakTarget(Handle<String>(), CHECK_OK);
2975 Statement* stop = factory()->NewBreakStatement(t, RelocInfo::kNoPosition);
2976 Statement* if_not_cond_break = factory()->NewIfStatement(
2977 cond, empty, stop, RelocInfo::kNoPosition);
2978 inner_block->AddStatement(if_not_cond_break, zone());
2979 }
2980
2981 inner_block->AddStatement(body, zone());
2982
2983 // For each let variable x:
2984 // make statement: temp_x = x;
2985 for (int i = 0; i < names->length(); i++) {
2986 VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
2987 int pos = scanner()->location().end_pos;
2988 VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
2989 Statement* statement = Assign(Token::ASSIGN, temp_proxy, proxy);
2990 inner_block->AddStatement(statement, zone());
2991 }
2992
2993 inner_scope->set_end_position(scanner()->location().end_pos);
2994 inner_block->set_scope(inner_scope);
2995 scope_ = for_scope;
2996
2997 loop->Initialize(NULL, NULL, NULL, inner_block);
2998 return outer_block;
2999 }
3000
3001
2840 Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { 3002 Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
2841 // ForStatement :: 3003 // ForStatement ::
2842 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement 3004 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
2843 3005
2844 int pos = peek_position(); 3006 int pos = peek_position();
2845 Statement* init = NULL; 3007 Statement* init = NULL;
3008 ZoneStringList let_bindings(1, zone());
rossberg 2014/05/22 12:55:44 lexical_bindings
ulan 2014/05/23 14:29:03 Leaving as is.
2846 3009
2847 // Create an in-between scope for let-bound iteration variables. 3010 // Create an in-between scope for let-bound iteration variables.
2848 Scope* saved_scope = scope_; 3011 Scope* saved_scope = scope_;
2849 Scope* for_scope = NewScope(scope_, BLOCK_SCOPE); 3012 Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
2850 scope_ = for_scope; 3013 scope_ = for_scope;
2851 3014
2852 Expect(Token::FOR, CHECK_OK); 3015 Expect(Token::FOR, CHECK_OK);
2853 Expect(Token::LPAREN, CHECK_OK); 3016 Expect(Token::LPAREN, CHECK_OK);
2854 for_scope->set_start_position(scanner()->location().beg_pos); 3017 for_scope->set_start_position(scanner()->location().beg_pos);
2855 if (peek() != Token::SEMICOLON) { 3018 if (peek() != Token::SEMICOLON) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2887 ASSERT(for_scope == NULL); 3050 ASSERT(for_scope == NULL);
2888 // Parsed for-in loop w/ variable/const declaration. 3051 // Parsed for-in loop w/ variable/const declaration.
2889 return result; 3052 return result;
2890 } else { 3053 } else {
2891 init = variable_statement; 3054 init = variable_statement;
2892 } 3055 }
2893 } else if (peek() == Token::LET) { 3056 } else if (peek() == Token::LET) {
2894 Handle<String> name; 3057 Handle<String> name;
2895 VariableDeclarationProperties decl_props = kHasNoInitializers; 3058 VariableDeclarationProperties decl_props = kHasNoInitializers;
2896 Block* variable_statement = 3059 Block* variable_statement =
2897 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, 3060 ParseVariableDeclarations(kForStatement, &decl_props, &let_bindings,
2898 CHECK_OK); 3061 &name, CHECK_OK);
2899 bool accept_IN = !name.is_null() && decl_props != kHasInitializers; 3062 bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
2900 bool accept_OF = decl_props == kHasNoInitializers; 3063 bool accept_OF = decl_props == kHasNoInitializers;
2901 ForEachStatement::VisitMode mode; 3064 ForEachStatement::VisitMode mode;
2902 3065
2903 if (accept_IN && CheckInOrOf(accept_OF, &mode)) { 3066 if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
2904 // Rewrite a for-in statement of the form 3067 // Rewrite a for-in statement of the form
2905 // 3068 //
2906 // for (let x in e) b 3069 // for (let x in e) b
2907 // 3070 //
2908 // into 3071 // into
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
2991 } 3154 }
2992 } 3155 }
2993 3156
2994 // Standard 'for' loop 3157 // Standard 'for' loop
2995 ForStatement* loop = factory()->NewForStatement(labels, pos); 3158 ForStatement* loop = factory()->NewForStatement(labels, pos);
2996 Target target(&this->target_stack_, loop); 3159 Target target(&this->target_stack_, loop);
2997 3160
2998 // Parsed initializer at this point. 3161 // Parsed initializer at this point.
2999 Expect(Token::SEMICOLON, CHECK_OK); 3162 Expect(Token::SEMICOLON, CHECK_OK);
3000 3163
3164 // If there are let bindings, then condition and the next statement of the
rossberg 2014/05/22 12:55:44 "let bindings" -> "lexical declarations"
ulan 2014/05/23 14:29:03 Leaving as is.
3165 // for loop must be parsed in a new scope.
3166 Scope* inner_scope = NULL;
3167 if (let_bindings.length() > 0) {
3168 inner_scope = NewScope(for_scope, BLOCK_SCOPE);
3169 inner_scope->set_start_position(scanner()->location().beg_pos);
3170 scope_ = inner_scope;
3171 }
3172
3001 Expression* cond = NULL; 3173 Expression* cond = NULL;
3002 if (peek() != Token::SEMICOLON) { 3174 if (peek() != Token::SEMICOLON) {
3003 cond = ParseExpression(true, CHECK_OK); 3175 cond = ParseExpression(true, CHECK_OK);
3004 } 3176 }
3005 Expect(Token::SEMICOLON, CHECK_OK); 3177 Expect(Token::SEMICOLON, CHECK_OK);
3006 3178
3007 Statement* next = NULL; 3179 Statement* next = NULL;
3008 if (peek() != Token::RPAREN) { 3180 if (peek() != Token::RPAREN) {
3009 Expression* exp = ParseExpression(true, CHECK_OK); 3181 Expression* exp = ParseExpression(true, CHECK_OK);
3010 next = factory()->NewExpressionStatement(exp, RelocInfo::kNoPosition); 3182 next = factory()->NewExpressionStatement(exp, RelocInfo::kNoPosition);
3011 } 3183 }
3012 Expect(Token::RPAREN, CHECK_OK); 3184 Expect(Token::RPAREN, CHECK_OK);
3013 3185
3014 Statement* body = ParseStatement(NULL, CHECK_OK); 3186 Statement* result = NULL;
3015 scope_ = saved_scope; 3187 if (let_bindings.length() > 0) {
3016 for_scope->set_end_position(scanner()->location().end_pos); 3188 scope_ = for_scope;
3017 for_scope = for_scope->FinalizeBlockScope(); 3189 result = DesugarLetBindingsInForStatement(inner_scope, &let_bindings, loop,
3018 if (for_scope != NULL) { 3190 init, cond, next, CHECK_OK);
3019 // Rewrite a for statement of the form 3191 scope_ = saved_scope;
3020 // 3192 for_scope->set_end_position(scanner()->location().end_pos);
3021 // for (let x = i; c; n) b
3022 //
3023 // into
3024 //
3025 // {
3026 // let x = i;
3027 // for (; c; n) b
3028 // }
3029 ASSERT(init != NULL);
3030 Block* result = factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
3031 result->AddStatement(init, zone());
3032 result->AddStatement(loop, zone());
3033 result->set_scope(for_scope);
3034 loop->Initialize(NULL, cond, next, body);
3035 return result;
3036 } else { 3193 } else {
3194 Statement* body = ParseStatement(NULL, CHECK_OK);
3037 loop->Initialize(init, cond, next, body); 3195 loop->Initialize(init, cond, next, body);
3038 return loop; 3196 result = loop;
3197 scope_ = saved_scope;
3198 for_scope->set_end_position(scanner()->location().end_pos);
3199 for_scope->FinalizeBlockScope();
3039 } 3200 }
3201 return result;
3040 } 3202 }
3041 3203
3042 3204
3043 DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) { 3205 DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
3044 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser 3206 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
3045 // contexts this is used as a statement which invokes the debugger as i a 3207 // contexts this is used as a statement which invokes the debugger as i a
3046 // break point is present. 3208 // break point is present.
3047 // DebuggerStatement :: 3209 // DebuggerStatement ::
3048 // 'debugger' ';' 3210 // 'debugger' ';'
3049 3211
(...skipping 1568 matching lines...) Expand 10 before | Expand all | Expand 10 after
4618 ASSERT(info()->isolate()->has_pending_exception()); 4780 ASSERT(info()->isolate()->has_pending_exception());
4619 } else { 4781 } else {
4620 result = ParseProgram(); 4782 result = ParseProgram();
4621 } 4783 }
4622 } 4784 }
4623 info()->SetFunction(result); 4785 info()->SetFunction(result);
4624 return (result != NULL); 4786 return (result != NULL);
4625 } 4787 }
4626 4788
4627 } } // namespace v8::internal 4789 } } // namespace v8::internal
OLDNEW
« src/parser.h ('K') | « src/parser.h ('k') | test/mjsunit/harmony/block-for.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698