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}