1use crate::symbol::*;
12use crate::{concrete::expr::*, concrete::Book};
13
14use super::pat::{Pat, PatIdent, PatKind};
15use super::TopLevel;
16use super::{Argument, Attribute, AttributeStyle, Constructor, Entry, Module, Rule};
17
18#[macro_export]
19macro_rules! visit_vec {
20 ($args:expr, $pat:pat => $fun:expr) => {
21 for $pat in $args {
22 $fun
23 }
24 };
25}
26
27#[macro_export]
28macro_rules! visit_opt {
29 ($args:expr, $pat:pat => $fun:expr) => {
30 match $args {
31 Some($pat) => $fun,
32 None => (),
33 }
34 };
35}
36
37use kind_span::{Range, SyntaxCtxIndex};
38
39pub(crate) use visit_opt;
40pub(crate) use visit_vec;
41
42pub trait Visitor: Sized {
43 fn visit_range(&mut self, x: &mut Range) {
44 walk_range(self, x);
45 }
46
47 fn visit_attr_style(&mut self, attr: &mut AttributeStyle) {
48 walk_attr_style(self, attr);
49 }
50
51 fn visit_attr(&mut self, attr: &mut Attribute) {
52 walk_attr(self, attr);
53 }
54
55 fn visit_syntax_ctx(&mut self, synt: &mut SyntaxCtxIndex) {
56 walk_syntax_ctx(self, synt);
57 }
58
59 fn visit_literal(&mut self, range: Range, lit: &mut Literal) {
60 walk_literal(self, range, lit);
61 }
62
63 fn visit_pat_ident(&mut self, ident: &mut PatIdent) {
64 walk_pat_ident(self, ident);
65 }
66
67 fn visit_qualified_ident(&mut self, ident: &mut QualifiedIdent) {
68 walk_qualified_ident(self, ident);
69 }
70
71 fn visit_ident(&mut self, ident: &mut Ident) {
72 walk_ident(self, ident);
73 }
74
75 fn visit_app_binding(&mut self, ident: &mut AppBinding) {
76 walk_app_binding(self, ident);
77 }
78
79 fn visit_destruct(&mut self, ident: &mut Destruct) {
80 walk_destruct(self, ident);
81 }
82
83 fn visit_match(&mut self, matcher: &mut Match) {
84 walk_match(self, matcher);
85 }
86
87 fn visit_constructor(&mut self, construtor: &mut Constructor) {
88 walk_constructor(self, construtor);
89 }
90
91 fn visit_argument(&mut self, argument: &mut Argument) {
92 walk_argument(self, argument);
93 }
94
95 fn visit_book(&mut self, book: &mut Book) {
96 walk_book(self, book)
97 }
98
99 fn visit_entry(&mut self, entry: &mut Entry) {
100 walk_entry(self, entry);
101 }
102
103 fn visit_pat(&mut self, pat: &mut Pat) {
104 walk_pat(self, pat);
105 }
106
107 fn visit_binding(&mut self, binding: &mut Binding) {
108 walk_binding(self, binding);
109 }
110
111 fn visit_top_level(&mut self, toplevel: &mut TopLevel) {
112 walk_top_level(self, toplevel)
113 }
114
115 fn visit_rule(&mut self, rule: &mut Rule) {
116 walk_rule(self, rule);
117 }
118
119 fn visit_module(&mut self, module: &mut Module) {
120 walk_module(self, module);
121 }
122
123 fn visit_substitution(&mut self, subst: &mut Substitution) {
124 walk_substitution(self, subst);
125 }
126
127 fn visit_case_binding(&mut self, case_binding: &mut CaseBinding) {
128 walk_case_binding(self, case_binding);
129 }
130
131 fn visit_case(&mut self, case: &mut Case) {
132 walk_case(self, case);
133 }
134
135 fn visit_sttm(&mut self, sttm: &mut Sttm) {
136 walk_sttm(self, sttm);
137 }
138
139 fn visit_expr(&mut self, expr: &mut Expr) {
140 walk_expr(self, expr);
141 }
142}
143
144pub fn walk_range<T: Visitor>(_: &mut T, _: &mut Range) {}
145
146pub fn walk_syntax_ctx<T: Visitor>(_: &mut T, _: &mut SyntaxCtxIndex) {}
147
148pub fn walk_literal<T: Visitor>( _: &mut T, _: Range, _: &mut Literal) {}
149
150pub fn walk_constructor<T: Visitor>(ctx: &mut T, cons: &mut Constructor) {
151 ctx.visit_ident(&mut cons.name);
152 visit_vec!(cons.args.get_vec(), arg => ctx.visit_argument(arg));
153 visit_opt!(&mut cons.typ, arg => ctx.visit_expr(arg))
154}
155
156pub fn walk_book<T: Visitor>(ctx: &mut T, book: &mut Book) {
157 visit_vec!(&mut book.entries, (_, arg) => ctx.visit_top_level(arg));
158}
159
160pub fn walk_pat_ident<T: Visitor>(ctx: &mut T, ident: &mut PatIdent) {
161 ctx.visit_range(&mut ident.0.range);
162}
163
164pub fn walk_ident<T: Visitor>(ctx: &mut T, ident: &mut Ident) {
165 ctx.visit_range(&mut ident.range);
166}
167
168pub fn walk_qualified_ident<T: Visitor>(ctx: &mut T, ident: &mut QualifiedIdent) {
169 ctx.visit_range(&mut ident.range);
170}
171
172pub fn walk_destruct<T: Visitor>(ctx: &mut T, destruct: &mut Destruct) {
173 match destruct {
174 Destruct::Destruct(range, i, e, _) => {
175 ctx.visit_qualified_ident(i);
176 ctx.visit_range(range);
177 visit_vec!(e, e => ctx.visit_case_binding(e))
178 }
179 Destruct::Ident(i) => ctx.visit_ident(i),
180 }
181}
182
183pub fn walk_binding<T: Visitor>(ctx: &mut T, binding: &mut Binding) {
184 match binding {
185 Binding::Positional(e) => ctx.visit_expr(e),
186 Binding::Named(span, ident, e) => {
187 ctx.visit_range(span);
188 ctx.visit_ident(ident);
189 ctx.visit_expr(e);
190 }
191 }
192}
193
194pub fn walk_app_binding<T: Visitor>(ctx: &mut T, binding: &mut AppBinding) {
195 ctx.visit_expr(&mut binding.data)
196}
197
198pub fn walk_case_binding<T: Visitor>(ctx: &mut T, binding: &mut CaseBinding) {
199 match binding {
200 CaseBinding::Field(ident) => ctx.visit_ident(ident),
201 CaseBinding::Renamed(ident, rename) => {
202 ctx.visit_ident(ident);
203 ctx.visit_ident(rename);
204 }
205 }
206}
207
208pub fn walk_case<T: Visitor>(ctx: &mut T, case: &mut Case) {
209 ctx.visit_ident(&mut case.constructor);
210 for binding in &mut case.bindings {
211 ctx.visit_case_binding(binding);
212 }
213 ctx.visit_expr(&mut case.value)
214}
215
216pub fn walk_match<T: Visitor>(ctx: &mut T, matcher: &mut Match) {
217 ctx.visit_qualified_ident(&mut matcher.typ);
218
219 ctx.visit_ident(&mut matcher.scrutinee);
220
221 if let Some(opt) = &mut matcher.value {
222 ctx.visit_expr(opt);
223 }
224
225 for (name, expr) in &mut matcher.with_vars {
226 ctx.visit_ident(name);
227 if let Some(expr) = expr {
228 ctx.visit_expr(expr);
229 }
230 }
231
232 match &mut matcher.motive {
233 Some(expr) => ctx.visit_expr(expr),
234 None => (),
235 }
236
237 for case in &mut matcher.cases {
238 ctx.visit_case(case)
239 }
240}
241
242pub fn walk_argument<T: Visitor>(ctx: &mut T, argument: &mut Argument) {
243 ctx.visit_ident(&mut argument.name);
244 match &mut argument.typ {
245 Some(typ) => ctx.visit_expr(typ),
246 None => (),
247 }
248 ctx.visit_range(&mut argument.range);
249}
250
251pub fn walk_entry<T: Visitor>(ctx: &mut T, entry: &mut Entry) {
252 ctx.visit_qualified_ident(&mut entry.name);
253 for arg in entry.args.iter_mut() {
254 ctx.visit_argument(arg)
255 }
256 ctx.visit_expr(&mut entry.typ);
257 for rule in &mut entry.rules {
258 ctx.visit_rule(rule)
259 }
260 for attr in &mut entry.attrs {
261 ctx.visit_attr(attr);
262 }
263 ctx.visit_range(&mut entry.range);
264}
265
266pub fn walk_attr<T: Visitor>(ctx: &mut T, attr: &mut Attribute) {
267 ctx.visit_ident(&mut attr.name);
268 ctx.visit_range(&mut attr.range);
269 visit_opt!(&mut attr.value, x => ctx.visit_attr_style(x))
270}
271
272pub fn walk_attr_style<T: Visitor>(ctx: &mut T, attr: &mut AttributeStyle) {
273 match attr {
274 AttributeStyle::Ident(r, _) => {
275 ctx.visit_range(r);
276 }
277 AttributeStyle::String(r, _) => {
278 ctx.visit_range(r);
279 }
280 AttributeStyle::Number(r, _) => {
281 ctx.visit_range(r);
282 }
283 AttributeStyle::List(r, l) => {
284 ctx.visit_range(r);
285 visit_vec!(l.iter_mut(), attr => ctx.visit_attr_style(attr))
286 }
287 }
288}
289
290pub fn walk_pat<T: Visitor>(ctx: &mut T, pat: &mut Pat) {
291 ctx.visit_range(&mut pat.range);
292 match &mut pat.data {
293 PatKind::Var(ident) => ctx.visit_pat_ident(ident),
294 PatKind::Str(_) => (),
295 PatKind::U60(_) => (),
296 PatKind::U120(_) => (),
297 PatKind::F60(_) => (),
298 PatKind::Char(_) => (),
299 PatKind::Hole => (),
300 PatKind::List(ls) => {
301 for pat in ls {
302 ctx.visit_pat(pat)
303 }
304 }
305 PatKind::Pair(fst, snd) => {
306 ctx.visit_pat(fst);
307 ctx.visit_pat(snd);
308 }
309 PatKind::App(t, ls) => {
310 ctx.visit_qualified_ident(t);
311 for pat in ls {
312 ctx.visit_pat(pat)
313 }
314 }
315 }
316}
317
318pub fn walk_rule<T: Visitor>(ctx: &mut T, rule: &mut Rule) {
319 ctx.visit_qualified_ident(&mut rule.name);
320 for pat in &mut rule.pats {
321 ctx.visit_pat(pat);
322 }
323 ctx.visit_expr(&mut rule.body);
324 ctx.visit_range(&mut rule.range);
325}
326
327pub fn walk_top_level<T: Visitor>(ctx: &mut T, toplevel: &mut TopLevel) {
328 match toplevel {
329 super::TopLevel::SumType(sum) => {
330 ctx.visit_qualified_ident(&mut sum.name);
331 visit_vec!(&mut sum.attrs, arg => ctx.visit_attr(arg));
332 visit_vec!(sum.parameters.get_vec(), arg => ctx.visit_argument(arg));
333 visit_vec!(sum.indices.get_vec(), arg => ctx.visit_argument(arg));
334 visit_vec!(&mut sum.constructors, arg => ctx.visit_constructor(arg));
335 }
336 super::TopLevel::RecordType(rec) => {
337 ctx.visit_qualified_ident(&mut rec.name);
338 visit_vec!(&mut rec.attrs, arg => ctx.visit_attr(arg));
339 visit_vec!(rec.parameters.get_vec(), arg => ctx.visit_argument(arg));
340 visit_vec!(&mut rec.fields, (name, _docs, typ) => {
341 ctx.visit_ident(name);
342 ctx.visit_expr(typ);
343 });
344 }
345 super::TopLevel::Entry(entry) => {
346 ctx.visit_entry(entry);
347 }
348 }
349}
350
351pub fn walk_module<T: Visitor>(ctx: &mut T, module: &mut Module) {
352 for toplevel in &mut module.entries {
353 walk_top_level(ctx, toplevel)
354 }
355}
356
357pub fn walk_substitution<T: Visitor>(ctx: &mut T, subst: &mut Substitution) {
358 ctx.visit_expr(&mut subst.expr);
359 ctx.visit_ident(&mut subst.name);
360}
361
362pub fn walk_sttm<T: Visitor>(ctx: &mut T, sttm: &mut Sttm) {
363 ctx.visit_range(&mut sttm.range);
364 match &mut sttm.data {
365 SttmKind::Ask(ident, val, next) => {
366 ctx.visit_destruct(ident);
367 ctx.visit_expr(val);
368 ctx.visit_sttm(next);
369 }
370 SttmKind::Let(destrut, val, next) => {
371 ctx.visit_destruct(destrut);
372 ctx.visit_expr(val);
373 ctx.visit_sttm(next);
374 }
375 SttmKind::Expr(expr, next) => {
376 ctx.visit_expr(expr);
377 ctx.visit_sttm(next);
378 }
379 SttmKind::Return(expr) => {
380 ctx.visit_expr(expr);
381 }
382 SttmKind::RetExpr(expr) => {
383 ctx.visit_expr(expr);
384 }
385 }
386}
387
388pub fn walk_expr<T: Visitor>(ctx: &mut T, expr: &mut Expr) {
389 ctx.visit_range(&mut expr.range);
390 match &mut expr.data {
391 ExprKind::Var { name } => ctx.visit_ident(name),
392 ExprKind::Constr { name, args } => {
393 ctx.visit_qualified_ident(name);
394 for arg in args {
395 ctx.visit_binding(arg);
396 }
397 }
398 ExprKind::Pair { fst, snd } => {
399 ctx.visit_expr(fst);
400 ctx.visit_expr(snd);
401 }
402 ExprKind::All {
403 param: None,
404 typ,
405 body,
406 ..
407 } => {
408 ctx.visit_expr(typ);
409 ctx.visit_expr(body);
410 }
411 ExprKind::All {
412 param: Some(ident),
413 typ,
414 body,
415 ..
416 } => {
417 ctx.visit_ident(ident);
418 ctx.visit_expr(typ);
419 ctx.visit_expr(body);
420 }
421 ExprKind::Sigma {
422 param: None,
423 fst,
424 snd,
425 } => {
426 ctx.visit_expr(fst);
427 ctx.visit_expr(snd);
428 }
429 ExprKind::If { cond, then_, else_ } => {
430 ctx.visit_expr(cond);
431 ctx.visit_expr(then_);
432 ctx.visit_expr(else_);
433 }
434 ExprKind::Sigma {
435 param: Some(ident),
436 fst,
437 snd,
438 } => {
439 ctx.visit_ident(ident);
440 ctx.visit_expr(fst);
441 ctx.visit_expr(snd);
442 }
443 ExprKind::Do { typ, sttm } => {
444 ctx.visit_qualified_ident(typ);
445 ctx.visit_sttm(sttm)
446 }
447 ExprKind::Lambda {
448 param, typ, body, ..
449 } => {
450 ctx.visit_ident(param);
451 match typ {
452 Some(x) => ctx.visit_expr(x),
453 None => (),
454 }
455 ctx.visit_expr(body);
456 }
457 ExprKind::App { fun, args } => {
458 ctx.visit_expr(fun);
459 for arg in args {
460 ctx.visit_app_binding(arg);
461 }
462 }
463 ExprKind::List { args } => {
464 for arg in args {
465 ctx.visit_expr(arg);
466 }
467 }
468 ExprKind::Let { name, val, next } => {
469 ctx.visit_destruct(name);
470 ctx.visit_expr(val);
471 ctx.visit_expr(next);
472 }
473 ExprKind::Ann { val, typ } => {
474 ctx.visit_expr(val);
475 ctx.visit_expr(typ);
476 }
477 ExprKind::Lit { lit } => {
478 ctx.visit_literal(expr.range, lit);
479 }
480 ExprKind::Binary { op: _, fst, snd } => {
481 ctx.visit_expr(fst);
482 ctx.visit_expr(snd);
483 }
484 ExprKind::Open { type_name, var_name, motive, next } => {
485 ctx.visit_qualified_ident(type_name);
486 ctx.visit_ident(var_name);
487 ctx.visit_expr(next);
488 if let Some(res) = motive {
489 ctx.visit_expr(res);
490 }
491 },
492 ExprKind::Hole => {}
493 ExprKind::Subst(subst) => ctx.visit_substitution(subst),
494 ExprKind::Match(matcher) => ctx.visit_match(matcher),
495 ExprKind::SeqRecord(seq) => {
496 ctx.visit_expr(&mut seq.expr);
497 ctx.visit_expr(&mut seq.typ);
498
499 match &mut seq.operation {
500 SeqOperation::Set(expr) => ctx.visit_expr(expr),
501 SeqOperation::Mut(expr) => ctx.visit_expr(expr),
502 SeqOperation::Get => (),
503 }
504 },
505 }
506}