| 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 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 | 453 |
| 454 | 454 |
| 455 struct NodeInfo { | 455 struct NodeInfo { |
| 456 enum TriBool { | 456 enum TriBool { |
| 457 UNKNOWN = -1, FALSE = 0, TRUE = 1 | 457 UNKNOWN = -1, FALSE = 0, TRUE = 1 |
| 458 }; | 458 }; |
| 459 | 459 |
| 460 NodeInfo() | 460 NodeInfo() |
| 461 : being_analyzed(false), | 461 : being_analyzed(false), |
| 462 been_analyzed(false), | 462 been_analyzed(false), |
| 463 being_expanded(false), | |
| 464 been_expanded(false), | |
| 465 determine_word(false), | |
| 466 determine_newline(false), | |
| 467 determine_start(false), | |
| 468 does_determine_word(false), | |
| 469 does_determine_newline(false), | |
| 470 does_determine_start(false), | |
| 471 follows_word_interest(false), | 463 follows_word_interest(false), |
| 472 follows_newline_interest(false), | 464 follows_newline_interest(false), |
| 473 follows_start_interest(false), | 465 follows_start_interest(false), |
| 474 is_word(UNKNOWN), | |
| 475 is_newline(UNKNOWN), | |
| 476 at_end(false), | 466 at_end(false), |
| 477 follows_word(UNKNOWN), | |
| 478 follows_newline(UNKNOWN), | |
| 479 follows_start(UNKNOWN), | |
| 480 visited(false) { } | 467 visited(false) { } |
| 481 | 468 |
| 482 // Returns true if the interests and assumptions of this node | 469 // Returns true if the interests and assumptions of this node |
| 483 // matches the given one. | 470 // matches the given one. |
| 484 bool Matches(NodeInfo* that) { | 471 bool Matches(NodeInfo* that) { |
| 485 return (at_end == that->at_end) && | 472 return (at_end == that->at_end) && |
| 486 (follows_word_interest == that->follows_word_interest) && | 473 (follows_word_interest == that->follows_word_interest) && |
| 487 (follows_newline_interest == that->follows_newline_interest) && | 474 (follows_newline_interest == that->follows_newline_interest) && |
| 488 (follows_start_interest == that->follows_start_interest) && | 475 (follows_start_interest == that->follows_start_interest); |
| 489 (follows_word == that->follows_word) && | |
| 490 (follows_newline == that->follows_newline) && | |
| 491 (follows_start == that->follows_start) && | |
| 492 (does_determine_word == that->does_determine_word) && | |
| 493 (does_determine_newline == that->does_determine_newline) && | |
| 494 (does_determine_start == that->does_determine_start); | |
| 495 } | |
| 496 | |
| 497 bool HasAssertions() { | |
| 498 return (follows_word != UNKNOWN) || | |
| 499 (follows_newline != UNKNOWN) || | |
| 500 (follows_start != UNKNOWN); | |
| 501 } | 476 } |
| 502 | 477 |
| 503 // Updates the interests of this node given the interests of the | 478 // Updates the interests of this node given the interests of the |
| 504 // node preceding it. | 479 // node preceding it. |
| 505 void AddFromPreceding(NodeInfo* that) { | 480 void AddFromPreceding(NodeInfo* that) { |
| 506 at_end |= that->at_end; | 481 at_end |= that->at_end; |
| 507 follows_word_interest |= that->follows_word_interest; | 482 follows_word_interest |= that->follows_word_interest; |
| 508 follows_newline_interest |= that->follows_newline_interest; | 483 follows_newline_interest |= that->follows_newline_interest; |
| 509 follows_start_interest |= that->follows_start_interest; | 484 follows_start_interest |= that->follows_start_interest; |
| 510 } | 485 } |
| 511 | 486 |
| 512 void AddAssumptions(NodeInfo* that) { | |
| 513 if (that->follows_word != UNKNOWN) { | |
| 514 ASSERT(follows_word == UNKNOWN || follows_word == that->follows_word); | |
| 515 follows_word = that->follows_word; | |
| 516 } | |
| 517 if (that->follows_newline != UNKNOWN) { | |
| 518 ASSERT(follows_newline == UNKNOWN || | |
| 519 follows_newline == that->follows_newline); | |
| 520 follows_newline = that->follows_newline; | |
| 521 } | |
| 522 if (that->follows_start != UNKNOWN) { | |
| 523 ASSERT(follows_start == UNKNOWN || | |
| 524 follows_start == that->follows_start); | |
| 525 follows_start = that->follows_start; | |
| 526 } | |
| 527 does_determine_word = that->does_determine_word; | |
| 528 does_determine_newline = that->does_determine_newline; | |
| 529 does_determine_start = that->does_determine_start; | |
| 530 } | |
| 531 | |
| 532 bool HasLookbehind() { | 487 bool HasLookbehind() { |
| 533 return follows_word_interest || | 488 return follows_word_interest || |
| 534 follows_newline_interest || | 489 follows_newline_interest || |
| 535 follows_start_interest; | 490 follows_start_interest; |
| 536 } | 491 } |
| 537 | 492 |
| 538 // Sets the interests of this node to include the interests of the | 493 // Sets the interests of this node to include the interests of the |
| 539 // following node. | 494 // following node. |
| 540 void AddFromFollowing(NodeInfo* that) { | 495 void AddFromFollowing(NodeInfo* that) { |
| 541 follows_word_interest |= that->follows_word_interest; | 496 follows_word_interest |= that->follows_word_interest; |
| 542 follows_newline_interest |= that->follows_newline_interest; | 497 follows_newline_interest |= that->follows_newline_interest; |
| 543 follows_start_interest |= that->follows_start_interest; | 498 follows_start_interest |= that->follows_start_interest; |
| 544 } | 499 } |
| 545 | 500 |
| 546 void ResetCompilationState() { | 501 void ResetCompilationState() { |
| 547 being_analyzed = false; | 502 being_analyzed = false; |
| 548 been_analyzed = false; | 503 been_analyzed = false; |
| 549 being_expanded = false; | |
| 550 been_expanded = false; | |
| 551 } | 504 } |
| 552 | 505 |
| 553 bool being_analyzed: 1; | 506 bool being_analyzed: 1; |
| 554 bool been_analyzed: 1; | 507 bool been_analyzed: 1; |
| 555 bool being_expanded: 1; | |
| 556 bool been_expanded: 1; | |
| 557 | |
| 558 // These bits are set if this node must propagate forward information | |
| 559 // about the last character it consumed (or, in the case of 'start', | |
| 560 // if it is at the start of the input). | |
| 561 bool determine_word: 1; | |
| 562 bool determine_newline: 1; | |
| 563 bool determine_start: 1; | |
| 564 | |
| 565 bool does_determine_word: 1; | |
| 566 bool does_determine_newline: 1; | |
| 567 bool does_determine_start: 1; | |
| 568 | 508 |
| 569 // These bits are set of this node has to know what the preceding | 509 // These bits are set of this node has to know what the preceding |
| 570 // character was. | 510 // character was. |
| 571 bool follows_word_interest: 1; | 511 bool follows_word_interest: 1; |
| 572 bool follows_newline_interest: 1; | 512 bool follows_newline_interest: 1; |
| 573 bool follows_start_interest: 1; | 513 bool follows_start_interest: 1; |
| 574 | 514 |
| 575 TriBool is_word: 2; | |
| 576 TriBool is_newline: 2; | |
| 577 | |
| 578 bool at_end: 1; | 515 bool at_end: 1; |
| 579 | |
| 580 // These bits are set if the node can make assumptions about what | |
| 581 // the previous character was. | |
| 582 TriBool follows_word: 2; | |
| 583 TriBool follows_newline: 2; | |
| 584 TriBool follows_start: 2; | |
| 585 | |
| 586 bool visited: 1; | 516 bool visited: 1; |
| 587 }; | 517 }; |
| 588 | 518 |
| 589 | 519 |
| 590 class ExpansionGuard { | |
| 591 public: | |
| 592 explicit inline ExpansionGuard(NodeInfo* info) : info_(info) { | |
| 593 ASSERT(!info->being_expanded); | |
| 594 info->being_expanded = true; | |
| 595 } | |
| 596 inline ~ExpansionGuard() { | |
| 597 info_->being_expanded = false; | |
| 598 } | |
| 599 private: | |
| 600 NodeInfo* info_; | |
| 601 }; | |
| 602 | |
| 603 | |
| 604 class SiblingList { | 520 class SiblingList { |
| 605 public: | 521 public: |
| 606 SiblingList() : list_(NULL) { } | 522 SiblingList() : list_(NULL) { } |
| 607 int length() { | 523 int length() { |
| 608 return list_ == NULL ? 0 : list_->length(); | 524 return list_ == NULL ? 0 : list_->length(); |
| 609 } | 525 } |
| 610 void Ensure(RegExpNode* parent) { | 526 void Ensure(RegExpNode* parent) { |
| 611 if (list_ == NULL) { | 527 if (list_ == NULL) { |
| 612 list_ = new ZoneList<RegExpNode*>(2); | 528 list_ = new ZoneList<RegExpNode*>(2); |
| 613 list_->Add(parent); | 529 list_->Add(parent); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 627 virtual void Accept(NodeVisitor* visitor) = 0; | 543 virtual void Accept(NodeVisitor* visitor) = 0; |
| 628 // Generates a goto to this node or actually generates the code at this point. | 544 // Generates a goto to this node or actually generates the code at this point. |
| 629 // Until the implementation is complete we will return true for success and | 545 // Until the implementation is complete we will return true for success and |
| 630 // false for failure. | 546 // false for failure. |
| 631 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant) = 0; | 547 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant) = 0; |
| 632 static const int kNodeIsTooComplexForGreedyLoops = -1; | 548 static const int kNodeIsTooComplexForGreedyLoops = -1; |
| 633 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } | 549 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
| 634 Label* label() { return &label_; } | 550 Label* label() { return &label_; } |
| 635 static const int kMaxVariantsGenerated = 10; | 551 static const int kMaxVariantsGenerated = 10; |
| 636 | 552 |
| 637 RegExpNode* EnsureExpanded(NodeInfo* info); | |
| 638 virtual RegExpNode* ExpandLocal(NodeInfo* info) = 0; | |
| 639 virtual void ExpandChildren() = 0; | |
| 640 | |
| 641 // Propagates the given interest information forward. When seeing | 553 // Propagates the given interest information forward. When seeing |
| 642 // \bfoo for instance, the \b is implemented by propagating forward | 554 // \bfoo for instance, the \b is implemented by propagating forward |
| 643 // to the 'foo' string that it should only succeed if its first | 555 // to the 'foo' string that it should only succeed if its first |
| 644 // character is a letter xor the previous character was a letter. | 556 // character is a letter xor the previous character was a letter. |
| 645 virtual RegExpNode* PropagateForward(NodeInfo* info) = 0; | 557 virtual RegExpNode* PropagateForward(NodeInfo* info) = 0; |
| 646 | 558 |
| 647 NodeInfo* info() { return &info_; } | 559 NodeInfo* info() { return &info_; } |
| 648 | 560 |
| 649 void AddSibling(RegExpNode* node) { siblings_.Add(node); } | 561 void AddSibling(RegExpNode* node) { siblings_.Add(node); } |
| 650 | 562 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 static ActionNode* BeginSubmatch( | 626 static ActionNode* BeginSubmatch( |
| 715 int stack_pointer_reg, | 627 int stack_pointer_reg, |
| 716 int position_reg, | 628 int position_reg, |
| 717 RegExpNode* on_success); | 629 RegExpNode* on_success); |
| 718 static ActionNode* PositiveSubmatchSuccess( | 630 static ActionNode* PositiveSubmatchSuccess( |
| 719 int stack_pointer_reg, | 631 int stack_pointer_reg, |
| 720 int restore_reg, | 632 int restore_reg, |
| 721 RegExpNode* on_success); | 633 RegExpNode* on_success); |
| 722 virtual void Accept(NodeVisitor* visitor); | 634 virtual void Accept(NodeVisitor* visitor); |
| 723 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 635 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
| 724 virtual RegExpNode* ExpandLocal(NodeInfo* info); | |
| 725 virtual void ExpandChildren(); | |
| 726 virtual RegExpNode* PropagateForward(NodeInfo* info); | 636 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 727 Type type() { return type_; } | 637 Type type() { return type_; } |
| 728 // TODO(erikcorry): We should allow some action nodes in greedy loops. | 638 // TODO(erikcorry): We should allow some action nodes in greedy loops. |
| 729 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } | 639 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
| 730 virtual ActionNode* Clone() { return new ActionNode(*this); } | 640 virtual ActionNode* Clone() { return new ActionNode(*this); } |
| 731 | 641 |
| 732 private: | 642 private: |
| 733 union { | 643 union { |
| 734 struct { | 644 struct { |
| 735 int reg; | 645 int reg; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 761 : SeqRegExpNode(on_success), | 671 : SeqRegExpNode(on_success), |
| 762 elms_(elms) { } | 672 elms_(elms) { } |
| 763 TextNode(RegExpCharacterClass* that, | 673 TextNode(RegExpCharacterClass* that, |
| 764 RegExpNode* on_success) | 674 RegExpNode* on_success) |
| 765 : SeqRegExpNode(on_success), | 675 : SeqRegExpNode(on_success), |
| 766 elms_(new ZoneList<TextElement>(1)) { | 676 elms_(new ZoneList<TextElement>(1)) { |
| 767 elms_->Add(TextElement::CharClass(that)); | 677 elms_->Add(TextElement::CharClass(that)); |
| 768 } | 678 } |
| 769 virtual void Accept(NodeVisitor* visitor); | 679 virtual void Accept(NodeVisitor* visitor); |
| 770 virtual RegExpNode* PropagateForward(NodeInfo* info); | 680 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 771 virtual RegExpNode* ExpandLocal(NodeInfo* info); | |
| 772 virtual void ExpandChildren(); | |
| 773 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 681 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
| 774 ZoneList<TextElement>* elements() { return elms_; } | 682 ZoneList<TextElement>* elements() { return elms_; } |
| 775 void MakeCaseIndependent(); | 683 void MakeCaseIndependent(); |
| 776 virtual int GreedyLoopTextLength(); | 684 virtual int GreedyLoopTextLength(); |
| 777 virtual TextNode* Clone() { | 685 virtual TextNode* Clone() { |
| 778 TextNode* result = new TextNode(*this); | 686 TextNode* result = new TextNode(*this); |
| 779 result->CalculateOffsets(); | 687 result->CalculateOffsets(); |
| 780 return result; | 688 return result; |
| 781 } | 689 } |
| 782 void CalculateOffsets(); | 690 void CalculateOffsets(); |
| 691 |
| 783 private: | 692 private: |
| 784 void ExpandAtomChildren(RegExpAtom* that); | |
| 785 void ExpandCharClassChildren(RegExpCharacterClass* that); | |
| 786 | |
| 787 ZoneList<TextElement>* elms_; | 693 ZoneList<TextElement>* elms_; |
| 788 }; | 694 }; |
| 789 | 695 |
| 790 | 696 |
| 791 class BackReferenceNode: public SeqRegExpNode { | 697 class BackReferenceNode: public SeqRegExpNode { |
| 792 public: | 698 public: |
| 793 BackReferenceNode(int start_reg, | 699 BackReferenceNode(int start_reg, |
| 794 int end_reg, | 700 int end_reg, |
| 795 RegExpNode* on_success) | 701 RegExpNode* on_success) |
| 796 : SeqRegExpNode(on_success), | 702 : SeqRegExpNode(on_success), |
| 797 start_reg_(start_reg), | 703 start_reg_(start_reg), |
| 798 end_reg_(end_reg) { } | 704 end_reg_(end_reg) { } |
| 799 virtual void Accept(NodeVisitor* visitor); | 705 virtual void Accept(NodeVisitor* visitor); |
| 800 int start_register() { return start_reg_; } | 706 int start_register() { return start_reg_; } |
| 801 int end_register() { return end_reg_; } | 707 int end_register() { return end_reg_; } |
| 802 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 708 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
| 803 virtual RegExpNode* PropagateForward(NodeInfo* info); | 709 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 804 virtual RegExpNode* ExpandLocal(NodeInfo* info); | |
| 805 virtual void ExpandChildren(); | |
| 806 virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } | 710 virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } |
| 807 | 711 |
| 808 private: | 712 private: |
| 809 int start_reg_; | 713 int start_reg_; |
| 810 int end_reg_; | 714 int end_reg_; |
| 811 }; | 715 }; |
| 812 | 716 |
| 813 | 717 |
| 814 class EndNode: public RegExpNode { | 718 class EndNode: public RegExpNode { |
| 815 public: | 719 public: |
| 816 enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; | 720 enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; |
| 817 explicit EndNode(Action action) : action_(action) { } | 721 explicit EndNode(Action action) : action_(action) { } |
| 818 virtual void Accept(NodeVisitor* visitor); | 722 virtual void Accept(NodeVisitor* visitor); |
| 819 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 723 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
| 820 virtual RegExpNode* PropagateForward(NodeInfo* info); | 724 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 821 virtual RegExpNode* ExpandLocal(NodeInfo* info); | |
| 822 virtual void ExpandChildren(); | |
| 823 virtual EndNode* Clone() { return new EndNode(*this); } | 725 virtual EndNode* Clone() { return new EndNode(*this); } |
| 824 | 726 |
| 825 protected: | 727 protected: |
| 826 void EmitInfoChecks(RegExpMacroAssembler* macro, GenerationVariant* variant); | 728 void EmitInfoChecks(RegExpMacroAssembler* macro, GenerationVariant* variant); |
| 827 | 729 |
| 828 private: | 730 private: |
| 829 Action action_; | 731 Action action_; |
| 830 }; | 732 }; |
| 831 | 733 |
| 832 | 734 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 explicit ChoiceNode(int expected_size) | 783 explicit ChoiceNode(int expected_size) |
| 882 : alternatives_(new ZoneList<GuardedAlternative>(expected_size)), | 784 : alternatives_(new ZoneList<GuardedAlternative>(expected_size)), |
| 883 table_(NULL), | 785 table_(NULL), |
| 884 being_calculated_(false) { } | 786 being_calculated_(false) { } |
| 885 virtual void Accept(NodeVisitor* visitor); | 787 virtual void Accept(NodeVisitor* visitor); |
| 886 void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } | 788 void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } |
| 887 ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } | 789 ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } |
| 888 DispatchTable* GetTable(bool ignore_case); | 790 DispatchTable* GetTable(bool ignore_case); |
| 889 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 791 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
| 890 virtual RegExpNode* PropagateForward(NodeInfo* info); | 792 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 891 virtual RegExpNode* ExpandLocal(NodeInfo* info); | |
| 892 virtual void ExpandChildren(); | |
| 893 virtual ChoiceNode* Clone() { return new ChoiceNode(*this); } | 793 virtual ChoiceNode* Clone() { return new ChoiceNode(*this); } |
| 894 | 794 |
| 895 bool being_calculated() { return being_calculated_; } | 795 bool being_calculated() { return being_calculated_; } |
| 896 void set_being_calculated(bool b) { being_calculated_ = b; } | 796 void set_being_calculated(bool b) { being_calculated_ = b; } |
| 897 | 797 |
| 898 protected: | 798 protected: |
| 899 int GreedyLoopTextLength(GuardedAlternative *alternative); | 799 int GreedyLoopTextLength(GuardedAlternative *alternative); |
| 900 ZoneList<GuardedAlternative>* alternatives_; | 800 ZoneList<GuardedAlternative>* alternatives_; |
| 901 | 801 |
| 902 private: | 802 private: |
| 903 friend class DispatchTableConstructor; | 803 friend class DispatchTableConstructor; |
| 904 friend class AssertionPropagation; | 804 friend class Analysis; |
| 905 void GenerateGuard(RegExpMacroAssembler* macro_assembler, | 805 void GenerateGuard(RegExpMacroAssembler* macro_assembler, |
| 906 Guard *guard, | 806 Guard *guard, |
| 907 GenerationVariant* variant); | 807 GenerationVariant* variant); |
| 908 DispatchTable* table_; | 808 DispatchTable* table_; |
| 909 bool being_calculated_; | 809 bool being_calculated_; |
| 910 }; | 810 }; |
| 911 | 811 |
| 912 | 812 |
| 913 class LoopChoiceNode: public ChoiceNode { | 813 class LoopChoiceNode: public ChoiceNode { |
| 914 public: | 814 public: |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1084 // be propagated to the first '.' that whatever follows needs to know | 984 // be propagated to the first '.' that whatever follows needs to know |
| 1085 // if it matched a word or a non-word, and to the second '.' that it | 985 // if it matched a word or a non-word, and to the second '.' that it |
| 1086 // has to check if it succeeds a word or non-word. In this case the | 986 // has to check if it succeeds a word or non-word. In this case the |
| 1087 // result will be something like: | 987 // result will be something like: |
| 1088 // | 988 // |
| 1089 // +-------+ +------------+ | 989 // +-------+ +------------+ |
| 1090 // | . | | . | | 990 // | . | | . | |
| 1091 // +-------+ ---> +------------+ | 991 // +-------+ ---> +------------+ |
| 1092 // | word? | | check word | | 992 // | word? | | check word | |
| 1093 // +-------+ +------------+ | 993 // +-------+ +------------+ |
| 1094 // | 994 class Analysis: public NodeVisitor { |
| 1095 // At a later phase all nodes that determine information for their | |
| 1096 // following nodes are split into several 'sibling' nodes. In this | |
| 1097 // case the first '.' is split into one node that only matches words | |
| 1098 // and one that only matches non-words. The second '.' is also split, | |
| 1099 // into one node that assumes that the previous character was a word | |
| 1100 // character and one that assumes that is was non-word. In this case | |
| 1101 // the result is | |
| 1102 // | |
| 1103 // +------------------+ +------------------+ | |
| 1104 // /--> | intersect(., \w) | ---> | intersect(., \W) | | |
| 1105 // | +------------------+ +------------------+ | |
| 1106 // | | follows \w | | |
| 1107 // | +------------------+ | |
| 1108 // --? | |
| 1109 // | +------------------+ +------------------+ | |
| 1110 // \--> | intersect(., \W) | ---> | intersect(., \w) | | |
| 1111 // +------------------+ +------------------+ | |
| 1112 // | follows \W | | |
| 1113 // +------------------+ | |
| 1114 // | |
| 1115 // This way we don't need to explicitly check the previous character | |
| 1116 // but can always assume that whoever consumed the previous character | |
| 1117 // has propagated the relevant information forward. | |
| 1118 class AssertionPropagation: public NodeVisitor { | |
| 1119 public: | 995 public: |
| 1120 explicit AssertionPropagation(bool ignore_case) | 996 explicit Analysis(bool ignore_case) |
| 1121 : ignore_case_(ignore_case) { } | 997 : ignore_case_(ignore_case) { } |
| 1122 void EnsureAnalyzed(RegExpNode* node); | 998 void EnsureAnalyzed(RegExpNode* node); |
| 1123 | 999 |
| 1124 #define DECLARE_VISIT(Type) \ | 1000 #define DECLARE_VISIT(Type) \ |
| 1125 virtual void Visit##Type(Type##Node* that); | 1001 virtual void Visit##Type(Type##Node* that); |
| 1126 FOR_EACH_NODE_TYPE(DECLARE_VISIT) | 1002 FOR_EACH_NODE_TYPE(DECLARE_VISIT) |
| 1127 #undef DECLARE_VISIT | 1003 #undef DECLARE_VISIT |
| 1128 virtual void VisitLoopChoice(LoopChoiceNode* that); | 1004 virtual void VisitLoopChoice(LoopChoiceNode* that); |
| 1129 | 1005 |
| 1130 private: | 1006 private: |
| 1131 bool ignore_case_; | 1007 bool ignore_case_; |
| 1132 | 1008 |
| 1133 DISALLOW_IMPLICIT_CONSTRUCTORS(AssertionPropagation); | 1009 DISALLOW_IMPLICIT_CONSTRUCTORS(Analysis); |
| 1134 }; | 1010 }; |
| 1135 | 1011 |
| 1136 | 1012 |
| 1137 struct RegExpCompileData { | 1013 struct RegExpCompileData { |
| 1138 RegExpCompileData() | 1014 RegExpCompileData() |
| 1139 : tree(NULL), | 1015 : tree(NULL), |
| 1140 node(NULL), | 1016 node(NULL), |
| 1141 has_lookbehind(false), | |
| 1142 simple(true), | 1017 simple(true), |
| 1143 capture_count(0) { } | 1018 capture_count(0) { } |
| 1144 RegExpTree* tree; | 1019 RegExpTree* tree; |
| 1145 RegExpNode* node; | 1020 RegExpNode* node; |
| 1146 bool has_lookbehind; | |
| 1147 bool simple; | 1021 bool simple; |
| 1148 Handle<String> error; | 1022 Handle<String> error; |
| 1149 int capture_count; | 1023 int capture_count; |
| 1150 }; | 1024 }; |
| 1151 | 1025 |
| 1152 | 1026 |
| 1153 class RegExpEngine: public AllStatic { | 1027 class RegExpEngine: public AllStatic { |
| 1154 public: | 1028 public: |
| 1155 static Handle<FixedArray> Compile(RegExpCompileData* input, | 1029 static Handle<FixedArray> Compile(RegExpCompileData* input, |
| 1156 bool ignore_case, | 1030 bool ignore_case, |
| 1157 bool multiline, | 1031 bool multiline, |
| 1158 Handle<String> pattern, | 1032 Handle<String> pattern, |
| 1159 bool is_ascii); | 1033 bool is_ascii); |
| 1160 | 1034 |
| 1161 static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); | 1035 static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); |
| 1162 }; | 1036 }; |
| 1163 | 1037 |
| 1164 | 1038 |
| 1165 } } // namespace v8::internal | 1039 } } // namespace v8::internal |
| 1166 | 1040 |
| 1167 #endif // V8_JSREGEXP_H_ | 1041 #endif // V8_JSREGEXP_H_ |
| OLD | NEW |