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