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

Side by Side Diff: src/parser.cc

Issue 671913002: harmony-scoping: Allow 'const' iteration variables in strict mode. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Remove assertion (checked downstream) Created 6 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
« no previous file with comments | « no previous file | src/preparser.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"
(...skipping 2138 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/preparser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698