@@ -478,11 +478,6 @@ pub struct OnePassCompiler {
478478 /// A mapping from instruction indices to flags indicating
479479 /// if they should have the STATE_MATCH flag set.
480480 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 ,
486481}
487482
488483#[ derive( Debug ) ]
@@ -568,27 +563,33 @@ impl OnePassCompiler {
568563 x
569564 } ,
570565 accepting_states : vec ! [ false ; prog. len( ) ] ,
571- forwards : Forwards :: new ( ) ,
572566 prog : prog,
573567 } )
574568 }
575569
576570 /// Attempt to compile the regex to a OnePass DFA
577571 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+
578577 // Compute the prioritized transition tables for all of the
579578 // instructions which get states.
580579 let mut state_edge = vec ! [ 0 ] ;
581580 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 ) ) ) ;
583582 }
584583
585584 // Solve the dependency relationships between all the
586585 // 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+ }
588589
589590 // Now emit the transitions in a form that we can actually
590591 // execute.
591- self . emit_transitions ( ) ;
592+ self . bake_transitions ( ) ;
592593
593594 Ok ( OnePass {
594595 table : self . table ,
@@ -611,7 +612,8 @@ impl OnePassCompiler {
611612 /// via `inst_trans`.
612613 fn inst_trans (
613614 & mut self ,
614- inst_idx : usize
615+ inst_idx : usize ,
616+ forwards : & mut Forwards ,
615617 ) -> Result < Vec < usize > , OnePassError > {
616618 trace ! ( "::inst_trans inst_idx={}" , inst_idx) ;
617619
@@ -642,7 +644,7 @@ impl OnePassCompiler {
642644 while let Some ( child_idx) = resume. pop ( ) {
643645 match & self . prog [ child_idx] {
644646 & Inst :: EmptyLook ( _) | & Inst :: Save ( _) => {
645- self . forwards . forward ( inst_idx, child_idx, priority) ;
647+ forwards. forward ( inst_idx, child_idx, priority) ;
646648 children. push ( child_idx) ;
647649 }
648650 & Inst :: Bytes ( ref inst) => {
@@ -685,10 +687,7 @@ impl OnePassCompiler {
685687 Ok ( children)
686688 }
687689
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.
692691 ///
693692 /// To make that a little more concrete, consider the program snippet:
694693 ///
@@ -724,71 +723,65 @@ impl OnePassCompiler {
724723 /// The arrow flows in a funny direction because we want the jobs
725724 /// with no dependencies to live at the roots of the DAG so that
726725 /// 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) ;
732728
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+ } ;
747734
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+ } ;
754750
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+ }
763759
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) ;
766762
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+ }
772768
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 ] ;
781775 }
776+ _ => { }
782777 }
783-
784- Ok ( ( ) )
785778 }
786779
787780 /// Once all the per-instruction transition tables have been worked
788781 /// out, we can bake them into the single flat transition table we
789782 /// are going to use for the actual DFA. This function creates the
790783 /// baked form, storing it in `self.table`.
791- fn emit_transitions ( & mut self ) {
784+ fn bake_transitions ( & mut self ) {
792785 // pre-compute the state indices
793786 let mut state_starts = Vec :: with_capacity ( self . prog . len ( ) ) ;
794787 let mut off = 0 ;
@@ -897,9 +890,6 @@ enum TransitionTarget {
897890
898891
899892/// A (hopefully) DAG of forwarding jobs.
900- ///
901- /// TODO(ethan):yakshaving there are more clones than I am comfortable
902- /// with here.
903893#[ derive( Debug , Clone ) ]
904894struct Forwards {
905895 jobs : Vec < Forward > ,
0 commit comments