OLD | NEW |
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" |
(...skipping 2138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2149 // We mark the block as initializer block because we don't want the | 2149 // We mark the block as initializer block because we don't want the |
2150 // rewriter to add a '.result' assignment to such a block (to get compliant | 2150 // rewriter to add a '.result' assignment to such a block (to get compliant |
2151 // behavior for code such as print(eval('var x = 7')), and for cosmetic | 2151 // behavior for code such as print(eval('var x = 7')), and for cosmetic |
2152 // reasons when pretty-printing. Also, unless an assignment (initialization) | 2152 // reasons when pretty-printing. Also, unless an assignment (initialization) |
2153 // is inside an initializer block, it is ignored. | 2153 // is inside an initializer block, it is ignored. |
2154 // | 2154 // |
2155 // Create new block with one expected declaration. | 2155 // Create new block with one expected declaration. |
2156 Block* block = factory()->NewBlock(NULL, 1, true, pos); | 2156 Block* block = factory()->NewBlock(NULL, 1, true, pos); |
2157 int nvars = 0; // the number of variables declared | 2157 int nvars = 0; // the number of variables declared |
2158 const AstRawString* name = NULL; | 2158 const AstRawString* name = NULL; |
| 2159 bool is_for_iteration_variable; |
2159 do { | 2160 do { |
2160 if (fni_ != NULL) fni_->Enter(); | 2161 if (fni_ != NULL) fni_->Enter(); |
2161 | 2162 |
2162 // Parse variable name. | 2163 // Parse variable name. |
2163 if (nvars > 0) Consume(Token::COMMA); | 2164 if (nvars > 0) Consume(Token::COMMA); |
2164 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); | 2165 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
2165 if (fni_ != NULL) fni_->PushVariableName(name); | 2166 if (fni_ != NULL) fni_->PushVariableName(name); |
2166 | 2167 |
2167 // Declare variable. | 2168 // Declare variable. |
2168 // Note that we *always* must treat the initial value via a separate init | 2169 // Note that we *always* must treat the initial value via a separate init |
2169 // assignment for variables and constants because the value must be assigned | 2170 // assignment for variables and constants because the value must be assigned |
2170 // when the variable is encountered in the source. But the variable/constant | 2171 // when the variable is encountered in the source. But the variable/constant |
2171 // is declared (and set to 'undefined') upon entering the function within | 2172 // is declared (and set to 'undefined') upon entering the function within |
2172 // which the variable or constant is declared. Only function variables have | 2173 // which the variable or constant is declared. Only function variables have |
2173 // an initial value in the declaration (because they are initialized upon | 2174 // an initial value in the declaration (because they are initialized upon |
2174 // entering the function). | 2175 // entering the function). |
2175 // | 2176 // |
2176 // If we have a const declaration, in an inner scope, the proxy is always | 2177 // If we have a const declaration, in an inner scope, the proxy is always |
2177 // bound to the declared variable (independent of possibly surrounding with | 2178 // bound to the declared variable (independent of possibly surrounding with |
2178 // statements). | 2179 // statements). |
2179 // For let/const declarations in harmony mode, we can also immediately | 2180 // For let/const declarations in harmony mode, we can also immediately |
2180 // pre-resolve the proxy because it resides in the same scope as the | 2181 // pre-resolve the proxy because it resides in the same scope as the |
2181 // declaration. | 2182 // declaration. |
| 2183 is_for_iteration_variable = |
| 2184 var_context == kForStatement && |
| 2185 (peek() == Token::IN || PeekContextualKeyword(CStrVector("of"))); |
| 2186 if (is_for_iteration_variable && mode == CONST) { |
| 2187 needs_init = false; |
| 2188 } |
| 2189 |
2182 Interface* interface = | 2190 Interface* interface = |
2183 is_const ? Interface::NewConst() : Interface::NewValue(); | 2191 is_const ? Interface::NewConst() : Interface::NewValue(); |
2184 VariableProxy* proxy = NewUnresolved(name, mode, interface); | 2192 VariableProxy* proxy = NewUnresolved(name, mode, interface); |
2185 Declaration* declaration = | 2193 Declaration* declaration = |
2186 factory()->NewVariableDeclaration(proxy, mode, scope_, pos); | 2194 factory()->NewVariableDeclaration(proxy, mode, scope_, pos); |
2187 Declare(declaration, mode != VAR, CHECK_OK); | 2195 Declare(declaration, mode != VAR, CHECK_OK); |
2188 nvars++; | 2196 nvars++; |
2189 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { | 2197 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { |
2190 ReportMessage("too_many_variables"); | 2198 ReportMessage("too_many_variables"); |
2191 *ok = false; | 2199 *ok = false; |
(...skipping 25 matching lines...) Expand all Loading... |
2217 // const c; c = x; | 2225 // const c; c = x; |
2218 // | 2226 // |
2219 // The "variable" c initialized to x is the same as the declared | 2227 // The "variable" c initialized to x is the same as the declared |
2220 // one - there is no re-lookup (see the last parameter of the | 2228 // one - there is no re-lookup (see the last parameter of the |
2221 // Declare() call above). | 2229 // Declare() call above). |
2222 | 2230 |
2223 Scope* initialization_scope = is_const ? declaration_scope : scope_; | 2231 Scope* initialization_scope = is_const ? declaration_scope : scope_; |
2224 Expression* value = NULL; | 2232 Expression* value = NULL; |
2225 int pos = -1; | 2233 int pos = -1; |
2226 // Harmony consts have non-optional initializers. | 2234 // Harmony consts have non-optional initializers. |
2227 if (peek() == Token::ASSIGN || mode == CONST) { | 2235 if (peek() == Token::ASSIGN || |
| 2236 (mode == CONST && !is_for_iteration_variable)) { |
2228 Expect(Token::ASSIGN, CHECK_OK); | 2237 Expect(Token::ASSIGN, CHECK_OK); |
2229 pos = position(); | 2238 pos = position(); |
2230 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK); | 2239 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK); |
2231 // Don't infer if it is "a = function(){...}();"-like expression. | 2240 // Don't infer if it is "a = function(){...}();"-like expression. |
2232 if (fni_ != NULL && | 2241 if (fni_ != NULL && |
2233 value->AsCall() == NULL && | 2242 value->AsCall() == NULL && |
2234 value->AsCallNew() == NULL) { | 2243 value->AsCallNew() == NULL) { |
2235 fni_->Infer(); | 2244 fni_->Infer(); |
2236 } else { | 2245 } else { |
2237 fni_->RemoveLastFunction(); | 2246 fni_->RemoveLastFunction(); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2350 block->AddStatement( | 2359 block->AddStatement( |
2351 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 2360 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), |
2352 zone()); | 2361 zone()); |
2353 } | 2362 } |
2354 | 2363 |
2355 if (fni_ != NULL) fni_->Leave(); | 2364 if (fni_ != NULL) fni_->Leave(); |
2356 } while (peek() == Token::COMMA); | 2365 } while (peek() == Token::COMMA); |
2357 | 2366 |
2358 // If there was a single non-const declaration, return it in the output | 2367 // If there was a single non-const declaration, return it in the output |
2359 // parameter for possible use by for/in. | 2368 // parameter for possible use by for/in. |
2360 if (nvars == 1 && !is_const) { | 2369 if (nvars == 1 && (!is_const || is_for_iteration_variable)) { |
2361 *out = name; | 2370 *out = name; |
2362 } | 2371 } |
2363 | 2372 |
2364 return block; | 2373 return block; |
2365 } | 2374 } |
2366 | 2375 |
2367 | 2376 |
2368 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, | 2377 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, |
2369 const AstRawString* label) { | 2378 const AstRawString* label) { |
2370 DCHECK(label != NULL); | 2379 DCHECK(label != NULL); |
(...skipping 716 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3087 | 3096 |
3088 // Create an in-between scope for let-bound iteration variables. | 3097 // Create an in-between scope for let-bound iteration variables. |
3089 Scope* saved_scope = scope_; | 3098 Scope* saved_scope = scope_; |
3090 Scope* for_scope = NewScope(scope_, BLOCK_SCOPE); | 3099 Scope* for_scope = NewScope(scope_, BLOCK_SCOPE); |
3091 scope_ = for_scope; | 3100 scope_ = for_scope; |
3092 | 3101 |
3093 Expect(Token::FOR, CHECK_OK); | 3102 Expect(Token::FOR, CHECK_OK); |
3094 Expect(Token::LPAREN, CHECK_OK); | 3103 Expect(Token::LPAREN, CHECK_OK); |
3095 for_scope->set_start_position(scanner()->location().beg_pos); | 3104 for_scope->set_start_position(scanner()->location().beg_pos); |
3096 if (peek() != Token::SEMICOLON) { | 3105 if (peek() != Token::SEMICOLON) { |
3097 if (peek() == Token::VAR || peek() == Token::CONST) { | 3106 if (peek() == Token::VAR || |
| 3107 (peek() == Token::CONST && strict_mode() == SLOPPY)) { |
3098 bool is_const = peek() == Token::CONST; | 3108 bool is_const = peek() == Token::CONST; |
3099 const AstRawString* name = NULL; | 3109 const AstRawString* name = NULL; |
3100 VariableDeclarationProperties decl_props = kHasNoInitializers; | 3110 VariableDeclarationProperties decl_props = kHasNoInitializers; |
3101 Block* variable_statement = | 3111 Block* variable_statement = |
3102 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, | 3112 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, |
3103 CHECK_OK); | 3113 CHECK_OK); |
3104 bool accept_OF = decl_props == kHasNoInitializers; | 3114 bool accept_OF = decl_props == kHasNoInitializers; |
3105 ForEachStatement::VisitMode mode; | 3115 ForEachStatement::VisitMode mode; |
3106 | 3116 |
3107 if (name != NULL && CheckInOrOf(accept_OF, &mode)) { | 3117 if (name != NULL && CheckInOrOf(accept_OF, &mode)) { |
(...skipping 16 matching lines...) Expand all Loading... |
3124 result->AddStatement(loop, zone()); | 3134 result->AddStatement(loop, zone()); |
3125 scope_ = saved_scope; | 3135 scope_ = saved_scope; |
3126 for_scope->set_end_position(scanner()->location().end_pos); | 3136 for_scope->set_end_position(scanner()->location().end_pos); |
3127 for_scope = for_scope->FinalizeBlockScope(); | 3137 for_scope = for_scope->FinalizeBlockScope(); |
3128 DCHECK(for_scope == NULL); | 3138 DCHECK(for_scope == NULL); |
3129 // Parsed for-in loop w/ variable/const declaration. | 3139 // Parsed for-in loop w/ variable/const declaration. |
3130 return result; | 3140 return result; |
3131 } else { | 3141 } else { |
3132 init = variable_statement; | 3142 init = variable_statement; |
3133 } | 3143 } |
3134 } else if (peek() == Token::LET && strict_mode() == STRICT) { | 3144 } else if ((peek() == Token::LET || peek() == Token::CONST) && |
3135 DCHECK(allow_harmony_scoping()); | 3145 strict_mode() == STRICT) { |
| 3146 bool is_const = peek() == Token::CONST; |
3136 const AstRawString* name = NULL; | 3147 const AstRawString* name = NULL; |
3137 VariableDeclarationProperties decl_props = kHasNoInitializers; | 3148 VariableDeclarationProperties decl_props = kHasNoInitializers; |
3138 Block* variable_statement = | 3149 Block* variable_statement = |
3139 ParseVariableDeclarations(kForStatement, &decl_props, &let_bindings, | 3150 ParseVariableDeclarations(kForStatement, &decl_props, &let_bindings, |
3140 &name, CHECK_OK); | 3151 &name, CHECK_OK); |
3141 bool accept_IN = name != NULL && decl_props != kHasInitializers; | 3152 bool accept_IN = name != NULL && decl_props != kHasInitializers; |
3142 bool accept_OF = decl_props == kHasNoInitializers; | 3153 bool accept_OF = decl_props == kHasNoInitializers; |
3143 ForEachStatement::VisitMode mode; | 3154 ForEachStatement::VisitMode mode; |
3144 | 3155 |
3145 if (accept_IN && CheckInOrOf(accept_OF, &mode)) { | 3156 if (accept_IN && CheckInOrOf(accept_OF, &mode)) { |
3146 // Rewrite a for-in statement of the form | 3157 // Rewrite a for-in statement of the form |
3147 // | 3158 // |
3148 // for (let x in e) b | 3159 // for (let/const x in e) b |
3149 // | 3160 // |
3150 // into | 3161 // into |
3151 // | 3162 // |
3152 // <let x' be a temporary variable> | 3163 // <let x' be a temporary variable> |
3153 // for (x' in e) { | 3164 // for (x' in e) { |
3154 // let x; | 3165 // let/const x; |
3155 // x = x'; | 3166 // x = x'; |
3156 // b; | 3167 // b; |
3157 // } | 3168 // } |
3158 | 3169 |
3159 // TODO(keuchel): Move the temporary variable to the block scope, after | 3170 // TODO(keuchel): Move the temporary variable to the block scope, after |
3160 // implementing stack allocated block scoped variables. | 3171 // implementing stack allocated block scoped variables. |
3161 Variable* temp = scope_->DeclarationScope()->NewTemporary( | 3172 Variable* temp = scope_->DeclarationScope()->NewTemporary( |
3162 ast_value_factory()->dot_for_string()); | 3173 ast_value_factory()->dot_for_string()); |
3163 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); | 3174 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); |
3164 ForEachStatement* loop = | 3175 ForEachStatement* loop = |
3165 factory()->NewForEachStatement(mode, labels, pos); | 3176 factory()->NewForEachStatement(mode, labels, pos); |
3166 Target target(&this->target_stack_, loop); | 3177 Target target(&this->target_stack_, loop); |
3167 | 3178 |
3168 // The expression does not see the loop variable. | 3179 // The expression does not see the loop variable. |
3169 scope_ = saved_scope; | 3180 scope_ = saved_scope; |
3170 Expression* enumerable = ParseExpression(true, CHECK_OK); | 3181 Expression* enumerable = ParseExpression(true, CHECK_OK); |
3171 scope_ = for_scope; | 3182 scope_ = for_scope; |
3172 Expect(Token::RPAREN, CHECK_OK); | 3183 Expect(Token::RPAREN, CHECK_OK); |
3173 | 3184 |
3174 VariableProxy* each = | 3185 VariableProxy* each = scope_->NewUnresolved(factory(), name); |
3175 scope_->NewUnresolved(factory(), name, Interface::NewValue()); | |
3176 Statement* body = ParseStatement(NULL, CHECK_OK); | 3186 Statement* body = ParseStatement(NULL, CHECK_OK); |
3177 Block* body_block = | 3187 Block* body_block = |
3178 factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); | 3188 factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); |
| 3189 Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN; |
3179 Assignment* assignment = factory()->NewAssignment( | 3190 Assignment* assignment = factory()->NewAssignment( |
3180 Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition); | 3191 init_op, each, temp_proxy, RelocInfo::kNoPosition); |
3181 Statement* assignment_statement = factory()->NewExpressionStatement( | 3192 Statement* assignment_statement = factory()->NewExpressionStatement( |
3182 assignment, RelocInfo::kNoPosition); | 3193 assignment, RelocInfo::kNoPosition); |
3183 body_block->AddStatement(variable_statement, zone()); | 3194 body_block->AddStatement(variable_statement, zone()); |
3184 body_block->AddStatement(assignment_statement, zone()); | 3195 body_block->AddStatement(assignment_statement, zone()); |
3185 body_block->AddStatement(body, zone()); | 3196 body_block->AddStatement(body, zone()); |
3186 InitializeForEachStatement(loop, temp_proxy, enumerable, body_block); | 3197 InitializeForEachStatement(loop, temp_proxy, enumerable, body_block); |
3187 scope_ = saved_scope; | 3198 scope_ = saved_scope; |
3188 for_scope->set_end_position(scanner()->location().end_pos); | 3199 for_scope->set_end_position(scanner()->location().end_pos); |
3189 for_scope = for_scope->FinalizeBlockScope(); | 3200 for_scope = for_scope->FinalizeBlockScope(); |
3190 body_block->set_scope(for_scope); | 3201 body_block->set_scope(for_scope); |
(...skipping 1759 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4950 | 4961 |
4951 // We cannot internalize on a background thread; a foreground task will take | 4962 // We cannot internalize on a background thread; a foreground task will take |
4952 // care of calling Parser::Internalize just before compilation. | 4963 // care of calling Parser::Internalize just before compilation. |
4953 | 4964 |
4954 if (compile_options() == ScriptCompiler::kProduceParserCache) { | 4965 if (compile_options() == ScriptCompiler::kProduceParserCache) { |
4955 if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); | 4966 if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); |
4956 log_ = NULL; | 4967 log_ = NULL; |
4957 } | 4968 } |
4958 } | 4969 } |
4959 } } // namespace v8::internal | 4970 } } // namespace v8::internal |
OLD | NEW |