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 2199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2210 } | 2210 } |
2211 | 2211 |
2212 | 2212 |
2213 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, | 2213 Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
2214 ZoneList<const AstRawString*>* names, | 2214 ZoneList<const AstRawString*>* names, |
2215 bool* ok) { | 2215 bool* ok) { |
2216 // VariableStatement :: | 2216 // VariableStatement :: |
2217 // VariableDeclarations ';' | 2217 // VariableDeclarations ';' |
2218 | 2218 |
2219 const AstRawString* ignore; | 2219 const AstRawString* ignore; |
2220 Block* result = | 2220 Block* result = ParseVariableDeclarations( |
2221 ParseVariableDeclarations(var_context, names, &ignore, nullptr, CHECK_OK); | 2221 var_context, nullptr, names, &ignore, nullptr, nullptr, CHECK_OK); |
2222 ExpectSemicolon(CHECK_OK); | 2222 ExpectSemicolon(CHECK_OK); |
2223 return result; | 2223 return result; |
2224 } | 2224 } |
2225 | 2225 |
2226 | 2226 |
2227 // If the variable declaration declares exactly one non-const | 2227 // If the variable declaration declares exactly one non-const |
2228 // variable, then *out is set to that variable. In all other cases, | 2228 // variable, then *out is set to that variable. In all other cases, |
2229 // *out is untouched; in particular, it is the caller's responsibility | 2229 // *out is untouched; in particular, it is the caller's responsibility |
2230 // to initialize it properly. This mechanism is used for the parsing | 2230 // to initialize it properly. This mechanism is used for the parsing |
2231 // of 'for-in' loops. | 2231 // of 'for-in' loops. |
2232 Block* Parser::ParseVariableDeclarations( | 2232 Block* Parser::ParseVariableDeclarations( |
2233 VariableDeclarationContext var_context, | 2233 VariableDeclarationContext var_context, int* num_decl, |
2234 ZoneList<const AstRawString*>* names, const AstRawString** out, | 2234 ZoneList<const AstRawString*>* names, const AstRawString** out, |
2235 Scanner::Location* first_initializer_loc, bool* ok) { | 2235 Scanner::Location* first_initializer_loc, Scanner::Location* bindings_loc, |
2236 bool* ok) { | |
2236 // VariableDeclarations :: | 2237 // VariableDeclarations :: |
2237 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] | 2238 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] |
2238 // | 2239 // |
2239 // The ES6 Draft Rev3 specifies the following grammar for const declarations | 2240 // The ES6 Draft Rev3 specifies the following grammar for const declarations |
2240 // | 2241 // |
2241 // ConstDeclaration :: | 2242 // ConstDeclaration :: |
2242 // const ConstBinding (',' ConstBinding)* ';' | 2243 // const ConstBinding (',' ConstBinding)* ';' |
2243 // ConstBinding :: | 2244 // ConstBinding :: |
2244 // Identifier '=' AssignmentExpression | 2245 // Identifier '=' AssignmentExpression |
2245 // | 2246 // |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2297 // | 2298 // |
2298 // We mark the block as initializer block because we don't want the | 2299 // We mark the block as initializer block because we don't want the |
2299 // rewriter to add a '.result' assignment to such a block (to get compliant | 2300 // rewriter to add a '.result' assignment to such a block (to get compliant |
2300 // behavior for code such as print(eval('var x = 7')), and for cosmetic | 2301 // behavior for code such as print(eval('var x = 7')), and for cosmetic |
2301 // reasons when pretty-printing. Also, unless an assignment (initialization) | 2302 // reasons when pretty-printing. Also, unless an assignment (initialization) |
2302 // is inside an initializer block, it is ignored. | 2303 // is inside an initializer block, it is ignored. |
2303 // | 2304 // |
2304 // Create new block with one expected declaration. | 2305 // Create new block with one expected declaration. |
2305 Block* block = factory()->NewBlock(NULL, 1, true, pos); | 2306 Block* block = factory()->NewBlock(NULL, 1, true, pos); |
2306 int nvars = 0; // the number of variables declared | 2307 int nvars = 0; // the number of variables declared |
2308 int bindings_start = peek_position(); | |
2307 const AstRawString* name = NULL; | 2309 const AstRawString* name = NULL; |
2310 const AstRawString* first_name = NULL; | |
2308 bool is_for_iteration_variable; | 2311 bool is_for_iteration_variable; |
2309 do { | 2312 do { |
2310 if (fni_ != NULL) fni_->Enter(); | 2313 if (fni_ != NULL) fni_->Enter(); |
2311 | 2314 |
2312 // Parse variable name. | 2315 // Parse variable name. |
2313 if (nvars > 0) Consume(Token::COMMA); | 2316 if (nvars > 0) Consume(Token::COMMA); |
2314 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); | 2317 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
2318 if (!first_name) first_name = name; | |
2315 Scanner::Location variable_loc = scanner()->location(); | 2319 Scanner::Location variable_loc = scanner()->location(); |
2316 if (fni_ != NULL) fni_->PushVariableName(name); | 2320 if (fni_ != NULL) fni_->PushVariableName(name); |
2317 | 2321 |
2318 // Declare variable. | 2322 // Declare variable. |
2319 // Note that we *always* must treat the initial value via a separate init | 2323 // Note that we *always* must treat the initial value via a separate init |
2320 // assignment for variables and constants because the value must be assigned | 2324 // assignment for variables and constants because the value must be assigned |
2321 // when the variable is encountered in the source. But the variable/constant | 2325 // when the variable is encountered in the source. But the variable/constant |
2322 // is declared (and set to 'undefined') upon entering the function within | 2326 // is declared (and set to 'undefined') upon entering the function within |
2323 // which the variable or constant is declared. Only function variables have | 2327 // which the variable or constant is declared. Only function variables have |
2324 // an initial value in the declaration (because they are initialized upon | 2328 // an initial value in the declaration (because they are initialized upon |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2512 Assignment* assignment = | 2516 Assignment* assignment = |
2513 factory()->NewAssignment(init_op, proxy, value, pos); | 2517 factory()->NewAssignment(init_op, proxy, value, pos); |
2514 block->AddStatement( | 2518 block->AddStatement( |
2515 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 2519 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), |
2516 zone()); | 2520 zone()); |
2517 } | 2521 } |
2518 | 2522 |
2519 if (fni_ != NULL) fni_->Leave(); | 2523 if (fni_ != NULL) fni_->Leave(); |
2520 } while (peek() == Token::COMMA); | 2524 } while (peek() == Token::COMMA); |
2521 | 2525 |
2522 // If there was a single non-const declaration, return it in the output | 2526 if (bindings_loc) { |
2523 // parameter for possible use by for/in. | 2527 *bindings_loc = |
2524 if (nvars == 1 && (!is_const || is_for_iteration_variable)) { | 2528 Scanner::Location(bindings_start, scanner()->location().end_pos); |
2525 *out = name; | |
2526 } | 2529 } |
2527 | 2530 |
2531 if (num_decl) *num_decl = nvars; | |
2532 *out = first_name; | |
2533 | |
2528 return block; | 2534 return block; |
2529 } | 2535 } |
2530 | 2536 |
2531 | 2537 |
2532 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, | 2538 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, |
2533 const AstRawString* label) { | 2539 const AstRawString* label) { |
2534 DCHECK(label != NULL); | 2540 DCHECK(label != NULL); |
2535 if (labels != NULL) { | 2541 if (labels != NULL) { |
2536 for (int i = labels->length(); i-- > 0; ) { | 2542 for (int i = labels->length(); i-- > 0; ) { |
2537 if (labels->at(i) == label) { | 2543 if (labels->at(i) == label) { |
(...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3361 | 3367 |
3362 Expect(Token::FOR, CHECK_OK); | 3368 Expect(Token::FOR, CHECK_OK); |
3363 Expect(Token::LPAREN, CHECK_OK); | 3369 Expect(Token::LPAREN, CHECK_OK); |
3364 for_scope->set_start_position(scanner()->location().beg_pos); | 3370 for_scope->set_start_position(scanner()->location().beg_pos); |
3365 bool is_let_identifier_expression = false; | 3371 bool is_let_identifier_expression = false; |
3366 if (peek() != Token::SEMICOLON) { | 3372 if (peek() != Token::SEMICOLON) { |
3367 if (peek() == Token::VAR || | 3373 if (peek() == Token::VAR || |
3368 (peek() == Token::CONST && is_sloppy(language_mode()))) { | 3374 (peek() == Token::CONST && is_sloppy(language_mode()))) { |
3369 const AstRawString* name = NULL; | 3375 const AstRawString* name = NULL; |
3370 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); | 3376 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); |
3377 Scanner::Location bindings_loc = Scanner::Location::invalid(); | |
3378 int num_decl; | |
3371 Block* variable_statement = ParseVariableDeclarations( | 3379 Block* variable_statement = ParseVariableDeclarations( |
3372 kForStatement, nullptr, &name, &first_initializer_loc, CHECK_OK); | 3380 kForStatement, &num_decl, nullptr, &name, &first_initializer_loc, |
3381 &bindings_loc, CHECK_OK); | |
3382 bool accept_IN = num_decl >= 1; | |
marja
2015/04/08 15:11:05
I was reading this code for a while and it's sligh
| |
3373 bool accept_OF = true; | 3383 bool accept_OF = true; |
3374 ForEachStatement::VisitMode mode; | 3384 ForEachStatement::VisitMode mode; |
3375 int each_beg_pos = scanner()->location().beg_pos; | 3385 int each_beg_pos = scanner()->location().beg_pos; |
3376 int each_end_pos = scanner()->location().end_pos; | 3386 int each_end_pos = scanner()->location().end_pos; |
3377 | 3387 |
3378 if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) { | 3388 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { |
3379 if (!*ok) return nullptr; | 3389 if (!*ok) return nullptr; |
3390 if (num_decl != 1) { | |
3391 const char* loop_type = | |
3392 mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; | |
3393 ParserTraits::ReportMessageAt( | |
3394 bindings_loc, "for_inof_loop_multi_bindings", loop_type); | |
3395 *ok = false; | |
3396 return nullptr; | |
3397 } | |
3380 if (first_initializer_loc.IsValid() && | 3398 if (first_initializer_loc.IsValid() && |
3381 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { | 3399 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { |
3382 if (mode == ForEachStatement::ITERATE) { | 3400 if (mode == ForEachStatement::ITERATE) { |
3383 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); | 3401 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); |
3384 } else { | 3402 } else { |
3385 // TODO(caitp): This should be an error in sloppy mode too. | 3403 // TODO(caitp): This should be an error in sloppy mode too. |
3386 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); | 3404 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); |
3387 } | 3405 } |
3388 *ok = false; | 3406 *ok = false; |
3389 return nullptr; | 3407 return nullptr; |
(...skipping 20 matching lines...) Expand all Loading... | |
3410 // Parsed for-in loop w/ variable/const declaration. | 3428 // Parsed for-in loop w/ variable/const declaration. |
3411 return result; | 3429 return result; |
3412 } else { | 3430 } else { |
3413 init = variable_statement; | 3431 init = variable_statement; |
3414 } | 3432 } |
3415 } else if ((peek() == Token::LET || peek() == Token::CONST) && | 3433 } else if ((peek() == Token::LET || peek() == Token::CONST) && |
3416 is_strict(language_mode())) { | 3434 is_strict(language_mode())) { |
3417 is_const = peek() == Token::CONST; | 3435 is_const = peek() == Token::CONST; |
3418 const AstRawString* name = NULL; | 3436 const AstRawString* name = NULL; |
3419 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); | 3437 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); |
3420 Block* variable_statement = | 3438 Scanner::Location bindings_loc = Scanner::Location::invalid(); |
3421 ParseVariableDeclarations(kForStatement, &lexical_bindings, &name, | 3439 int num_decl; |
3422 &first_initializer_loc, CHECK_OK); | 3440 Block* variable_statement = ParseVariableDeclarations( |
3423 bool accept_IN = name != NULL; | 3441 kForStatement, &num_decl, &lexical_bindings, &name, |
3442 &first_initializer_loc, &bindings_loc, CHECK_OK); | |
3443 bool accept_IN = num_decl >= 1; | |
3424 bool accept_OF = true; | 3444 bool accept_OF = true; |
3425 ForEachStatement::VisitMode mode; | 3445 ForEachStatement::VisitMode mode; |
3426 int each_beg_pos = scanner()->location().beg_pos; | 3446 int each_beg_pos = scanner()->location().beg_pos; |
3427 int each_end_pos = scanner()->location().end_pos; | 3447 int each_end_pos = scanner()->location().end_pos; |
3428 | 3448 |
3429 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { | 3449 if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { |
3430 if (!*ok) return nullptr; | 3450 if (!*ok) return nullptr; |
3451 if (num_decl != 1) { | |
3452 const char* loop_type = | |
3453 mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; | |
3454 ParserTraits::ReportMessageAt( | |
3455 bindings_loc, "for_inof_loop_multi_bindings", loop_type); | |
3456 *ok = false; | |
3457 return nullptr; | |
3458 } | |
3431 if (first_initializer_loc.IsValid() && | 3459 if (first_initializer_loc.IsValid() && |
3432 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { | 3460 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { |
3433 if (mode == ForEachStatement::ITERATE) { | 3461 if (mode == ForEachStatement::ITERATE) { |
3434 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); | 3462 ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); |
3435 } else { | 3463 } else { |
3436 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); | 3464 ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); |
3437 } | 3465 } |
3438 *ok = false; | 3466 *ok = false; |
3439 return nullptr; | 3467 return nullptr; |
3440 } | 3468 } |
(...skipping 2139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5580 } else { | 5608 } else { |
5581 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data()); | 5609 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data()); |
5582 running_hash = StringHasher::ComputeRunningHash(running_hash, data, | 5610 running_hash = StringHasher::ComputeRunningHash(running_hash, data, |
5583 raw_string->length()); | 5611 raw_string->length()); |
5584 } | 5612 } |
5585 } | 5613 } |
5586 | 5614 |
5587 return running_hash; | 5615 return running_hash; |
5588 } | 5616 } |
5589 } } // namespace v8::internal | 5617 } } // namespace v8::internal |
OLD | NEW |