1use anyhow::{Result, anyhow};
2use dynamic::{Dynamic, Type};
3use smol_str::SmolStr;
4
5use super::{BinaryOp, Parser, Span, expr::Expr, expr::ExprKind};
6
7#[derive(Debug, Clone)]
8pub struct Pattern {
9 pub kind: PatternKind,
10 pub span: Span,
11}
12
13#[derive(Debug, Clone)]
14pub enum PatternKind {
15 Wildcard,
16 Var { idx: u32, ty: Type },
17 Ident { name: SmolStr, ty: Type },
18 Literal(Dynamic),
19 Tuple(Vec<Pattern>),
20 List { elems: Vec<Pattern>, has_rest: bool },
21 Struct { name: SmolStr, fields: Vec<(SmolStr, Option<Pattern>)> },
22 Member(Box<Pattern>, SmolStr),
23 Idx(Box<Pattern>, Expr),
24}
25
26impl Pattern {
27 pub fn new(kind: PatternKind, span: Span) -> Self {
28 Self { kind, span }
29 }
30
31 pub fn var(&self) -> Option<u32> {
32 if let PatternKind::Var { idx, .. } = &self.kind { Some(*idx) } else { None }
33 }
34
35 pub fn expr(&self) -> Result<Expr> {
36 if let PatternKind::Var { idx, .. } = &self.kind { Ok(Expr::new(super::expr::ExprKind::Var(*idx), self.span)) } else { Err(anyhow!("不是变量")) }
37 }
38
39 pub fn match_test(&self, scrut: &Expr) -> Expr {
43 let span = self.span;
44 match &self.kind {
45 PatternKind::Wildcard | PatternKind::Var { .. } | PatternKind::Ident { .. } => Expr::new(ExprKind::Value(Dynamic::Bool(true)), span),
46 PatternKind::Literal(v) => bin(scrut.clone(), BinaryOp::Eq, ExprKind::Value(v.clone()).at(span), span),
47 PatternKind::Tuple(items) => {
48 let mut tests = Vec::new();
49 tests.push(bin(method_call(scrut.clone(), "len", Vec::new(), span), BinaryOp::Eq, ExprKind::Value(Dynamic::I32(items.len() as i32)).at(span), span));
50 for (i, p) in items.iter().enumerate() {
51 let elem = idx_expr(scrut.clone(), i as i32, span);
52 tests.push(p.match_test(&elem));
53 }
54 and_chain(tests, span)
55 }
56 PatternKind::List { elems, has_rest } => {
57 let prefix_len = if *has_rest { elems.len() - 1 } else { elems.len() };
58 let mut tests = Vec::new();
59 tests.push(method_call(scrut.clone(), "is_list", Vec::new(), span));
60 let len_expr = method_call(scrut.clone(), "len", Vec::new(), span);
61 let len_lit = ExprKind::Value(Dynamic::I32(prefix_len as i32)).at(span);
62 let len_op = if *has_rest { BinaryOp::Ge } else { BinaryOp::Eq };
63 tests.push(bin(len_expr, len_op, len_lit, span));
64 for (i, p) in elems.iter().take(prefix_len).enumerate() {
65 let elem = idx_expr(scrut.clone(), i as i32, span);
66 tests.push(p.match_test(&elem));
67 }
68 and_chain(tests, span)
69 }
70 PatternKind::Struct { fields, .. } => {
71 let mut tests = Vec::new();
72 for (name, sub) in fields {
73 let field = field_expr(scrut.clone(), name.clone(), span);
74 if let Some(sub) = sub {
75 tests.push(sub.match_test(&field));
76 }
77 }
79 if tests.is_empty() { ExprKind::Value(Dynamic::Bool(true)).at(span) } else { and_chain(tests, span) }
80 }
81 PatternKind::Member(_, _) | PatternKind::Idx(_, _) => ExprKind::Value(Dynamic::Bool(true)).at(span),
82 }
83 }
84}
85
86fn bin(left: Expr, op: BinaryOp, right: Expr, span: Span) -> Expr {
87 Expr::new(ExprKind::Binary { left: Box::new(left), op, right: Box::new(right) }, span)
88}
89
90fn idx_expr(scrut: Expr, idx: i32, span: Span) -> Expr {
91 bin(scrut, BinaryOp::Idx, ExprKind::Value(Dynamic::I32(idx)).at(span), span)
92}
93
94fn field_expr(scrut: Expr, name: SmolStr, span: Span) -> Expr {
95 bin(scrut, BinaryOp::Idx, ExprKind::Value(Dynamic::String(name)).at(span), span)
96}
97
98fn method_call(obj: Expr, name: &str, args: Vec<Expr>, span: Span) -> Expr {
99 let member = field_expr(obj, SmolStr::from(name), span);
100 Expr::new(ExprKind::Call { obj: Box::new(member), params: args }, span)
101}
102
103fn and_chain(mut parts: Vec<Expr>, span: Span) -> Expr {
104 if parts.is_empty() {
105 return ExprKind::Value(Dynamic::Bool(true)).at(span);
106 }
107 let first = parts.remove(0);
108 parts.into_iter().fold(first, |acc, e| bin(acc, BinaryOp::And, e, span))
109}
110
111trait ExprKindExt {
112 fn at(self, span: Span) -> Expr;
113}
114
115impl ExprKindExt for ExprKind {
116 fn at(self, span: Span) -> Expr {
117 Expr::new(self, span)
118 }
119}
120
121impl Parser {
122 pub fn pattern(&mut self) -> Result<Pattern> {
123 self.whitespace()?;
124 let start = self.current_pos();
125 if self.get()?.is_ascii_digit() || (self.get()? == b'-' && self.ahead().map(|c| c.is_ascii_digit()).unwrap_or(false)) {
127 let negative = if self.get()? == b'-' {
128 self.pos += 1;
129 true
130 } else {
131 false
132 };
133 let mut value = self.number()?;
134 if negative {
135 value = match value {
136 Dynamic::I32(n) => Dynamic::I32(-n),
137 Dynamic::I64(n) => Dynamic::I64(-n),
138 Dynamic::F32(n) => Dynamic::F32(-n),
139 Dynamic::F64(n) => Dynamic::F64(-n),
140 other => return Err(anyhow!("不支持负数模式: {:?}", other)),
141 };
142 }
143 return Ok(Pattern::new(PatternKind::Literal(value), self.span_from(start)));
144 }
145 if self.keyword("_").is_ok() {
146 Ok(Pattern::new(PatternKind::Wildcard, self.span_from(start)))
147 } else if self.keyword("true").is_ok() {
148 Ok(Pattern::new(PatternKind::Literal(Dynamic::Bool(true)), self.span_from(start)))
149 } else if self.keyword("false").is_ok() {
150 Ok(Pattern::new(PatternKind::Literal(Dynamic::Bool(false)), self.span_from(start)))
151 } else if self.keyword("null").is_ok() {
152 Ok(Pattern::new(PatternKind::Literal(Dynamic::Null), self.span_from(start)))
153 } else if self.just("(").is_ok() {
154 self.whitespace()?;
155 if self.take(b')').is_ok() {
156 return Ok(Pattern::new(PatternKind::Tuple(Vec::new()), self.span_from(start)));
157 }
158 let first = self.pattern()?;
159 self.whitespace()?;
160 if self.take(b',').is_ok() {
161 let mut items = vec![first];
162 loop {
163 self.whitespace()?;
164 if self.take(b')').is_ok() {
165 break;
166 }
167 items.push(self.pattern()?);
168 self.whitespace()?;
169 if self.take(b',').is_err() {
170 self.take(b')')?;
171 break;
172 }
173 }
174 Ok(Pattern::new(PatternKind::Tuple(items), self.span_from(start)))
175 } else {
176 self.take(b')')?;
177 Ok(first)
178 }
179 } else if self.just("[").is_ok() {
180 let mut elems = Vec::new();
182 let mut has_rest = false;
183 self.whitespace()?;
184 if self.take(b']').is_ok() {
185 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
186 }
187 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
189 self.whitespace()?;
190 let (name, ty) = self.ident_typed()?;
191 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
192 has_rest = true;
193 self.whitespace()?;
194 self.take(b']')?;
195 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
196 }
197 elems.push(self.pattern()?);
198 self.whitespace()?;
199 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
200 self.whitespace()?;
201 let (name, ty) = self.ident_typed()?;
202 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
203 has_rest = true;
204 self.whitespace()?;
205 let _ = self.take(b','); self.whitespace()?;
207 self.take(b']')?;
208 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
209 } else if self.take(b',').is_ok() {
210 loop {
211 self.whitespace()?;
212 if self.take(b']').is_ok() {
213 break;
214 }
215 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
216 self.whitespace()?;
217 let (name, ty) = self.ident_typed()?;
218 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
219 has_rest = true;
220 self.whitespace()?;
221 self.take(b']')?;
222 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
223 }
224 elems.push(self.pattern()?);
225 self.whitespace()?;
226 if !self.take(b',').is_ok() {
227 break;
228 }
229 }
230 }
231 self.whitespace()?;
232 self.take(b']')?;
233 Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)))
234 } else if let Ok(text) = self.string() {
235 Ok(Pattern::new(PatternKind::Literal(Dynamic::String(text)), self.span_from(start)))
236 } else if let Ok((name, ty)) = self.ident_typed() {
237 self.whitespace()?;
239 if matches!(self.get(), Ok(b'{')) {
240 self.pos += 1;
241 let mut fields: Vec<(SmolStr, Option<Pattern>)> = Vec::new();
242 self.whitespace()?;
243 if self.take(b'}').is_err() {
244 loop {
245 self.whitespace()?;
246 let field_name = self.ident()?;
247 self.whitespace()?;
248 let sub = if self.take(b':').is_ok() { Some(self.pattern()?) } else { None };
249 fields.push((field_name, sub));
250 self.whitespace()?;
251 if !self.take(b',').is_ok() {
252 break;
253 }
254 }
255 self.whitespace()?;
256 self.take(b'}')?;
257 }
258 return Ok(Pattern::new(PatternKind::Struct { name, fields }, self.span_from(start)));
259 }
260 Ok(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)))
261 } else {
262 Err(anyhow!("无效的模式 {:?}", String::from_utf8_lossy(&self.buf[self.pos..])))
263 }
264 }
265}