Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 488 terms_.Add(new RegExpQuantifier(min, max, is_greedy, atom)); | 488 terms_.Add(new RegExpQuantifier(min, max, is_greedy, atom)); |
| 489 LAST(ADD_TERM); | 489 LAST(ADD_TERM); |
| 490 } | 490 } |
| 491 | 491 |
| 492 | 492 |
| 493 class RegExpParser { | 493 class RegExpParser { |
| 494 public: | 494 public: |
| 495 RegExpParser(FlatStringReader* in, | 495 RegExpParser(FlatStringReader* in, |
| 496 Handle<String>* error, | 496 Handle<String>* error, |
| 497 bool multiline_mode); | 497 bool multiline_mode); |
| 498 RegExpTree* ParsePattern(bool* ok); | 498 RegExpTree* ParsePattern(); |
| 499 RegExpTree* ParseDisjunction(bool* ok); | 499 RegExpTree* ParseDisjunction(); |
| 500 RegExpTree* ParseGroup(bool* ok); | 500 RegExpTree* ParseGroup(); |
| 501 RegExpTree* ParseCharacterClass(bool* ok); | 501 RegExpTree* ParseCharacterClass(); |
| 502 | 502 |
| 503 // Parses a {...,...} quantifier and stores the range in the given | 503 // Parses a {...,...} quantifier and stores the range in the given |
| 504 // out parameters. | 504 // out parameters. |
| 505 bool ParseIntervalQuantifier(int* min_out, int* max_out); | 505 bool ParseIntervalQuantifier(int* min_out, int* max_out); |
| 506 | 506 |
| 507 // Parses and returns a single escaped character. The character | 507 // Parses and returns a single escaped character. The character |
| 508 // must not be 'b' or 'B' since they are usually handle specially. | 508 // must not be 'b' or 'B' since they are usually handle specially. |
| 509 uc32 ParseClassCharacterEscape(bool* ok); | 509 uc32 ParseClassCharacterEscape(); |
| 510 | 510 |
| 511 // Checks whether the following is a length-digit hexadecimal number, | 511 // Checks whether the following is a length-digit hexadecimal number, |
| 512 // and sets the value if it is. | 512 // and sets the value if it is. |
| 513 bool ParseHexEscape(int length, uc32* value); | 513 bool ParseHexEscape(int length, uc32* value); |
| 514 | 514 |
| 515 uc32 ParseControlLetterEscape(bool* ok); | 515 uc32 ParseControlLetterEscape(); |
| 516 uc32 ParseOctalLiteral(); | 516 uc32 ParseOctalLiteral(); |
| 517 | 517 |
| 518 // Tries to parse the input as a back reference. If successful it | 518 // Tries to parse the input as a back reference. If successful it |
| 519 // stores the result in the output parameter and returns true. If | 519 // stores the result in the output parameter and returns true. If |
| 520 // it fails it will push back the characters read so the same characters | 520 // it fails it will push back the characters read so the same characters |
| 521 // can be reparsed. | 521 // can be reparsed. |
| 522 bool ParseBackReferenceIndex(int* index_out); | 522 bool ParseBackReferenceIndex(int* index_out); |
| 523 | 523 |
| 524 CharacterRange ParseClassAtom(uc16* char_class, | 524 CharacterRange ParseClassAtom(uc16* char_class); |
| 525 bool* ok); | 525 RegExpTree* ReportError(Vector<const char> message); |
| 526 RegExpTree* ReportError(Vector<const char> message, bool* ok); | |
| 527 void Advance(); | 526 void Advance(); |
| 528 void Advance(int dist); | 527 void Advance(int dist); |
| 529 void Reset(int pos); | 528 void Reset(int pos); |
| 530 | 529 |
| 531 bool HasCharacterEscapes(); | 530 bool HasCharacterEscapes(); |
| 532 | 531 |
| 533 int captures_started() { return captures_ == NULL ? 0 : captures_->length(); } | 532 int captures_started() { return captures_ == NULL ? 0 : captures_->length(); } |
| 534 int position() { return next_pos_ - 1; } | 533 int position() { return next_pos_ - 1; } |
| 534 bool failed() { return failed_; } | |
| 535 | 535 |
| 536 static const uc32 kEndMarker = (1 << 21); | 536 static const uc32 kEndMarker = (1 << 21); |
| 537 private: | 537 private: |
| 538 uc32 current() { return current_; } | 538 uc32 current() { return current_; } |
| 539 bool has_more() { return has_more_; } | 539 bool has_more() { return has_more_; } |
| 540 bool has_next() { return next_pos_ < in()->length(); } | 540 bool has_next() { return next_pos_ < in()->length(); } |
| 541 uc32 Next(); | 541 uc32 Next(); |
| 542 FlatStringReader* in() { return in_; } | 542 FlatStringReader* in() { return in_; } |
| 543 void ScanForCaptures(); | 543 void ScanForCaptures(); |
| 544 bool CaptureAvailable(int index); | 544 bool CaptureAvailable(int index); |
| 545 uc32 current_; | 545 uc32 current_; |
| 546 bool has_more_; | 546 bool has_more_; |
| 547 bool multiline_; | 547 bool multiline_; |
| 548 int next_pos_; | 548 int next_pos_; |
| 549 FlatStringReader* in_; | 549 FlatStringReader* in_; |
| 550 Handle<String>* error_; | 550 Handle<String>* error_; |
| 551 bool has_character_escapes_; | 551 bool has_character_escapes_; |
| 552 ZoneList<RegExpCapture*>* captures_; | 552 ZoneList<RegExpCapture*>* captures_; |
| 553 bool is_scanned_for_captures_; | 553 bool is_scanned_for_captures_; |
| 554 // The capture count is only valid after we have scanned for captures. | 554 // The capture count is only valid after we have scanned for captures. |
| 555 int capture_count_; | 555 int capture_count_; |
| 556 bool failed_; | |
| 556 }; | 557 }; |
| 557 | 558 |
| 558 | 559 |
| 559 // A temporary scope stores information during parsing, just like | 560 // A temporary scope stores information during parsing, just like |
| 560 // a plain scope. However, temporary scopes are not kept around | 561 // a plain scope. However, temporary scopes are not kept around |
| 561 // after parsing or referenced by syntax trees so they can be stack- | 562 // after parsing or referenced by syntax trees so they can be stack- |
| 562 // allocated and hence used by the pre-parser. | 563 // allocated and hence used by the pre-parser. |
| 563 class TemporaryScope BASE_EMBEDDED { | 564 class TemporaryScope BASE_EMBEDDED { |
| 564 public: | 565 public: |
| 565 explicit TemporaryScope(Parser* parser); | 566 explicit TemporaryScope(Parser* parser); |
| (...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1020 // CAUTION: This macro appends extra statements after a call, | 1021 // CAUTION: This macro appends extra statements after a call, |
| 1021 // thus it must never be used where only a single statement | 1022 // thus it must never be used where only a single statement |
| 1022 // is correct (e.g. an if statement branch w/o braces)! | 1023 // is correct (e.g. an if statement branch w/o braces)! |
| 1023 | 1024 |
| 1024 #define CHECK_OK ok); \ | 1025 #define CHECK_OK ok); \ |
| 1025 if (!*ok) return NULL; \ | 1026 if (!*ok) return NULL; \ |
| 1026 ((void)0 | 1027 ((void)0 |
| 1027 #define DUMMY ) // to make indentation work | 1028 #define DUMMY ) // to make indentation work |
| 1028 #undef DUMMY | 1029 #undef DUMMY |
| 1029 | 1030 |
| 1031 #define CHECK_FAILED ); \ | |
| 1032 if (failed_) return NULL; \ | |
| 1033 ((void)0 | |
|
Mads Ager (chromium)
2008/12/01 15:29:09
Maybe we should add a dummy parenthesis as above s
Christian Plesner Hansen
2008/12/01 15:52:55
Aah, so that's what DUMMY was for.
| |
| 1034 | |
| 1030 | 1035 |
| 1031 // ---------------------------------------------------------------------------- | 1036 // ---------------------------------------------------------------------------- |
| 1032 // Implementation of Parser | 1037 // Implementation of Parser |
| 1033 | 1038 |
| 1034 Parser::Parser(Handle<Script> script, | 1039 Parser::Parser(Handle<Script> script, |
| 1035 bool allow_natives_syntax, | 1040 bool allow_natives_syntax, |
| 1036 v8::Extension* extension, | 1041 v8::Extension* extension, |
| 1037 bool is_pre_parsing, | 1042 bool is_pre_parsing, |
| 1038 ParserFactory* factory, | 1043 ParserFactory* factory, |
| 1039 ParserLog* log, | 1044 ParserLog* log, |
| (...skipping 2452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3492 bool multiline) | 3497 bool multiline) |
| 3493 : current_(kEndMarker), | 3498 : current_(kEndMarker), |
| 3494 has_more_(true), | 3499 has_more_(true), |
| 3495 multiline_(multiline), | 3500 multiline_(multiline), |
| 3496 next_pos_(0), | 3501 next_pos_(0), |
| 3497 in_(in), | 3502 in_(in), |
| 3498 error_(error), | 3503 error_(error), |
| 3499 has_character_escapes_(false), | 3504 has_character_escapes_(false), |
| 3500 captures_(NULL), | 3505 captures_(NULL), |
| 3501 is_scanned_for_captures_(false), | 3506 is_scanned_for_captures_(false), |
| 3502 capture_count_(0) { | 3507 capture_count_(0), |
| 3508 failed_(false) { | |
| 3503 Advance(1); | 3509 Advance(1); |
| 3504 } | 3510 } |
| 3505 | 3511 |
| 3506 | 3512 |
| 3507 uc32 RegExpParser::Next() { | 3513 uc32 RegExpParser::Next() { |
| 3508 if (has_next()) { | 3514 if (has_next()) { |
| 3509 return in()->Get(next_pos_); | 3515 return in()->Get(next_pos_); |
| 3510 } else { | 3516 } else { |
| 3511 return kEndMarker; | 3517 return kEndMarker; |
| 3512 } | 3518 } |
| 3513 } | 3519 } |
| 3514 | 3520 |
| 3515 | 3521 |
| 3516 void RegExpParser::Advance() { | 3522 void RegExpParser::Advance() { |
| 3517 if (next_pos_ < in()->length()) { | 3523 if (next_pos_ < in()->length()) { |
| 3518 current_ = in()->Get(next_pos_); | 3524 StackLimitCheck check; |
| 3519 next_pos_++; | 3525 if (check.HasOverflowed()) { |
| 3526 ReportError(CStrVector(Top::kStackOverflowMessage)); | |
| 3527 } else if (Zone::excess_allocation()) { | |
| 3528 ReportError(CStrVector("Regular expression too large")); | |
| 3529 } else { | |
| 3530 current_ = in()->Get(next_pos_); | |
| 3531 next_pos_++; | |
| 3532 } | |
| 3520 } else { | 3533 } else { |
| 3521 current_ = kEndMarker; | 3534 current_ = kEndMarker; |
| 3522 has_more_ = false; | 3535 has_more_ = false; |
| 3523 } | 3536 } |
| 3524 } | 3537 } |
| 3525 | 3538 |
| 3526 | 3539 |
| 3527 void RegExpParser::Reset(int pos) { | 3540 void RegExpParser::Reset(int pos) { |
| 3528 next_pos_ = pos; | 3541 next_pos_ = pos; |
| 3529 Advance(); | 3542 Advance(); |
| 3530 } | 3543 } |
| 3531 | 3544 |
| 3532 | 3545 |
| 3533 void RegExpParser::Advance(int dist) { | 3546 void RegExpParser::Advance(int dist) { |
| 3534 for (int i = 0; i < dist; i++) | 3547 for (int i = 0; i < dist; i++) |
| 3535 Advance(); | 3548 Advance(); |
| 3536 } | 3549 } |
| 3537 | 3550 |
| 3538 | 3551 |
| 3539 // Reports whether the parsed string atoms contain any characters that were | 3552 // Reports whether the parsed string atoms contain any characters that were |
| 3540 // escaped in the original pattern. If not, all atoms are proper substrings | 3553 // escaped in the original pattern. If not, all atoms are proper substrings |
| 3541 // of the original pattern. | 3554 // of the original pattern. |
| 3542 bool RegExpParser::HasCharacterEscapes() { | 3555 bool RegExpParser::HasCharacterEscapes() { |
| 3543 return has_character_escapes_; | 3556 return has_character_escapes_; |
| 3544 } | 3557 } |
| 3545 | 3558 |
| 3546 RegExpTree* RegExpParser::ReportError(Vector<const char> message, bool* ok) { | 3559 RegExpTree* RegExpParser::ReportError(Vector<const char> message) { |
| 3547 *ok = false; | 3560 failed_ = true; |
| 3548 *error_ = Factory::NewStringFromAscii(message, NOT_TENURED); | 3561 *error_ = Factory::NewStringFromAscii(message, NOT_TENURED); |
| 3562 // Zip to the end to make sure the no more input is read. | |
| 3563 current_ = kEndMarker; | |
| 3564 next_pos_ = in()->length(); | |
| 3549 return NULL; | 3565 return NULL; |
| 3550 } | 3566 } |
| 3551 | 3567 |
| 3552 | 3568 |
| 3553 // Pattern :: | 3569 // Pattern :: |
| 3554 // Disjunction | 3570 // Disjunction |
| 3555 RegExpTree* RegExpParser::ParsePattern(bool* ok) { | 3571 RegExpTree* RegExpParser::ParsePattern() { |
| 3556 RegExpTree* result = ParseDisjunction(CHECK_OK); | 3572 RegExpTree* result = ParseDisjunction(CHECK_FAILED); |
| 3557 if (has_more()) { | 3573 if (has_more()) { |
| 3558 ReportError(CStrVector("Unmatched ')'"), CHECK_OK); | 3574 ReportError(CStrVector("Unmatched ')'") CHECK_FAILED); |
| 3559 } | 3575 } |
| 3560 return result; | 3576 return result; |
| 3561 } | 3577 } |
| 3562 | 3578 |
| 3563 | 3579 |
| 3564 bool RegExpParser::CaptureAvailable(int index) { | 3580 bool RegExpParser::CaptureAvailable(int index) { |
| 3565 if (captures_ == NULL) return false; | 3581 if (captures_ == NULL) return false; |
| 3566 if (index >= captures_->length()) return false; | 3582 if (index >= captures_->length()) return false; |
| 3567 RegExpCapture* capture = captures_->at(index); | 3583 RegExpCapture* capture = captures_->at(index); |
| 3568 return capture != NULL && capture->available() == CAPTURE_AVAILABLE; | 3584 return capture != NULL && capture->available() == CAPTURE_AVAILABLE; |
| 3569 } | 3585 } |
| 3570 | 3586 |
| 3571 | 3587 |
| 3572 // Disjunction :: | 3588 // Disjunction :: |
| 3573 // Alternative | 3589 // Alternative |
| 3574 // Alternative | Disjunction | 3590 // Alternative | Disjunction |
| 3575 // Alternative :: | 3591 // Alternative :: |
| 3576 // [empty] | 3592 // [empty] |
| 3577 // Term Alternative | 3593 // Term Alternative |
| 3578 // Term :: | 3594 // Term :: |
| 3579 // Assertion | 3595 // Assertion |
| 3580 // Atom | 3596 // Atom |
| 3581 // Atom Quantifier | 3597 // Atom Quantifier |
| 3582 RegExpTree* RegExpParser::ParseDisjunction(bool* ok) { | 3598 RegExpTree* RegExpParser::ParseDisjunction() { |
| 3583 RegExpBuilder builder; | 3599 RegExpBuilder builder; |
| 3584 int capture_start_index = captures_started(); | 3600 int capture_start_index = captures_started(); |
| 3585 while (true) { | 3601 while (true) { |
| 3586 switch (current()) { | 3602 switch (current()) { |
| 3587 case kEndMarker: | 3603 case kEndMarker: |
| 3588 case ')': | 3604 case ')': |
| 3589 return builder.ToRegExp(); | 3605 return builder.ToRegExp(); |
| 3590 case '|': { | 3606 case '|': { |
| 3591 Advance(); | 3607 Advance(); |
| 3592 builder.NewAlternative(); | 3608 builder.NewAlternative(); |
| 3593 int capture_new_alt_start_index = captures_started(); | 3609 int capture_new_alt_start_index = captures_started(); |
| 3594 for (int i = capture_start_index; i < capture_new_alt_start_index; i++) { | 3610 for (int i = capture_start_index; i < capture_new_alt_start_index; i++) { |
| 3595 RegExpCapture* capture = captures_->at(i); | 3611 RegExpCapture* capture = captures_->at(i); |
| 3596 if (capture->available() == CAPTURE_AVAILABLE) { | 3612 if (capture->available() == CAPTURE_AVAILABLE) { |
| 3597 capture->set_available(CAPTURE_UNREACHABLE); | 3613 capture->set_available(CAPTURE_UNREACHABLE); |
| 3598 } | 3614 } |
| 3599 } | 3615 } |
| 3600 capture_start_index = capture_new_alt_start_index; | 3616 capture_start_index = capture_new_alt_start_index; |
| 3601 continue; | 3617 continue; |
| 3602 } | 3618 } |
| 3603 case '*': | 3619 case '*': |
| 3604 case '+': | 3620 case '+': |
| 3605 case '?': | 3621 case '?': |
| 3606 ReportError(CStrVector("Nothing to repeat"), CHECK_OK); | 3622 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED); |
| 3607 case '^': { | 3623 case '^': { |
| 3608 Advance(); | 3624 Advance(); |
| 3609 RegExpAssertion::Type type = | 3625 RegExpAssertion::Type type = |
| 3610 multiline_ ? RegExpAssertion::START_OF_LINE : | 3626 multiline_ ? RegExpAssertion::START_OF_LINE : |
| 3611 RegExpAssertion::START_OF_INPUT; | 3627 RegExpAssertion::START_OF_INPUT; |
| 3612 builder.AddAssertion(new RegExpAssertion(type)); | 3628 builder.AddAssertion(new RegExpAssertion(type)); |
| 3613 continue; | 3629 continue; |
| 3614 } | 3630 } |
| 3615 case '$': { | 3631 case '$': { |
| 3616 Advance(); | 3632 Advance(); |
| 3617 RegExpAssertion::Type type = | 3633 RegExpAssertion::Type type = |
| 3618 multiline_ ? RegExpAssertion::END_OF_LINE : | 3634 multiline_ ? RegExpAssertion::END_OF_LINE : |
| 3619 RegExpAssertion::END_OF_INPUT; | 3635 RegExpAssertion::END_OF_INPUT; |
| 3620 builder.AddAssertion(new RegExpAssertion(type)); | 3636 builder.AddAssertion(new RegExpAssertion(type)); |
| 3621 continue; | 3637 continue; |
| 3622 } | 3638 } |
| 3623 case '.': { | 3639 case '.': { |
| 3624 Advance(); | 3640 Advance(); |
| 3625 // everything except \x0a, \x0d, \u2028 and \u2029 | 3641 // everything except \x0a, \x0d, \u2028 and \u2029 |
| 3626 ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); | 3642 ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); |
| 3627 CharacterRange::AddClassEscape('.', ranges); | 3643 CharacterRange::AddClassEscape('.', ranges); |
| 3628 RegExpTree* atom = new RegExpCharacterClass(ranges, false); | 3644 RegExpTree* atom = new RegExpCharacterClass(ranges, false); |
| 3629 builder.AddAtom(atom); | 3645 builder.AddAtom(atom); |
| 3630 break; | 3646 break; |
| 3631 } | 3647 } |
| 3632 case '(': { | 3648 case '(': { |
| 3633 RegExpTree* atom = ParseGroup(CHECK_OK); | 3649 RegExpTree* atom = ParseGroup(CHECK_FAILED); |
| 3634 builder.AddAtom(atom); | 3650 builder.AddAtom(atom); |
| 3635 break; | 3651 break; |
| 3636 } | 3652 } |
| 3637 case '[': { | 3653 case '[': { |
| 3638 RegExpTree* atom = ParseCharacterClass(CHECK_OK); | 3654 RegExpTree* atom = ParseCharacterClass(CHECK_FAILED); |
| 3639 builder.AddAtom(atom); | 3655 builder.AddAtom(atom); |
| 3640 break; | 3656 break; |
| 3641 } | 3657 } |
| 3642 // Atom :: | 3658 // Atom :: |
| 3643 // \ AtomEscape | 3659 // \ AtomEscape |
| 3644 case '\\': | 3660 case '\\': |
| 3645 switch (Next()) { | 3661 switch (Next()) { |
| 3646 case kEndMarker: | 3662 case kEndMarker: |
| 3647 ReportError(CStrVector("\\ at end of pattern"), CHECK_OK); | 3663 ReportError(CStrVector("\\ at end of pattern") CHECK_FAILED); |
| 3648 case 'b': | 3664 case 'b': |
| 3649 Advance(2); | 3665 Advance(2); |
| 3650 builder.AddAssertion( | 3666 builder.AddAssertion( |
| 3651 new RegExpAssertion(RegExpAssertion::BOUNDARY)); | 3667 new RegExpAssertion(RegExpAssertion::BOUNDARY)); |
| 3652 continue; | 3668 continue; |
| 3653 case 'B': | 3669 case 'B': |
| 3654 Advance(2); | 3670 Advance(2); |
| 3655 builder.AddAssertion( | 3671 builder.AddAssertion( |
| 3656 new RegExpAssertion(RegExpAssertion::NON_BOUNDARY)); | 3672 new RegExpAssertion(RegExpAssertion::NON_BOUNDARY)); |
| 3657 continue; | 3673 continue; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3715 case 't': | 3731 case 't': |
| 3716 Advance(2); | 3732 Advance(2); |
| 3717 builder.AddCharacter('\t'); | 3733 builder.AddCharacter('\t'); |
| 3718 break; | 3734 break; |
| 3719 case 'v': | 3735 case 'v': |
| 3720 Advance(2); | 3736 Advance(2); |
| 3721 builder.AddCharacter('\v'); | 3737 builder.AddCharacter('\v'); |
| 3722 break; | 3738 break; |
| 3723 case 'c': { | 3739 case 'c': { |
| 3724 Advance(2); | 3740 Advance(2); |
| 3725 uc32 control = ParseControlLetterEscape(ok); | 3741 uc32 control = ParseControlLetterEscape(); |
| 3726 builder.AddCharacter(control); | 3742 builder.AddCharacter(control); |
| 3727 break; | 3743 break; |
| 3728 } | 3744 } |
| 3729 case 'x': { | 3745 case 'x': { |
| 3730 Advance(2); | 3746 Advance(2); |
| 3731 uc32 value; | 3747 uc32 value; |
| 3732 if (ParseHexEscape(2, &value)) { | 3748 if (ParseHexEscape(2, &value)) { |
| 3733 builder.AddCharacter(value); | 3749 builder.AddCharacter(value); |
| 3734 } else { | 3750 } else { |
| 3735 builder.AddCharacter('x'); | 3751 builder.AddCharacter('x'); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 3750 // Identity escape. | 3766 // Identity escape. |
| 3751 builder.AddCharacter(Next()); | 3767 builder.AddCharacter(Next()); |
| 3752 Advance(2); | 3768 Advance(2); |
| 3753 break; | 3769 break; |
| 3754 } | 3770 } |
| 3755 has_character_escapes_ = true; | 3771 has_character_escapes_ = true; |
| 3756 break; | 3772 break; |
| 3757 case '{': { | 3773 case '{': { |
| 3758 int dummy; | 3774 int dummy; |
| 3759 if (ParseIntervalQuantifier(&dummy, &dummy)) { | 3775 if (ParseIntervalQuantifier(&dummy, &dummy)) { |
| 3760 ReportError(CStrVector("Nothing to repeat"), CHECK_OK); | 3776 ReportError(CStrVector("Nothing to repeat") CHECK_FAILED); |
| 3761 } | 3777 } |
| 3762 // fallthrough | 3778 // fallthrough |
| 3763 } | 3779 } |
| 3764 default: | 3780 default: |
| 3765 builder.AddCharacter(current()); | 3781 builder.AddCharacter(current()); |
| 3766 Advance(); | 3782 Advance(); |
| 3767 break; | 3783 break; |
| 3768 } // end switch(current()) | 3784 } // end switch(current()) |
| 3769 | 3785 |
| 3770 has_read_atom: | 3786 has_read_atom: |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3967 } | 3983 } |
| 3968 *min_out = min; | 3984 *min_out = min; |
| 3969 *max_out = max; | 3985 *max_out = max; |
| 3970 return true; | 3986 return true; |
| 3971 } | 3987 } |
| 3972 | 3988 |
| 3973 | 3989 |
| 3974 // Upper and lower case letters differ by one bit. | 3990 // Upper and lower case letters differ by one bit. |
| 3975 STATIC_CHECK(('a' ^ 'A') == 0x20); | 3991 STATIC_CHECK(('a' ^ 'A') == 0x20); |
| 3976 | 3992 |
| 3977 uc32 RegExpParser::ParseControlLetterEscape(bool* ok) { | 3993 uc32 RegExpParser::ParseControlLetterEscape() { |
| 3978 if (!has_more()) { | 3994 if (!has_more()) { |
| 3979 ReportError(CStrVector("\\c at end of pattern"), ok); | 3995 ReportError(CStrVector("\\c at end of pattern")); |
| 3980 return '\0'; | 3996 return '\0'; |
| 3981 } | 3997 } |
| 3982 uc32 letter = current() & ~(0x20); // Collapse upper and lower case letters. | 3998 uc32 letter = current() & ~(0x20); // Collapse upper and lower case letters. |
| 3983 if (letter < 'A' || 'Z' < letter) { | 3999 if (letter < 'A' || 'Z' < letter) { |
| 3984 // Non-spec error-correction: "\c" followed by non-control letter is | 4000 // Non-spec error-correction: "\c" followed by non-control letter is |
| 3985 // interpreted as an IdentityEscape of 'c'. | 4001 // interpreted as an IdentityEscape of 'c'. |
| 3986 return 'c'; | 4002 return 'c'; |
| 3987 } | 4003 } |
| 3988 Advance(); | 4004 Advance(); |
| 3989 return letter & 0x1f; // Remainder modulo 32, per specification. | 4005 return letter & 0x1f; // Remainder modulo 32, per specification. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4023 Advance(); | 4039 Advance(); |
| 4024 if (i == length - 1) { | 4040 if (i == length - 1) { |
| 4025 done = true; | 4041 done = true; |
| 4026 } | 4042 } |
| 4027 } | 4043 } |
| 4028 *value = val; | 4044 *value = val; |
| 4029 return true; | 4045 return true; |
| 4030 } | 4046 } |
| 4031 | 4047 |
| 4032 | 4048 |
| 4033 uc32 RegExpParser::ParseClassCharacterEscape(bool* ok) { | 4049 uc32 RegExpParser::ParseClassCharacterEscape() { |
| 4034 ASSERT(current() == '\\'); | 4050 ASSERT(current() == '\\'); |
| 4035 ASSERT(has_next() && !IsSpecialClassEscape(Next())); | 4051 ASSERT(has_next() && !IsSpecialClassEscape(Next())); |
| 4036 Advance(); | 4052 Advance(); |
| 4037 switch (current()) { | 4053 switch (current()) { |
| 4038 case 'b': | 4054 case 'b': |
| 4039 Advance(); | 4055 Advance(); |
| 4040 return '\b'; | 4056 return '\b'; |
| 4041 // ControlEscape :: one of | 4057 // ControlEscape :: one of |
| 4042 // f n r t v | 4058 // f n r t v |
| 4043 case 'f': | 4059 case 'f': |
| 4044 Advance(); | 4060 Advance(); |
| 4045 return '\f'; | 4061 return '\f'; |
| 4046 case 'n': | 4062 case 'n': |
| 4047 Advance(); | 4063 Advance(); |
| 4048 return '\n'; | 4064 return '\n'; |
| 4049 case 'r': | 4065 case 'r': |
| 4050 Advance(); | 4066 Advance(); |
| 4051 return '\r'; | 4067 return '\r'; |
| 4052 case 't': | 4068 case 't': |
| 4053 Advance(); | 4069 Advance(); |
| 4054 return '\t'; | 4070 return '\t'; |
| 4055 case 'v': | 4071 case 'v': |
| 4056 Advance(); | 4072 Advance(); |
| 4057 return '\v'; | 4073 return '\v'; |
| 4058 case 'c': | 4074 case 'c': |
| 4059 return ParseControlLetterEscape(ok); | 4075 return ParseControlLetterEscape(); |
| 4060 case '0': case '1': case '2': case '3': case '4': case '5': | 4076 case '0': case '1': case '2': case '3': case '4': case '5': |
| 4061 case '6': case '7': | 4077 case '6': case '7': |
| 4062 // For compatibility, we interpret a decimal escape that isn't | 4078 // For compatibility, we interpret a decimal escape that isn't |
| 4063 // a back reference (and therefore either \0 or not valid according | 4079 // a back reference (and therefore either \0 or not valid according |
| 4064 // to the specification) as a 1..3 digit octal character code. | 4080 // to the specification) as a 1..3 digit octal character code. |
| 4065 return ParseOctalLiteral(); | 4081 return ParseOctalLiteral(); |
| 4066 case 'x': { | 4082 case 'x': { |
| 4067 Advance(); | 4083 Advance(); |
| 4068 uc32 value; | 4084 uc32 value; |
| 4069 if (ParseHexEscape(2, &value)) { | 4085 if (ParseHexEscape(2, &value)) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 4089 // by the ECMAScript specification. | 4105 // by the ECMAScript specification. |
| 4090 uc32 result = current(); | 4106 uc32 result = current(); |
| 4091 Advance(); | 4107 Advance(); |
| 4092 return result; | 4108 return result; |
| 4093 } | 4109 } |
| 4094 } | 4110 } |
| 4095 return 0; | 4111 return 0; |
| 4096 } | 4112 } |
| 4097 | 4113 |
| 4098 | 4114 |
| 4099 RegExpTree* RegExpParser::ParseGroup(bool* ok) { | 4115 RegExpTree* RegExpParser::ParseGroup() { |
| 4100 ASSERT_EQ(current(), '('); | 4116 ASSERT_EQ(current(), '('); |
| 4101 char type = '('; | 4117 char type = '('; |
| 4102 Advance(); | 4118 Advance(); |
| 4103 if (current() == '?') { | 4119 if (current() == '?') { |
| 4104 switch (Next()) { | 4120 switch (Next()) { |
| 4105 case ':': case '=': case '!': | 4121 case ':': case '=': case '!': |
| 4106 type = Next(); | 4122 type = Next(); |
| 4107 Advance(2); | 4123 Advance(2); |
| 4108 break; | 4124 break; |
| 4109 default: | 4125 default: |
| 4110 ReportError(CStrVector("Invalid group"), CHECK_OK); | 4126 ReportError(CStrVector("Invalid group") CHECK_FAILED); |
| 4111 break; | 4127 break; |
| 4112 } | 4128 } |
| 4113 } else { | 4129 } else { |
| 4114 if (captures_ == NULL) { | 4130 if (captures_ == NULL) { |
| 4115 captures_ = new ZoneList<RegExpCapture*>(2); | 4131 captures_ = new ZoneList<RegExpCapture*>(2); |
| 4116 } | 4132 } |
| 4117 captures_->Add(NULL); | 4133 captures_->Add(NULL); |
| 4118 } | 4134 } |
| 4119 int capture_index = captures_started(); | 4135 int capture_index = captures_started(); |
| 4120 RegExpTree* body = ParseDisjunction(CHECK_OK); | 4136 RegExpTree* body = ParseDisjunction(CHECK_FAILED); |
| 4121 if (current() != ')') { | 4137 if (current() != ')') { |
| 4122 ReportError(CStrVector("Unterminated group"), CHECK_OK); | 4138 ReportError(CStrVector("Unterminated group") CHECK_FAILED); |
| 4123 } | 4139 } |
| 4124 Advance(); | 4140 Advance(); |
| 4125 | 4141 |
| 4126 int end_capture_index = captures_started(); | 4142 int end_capture_index = captures_started(); |
| 4127 if (type == '!') { | 4143 if (type == '!') { |
| 4128 // Captures inside a negative lookahead are never available outside it. | 4144 // Captures inside a negative lookahead are never available outside it. |
| 4129 for (int i = capture_index; i < end_capture_index; i++) { | 4145 for (int i = capture_index; i < end_capture_index; i++) { |
| 4130 RegExpCapture* capture = captures_->at(i); | 4146 RegExpCapture* capture = captures_->at(i); |
| 4131 ASSERT(capture != NULL); | 4147 ASSERT(capture != NULL); |
| 4132 capture->set_available(CAPTURE_PERMANENTLY_UNREACHABLE); | 4148 capture->set_available(CAPTURE_PERMANENTLY_UNREACHABLE); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 4150 } else if (type == ':') { | 4166 } else if (type == ':') { |
| 4151 return body; | 4167 return body; |
| 4152 } else { | 4168 } else { |
| 4153 ASSERT(type == '=' || type == '!'); | 4169 ASSERT(type == '=' || type == '!'); |
| 4154 bool is_positive = (type == '='); | 4170 bool is_positive = (type == '='); |
| 4155 return new RegExpLookahead(body, is_positive); | 4171 return new RegExpLookahead(body, is_positive); |
| 4156 } | 4172 } |
| 4157 } | 4173 } |
| 4158 | 4174 |
| 4159 | 4175 |
| 4160 CharacterRange RegExpParser::ParseClassAtom(uc16* char_class, bool* ok) { | 4176 CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) { |
| 4161 ASSERT_EQ(0, *char_class); | 4177 ASSERT_EQ(0, *char_class); |
| 4162 uc32 first = current(); | 4178 uc32 first = current(); |
| 4163 if (first == '\\') { | 4179 if (first == '\\') { |
| 4164 switch (Next()) { | 4180 switch (Next()) { |
| 4165 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': { | 4181 case 'w': case 'W': case 'd': case 'D': case 's': case 'S': { |
| 4166 *char_class = Next(); | 4182 *char_class = Next(); |
| 4167 Advance(2); | 4183 Advance(2); |
| 4168 return CharacterRange::Singleton(0); // Return dummy value. | 4184 return CharacterRange::Singleton(0); // Return dummy value. |
| 4169 } | 4185 } |
| 4170 default: | 4186 default: |
| 4171 uc32 c = ParseClassCharacterEscape(CHECK_OK); | 4187 uc32 c = ParseClassCharacterEscape(CHECK_FAILED); |
| 4172 return CharacterRange::Singleton(c); | 4188 return CharacterRange::Singleton(c); |
| 4173 } | 4189 } |
| 4174 } else { | 4190 } else { |
| 4175 Advance(); | 4191 Advance(); |
| 4176 return CharacterRange::Singleton(first); | 4192 return CharacterRange::Singleton(first); |
| 4177 } | 4193 } |
| 4178 } | 4194 } |
| 4179 | 4195 |
| 4180 | 4196 |
| 4181 RegExpTree* RegExpParser::ParseCharacterClass(bool* ok) { | 4197 RegExpTree* RegExpParser::ParseCharacterClass() { |
| 4182 static const char* kUnterminated = "Unterminated character class"; | 4198 static const char* kUnterminated = "Unterminated character class"; |
| 4183 static const char* kRangeOutOfOrder = "Range out of order in character class"; | 4199 static const char* kRangeOutOfOrder = "Range out of order in character class"; |
| 4184 | 4200 |
| 4185 ASSERT_EQ(current(), '['); | 4201 ASSERT_EQ(current(), '['); |
| 4186 Advance(); | 4202 Advance(); |
| 4187 bool is_negated = false; | 4203 bool is_negated = false; |
| 4188 if (current() == '^') { | 4204 if (current() == '^') { |
| 4189 is_negated = true; | 4205 is_negated = true; |
| 4190 Advance(); | 4206 Advance(); |
| 4191 } | 4207 } |
| 4192 ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); | 4208 ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); |
| 4193 while (has_more() && current() != ']') { | 4209 while (has_more() && current() != ']') { |
| 4194 uc16 char_class = 0; | 4210 uc16 char_class = 0; |
| 4195 CharacterRange first = ParseClassAtom(&char_class, CHECK_OK); | 4211 CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED); |
| 4196 if (char_class) { | 4212 if (char_class) { |
| 4197 CharacterRange::AddClassEscape(char_class, ranges); | 4213 CharacterRange::AddClassEscape(char_class, ranges); |
| 4198 continue; | 4214 continue; |
| 4199 } | 4215 } |
| 4200 if (current() == '-') { | 4216 if (current() == '-') { |
| 4201 Advance(); | 4217 Advance(); |
| 4202 if (current() == kEndMarker) { | 4218 if (current() == kEndMarker) { |
| 4203 // If we reach the end we break out of the loop and let the | 4219 // If we reach the end we break out of the loop and let the |
| 4204 // following code report an error. | 4220 // following code report an error. |
| 4205 break; | 4221 break; |
| 4206 } else if (current() == ']') { | 4222 } else if (current() == ']') { |
| 4207 ranges->Add(first); | 4223 ranges->Add(first); |
| 4208 ranges->Add(CharacterRange::Singleton('-')); | 4224 ranges->Add(CharacterRange::Singleton('-')); |
| 4209 break; | 4225 break; |
| 4210 } | 4226 } |
| 4211 CharacterRange next = ParseClassAtom(&char_class, CHECK_OK); | 4227 CharacterRange next = ParseClassAtom(&char_class CHECK_FAILED); |
| 4212 if (char_class) { | 4228 if (char_class) { |
| 4213 ranges->Add(first); | 4229 ranges->Add(first); |
| 4214 ranges->Add(CharacterRange::Singleton('-')); | 4230 ranges->Add(CharacterRange::Singleton('-')); |
| 4215 CharacterRange::AddClassEscape(char_class, ranges); | 4231 CharacterRange::AddClassEscape(char_class, ranges); |
| 4216 continue; | 4232 continue; |
| 4217 } | 4233 } |
| 4218 if (first.from() > next.to()) { | 4234 if (first.from() > next.to()) { |
| 4219 return ReportError(CStrVector(kRangeOutOfOrder), CHECK_OK); | 4235 return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED); |
| 4220 } | 4236 } |
| 4221 ranges->Add(CharacterRange::Range(first.from(), next.to())); | 4237 ranges->Add(CharacterRange::Range(first.from(), next.to())); |
| 4222 } else { | 4238 } else { |
| 4223 ranges->Add(first); | 4239 ranges->Add(first); |
| 4224 } | 4240 } |
| 4225 } | 4241 } |
| 4226 if (!has_more()) { | 4242 if (!has_more()) { |
| 4227 return ReportError(CStrVector(kUnterminated), CHECK_OK); | 4243 return ReportError(CStrVector(kUnterminated) CHECK_FAILED); |
| 4228 } | 4244 } |
| 4229 Advance(); | 4245 Advance(); |
| 4230 if (ranges->length() == 0) { | 4246 if (ranges->length() == 0) { |
| 4231 ranges->Add(CharacterRange::Everything()); | 4247 ranges->Add(CharacterRange::Everything()); |
| 4232 is_negated = !is_negated; | 4248 is_negated = !is_negated; |
| 4233 } | 4249 } |
| 4234 return new RegExpCharacterClass(ranges, is_negated); | 4250 return new RegExpCharacterClass(ranges, is_negated); |
| 4235 } | 4251 } |
| 4236 | 4252 |
| 4237 | 4253 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4280 // the expected 50% too large. | 4296 // the expected 50% too large. |
| 4281 Vector<unsigned> store = parser.recorder()->store()->ToVector().Clone(); | 4297 Vector<unsigned> store = parser.recorder()->store()->ToVector().Clone(); |
| 4282 return new ScriptDataImpl(store); | 4298 return new ScriptDataImpl(store); |
| 4283 } | 4299 } |
| 4284 | 4300 |
| 4285 | 4301 |
| 4286 bool ParseRegExp(FlatStringReader* input, | 4302 bool ParseRegExp(FlatStringReader* input, |
| 4287 bool multiline, | 4303 bool multiline, |
| 4288 RegExpParseResult* result) { | 4304 RegExpParseResult* result) { |
| 4289 ASSERT(result != NULL); | 4305 ASSERT(result != NULL); |
| 4306 // Make sure we have a stack guard. | |
| 4307 StackGuard guard; | |
| 4290 RegExpParser parser(input, &result->error, multiline); | 4308 RegExpParser parser(input, &result->error, multiline); |
| 4291 bool ok = true; | 4309 result->tree = parser.ParsePattern(); |
| 4292 result->tree = parser.ParsePattern(&ok); | 4310 if (parser.failed()) { |
| 4293 if (!ok) { | |
| 4294 ASSERT(result->tree == NULL); | 4311 ASSERT(result->tree == NULL); |
| 4295 ASSERT(!result->error.is_null()); | 4312 ASSERT(!result->error.is_null()); |
| 4296 } else { | 4313 } else { |
| 4297 ASSERT(result->tree != NULL); | 4314 ASSERT(result->tree != NULL); |
| 4298 ASSERT(result->error.is_null()); | 4315 ASSERT(result->error.is_null()); |
| 4299 } | |
| 4300 if (ok) { | |
| 4301 result->has_character_escapes = parser.HasCharacterEscapes(); | 4316 result->has_character_escapes = parser.HasCharacterEscapes(); |
| 4302 result->capture_count = parser.captures_started(); | 4317 result->capture_count = parser.captures_started(); |
| 4303 } | 4318 } |
| 4304 return ok; | 4319 return !parser.failed(); |
| 4305 } | 4320 } |
| 4306 | 4321 |
| 4307 | 4322 |
| 4308 FunctionLiteral* MakeAST(bool compile_in_global_context, | 4323 FunctionLiteral* MakeAST(bool compile_in_global_context, |
| 4309 Handle<Script> script, | 4324 Handle<Script> script, |
| 4310 v8::Extension* extension, | 4325 v8::Extension* extension, |
| 4311 ScriptDataImpl* pre_data) { | 4326 ScriptDataImpl* pre_data) { |
| 4312 bool allow_natives_syntax = | 4327 bool allow_natives_syntax = |
| 4313 always_allow_natives_syntax || | 4328 always_allow_natives_syntax || |
| 4314 FLAG_allow_natives_syntax || | 4329 FLAG_allow_natives_syntax || |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4350 start_position, | 4365 start_position, |
| 4351 is_expression); | 4366 is_expression); |
| 4352 return result; | 4367 return result; |
| 4353 } | 4368 } |
| 4354 | 4369 |
| 4355 | 4370 |
| 4356 #undef NEW | 4371 #undef NEW |
| 4357 | 4372 |
| 4358 | 4373 |
| 4359 } } // namespace v8::internal | 4374 } } // namespace v8::internal |
| OLD | NEW |