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::Ignore => Ok(Type::Any),
139            Self::Bind(_) => Ok(Type::empty_tvar()),
140            Self::Literal(v) => Ok(Type::Primitive(Typ::get(v).into())),
141            Self::Tuple { all: _, binds } => {
142                let a = binds
143                    .iter()
144                    .map(|p| p.infer_type_predicate(env))
145                    .collect::<Result<SmallVec<[_; 8]>>>()?;
146                Ok(Type::Tuple(Arc::from_iter(a)))
147            }
148            Self::Variant { all: _, tag, binds } => {
149                let a = binds
150                    .iter()
151                    .map(|p| p.infer_type_predicate(env))
152                    .collect::<Result<SmallVec<[_; 8]>>>()?;
153                Ok(Type::Variant(tag.clone(), Arc::from_iter(a)))
154            }
155            Self::Slice { all: _, binds }
156            | Self::SlicePrefix { all: _, prefix: binds, tail: _ }
157            | Self::SliceSuffix { all: _, head: _, suffix: binds } => {
158                let t =
159                    binds.iter().fold(Ok::<_, anyhow::Error>(Type::Bottom), |t, p| {
160                        Ok(t?.union(env, &p.infer_type_predicate(env)?)?)
161                    })?;
162                Ok(Type::Array(Arc::new(t)))
163            }
164            Self::Struct { all: _, exhaustive: _, binds } => {
165                let mut typs = binds
166                    .iter()
167                    .map(|(n, p)| Ok((n.clone(), p.infer_type_predicate(env)?)))
168                    .collect::<Result<SmallVec<[(ArcStr, Type); 8]>>>()?;
169                typs.sort_by_key(|(n, _)| n.clone());
170                Ok(Type::Struct(Arc::from_iter(typs.into_iter())))
171            }
172        }
173    }
174}
175
176impl fmt::Display for StructurePattern {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        macro_rules! with_sep {
179            ($binds:expr) => {
180                for (i, b) in $binds.iter().enumerate() {
181                    write!(f, "{b}")?;
182                    if i < $binds.len() - 1 {
183                        write!(f, ", ")?
184                    }
185                }
186            };
187        }
188        match self {
189            StructurePattern::Ignore => write!(f, "_"),
190            StructurePattern::Literal(v) => write!(f, "{v}"),
191            StructurePattern::Bind(n) => write!(f, "{n}"),
192            StructurePattern::Slice { all, binds } => {
193                if let Some(all) = all {
194                    write!(f, "{all}@ ")?
195                }
196                write!(f, "[")?;
197                with_sep!(binds);
198                write!(f, "]")
199            }
200            StructurePattern::SlicePrefix { all, prefix, tail } => {
201                if let Some(all) = all {
202                    write!(f, "{all}@ ")?
203                }
204                write!(f, "[")?;
205                for b in prefix.iter() {
206                    write!(f, "{b}, ")?
207                }
208                match tail {
209                    None => write!(f, "..]"),
210                    Some(name) => write!(f, "{name}..]"),
211                }
212            }
213            StructurePattern::SliceSuffix { all, head, suffix } => {
214                if let Some(all) = all {
215                    write!(f, "{all}@ ")?
216                }
217                write!(f, "[")?;
218                match head {
219                    None => write!(f, ".., ")?,
220                    Some(name) => write!(f, "{name}.., ")?,
221                }
222                with_sep!(suffix);
223                write!(f, "]")
224            }
225            StructurePattern::Tuple { all, binds } => {
226                if let Some(all) = all {
227                    write!(f, "{all}@ ")?
228                }
229                write!(f, "(")?;
230                with_sep!(binds);
231                write!(f, ")")
232            }
233            StructurePattern::Variant { all, tag, binds } if binds.len() == 0 => {
234                if let Some(all) = all {
235                    write!(f, "{all}@")?
236                }
237                write!(f, "`{tag}")
238            }
239            StructurePattern::Variant { all, tag, binds } => {
240                if let Some(all) = all {
241                    write!(f, "{all}@")?
242                }
243                write!(f, "`{tag}(")?;
244                with_sep!(binds);
245                write!(f, ")")
246            }
247            StructurePattern::Struct { exhaustive, all, binds } => {
248                if let Some(all) = all {
249                    write!(f, "{all}@ ")?
250                }
251                write!(f, "{{")?;
252                for (i, (name, pat)) in binds.iter().enumerate() {
253                    write!(f, "{name}: {pat}")?;
254                    if !exhaustive || i < binds.len() - 1 {
255                        write!(f, ", ")?
256                    }
257                }
258                if !exhaustive {
259                    write!(f, "..")?
260                }
261                write!(f, "}}")
262            }
263        }
264    }
265}
266
267#[derive(Debug, Clone, PartialEq, PartialOrd)]
268pub struct Pattern {
269    pub type_predicate: Option<Type>,
270    pub structure_predicate: StructurePattern,
271    pub guard: Option<Expr>,
272}