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