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}