Skip to content

Commit f26f039

Browse files
committed
WIP:
commit-id:8cdbe243
1 parent 4137c15 commit f26f039

File tree

8 files changed

+964
-119
lines changed

8 files changed

+964
-119
lines changed

crates/cairo-lang-lowering/src/lower/flow_control/create_graph.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use cairo_lang_semantic::{self as semantic, Condition, PatternId};
22
use cairo_lang_syntax::node::TypedStablePtr;
3+
use filtered_patterns::IndexAndBindings;
34
use itertools::Itertools;
4-
use patterns::{create_node_for_patterns, get_pattern};
5+
use patterns::{Cache, create_node_for_patterns, get_pattern};
56

67
use super::graph::{
78
ArmExpr, BooleanIf, EvaluateExpr, FlowControlGraph, FlowControlGraphBuilder, FlowControlNode,
@@ -61,13 +62,25 @@ pub fn create_graph_expr_if<'db>(
6162
let expr_location = ctx.get_location(expr.stable_ptr().untyped());
6263
let expr_var = graph.new_var(expr.ty(), expr_location);
6364

65+
let cache = Cache::default();
66+
6467
let match_node_id = create_node_for_patterns(
6568
ctx,
6669
&mut graph,
6770
expr_var,
6871
&patterns.iter().map(|pattern| Some(get_pattern(ctx, *pattern))).collect_vec(),
69-
&|_graph, pattern_indices| {
70-
if pattern_indices.first().is_some() { current_node } else { false_branch }
72+
&|graph, pattern_indices| {
73+
if let Some(index_and_bindings) = pattern_indices.first() {
74+
cache.get_or_compute(
75+
&|graph, index_and_bindings: IndexAndBindings| {
76+
index_and_bindings.wrap_node(graph, current_node)
77+
},
78+
graph,
79+
index_and_bindings,
80+
)
81+
} else {
82+
false_branch
83+
}
7184
},
7285
expr_location,
7386
);
@@ -110,6 +123,8 @@ pub fn create_graph_expr_match<'db>(
110123
})
111124
.collect();
112125

126+
let cache = Cache::default();
127+
113128
// TODO(lior): add diagnostics if there is an unreachable arm.
114129
let match_node_id = create_node_for_patterns(
115130
ctx,
@@ -119,10 +134,17 @@ pub fn create_graph_expr_match<'db>(
119134
.iter()
120135
.map(|(pattern, _)| Some(get_pattern(ctx, *pattern)))
121136
.collect_vec(),
122-
&|_graph, pattern_indices| {
137+
&|graph, pattern_indices| {
123138
// TODO(lior): add diagnostics if pattern_indices is empty (instead of `unwrap`).
124-
let index = pattern_indices.first().unwrap();
125-
pattern_and_nodes[index].1
139+
let index_and_bindings = pattern_indices.first().unwrap();
140+
cache.get_or_compute(
141+
&|graph, index_and_bindings: IndexAndBindings| {
142+
let index = index_and_bindings.index;
143+
index_and_bindings.wrap_node(graph, pattern_and_nodes[index].1)
144+
},
145+
graph,
146+
index_and_bindings,
147+
)
126148
},
127149
matched_expr_location,
128150
);

crates/cairo-lang-lowering/src/lower/flow_control/create_graph/filtered_patterns.rs

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
use cairo_lang_semantic::PatternVariable;
12
use 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

Comments
 (0)