1+ use cairo_lang_semantic:: PatternVariable ;
12use itertools:: Itertools ;
23
4+ use crate :: lower:: flow_control:: graph:: {
5+ BindVar , FlowControlGraphBuilder , FlowControlNode , FlowControlVar , NodeId ,
6+ } ;
7+
38/// The pattern-matching function below take a list of patterns, and depending on the item at
49/// question, construct a filtered list of patterns that are relevant to the item.
510/// This struct represents the indices of those filtered patterns.
@@ -17,23 +22,37 @@ use itertools::Itertools;
1722/// For the latter, it is important to return both `0` and `1`, because the arm that will be chosen
1823/// depends on the value of `y` (which will be handled by the calling pattern matching function).
1924#[ derive( Clone , Hash , Eq , PartialEq ) ]
20- pub struct FilteredPatterns {
21- /// The indices of the patterns that are accepted by the filter.
22- filter : Vec < usize > ,
25+ pub struct FilteredPatterns < ' db > {
26+ /// The indices of the patterns that are accepted by the filter, together with binding
27+ /// information.
28+ filter : Vec < IndexAndBindings < ' db > > ,
2329}
2430
25- impl FilteredPatterns {
31+ impl < ' db > FilteredPatterns < ' db > {
2632 pub fn empty ( ) -> Self {
2733 Self { filter : vec ! [ ] }
2834 }
2935
30- pub fn add ( & mut self , idx : usize ) {
31- self . filter . push ( idx) ;
32- }
33-
3436 /// Returns a [FilteredPatterns] that accepts all patterns (no filtering).
3537 pub fn all ( n_patterns : usize ) -> Self {
36- Self { filter : ( 0 ..n_patterns) . collect_vec ( ) }
38+ Self {
39+ filter : ( 0 ..n_patterns)
40+ . map ( |idx| IndexAndBindings { index : idx, bindings : Bindings :: default ( ) } )
41+ . collect_vec ( ) ,
42+ }
43+ }
44+
45+ pub fn all_with_bindings ( bindings_vec : impl Iterator < Item = Bindings < ' db > > ) -> Self {
46+ Self {
47+ filter : bindings_vec
48+ . enumerate ( )
49+ . map ( |( index, bindings) | IndexAndBindings { index, bindings } )
50+ . collect_vec ( ) ,
51+ }
52+ }
53+
54+ pub fn add ( & mut self , idx : usize , bindings : Bindings < ' db > ) {
55+ self . filter . push ( IndexAndBindings { index : idx, bindings } ) ;
3756 }
3857
3958 /// Assuming `self` is a [FilteredPatterns] that applies to a *subset* of a list of patterns
@@ -45,14 +64,67 @@ impl FilteredPatterns {
4564 /// Suppose that `bar` filters this list to only `C`.
4665 /// `bar` returns the filter `[1]` since it uses its own indexing.
4766 /// `foo` needs to lift it to `[2]` to return to its caller using `foo`'s indexing.
48- pub fn lift ( self , outer_filter : & FilteredPatterns ) -> Self {
67+ pub fn lift ( self , outer_filter : & FilteredPatterns < ' db > ) -> Self {
4968 Self {
50- filter : self . filter . into_iter ( ) . map ( |index| outer_filter. filter [ index] ) . collect_vec ( ) ,
69+ filter : self
70+ . filter
71+ . into_iter ( )
72+ . map ( |index_and_bindings| index_and_bindings. lift ( outer_filter) )
73+ . collect_vec ( ) ,
5174 }
5275 }
5376
54- /// Returns the first pattern accepted by the filter.
55- pub fn first ( self ) -> Option < usize > {
77+ /// Returns the first index of the filtered patterns.
78+ // TODO: rename. Fix doc.
79+ pub fn first ( self ) -> Option < IndexAndBindings < ' db > > {
5680 self . filter . into_iter ( ) . next ( )
5781 }
82+
83+ /// Returns an iterator over the indices of the patterns accepted by the filter.
84+ pub fn indices < ' a > ( & ' a self ) -> impl Iterator < Item = usize > + ' a {
85+ self . filter . iter ( ) . map ( |index_and_bindings| index_and_bindings. index )
86+ }
87+ }
88+
89+ #[ derive( Clone , Hash , Eq , PartialEq ) ]
90+ pub struct IndexAndBindings < ' db > {
91+ /// The index of the pattern in the list of patterns.
92+ pub index : usize ,
93+ /// The bindings that should be applied if the pattern is chosen.
94+ bindings : Bindings < ' db > ,
95+ }
96+ impl < ' db > IndexAndBindings < ' db > {
97+ /// Lifts the index of the pattern to the outer level.
98+ /// See [FilteredPatterns::lift] for more details.
99+ fn lift ( self , outer_filter : & FilteredPatterns < ' db > ) -> IndexAndBindings < ' db > {
100+ IndexAndBindings {
101+ index : outer_filter. filter [ self . index ] . index ,
102+ bindings : self . bindings . union ( & outer_filter. filter [ self . index ] . bindings ) ,
103+ }
104+ }
105+
106+ // TODO: doc.
107+ pub fn wrap_node ( self , graph : & mut FlowControlGraphBuilder < ' db > , mut node : NodeId ) -> NodeId {
108+ for ( input, output) in self . bindings . bindings {
109+ node = graph. add_node ( FlowControlNode :: BindVar ( BindVar { input, output, next : node } ) ) ;
110+ }
111+ node
112+ }
113+ }
114+
115+ #[ derive( Clone , Default , Hash , Eq , PartialEq ) ]
116+ pub struct Bindings < ' db > {
117+ /// The bindings that should be applied if the pattern is chosen.
118+ bindings : Vec < ( FlowControlVar , PatternVariable < ' db > ) > ,
119+ }
120+ impl < ' db > Bindings < ' db > {
121+ pub fn single ( input : FlowControlVar , output : PatternVariable < ' db > ) -> Self {
122+ Self { bindings : vec ! [ ( input, output) ] }
123+ }
124+
125+ pub fn union ( & self , bindings : & Self ) -> Self {
126+ Self {
127+ bindings : self . bindings . iter ( ) . chain ( bindings. bindings . iter ( ) ) . cloned ( ) . collect_vec ( ) ,
128+ }
129+ }
58130}
0 commit comments