graphix_compiler/expr/
pattern.rs

1use std::fmt;
2
3use anyhow::Result;
4use arcstr::ArcStr;
5use netidx_value::{Typ, Value};
6use smallvec::{smallvec, SmallVec};
7use triomphe::Arc;
8
9use crate::{env::Env, typ::Type, Rt, UserEvent};
10
11use super::Expr;
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
14pub enum StructurePattern {
15    Ignore,
16    Literal(Value),
17    Bind(ArcStr),
18    Slice {
19        all: Option<ArcStr>,
20        binds: Arc<[StructurePattern]>,
21    },
22    SlicePrefix {
23        all: Option<ArcStr>,
24        prefix: Arc<[StructurePattern]>,
25        tail: Option<ArcStr>,
26    },
27    SliceSuffix {
28        all: Option<ArcStr>,
29        head: Option<ArcStr>,
30        suffix: Arc<[StructurePattern]>,
31    },
32    Tuple {
33        all: Option<ArcStr>,
34        binds: Arc<[StructurePattern]>,
35    },
36    Variant {
37        all: Option<ArcStr>,
38        tag: ArcStr,
39        binds: Arc<[StructurePattern]>,
40    },
41    Struct {
42        exhaustive: bool,
43        all: Option<ArcStr>,
44        binds: Arc<[(ArcStr, StructurePattern)]>,
45    },
46}
47
48impl StructurePattern {
49    pub fn single_bind(&self) -> Option<&ArcStr> {
50        match self {
51            Self::Bind(s) => Some(s),
52            Self::Ignore
53            | Self::Literal(_)
54            | Self::Slice { .. }
55            | Self::SlicePrefix { .. }
56            | Self::SliceSuffix { .. }
57            | Self::Tuple { .. }
58            | Self::Struct { .. }
59            | Self::Variant { .. } => None,
60        }
61    }
62
63    pub fn with_names<'a>(&'a self, f: &mut impl FnMut(&'a ArcStr)) {
64        match self {
65            Self::Bind(n) => f(n),
66            Self::Ignore | Self::Literal(_) => (),
67            Self::Slice { all, binds } => {
68                if let Some(n) = all {
69                    f(n)
70                }
71                for t in binds.iter() {
72                    t.with_names(f)
73                }
74            }
75            Self::SlicePrefix { all, prefix, tail } => {
76                if let Some(n) = all {
77                    f(n)
78                }
79                if let Some(n) = tail {
80                    f(n)
81                }
82                for t in prefix.iter() {
83                    t.with_names(f)
84                }
85            }
86            Self::SliceSuffix { all, head, suffix } => {
87                if let Some(n) = all {
88                    f(n)
89                }
90                if let Some(n) = head {
91                    f(n)
92                }
93                for t in suffix.iter() {
94                    t.with_names(f)
95                }
96            }
97            Self::Tuple { all, binds } => {
98                if let Some(n) = all {
99                    f(n)
100                }
101                for t in binds.iter() {
102                    t.with_names(f)
103                }
104            }
105            Self::Variant { all, tag: _, binds } => {
106                if let Some(n) = all {
107                    f(n)
108                }
109                for t in binds.iter() {
110                    t.with_names(f)
111                }
112            }
113            Self::Struct { exhaustive: _, all, binds } => {
114                if let Some(n) = all {
115                    f(n)
116                }
117                for (_, t) in binds.iter() {
118                    t.with_names(f)
119                }
120            }
121        }
122    }
123
124    pub fn binds_uniq(&self) -> bool {
125        let mut names: SmallVec<[&ArcStr; 16]> = smallvec![];
126        self.with_names(&mut |s| names.push(s));
127        names.sort();
128        let len = names.len();
129        names.dedup();
130        names.len() == len
131    }
132
133    pub fn infer_type_predicate<R: Rt, E: UserEvent>(
134        &self,
135        env: &Env<R, E>,
136    ) -> Result<Type> {
137        match self {
138            Self::Bind(_) | Self::Ignore => Ok(Type::empty_tvar()),
139            Self::Literal(v) => Ok(Type::Primitive(Typ::get(v).into())),
140            Self::Tuple { all: _, binds } => {
141                let a = binds
142                    .iter()
143                    .map(|p| p.infer_type_predicate(env))
144                    .collect::<Result<SmallVec<[_; 8]>>>()?;
145                Ok(Type::Tuple(Arc::from_iter(a)))
146            }
147            Self::Variant { all: _, tag, binds } => {
148                let a = binds
149                    .iter()
150                    .map(|p| p.infer_type_predicate(env))
151                    .collect::<Result<SmallVec<[_; 8]>>>()?;
152                Ok(Type::Variant(tag.clone(), Arc::from_iter(a)))
153            }
154            Self::Slice { all: _, binds }
155            | Self::SlicePrefix { all: _, prefix: binds, tail: _ }
156            | Self::SliceSuffix { all: _, head: _, suffix: binds } => {
157                let t =
158                    binds.iter().fold(Ok::<_, anyhow::Error>(Type::Bottom), |t, p| {
159                        Ok(t?.union(env, &p.infer_type_predicate(env)?)?)
160                    })?;
161                Ok(Type::Array(Arc::new(t)))
162            }
163            Self::Struct { all: _, exhaustive: _, binds } => {
164                let mut typs = binds
165                    .iter()
166                    .map(|(n, p)| Ok((n.clone(), p.infer_type_predicate(env)?)))
167                    .collect::<Result<SmallVec<[(ArcStr, Type); 8]>>>()?;
168                typs.sort_by_key(|(n, _)| n.clone());
169                Ok(Type::Struct(Arc::from_iter(typs.into_iter())))
170            }
171        }
172    }
173}
174
175impl fmt::Display for StructurePattern {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        macro_rules! with_sep {
178            ($binds:expr) => {
179                for (i, b) in $binds.iter().enumerate() {
180                    write!(f, "{b}")?;
181                    if i < $binds.len() - 1 {
182                        write!(f, ", ")?
183                    }
184                }
185            };
186        }
187        match self {
188            StructurePattern::Ignore => write!(f, "_"),
189            StructurePattern::Literal(v) => write!(f, "{v}"),
190            StructurePattern::Bind(n) => write!(f, "{n}"),
191            StructurePattern::Slice { all, binds } => {
192                if let Some(all) = all {
193                    write!(f, "{all}@ ")?
194                }
195                write!(f, "[")?;
196                with_sep!(binds);
197                write!(f, "]")
198            }
199            StructurePattern::SlicePrefix { all, prefix, tail } => {
200                if let Some(all) = all {
201                    write!(f, "{all}@ ")?
202                }
203                write!(f, "[")?;
204                for b in prefix.iter() {
205                    write!(f, "{b}, ")?
206                }
207                match tail {
208                    None => write!(f, "..]"),
209                    Some(name) => write!(f, "{name}..]"),
210                }
211            }
212            StructurePattern::SliceSuffix { all, head, suffix } => {
213                if let Some(all) = all {
214                    write!(f, "{all}@ ")?
215                }
216                write!(f, "[")?;
217                match head {
218                    None => write!(f, ".., ")?,
219                    Some(name) => write!(f, "{name}.., ")?,
220                }
221                with_sep!(suffix);
222                write!(f, "]")
223            }
224            StructurePattern::Tuple { all, binds } => {
225                if let Some(all) = all {
226                    write!(f, "{all}@ ")?
227                }
228                write!(f, "(")?;
229                with_sep!(binds);
230                write!(f, ")")
231            }
232            StructurePattern::Variant { all, tag, binds } if binds.len() == 0 => {
233                if let Some(all) = all {
234                    write!(f, "{all}@")?
235                }
236                write!(f, "`{tag}")
237            }
238            StructurePattern::Variant { all, tag, binds } => {
239                if let Some(all) = all {
240                    write!(f, "{all}@")?
241                }
242                write!(f, "`{tag}(")?;
243                with_sep!(binds);
244                write!(f, ")")
245            }
246            StructurePattern::Struct { exhaustive, all, binds } => {
247                if let Some(all) = all {
248                    write!(f, "{all}@ ")?
249                }
250                write!(f, "{{")?;
251                for (i, (name, pat)) in binds.iter().enumerate() {
252                    write!(f, "{name}: {pat}")?;
253                    if !exhaustive || i < binds.len() - 1 {
254                        write!(f, ", ")?
255                    }
256                }
257                if !exhaustive {
258                    write!(f, "..")?
259                }
260                write!(f, "}}")
261            }
262        }
263    }
264}
265
266#[derive(Debug, Clone, PartialEq, PartialOrd)]
267pub struct Pattern {
268    pub type_predicate: Option<Type>,
269    pub structure_predicate: StructurePattern,
270    pub guard: Option<Expr>,
271}