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/parsing/parser.h" | 5 #include "src/parsing/parser.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/ast/ast.h" | 8 #include "src/ast/ast.h" |
9 #include "src/ast/ast-expression-rewriter.h" | 9 #include "src/ast/ast-expression-rewriter.h" |
10 #include "src/ast/ast-expression-visitor.h" | 10 #include "src/ast/ast-expression-visitor.h" |
(...skipping 2314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2325 // Scope declaration, and rewrite the source-level initialization into an | 2325 // Scope declaration, and rewrite the source-level initialization into an |
2326 // assignment statement. We use a block to collect multiple assignments. | 2326 // assignment statement. We use a block to collect multiple assignments. |
2327 // | 2327 // |
2328 // We mark the block as initializer block because we don't want the | 2328 // We mark the block as initializer block because we don't want the |
2329 // rewriter to add a '.result' assignment to such a block (to get compliant | 2329 // rewriter to add a '.result' assignment to such a block (to get compliant |
2330 // behavior for code such as print(eval('var x = 7')), and for cosmetic | 2330 // behavior for code such as print(eval('var x = 7')), and for cosmetic |
2331 // reasons when pretty-printing. Also, unless an assignment (initialization) | 2331 // reasons when pretty-printing. Also, unless an assignment (initialization) |
2332 // is inside an initializer block, it is ignored. | 2332 // is inside an initializer block, it is ignored. |
2333 | 2333 |
2334 DeclarationParsingResult parsing_result; | 2334 DeclarationParsingResult parsing_result; |
2335 ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK); | 2335 Block* result = |
| 2336 ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK); |
2336 ExpectSemicolon(CHECK_OK); | 2337 ExpectSemicolon(CHECK_OK); |
2337 | |
2338 Block* result = parsing_result.BuildInitializationBlock(names, CHECK_OK); | |
2339 return result; | 2338 return result; |
2340 } | 2339 } |
2341 | 2340 |
2342 | 2341 Block* Parser::ParseVariableDeclarations( |
2343 void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, | 2342 VariableDeclarationContext var_context, |
2344 DeclarationParsingResult* parsing_result, | 2343 DeclarationParsingResult* parsing_result, |
2345 bool* ok) { | 2344 ZoneList<const AstRawString*>* names, bool* ok) { |
2346 // VariableDeclarations :: | 2345 // VariableDeclarations :: |
2347 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] | 2346 // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] |
2348 // | 2347 // |
2349 // The ES6 Draft Rev3 specifies the following grammar for const declarations | 2348 // The ES6 Draft Rev3 specifies the following grammar for const declarations |
2350 // | 2349 // |
2351 // ConstDeclaration :: | 2350 // ConstDeclaration :: |
2352 // const ConstBinding (',' ConstBinding)* ';' | 2351 // const ConstBinding (',' ConstBinding)* ';' |
2353 // ConstBinding :: | 2352 // ConstBinding :: |
2354 // Identifier '=' AssignmentExpression | 2353 // Identifier '=' AssignmentExpression |
2355 // | 2354 // |
2356 // TODO(ES6): | 2355 // TODO(ES6): |
2357 // ConstBinding :: | 2356 // ConstBinding :: |
2358 // BindingPattern '=' AssignmentExpression | 2357 // BindingPattern '=' AssignmentExpression |
2359 | 2358 |
2360 parsing_result->descriptor.parser = this; | 2359 parsing_result->descriptor.parser = this; |
2361 parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL; | 2360 parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL; |
2362 parsing_result->descriptor.declaration_pos = peek_position(); | 2361 parsing_result->descriptor.declaration_pos = peek_position(); |
2363 parsing_result->descriptor.initialization_pos = peek_position(); | 2362 parsing_result->descriptor.initialization_pos = peek_position(); |
2364 parsing_result->descriptor.mode = VAR; | 2363 parsing_result->descriptor.mode = VAR; |
| 2364 |
| 2365 Block* init_block = nullptr; |
| 2366 if (var_context != kForStatement) { |
| 2367 init_block = factory()->NewBlock( |
| 2368 NULL, 1, true, parsing_result->descriptor.declaration_pos); |
| 2369 } |
| 2370 |
2365 if (peek() == Token::VAR) { | 2371 if (peek() == Token::VAR) { |
2366 if (is_strong(language_mode())) { | 2372 if (is_strong(language_mode())) { |
2367 Scanner::Location location = scanner()->peek_location(); | 2373 Scanner::Location location = scanner()->peek_location(); |
2368 ReportMessageAt(location, MessageTemplate::kStrongVar); | 2374 ReportMessageAt(location, MessageTemplate::kStrongVar); |
2369 *ok = false; | 2375 *ok = false; |
2370 return; | 2376 return nullptr; |
2371 } | 2377 } |
2372 Consume(Token::VAR); | 2378 Consume(Token::VAR); |
2373 } else if (peek() == Token::CONST && allow_const()) { | 2379 } else if (peek() == Token::CONST && allow_const()) { |
2374 Consume(Token::CONST); | 2380 Consume(Token::CONST); |
2375 if (is_sloppy(language_mode()) && allow_legacy_const()) { | 2381 if (is_sloppy(language_mode()) && allow_legacy_const()) { |
2376 parsing_result->descriptor.mode = CONST_LEGACY; | 2382 parsing_result->descriptor.mode = CONST_LEGACY; |
2377 ++use_counts_[v8::Isolate::kLegacyConst]; | 2383 ++use_counts_[v8::Isolate::kLegacyConst]; |
2378 } else { | 2384 } else { |
2379 DCHECK(is_strict(language_mode()) || allow_harmony_sloppy()); | 2385 DCHECK(is_strict(language_mode()) || allow_harmony_sloppy()); |
2380 DCHECK(var_context != kStatement); | 2386 DCHECK(var_context != kStatement); |
(...skipping 17 matching lines...) Expand all Loading... |
2398 FuncNameInferrer::State fni_state(fni_); | 2404 FuncNameInferrer::State fni_state(fni_); |
2399 | 2405 |
2400 // Parse name. | 2406 // Parse name. |
2401 if (!first_declaration) Consume(Token::COMMA); | 2407 if (!first_declaration) Consume(Token::COMMA); |
2402 | 2408 |
2403 Expression* pattern; | 2409 Expression* pattern; |
2404 int decl_pos = peek_position(); | 2410 int decl_pos = peek_position(); |
2405 { | 2411 { |
2406 ExpressionClassifier pattern_classifier; | 2412 ExpressionClassifier pattern_classifier; |
2407 Token::Value next = peek(); | 2413 Token::Value next = peek(); |
2408 pattern = ParsePrimaryExpression(&pattern_classifier, ok); | 2414 pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK); |
2409 if (!*ok) return; | 2415 ValidateBindingPattern(&pattern_classifier, CHECK_OK); |
2410 ValidateBindingPattern(&pattern_classifier, ok); | |
2411 if (!*ok) return; | |
2412 if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { | 2416 if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { |
2413 ValidateLetPattern(&pattern_classifier, ok); | 2417 ValidateLetPattern(&pattern_classifier, CHECK_OK); |
2414 if (!*ok) return; | |
2415 } | 2418 } |
2416 if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) { | 2419 if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) { |
2417 ReportUnexpectedToken(next); | 2420 ReportUnexpectedToken(next); |
2418 *ok = false; | 2421 *ok = false; |
2419 return; | 2422 return nullptr; |
2420 } | 2423 } |
2421 } | 2424 } |
2422 | 2425 |
2423 Scanner::Location variable_loc = scanner()->location(); | 2426 Scanner::Location variable_loc = scanner()->location(); |
2424 const AstRawString* single_name = | 2427 const AstRawString* single_name = |
2425 pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name() | 2428 pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name() |
2426 : nullptr; | 2429 : nullptr; |
2427 if (single_name != nullptr) { | 2430 if (single_name != nullptr) { |
2428 if (fni_ != NULL) fni_->PushVariableName(single_name); | 2431 if (fni_ != NULL) fni_->PushVariableName(single_name); |
2429 } | 2432 } |
2430 | 2433 |
2431 Expression* value = NULL; | 2434 Expression* value = NULL; |
2432 int initializer_position = RelocInfo::kNoPosition; | 2435 int initializer_position = RelocInfo::kNoPosition; |
2433 if (Check(Token::ASSIGN)) { | 2436 if (Check(Token::ASSIGN)) { |
2434 ExpressionClassifier classifier; | 2437 ExpressionClassifier classifier; |
2435 value = ParseAssignmentExpression(var_context != kForStatement, | 2438 value = ParseAssignmentExpression(var_context != kForStatement, |
2436 &classifier, ok); | 2439 &classifier, CHECK_OK); |
2437 if (!*ok) return; | 2440 value = ParserTraits::RewriteNonPattern(value, &classifier, CHECK_OK); |
2438 value = ParserTraits::RewriteNonPattern(value, &classifier, ok); | |
2439 if (!*ok) return; | |
2440 variable_loc.end_pos = scanner()->location().end_pos; | 2441 variable_loc.end_pos = scanner()->location().end_pos; |
2441 | 2442 |
2442 if (!parsing_result->first_initializer_loc.IsValid()) { | 2443 if (!parsing_result->first_initializer_loc.IsValid()) { |
2443 parsing_result->first_initializer_loc = variable_loc; | 2444 parsing_result->first_initializer_loc = variable_loc; |
2444 } | 2445 } |
2445 | 2446 |
2446 // Don't infer if it is "a = function(){...}();"-like expression. | 2447 // Don't infer if it is "a = function(){...}();"-like expression. |
2447 if (single_name) { | 2448 if (single_name) { |
2448 if (fni_ != NULL && value->AsCall() == NULL && | 2449 if (fni_ != NULL && value->AsCall() == NULL && |
2449 value->AsCallNew() == NULL) { | 2450 value->AsCallNew() == NULL) { |
(...skipping 14 matching lines...) Expand all Loading... |
2464 // for-in/of iteration variable. | 2465 // for-in/of iteration variable. |
2465 if (var_context != kForStatement || !PeekInOrOf()) { | 2466 if (var_context != kForStatement || !PeekInOrOf()) { |
2466 // ES6 'const' and binding patterns require initializers. | 2467 // ES6 'const' and binding patterns require initializers. |
2467 if (parsing_result->descriptor.mode == CONST || | 2468 if (parsing_result->descriptor.mode == CONST || |
2468 !pattern->IsVariableProxy()) { | 2469 !pattern->IsVariableProxy()) { |
2469 ParserTraits::ReportMessageAt( | 2470 ParserTraits::ReportMessageAt( |
2470 Scanner::Location(decl_pos, scanner()->location().end_pos), | 2471 Scanner::Location(decl_pos, scanner()->location().end_pos), |
2471 MessageTemplate::kDeclarationMissingInitializer, | 2472 MessageTemplate::kDeclarationMissingInitializer, |
2472 !pattern->IsVariableProxy() ? "destructuring" : "const"); | 2473 !pattern->IsVariableProxy() ? "destructuring" : "const"); |
2473 *ok = false; | 2474 *ok = false; |
2474 return; | 2475 return nullptr; |
2475 } | 2476 } |
2476 | 2477 |
2477 // 'let x' and (legacy) 'const x' initialize 'x' to undefined. | 2478 // 'let x' and (legacy) 'const x' initialize 'x' to undefined. |
2478 if (parsing_result->descriptor.mode == LET || | 2479 if (parsing_result->descriptor.mode == LET || |
2479 parsing_result->descriptor.mode == CONST_LEGACY) { | 2480 parsing_result->descriptor.mode == CONST_LEGACY) { |
2480 value = GetLiteralUndefined(position()); | 2481 value = GetLiteralUndefined(position()); |
2481 } | 2482 } |
2482 } | 2483 } |
2483 | 2484 |
2484 // End position of the initializer is after the variable. | 2485 // End position of the initializer is after the variable. |
2485 initializer_position = position(); | 2486 initializer_position = position(); |
2486 } | 2487 } |
2487 | 2488 |
2488 parsing_result->declarations.Add(DeclarationParsingResult::Declaration( | 2489 DeclarationParsingResult::Declaration decl(pattern, initializer_position, |
2489 pattern, initializer_position, value)); | 2490 value); |
| 2491 if (var_context == kForStatement) { |
| 2492 // Save the declaration for further handling in ParseForStatement. |
| 2493 parsing_result->declarations.Add(decl); |
| 2494 } else { |
| 2495 // Immediately declare the variable otherwise. This avoids O(N^2) |
| 2496 // behavior (where N is the number of variables in a single |
| 2497 // declaration) in the PatternRewriter having to do with removing |
| 2498 // and adding VariableProxies to the Scope (see bug 4699). |
| 2499 DCHECK_NOT_NULL(init_block); |
| 2500 PatternRewriter::DeclareAndInitializeVariables( |
| 2501 init_block, &parsing_result->descriptor, &decl, names, CHECK_OK); |
| 2502 } |
2490 first_declaration = false; | 2503 first_declaration = false; |
2491 } while (peek() == Token::COMMA); | 2504 } while (peek() == Token::COMMA); |
2492 | 2505 |
2493 parsing_result->bindings_loc = | 2506 parsing_result->bindings_loc = |
2494 Scanner::Location(bindings_start, scanner()->location().end_pos); | 2507 Scanner::Location(bindings_start, scanner()->location().end_pos); |
| 2508 |
| 2509 DCHECK(*ok); |
| 2510 return init_block; |
2495 } | 2511 } |
2496 | 2512 |
2497 | 2513 |
2498 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, | 2514 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, |
2499 const AstRawString* label) { | 2515 const AstRawString* label) { |
2500 DCHECK(label != NULL); | 2516 DCHECK(label != NULL); |
2501 if (labels != NULL) { | 2517 if (labels != NULL) { |
2502 for (int i = labels->length(); i-- > 0; ) { | 2518 for (int i = labels->length(); i-- > 0; ) { |
2503 if (labels->at(i) == label) { | 2519 if (labels->at(i) == label) { |
2504 return true; | 2520 return true; |
(...skipping 1120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3625 | 3641 |
3626 BlockState block_state(&scope_, for_scope); | 3642 BlockState block_state(&scope_, for_scope); |
3627 Expect(Token::FOR, CHECK_OK); | 3643 Expect(Token::FOR, CHECK_OK); |
3628 Expect(Token::LPAREN, CHECK_OK); | 3644 Expect(Token::LPAREN, CHECK_OK); |
3629 for_scope->set_start_position(scanner()->location().beg_pos); | 3645 for_scope->set_start_position(scanner()->location().beg_pos); |
3630 bool is_let_identifier_expression = false; | 3646 bool is_let_identifier_expression = false; |
3631 DeclarationParsingResult parsing_result; | 3647 DeclarationParsingResult parsing_result; |
3632 if (peek() != Token::SEMICOLON) { | 3648 if (peek() != Token::SEMICOLON) { |
3633 if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || | 3649 if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || |
3634 (peek() == Token::LET && IsNextLetKeyword())) { | 3650 (peek() == Token::LET && IsNextLetKeyword())) { |
3635 ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK); | 3651 ParseVariableDeclarations(kForStatement, &parsing_result, nullptr, |
| 3652 CHECK_OK); |
3636 | 3653 |
3637 ForEachStatement::VisitMode mode; | 3654 ForEachStatement::VisitMode mode; |
3638 int each_beg_pos = scanner()->location().beg_pos; | 3655 int each_beg_pos = scanner()->location().beg_pos; |
3639 int each_end_pos = scanner()->location().end_pos; | 3656 int each_end_pos = scanner()->location().end_pos; |
3640 | 3657 |
3641 if (CheckInOrOf(&mode, ok)) { | 3658 if (CheckInOrOf(&mode, ok)) { |
3642 if (!*ok) return nullptr; | 3659 if (!*ok) return nullptr; |
3643 if (parsing_result.declarations.length() != 1) { | 3660 if (parsing_result.declarations.length() != 1) { |
3644 ParserTraits::ReportMessageAt( | 3661 ParserTraits::ReportMessageAt( |
3645 parsing_result.bindings_loc, | 3662 parsing_result.bindings_loc, |
(...skipping 2736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6382 | 6399 |
6383 statements->Add(get_return, zone); | 6400 statements->Add(get_return, zone); |
6384 statements->Add(check_return, zone); | 6401 statements->Add(check_return, zone); |
6385 statements->Add(call_return, zone); | 6402 statements->Add(call_return, zone); |
6386 statements->Add(validate_output, zone); | 6403 statements->Add(validate_output, zone); |
6387 } | 6404 } |
6388 | 6405 |
6389 | 6406 |
6390 } // namespace internal | 6407 } // namespace internal |
6391 } // namespace v8 | 6408 } // namespace v8 |
OLD | NEW |