@@ -478,11 +478,6 @@ pub struct OnePassCompiler {
478
478
/// A mapping from instruction indices to flags indicating
479
479
/// if they should have the STATE_MATCH flag set.
480
480
accepting_states : Vec < bool > ,
481
-
482
- /// A DAG of forwarding relationships indicating when
483
- /// a state needs to be forwarded to an Action state
484
- /// once that Action state has been fully constructed.
485
- forwards : Forwards ,
486
481
}
487
482
488
483
#[ derive( Debug ) ]
@@ -568,27 +563,33 @@ impl OnePassCompiler {
568
563
x
569
564
} ,
570
565
accepting_states : vec ! [ false ; prog. len( ) ] ,
571
- forwards : Forwards :: new ( ) ,
572
566
prog : prog,
573
567
} )
574
568
}
575
569
576
570
/// Attempt to compile the regex to a OnePass DFA
577
571
pub fn compile ( mut self ) -> Result < OnePass , OnePassError > {
572
+ // A DAG of forwarding relationships indicating when
573
+ // a state needs to be forwarded to an Action state
574
+ // once that Action state has been fully constructed.
575
+ let mut forwards = Forwards :: new ( ) ;
576
+
578
577
// Compute the prioritized transition tables for all of the
579
578
// instructions which get states.
580
579
let mut state_edge = vec ! [ 0 ] ;
581
580
while let Some ( i) = state_edge. pop ( ) {
582
- state_edge. extend ( try!( self . inst_trans ( i) ) ) ;
581
+ state_edge. extend ( try!( self . inst_trans ( i, & mut forwards ) ) ) ;
583
582
}
584
583
585
584
// Solve the dependency relationships between all the
586
585
// forwarding directives that were emitted by inst_trans.
587
- try!( self . solve_forwards ( ) ) ;
586
+ for fwd in forwards. into_iter_topo ( ) {
587
+ self . perform_forward ( try!( fwd) ) ;
588
+ }
588
589
589
590
// Now emit the transitions in a form that we can actually
590
591
// execute.
591
- self . emit_transitions ( ) ;
592
+ self . bake_transitions ( ) ;
592
593
593
594
Ok ( OnePass {
594
595
table : self . table ,
@@ -611,7 +612,8 @@ impl OnePassCompiler {
611
612
/// via `inst_trans`.
612
613
fn inst_trans (
613
614
& mut self ,
614
- inst_idx : usize
615
+ inst_idx : usize ,
616
+ forwards : & mut Forwards ,
615
617
) -> Result < Vec < usize > , OnePassError > {
616
618
trace ! ( "::inst_trans inst_idx={}" , inst_idx) ;
617
619
@@ -642,7 +644,7 @@ impl OnePassCompiler {
642
644
while let Some ( child_idx) = resume. pop ( ) {
643
645
match & self . prog [ child_idx] {
644
646
& Inst :: EmptyLook ( _) | & Inst :: Save ( _) => {
645
- self . forwards . forward ( inst_idx, child_idx, priority) ;
647
+ forwards. forward ( inst_idx, child_idx, priority) ;
646
648
children. push ( child_idx) ;
647
649
}
648
650
& Inst :: Bytes ( ref inst) => {
@@ -685,10 +687,7 @@ impl OnePassCompiler {
685
687
Ok ( children)
686
688
}
687
689
688
- /// Topologically sort the forwarding jobs so that we
689
- /// start with jobs that have no dependencies and then
690
- /// shuffle the transitions over. Mutate `self.transitions`
691
- /// in place.
690
+ /// Execute a forwarding job.
692
691
///
693
692
/// To make that a little more concrete, consider the program snippet:
694
693
///
@@ -724,71 +723,65 @@ impl OnePassCompiler {
724
723
/// The arrow flows in a funny direction because we want the jobs
725
724
/// with no dependencies to live at the roots of the DAG so that
726
725
/// we can process them first.
727
- fn solve_forwards ( & mut self ) -> Result < ( ) , OnePassError > {
728
- // TODO(ethan):yakshaving drop the clone
729
- for fwd in self . forwards . clone ( ) . into_iter_topo ( ) {
730
- let fwd = try!( fwd) ;
731
- debug_assert ! ( fwd. from != fwd. to) ;
726
+ fn perform_forward ( & mut self , fwd : Forward ) {
727
+ debug_assert ! ( fwd. from != fwd. to) ;
732
728
733
- let tgt = match & self . prog [ fwd. to ] {
734
- & Inst :: EmptyLook ( _) | & Inst :: Save ( _) =>
735
- TransitionTarget :: ActionInst ( fwd. to ) ,
736
- _ =>
737
- TransitionTarget :: BytesInst ( fwd. to ) ,
738
- } ;
739
-
740
- let ( from_ts, to_ts) = if fwd. from < fwd. to {
741
- let ( stub, tail) = self . transitions . split_at_mut ( fwd. to ) ;
742
- ( & mut stub[ fwd. from ] , & mut tail[ 0 ] )
743
- } else {
744
- let ( stub, tail) = self . transitions . split_at_mut ( fwd. from ) ;
745
- ( & mut tail[ 0 ] , & mut stub[ fwd. to ] )
746
- } ;
729
+ let tgt = match & self . prog [ fwd. to ] {
730
+ & Inst :: EmptyLook ( _) | & Inst :: Save ( _) =>
731
+ TransitionTarget :: ActionInst ( fwd. to ) ,
732
+ _ => TransitionTarget :: BytesInst ( fwd. to ) ,
733
+ } ;
747
734
748
- let ( from_ts, to_ts) = match ( from_ts, to_ts) {
749
- ( & mut Some ( ref mut from_ts) , & mut Some ( ref to_ts) ) => {
750
- ( from_ts, to_ts)
751
- }
752
- _ => unreachable ! ( "forwards must be between real nodes." ) ,
753
- } ;
735
+ // Get a pair of mutable references to the two different
736
+ // transition tables in borrow checker approved fashion.
737
+ let ( from_ts, to_ts) = if fwd. from < fwd. to {
738
+ let ( stub, tail) = self . transitions . split_at_mut ( fwd. to ) ;
739
+ ( & mut stub[ fwd. from ] , & mut tail[ 0 ] )
740
+ } else {
741
+ let ( stub, tail) = self . transitions . split_at_mut ( fwd. from ) ;
742
+ ( & mut tail[ 0 ] , & mut stub[ fwd. to ] )
743
+ } ;
744
+ let ( from_ts, to_ts) = match ( from_ts, to_ts) {
745
+ ( & mut Some ( ref mut from_ts) , & mut Some ( ref to_ts) ) => {
746
+ ( from_ts, to_ts)
747
+ }
748
+ _ => unreachable ! ( "forwards must be between real nodes." ) ,
749
+ } ;
754
750
755
- // now shuffle the transitions from `to` to `from`.
756
- for ( to_t, from_t) in to_ts. 0 . iter ( ) . zip ( from_ts. 0 . iter_mut ( ) ) {
757
- if to_t. tgt == TransitionTarget :: Die {
758
- continue ;
759
- }
760
- if from_t. priority > fwd. priority {
761
- continue ;
762
- }
751
+ // now shuffle the transitions from `to` to `from`.
752
+ for ( to_t, from_t) in to_ts. 0 . iter ( ) . zip ( from_ts. 0 . iter_mut ( ) ) {
753
+ if to_t. tgt == TransitionTarget :: Die {
754
+ continue ;
755
+ }
756
+ if from_t. priority > fwd. priority {
757
+ continue ;
758
+ }
763
759
764
- // we should never encounter equal priorities
765
- debug_assert ! ( from_t. priority != fwd. priority) ;
760
+ // we should never encounter equal priorities
761
+ debug_assert ! ( from_t. priority != fwd. priority) ;
766
762
767
- * from_t = Transition {
768
- tgt : tgt. clone ( ) ,
769
- priority : fwd. priority ,
770
- } ;
771
- }
763
+ * from_t = Transition {
764
+ tgt : tgt. clone ( ) ,
765
+ priority : fwd. priority ,
766
+ } ;
767
+ }
772
768
773
- // Finally, if a match instruction is reachable through
774
- // a save fwd (which can never fail), the from state is accepting.
775
- match & self . prog [ fwd. to ] {
776
- & Inst :: Save ( _) => {
777
- self . accepting_states [ fwd. from ] =
778
- self . accepting_states [ fwd. to ] ;
779
- }
780
- _ => { }
769
+ // Finally, if a match instruction is reachable through
770
+ // a save fwd (which can never fail), the from state is accepting.
771
+ match & self . prog [ fwd. to ] {
772
+ & Inst :: Save ( _) => {
773
+ self . accepting_states [ fwd. from ] =
774
+ self . accepting_states [ fwd. to ] ;
781
775
}
776
+ _ => { }
782
777
}
783
-
784
- Ok ( ( ) )
785
778
}
786
779
787
780
/// Once all the per-instruction transition tables have been worked
788
781
/// out, we can bake them into the single flat transition table we
789
782
/// are going to use for the actual DFA. This function creates the
790
783
/// baked form, storing it in `self.table`.
791
- fn emit_transitions ( & mut self ) {
784
+ fn bake_transitions ( & mut self ) {
792
785
// pre-compute the state indices
793
786
let mut state_starts = Vec :: with_capacity ( self . prog . len ( ) ) ;
794
787
let mut off = 0 ;
0 commit comments