1use super::*;
2
3pub(super) fn match_quote_pattern_expr(
4 pattern: &Expr,
5 target: &Expr,
6 captures: &mut BTreeMap<String, MetaValue>,
7) -> bool {
8 match (pattern, target) {
9 (Expr::Splice(capture), _) => {
10 if let MetaExpr::Ident(name) = capture.as_ref() {
11 let value = MetaValue::Expr {
12 expr: target.clone(),
13 ty: TypeExpr::Named("any".to_owned()),
14 };
15 if let Some(existing) = captures.get(name) {
16 existing == &value
17 } else {
18 captures.insert(name.clone(), value);
19 true
20 }
21 } else {
22 false
23 }
24 }
25 (Expr::Ident { name: left, .. }, Expr::Ident { name: right, .. }) => left == right,
26 (Expr::Int(left), Expr::Int(right)) => left == right,
27 (Expr::Int(left), Expr::Number(right)) => number_literal_to_i64(&right.raw) == Some(*left),
28 (Expr::Number(left), Expr::Int(right)) => number_literal_to_i64(&left.raw) == Some(*right),
29 (Expr::Number(left), Expr::Number(right)) => left == right,
30 (Expr::String(left), Expr::String(right)) => left == right,
31 (Expr::Bool(left), Expr::Bool(right)) => left == right,
32 (Expr::Array { items: left, .. }, Expr::Array { items: right, .. }) => {
33 left.len() == right.len()
34 && left
35 .iter()
36 .zip(right.iter())
37 .all(|(a, b)| match_quote_pattern_expr(a, b, captures))
38 }
39 (Expr::Tuple { items: left, .. }, Expr::Tuple { items: right, .. }) => {
40 left.len() == right.len()
41 && left
42 .iter()
43 .zip(right.iter())
44 .all(|(a, b)| match_quote_pattern_expr(a, b, captures))
45 }
46 (
47 Expr::StructLit {
48 name: left_name,
49 fields: left_fields,
50 ..
51 },
52 Expr::StructLit {
53 name: right_name,
54 fields: right_fields,
55 ..
56 },
57 ) => {
58 left_name == right_name
59 && left_fields.len() == right_fields.len()
60 && left_fields
61 .iter()
62 .zip(right_fields.iter())
63 .all(|(left_field, right_field)| {
64 left_field.name == right_field.name
65 && match_quote_pattern_expr(
66 &left_field.value,
67 &right_field.value,
68 captures,
69 )
70 })
71 }
72 (
73 Expr::Call {
74 callee: left_callee,
75 args: left_args,
76 ..
77 },
78 Expr::Call {
79 callee: right_callee,
80 args: right_args,
81 ..
82 },
83 ) => {
84 left_args.len() == right_args.len()
85 && match_quote_pattern_expr(left_callee, right_callee, captures)
86 && left_args
87 .iter()
88 .zip(right_args.iter())
89 .all(|(a, b)| match_quote_pattern_call_arg(a, b, captures))
90 }
91 (
92 Expr::Field {
93 base: left_base,
94 field: left_field,
95 },
96 Expr::Field {
97 base: right_base,
98 field: right_field,
99 },
100 ) => left_field == right_field && match_quote_pattern_expr(left_base, right_base, captures),
101 (
102 Expr::Index {
103 base: left_base,
104 index: left_index,
105 },
106 Expr::Index {
107 base: right_base,
108 index: right_index,
109 },
110 ) => {
111 match_quote_pattern_expr(left_base, right_base, captures)
112 && match_quote_pattern_expr(left_index, right_index, captures)
113 }
114 (
115 Expr::SliceRange {
116 base: left_base,
117 start: left_start,
118 end: left_end,
119 },
120 Expr::SliceRange {
121 base: right_base,
122 start: right_start,
123 end: right_end,
124 },
125 ) => {
126 match_quote_pattern_expr(left_base, right_base, captures)
127 && match (left_start, right_start) {
128 (Some(a), Some(b)) => match_quote_pattern_expr(a, b, captures),
129 (None, None) => true,
130 _ => false,
131 }
132 && match (left_end, right_end) {
133 (Some(a), Some(b)) => match_quote_pattern_expr(a, b, captures),
134 (None, None) => true,
135 _ => false,
136 }
137 }
138 (
139 Expr::Prefix {
140 op: left_op,
141 value: left_value,
142 },
143 Expr::Prefix {
144 op: right_op,
145 value: right_value,
146 },
147 ) => left_op == right_op && match_quote_pattern_expr(left_value, right_value, captures),
148 (
149 Expr::Binary {
150 op: left_op,
151 lhs: left_lhs,
152 rhs: left_rhs,
153 },
154 Expr::Binary {
155 op: right_op,
156 lhs: right_lhs,
157 rhs: right_rhs,
158 },
159 ) => {
160 left_op == right_op
161 && match_quote_pattern_expr(left_lhs, right_lhs, captures)
162 && match_quote_pattern_expr(left_rhs, right_rhs, captures)
163 }
164 (
165 Expr::Relational {
166 op: left_op,
167 lhs: left_lhs,
168 rhs: left_rhs,
169 },
170 Expr::Relational {
171 op: right_op,
172 lhs: right_lhs,
173 rhs: right_rhs,
174 },
175 ) => {
176 left_op == right_op
177 && match_quote_pattern_expr(left_lhs, right_lhs, captures)
178 && match_quote_pattern_expr(left_rhs, right_rhs, captures)
179 }
180 (Expr::Block(left), Expr::Block(right)) => {
181 left.statements.len() == right.statements.len()
182 && left
183 .statements
184 .iter()
185 .zip(right.statements.iter())
186 .all(|(a, b)| match_stmt_pattern(a, b, captures))
187 }
188 _ => false,
189 }
190}
191
192pub(super) fn number_literal_to_i64(raw: &str) -> Option<i64> {
193 if raw.contains('.')
194 || raw.ends_with("u8")
195 || raw.ends_with("u16")
196 || raw.ends_with("u32")
197 || raw.ends_with("u64")
198 || raw.ends_with("i8")
199 || raw.ends_with("i16")
200 || raw.ends_with("i32")
201 || raw.ends_with("i64")
202 || raw.ends_with("f32")
203 || raw.ends_with("f64")
204 {
205 return None;
206 }
207 let digits: String = raw.chars().filter(|ch| *ch != '_').collect();
208 digits.parse::<i64>().ok()
209}
210
211pub(super) fn match_quote_pattern_call_arg(
212 pattern: &CallArg,
213 target: &CallArg,
214 captures: &mut BTreeMap<String, MetaValue>,
215) -> bool {
216 match (pattern, target) {
217 (CallArg::Expr(pattern), CallArg::Expr(target)) => {
218 match_quote_pattern_expr(pattern, target, captures)
219 }
220 (CallArg::Spread(pattern), CallArg::Spread(target)) => {
221 match_quote_pattern_expr(pattern, target, captures)
222 }
223 (CallArg::Type(left), CallArg::Type(right)) => left == right,
224 _ => false,
225 }
226}
227
228pub(super) fn match_stmt_pattern(
229 pattern: &Stmt,
230 target: &Stmt,
231 captures: &mut BTreeMap<String, MetaValue>,
232) -> bool {
233 match (pattern, target) {
234 (
235 Stmt::Let {
236 name: left_name,
237 name_span: left_span,
238 ownership: left_ownership,
239 mode: left_mode,
240 value: left_value,
241 },
242 Stmt::Let {
243 name: right_name,
244 name_span: right_span,
245 ownership: right_ownership,
246 mode: right_mode,
247 value: right_value,
248 },
249 ) => {
250 left_name == right_name
251 && left_span == right_span
252 && left_ownership == right_ownership
253 && left_mode == right_mode
254 && match_quote_pattern_expr(left_value, right_value, captures)
255 }
256 (
257 Stmt::Assign {
258 target: left_target,
259 mode: left_mode,
260 value: left_value,
261 },
262 Stmt::Assign {
263 target: right_target,
264 mode: right_mode,
265 value: right_value,
266 },
267 ) => {
268 left_target == right_target
269 && left_mode == right_mode
270 && match_quote_pattern_expr(left_value, right_value, captures)
271 }
272 (
273 Stmt::If {
274 condition: left_condition,
275 then_block: left_then,
276 else_block: left_else,
277 },
278 Stmt::If {
279 condition: right_condition,
280 then_block: right_then,
281 else_block: right_else,
282 },
283 ) => {
284 match_quote_pattern_expr(left_condition, right_condition, captures)
285 && match_quote_pattern_expr(
286 &Expr::Block(left_then.clone()),
287 &Expr::Block(right_then.clone()),
288 captures,
289 )
290 && match (left_else, right_else) {
291 (None, None) => true,
292 (Some(left_block), Some(right_block)) => match_quote_pattern_expr(
293 &Expr::Block(left_block.clone()),
294 &Expr::Block(right_block.clone()),
295 captures,
296 ),
297 _ => false,
298 }
299 }
300 (
301 Stmt::For {
302 binding: left_binding,
303 iterable: left_iterable,
304 body: left_body,
305 },
306 Stmt::For {
307 binding: right_binding,
308 iterable: right_iterable,
309 body: right_body,
310 },
311 ) => {
312 left_binding == right_binding
313 && match_quote_pattern_expr(left_iterable, right_iterable, captures)
314 && match_quote_pattern_expr(
315 &Expr::Block(left_body.clone()),
316 &Expr::Block(right_body.clone()),
317 captures,
318 )
319 }
320 (
321 Stmt::While {
322 condition: left_condition,
323 body: left_body,
324 },
325 Stmt::While {
326 condition: right_condition,
327 body: right_body,
328 },
329 ) => {
330 match_quote_pattern_expr(left_condition, right_condition, captures)
331 && match_quote_pattern_expr(
332 &Expr::Block(left_body.clone()),
333 &Expr::Block(right_body.clone()),
334 captures,
335 )
336 }
337 (Stmt::Meta { body: left_body }, Stmt::Meta { body: right_body }) => {
338 left_body == right_body
339 }
340 (
341 Stmt::Expr {
342 expr: left_expr,
343 has_semi: left_has_semi,
344 },
345 Stmt::Expr {
346 expr: right_expr,
347 has_semi: right_has_semi,
348 },
349 ) => {
350 left_has_semi == right_has_semi
351 && match_quote_pattern_expr(left_expr, right_expr, captures)
352 }
353 _ => false,
354 }
355}
356
357pub(super) fn match_quote_pattern_type(pattern: &TypeExpr, target: &TypeExpr) -> bool {
358 match (pattern, target) {
359 (TypeExpr::Named(left), TypeExpr::Tuple(right)) if left == "Unit" && right.is_empty() => {
360 true
361 }
362 (TypeExpr::Tuple(left), TypeExpr::Named(right)) if left.is_empty() && right == "Unit" => {
363 true
364 }
365 _ => crate::meta_types::meta_types_compatible(pattern, target),
366 }
367}
368
369pub(super) fn kind_name(value: &MetaValue) -> &'static str {
370 match value {
371 MetaValue::Int(_) => "int",
372 MetaValue::Bool(_) => "bool",
373 MetaValue::String(_) => "string",
374 MetaValue::Type(_) => "type",
375 MetaValue::Expr { .. } => "expr",
376 MetaValue::Code(_) => "code",
377 }
378}
379
380pub(super) fn meta_value_type_name(value: &MetaValue) -> String {
381 match value {
382 MetaValue::Int(_) => "i64".to_owned(),
383 MetaValue::Bool(_) => "Bool".to_owned(),
384 MetaValue::String(_) => "String".to_owned(),
385 MetaValue::Type(_) => "type".to_owned(),
386 MetaValue::Expr { ty, .. } => format!("Expr[{}]", format_type_expr(ty)),
387 MetaValue::Code(CodeValue::Expr(_)) => "Code[expr]".to_owned(),
388 MetaValue::Code(CodeValue::Type(_)) => "Code[type]".to_owned(),
389 }
390}
391
392pub(super) fn format_meta_type(ty: &MetaType) -> String {
393 match ty {
394 MetaType::Int => "i64".to_owned(),
395 MetaType::Bool => "Bool".to_owned(),
396 MetaType::String => "String".to_owned(),
397 MetaType::Type => "type".to_owned(),
398 MetaType::Expr(item) => format!("Expr[{}]", format_type_expr(item)),
399 }
400}