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