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 Ok(Pattern::new(PatternKind::Tuple(crate::parse_list!(self, Vec::new(), b')', b',', self.pattern()?)), self.span_from(start)))
155 } else if self.just("[").is_ok() {
156 let mut elems = Vec::new();
158 let mut has_rest = false;
159 self.whitespace()?;
160 if self.take(b']').is_ok() {
161 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
162 }
163 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
165 self.whitespace()?;
166 let (name, ty) = self.ident_typed()?;
167 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
168 has_rest = true;
169 self.whitespace()?;
170 self.take(b']')?;
171 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
172 }
173 elems.push(self.pattern()?);
174 self.whitespace()?;
175 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
176 self.whitespace()?;
177 let (name, ty) = self.ident_typed()?;
178 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
179 has_rest = true;
180 self.whitespace()?;
181 let _ = self.take(b','); self.whitespace()?;
183 self.take(b']')?;
184 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
185 } else if self.take(b',').is_ok() {
186 loop {
187 self.whitespace()?;
188 if self.take(b']').is_ok() {
189 break;
190 }
191 if self.take(b'.').is_ok() && self.take(b'.').is_ok() {
192 self.whitespace()?;
193 let (name, ty) = self.ident_typed()?;
194 elems.push(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)));
195 has_rest = true;
196 self.whitespace()?;
197 self.take(b']')?;
198 return Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)));
199 }
200 elems.push(self.pattern()?);
201 self.whitespace()?;
202 if !self.take(b',').is_ok() {
203 break;
204 }
205 }
206 }
207 self.whitespace()?;
208 self.take(b']')?;
209 Ok(Pattern::new(PatternKind::List { elems, has_rest }, self.span_from(start)))
210 } else if let Ok(text) = self.string() {
211 Ok(Pattern::new(PatternKind::Literal(Dynamic::String(text)), self.span_from(start)))
212 } else if let Ok((name, ty)) = self.ident_typed() {
213 self.whitespace()?;
215 if matches!(self.get(), Ok(b'{')) {
216 self.pos += 1;
217 let mut fields: Vec<(SmolStr, Option<Pattern>)> = Vec::new();
218 self.whitespace()?;
219 if self.take(b'}').is_err() {
220 loop {
221 self.whitespace()?;
222 let field_name = self.ident()?;
223 self.whitespace()?;
224 let sub = if self.take(b':').is_ok() { Some(self.pattern()?) } else { None };
225 fields.push((field_name, sub));
226 self.whitespace()?;
227 if !self.take(b',').is_ok() {
228 break;
229 }
230 }
231 self.whitespace()?;
232 self.take(b'}')?;
233 }
234 return Ok(Pattern::new(PatternKind::Struct { name, fields }, self.span_from(start)));
235 }
236 Ok(Pattern::new(PatternKind::Ident { name, ty }, self.span_from(start)))
237 } else {
238 Err(anyhow!("无效的模式 {:?}", String::from_utf8_lossy(&self.buf[self.pos..])))
239 }
240 }
241}