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 {
138 Dynamic::I8(n) => Dynamic::I8(n.wrapping_neg()),
139 Dynamic::I16(n) => Dynamic::I16(n.wrapping_neg()),
140 Dynamic::I32(n) => Dynamic::I32(-n),
141 Dynamic::I64(n) => Dynamic::I64(-n),
142 Dynamic::F16(n) => Dynamic::F16(dynamic::f64_to_f16(-dynamic::f16_to_f64(n))),
143 Dynamic::F32(n) => Dynamic::F32(-n),
144 Dynamic::F64(n) => Dynamic::F64(-n),
145 other => return Err(anyhow!("不支持负数模式: {:?}", other)),
146 };
147 }
148 return Ok(Pattern::new(PatternKind::Literal(value), self.span_from(start)));
149 }
150 if self.keyword("_").is_ok() {
151 Ok(Pattern::new(PatternKind::Wildcard, self.span_from(start)))
152 } else if self.keyword("true").is_ok() {
153 Ok(Pattern::new(PatternKind::Literal(Dynamic::Bool(true)), self.span_from(start)))
154 } else if self.keyword("false").is_ok() {
155 Ok(Pattern::new(PatternKind::Literal(Dynamic::Bool(false)), self.span_from(start)))
156 } else if self.keyword("null").is_ok() {
157 Ok(Pattern::new(PatternKind::Literal(Dynamic::Null), self.span_from(start)))
158 } else if self.just("(").is_ok() {
159 self.whitespace()?;
160 if self.take(b')').is_ok() {
161 return Ok(Pattern::new(PatternKind::Tuple(Vec::new()), self.span_from(start)));
162 }
163 let first = self.pattern()?;
164 self.whitespace()?;
165 if self.take(b',').is_ok() {
166 let mut items = vec![first];
167 loop {
168 self.whitespace()?;
169 if self.take(b')').is_ok() {
170 break;
171 }
172 items.push(self.pattern()?);
173 self.whitespace()?;
174 if self.take(b',').is_err() {
175 self.take(b')')?;
176 break;
177 }
178 }
179 Ok(Pattern::new(PatternKind::Tuple(items), self.span_from(start)))
180 } else {
181 self.take(b')')?;
182 Ok(first)
183 }
184 } else if self.just("[").is_ok() {
185 let mut elems = Vec::new();
187 let mut has_rest = false;
188 self.whitespace()?;
189 if self.take(b']').is_ok() {
190 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
191 }
192 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
194 self.whitespace()?;
195 let (name, ty) = self.ident_typed()?;
196 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
197 has_rest = true;
198 self.whitespace()?;
199 self.take(b']')?;
200 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
201 }
202 elems.push(self.pattern()?);
203 self.whitespace()?;
204 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
205 self.whitespace()?;
206 let (name, ty) = self.ident_typed()?;
207 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
208 has_rest = true;
209 self.whitespace()?;
210 let _ = self.take(b','); self.whitespace()?;
212 self.take(b']')?;
213 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
214 } else if self.take(b',').is_ok() {
215 loop {
216 self.whitespace()?;
217 if self.take(b']').is_ok() {
218 break;
219 }
220 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
221 self.whitespace()?;
222 let (name, ty) = self.ident_typed()?;
223 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
224 has_rest = true;
225 self.whitespace()?;
226 self.take(b']')?;
227 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
228 }
229 elems.push(self.pattern()?);
230 self.whitespace()?;
231 if !self.take(b',').is_ok() {
232 break;
233 }
234 }
235 }
236 self.whitespace()?;
237 self.take(b']')?;
238 Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)))
239 } else if let Ok(text) = self.string() {
240 Ok(Pattern::new(PatternKind::Literal(Dynamic::String(text)), self.span_from(start)))
241 } else if let Ok((name, ty)) = self.ident_typed() {
242 self.whitespace()?;
244 if matches!(self.get(), Ok(b'{')) {
245 self.pos += 1;
246 let mut fields: Vec<(SmolStr, Option<Pattern>)> = Vec::new();
247 self.whitespace()?;
248 if self.take(b'}').is_err() {
249 loop {
250 self.whitespace()?;
251 let field_name = self.ident()?;
252 self.whitespace()?;
253 let sub = if self.take(b':').is_ok() { Some(self.pattern()?) } else { None };
254 fields.push((field_name, sub));
255 self.whitespace()?;
256 if !self.take(b',').is_ok() {
257 break;
258 }
259 }
260 self.whitespace()?;
261 self.take(b'}')?;
262 }
263 return Ok(Pattern::new(PatternKind::Struct { name, fields }, self.span_from(start)));
264 }
265 Ok(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)))
266 } else {
267 Err(anyhow!("无效的模式 {:?}", String::from_utf8_lossy(&self.buf[self.pos..])))
268 }
269 }
270}