1use std::collections::BTreeSet;
2
3use crate::syntax::ast::TypeRef;
4use crate::syntax::ast::{Block, Expr, MetaBlock, MetaExpr, Program, QuotedCode, Stmt, TypeExpr};
5
6pub fn qualify_program_module(program: &mut Program, module_prefix: &str) {
8 let local_function_names = program
9 .functions
10 .iter()
11 .map(|function| function.name.clone())
12 .chain(
13 program
14 .meta_functions
15 .iter()
16 .map(|function| function.name.clone()),
17 )
18 .collect::<BTreeSet<_>>();
19 let local_struct_names = program
20 .structs
21 .iter()
22 .map(|decl| decl.name.clone())
23 .chain(program.enums.iter().map(|decl| decl.name.clone()))
24 .collect::<BTreeSet<_>>();
25 let local_extern_module_names = program
26 .extern_modules
27 .iter()
28 .map(|decl| decl.name.clone())
29 .collect::<BTreeSet<_>>();
30
31 for decl in &mut program.structs {
32 decl.name = qualify_decl_name(module_prefix, decl.name.as_str());
33 for field in &mut decl.fields {
34 qualify_type_expr(
35 &mut field.ty,
36 module_prefix,
37 &local_function_names,
38 &local_struct_names,
39 &local_extern_module_names,
40 );
41 }
42 }
43
44 for decl in &mut program.enums {
45 decl.name = qualify_decl_name(module_prefix, decl.name.as_str());
46 for variant in &mut decl.variants {
47 for payload in &mut variant.payload {
48 qualify_type_expr(
49 payload,
50 module_prefix,
51 &local_function_names,
52 &local_struct_names,
53 &local_extern_module_names,
54 );
55 }
56 }
57 }
58
59 for module in &mut program.extern_modules {
60 module.name = qualify_decl_name(module_prefix, module.name.as_str());
61 for function in &mut module.functions {
62 for param in &mut function.params {
63 qualify_type_ref(
64 &mut param.ty,
65 module_prefix,
66 &local_function_names,
67 &local_struct_names,
68 &local_extern_module_names,
69 );
70 }
71 qualify_type_ref(
72 &mut function.return_type,
73 module_prefix,
74 &local_function_names,
75 &local_struct_names,
76 &local_extern_module_names,
77 );
78 }
79 }
80
81 for function in &mut program.functions {
82 function.name = qualify_decl_name(module_prefix, function.name.as_str());
83 for param in &mut function.params {
84 qualify_type_ref(
85 &mut param.ty,
86 module_prefix,
87 &local_function_names,
88 &local_struct_names,
89 &local_extern_module_names,
90 );
91 }
92 qualify_type_ref(
93 &mut function.return_type,
94 module_prefix,
95 &local_function_names,
96 &local_struct_names,
97 &local_extern_module_names,
98 );
99 qualify_block(
100 &mut function.body,
101 module_prefix,
102 &local_function_names,
103 &local_struct_names,
104 &local_extern_module_names,
105 );
106 }
107
108 for function in &mut program.meta_functions {
109 function.name = qualify_decl_name(module_prefix, function.name.as_str());
110 for param in &mut function.params {
111 qualify_type_expr(
112 &mut param.ty,
113 module_prefix,
114 &local_function_names,
115 &local_struct_names,
116 &local_extern_module_names,
117 );
118 }
119 qualify_type_expr(
120 &mut function.return_type,
121 module_prefix,
122 &local_function_names,
123 &local_struct_names,
124 &local_extern_module_names,
125 );
126 qualify_meta_block(
127 &mut function.body,
128 module_prefix,
129 &local_function_names,
130 &local_struct_names,
131 &local_extern_module_names,
132 );
133 }
134}
135
136fn qualify_decl_name(module_prefix: &str, name: &str) -> String {
138 format!("{module_prefix}::{name}")
139}
140
141fn qualify_symbol_name(
143 name: &str,
144 module_prefix: &str,
145 local_function_names: &BTreeSet<String>,
146 local_struct_names: &BTreeSet<String>,
147 local_extern_module_names: &BTreeSet<String>,
148) -> String {
149 if name.contains("::") {
150 let mut parts = name.split("::");
151 if let Some(head) = parts.next()
152 && (local_function_names.contains(head)
153 || local_struct_names.contains(head)
154 || local_extern_module_names.contains(head))
155 {
156 return format!("{module_prefix}::{name}");
157 }
158 return name.to_owned();
159 }
160
161 if local_function_names.contains(name)
162 || local_struct_names.contains(name)
163 || local_extern_module_names.contains(name)
164 {
165 format!("{module_prefix}::{name}")
166 } else {
167 name.to_owned()
168 }
169}
170
171fn qualify_type_ref(
173 ty: &mut TypeRef,
174 module_prefix: &str,
175 local_function_names: &BTreeSet<String>,
176 local_struct_names: &BTreeSet<String>,
177 local_extern_module_names: &BTreeSet<String>,
178) {
179 qualify_type_expr(
180 &mut ty.ty,
181 module_prefix,
182 local_function_names,
183 local_struct_names,
184 local_extern_module_names,
185 );
186}
187
188fn qualify_type_expr(
190 ty: &mut TypeExpr,
191 module_prefix: &str,
192 local_function_names: &BTreeSet<String>,
193 local_struct_names: &BTreeSet<String>,
194 local_extern_module_names: &BTreeSet<String>,
195) {
196 match ty {
197 TypeExpr::Named(name) => {
198 if local_struct_names.contains(name) {
199 *name = qualify_symbol_name(
200 name,
201 module_prefix,
202 local_function_names,
203 local_struct_names,
204 local_extern_module_names,
205 );
206 }
207 }
208 TypeExpr::Pointer { item } => qualify_type_expr(
209 item,
210 module_prefix,
211 local_function_names,
212 local_struct_names,
213 local_extern_module_names,
214 ),
215 TypeExpr::Array { item, .. } | TypeExpr::Slice { item } => qualify_type_expr(
216 item,
217 module_prefix,
218 local_function_names,
219 local_struct_names,
220 local_extern_module_names,
221 ),
222 TypeExpr::Tuple(items) => {
223 for item in items {
224 qualify_type_expr(
225 item,
226 module_prefix,
227 local_function_names,
228 local_struct_names,
229 local_extern_module_names,
230 );
231 }
232 }
233 TypeExpr::Apply { callee, args } => {
234 if local_struct_names.contains(callee) {
235 *callee = qualify_symbol_name(
236 callee,
237 module_prefix,
238 local_function_names,
239 local_struct_names,
240 local_extern_module_names,
241 );
242 }
243 for arg in args {
244 qualify_type_expr(
245 arg,
246 module_prefix,
247 local_function_names,
248 local_struct_names,
249 local_extern_module_names,
250 );
251 }
252 }
253 TypeExpr::Struct { fields } | TypeExpr::Union { fields } => {
254 for field in fields {
255 qualify_type_expr(
256 &mut field.ty,
257 module_prefix,
258 local_function_names,
259 local_struct_names,
260 local_extern_module_names,
261 );
262 }
263 }
264 TypeExpr::Enum { variants } => {
265 for variant in variants {
266 for payload in &mut variant.payload {
267 qualify_type_expr(
268 payload,
269 module_prefix,
270 local_function_names,
271 local_struct_names,
272 local_extern_module_names,
273 );
274 }
275 }
276 }
277 TypeExpr::TypeKind => {}
278 }
279}
280
281fn qualify_block(
283 block: &mut Block,
284 module_prefix: &str,
285 local_function_names: &BTreeSet<String>,
286 local_struct_names: &BTreeSet<String>,
287 local_extern_module_names: &BTreeSet<String>,
288) {
289 for stmt in &mut block.statements {
290 match stmt {
291 Stmt::Let { value, .. } => qualify_expr(
292 value,
293 module_prefix,
294 local_function_names,
295 local_struct_names,
296 local_extern_module_names,
297 ),
298 Stmt::Assign { value, .. } => qualify_expr(
299 value,
300 module_prefix,
301 local_function_names,
302 local_struct_names,
303 local_extern_module_names,
304 ),
305 Stmt::If {
306 condition,
307 then_block,
308 else_block,
309 ..
310 } => {
311 qualify_expr(
312 condition,
313 module_prefix,
314 local_function_names,
315 local_struct_names,
316 local_extern_module_names,
317 );
318 qualify_block(
319 then_block,
320 module_prefix,
321 local_function_names,
322 local_struct_names,
323 local_extern_module_names,
324 );
325 if let Some(else_block) = else_block {
326 qualify_block(
327 else_block,
328 module_prefix,
329 local_function_names,
330 local_struct_names,
331 local_extern_module_names,
332 );
333 }
334 }
335 Stmt::For { iterable, body, .. } => {
336 qualify_expr(
337 iterable,
338 module_prefix,
339 local_function_names,
340 local_struct_names,
341 local_extern_module_names,
342 );
343 qualify_block(
344 body,
345 module_prefix,
346 local_function_names,
347 local_struct_names,
348 local_extern_module_names,
349 );
350 }
351 Stmt::While { condition, body } => {
352 qualify_expr(
353 condition,
354 module_prefix,
355 local_function_names,
356 local_struct_names,
357 local_extern_module_names,
358 );
359 qualify_block(
360 body,
361 module_prefix,
362 local_function_names,
363 local_struct_names,
364 local_extern_module_names,
365 );
366 }
367 Stmt::Match { value, arms } => {
368 qualify_expr(
369 value,
370 module_prefix,
371 local_function_names,
372 local_struct_names,
373 local_extern_module_names,
374 );
375 for arm in arms {
376 qualify_block(
377 &mut arm.body,
378 module_prefix,
379 local_function_names,
380 local_struct_names,
381 local_extern_module_names,
382 );
383 }
384 }
385 Stmt::Meta { body } => qualify_meta_block(
386 body,
387 module_prefix,
388 local_function_names,
389 local_struct_names,
390 local_extern_module_names,
391 ),
392 Stmt::Expr { expr, .. } => qualify_expr(
393 expr,
394 module_prefix,
395 local_function_names,
396 local_struct_names,
397 local_extern_module_names,
398 ),
399 }
400 }
401}
402
403fn qualify_expr(
405 expr: &mut Expr,
406 module_prefix: &str,
407 local_function_names: &BTreeSet<String>,
408 local_struct_names: &BTreeSet<String>,
409 local_extern_module_names: &BTreeSet<String>,
410) {
411 match expr {
412 Expr::Call { callee, args, .. } => {
413 if let Expr::Ident { name, .. } = callee.as_mut() {
414 *name = qualify_symbol_name(
415 name,
416 module_prefix,
417 local_function_names,
418 local_struct_names,
419 local_extern_module_names,
420 );
421 } else {
422 qualify_expr(
423 callee,
424 module_prefix,
425 local_function_names,
426 local_struct_names,
427 local_extern_module_names,
428 );
429 }
430 for arg in args {
431 qualify_call_arg(
432 arg,
433 module_prefix,
434 local_function_names,
435 local_struct_names,
436 local_extern_module_names,
437 );
438 }
439 }
440 Expr::IntrinsicCall { args, .. } => {
441 for arg in args {
442 qualify_call_arg(
443 arg,
444 module_prefix,
445 local_function_names,
446 local_struct_names,
447 local_extern_module_names,
448 );
449 }
450 }
451 Expr::Tuple { items, .. } => {
452 for item in items {
453 qualify_expr(
454 item,
455 module_prefix,
456 local_function_names,
457 local_struct_names,
458 local_extern_module_names,
459 );
460 }
461 }
462 Expr::StructLit { name, fields, .. } => {
463 *name = qualify_symbol_name(
464 name,
465 module_prefix,
466 local_function_names,
467 local_struct_names,
468 local_extern_module_names,
469 );
470 for field in fields {
471 qualify_expr(
472 &mut field.value,
473 module_prefix,
474 local_function_names,
475 local_struct_names,
476 local_extern_module_names,
477 );
478 }
479 }
480 Expr::Field { base, .. } => qualify_expr(
481 base,
482 module_prefix,
483 local_function_names,
484 local_struct_names,
485 local_extern_module_names,
486 ),
487 Expr::Index { base, index } => {
488 qualify_expr(
489 base,
490 module_prefix,
491 local_function_names,
492 local_struct_names,
493 local_extern_module_names,
494 );
495 qualify_expr(
496 index,
497 module_prefix,
498 local_function_names,
499 local_struct_names,
500 local_extern_module_names,
501 );
502 }
503 Expr::SliceRange { base, start, end } => {
504 qualify_expr(
505 base,
506 module_prefix,
507 local_function_names,
508 local_struct_names,
509 local_extern_module_names,
510 );
511 if let Some(start) = start {
512 qualify_expr(
513 start,
514 module_prefix,
515 local_function_names,
516 local_struct_names,
517 local_extern_module_names,
518 );
519 }
520 if let Some(end) = end {
521 qualify_expr(
522 end,
523 module_prefix,
524 local_function_names,
525 local_struct_names,
526 local_extern_module_names,
527 );
528 }
529 }
530 Expr::Prefix { value, .. } => qualify_expr(
531 value,
532 module_prefix,
533 local_function_names,
534 local_struct_names,
535 local_extern_module_names,
536 ),
537 Expr::Binary { lhs, rhs, .. } => {
538 qualify_expr(
539 lhs,
540 module_prefix,
541 local_function_names,
542 local_struct_names,
543 local_extern_module_names,
544 );
545 qualify_expr(
546 rhs,
547 module_prefix,
548 local_function_names,
549 local_struct_names,
550 local_extern_module_names,
551 );
552 }
553 Expr::Relational { lhs, rhs, .. } => {
554 qualify_expr(
555 lhs,
556 module_prefix,
557 local_function_names,
558 local_struct_names,
559 local_extern_module_names,
560 );
561 qualify_expr(
562 rhs,
563 module_prefix,
564 local_function_names,
565 local_struct_names,
566 local_extern_module_names,
567 );
568 }
569 Expr::Block(block) => qualify_block(
570 block,
571 module_prefix,
572 local_function_names,
573 local_struct_names,
574 local_extern_module_names,
575 ),
576 Expr::Splice(meta) => qualify_meta_expr(
577 meta,
578 module_prefix,
579 local_function_names,
580 local_struct_names,
581 local_extern_module_names,
582 ),
583 Expr::Array { items, .. } => {
584 for item in items {
585 qualify_expr(
586 item,
587 module_prefix,
588 local_function_names,
589 local_struct_names,
590 local_extern_module_names,
591 );
592 }
593 }
594 Expr::Ident { .. } | Expr::Int(_) | Expr::Number(_) | Expr::String(_) | Expr::Bool(_) => {}
595 }
596}
597
598fn qualify_call_arg(
600 arg: &mut crate::syntax::ast::CallArg,
601 module_prefix: &str,
602 local_function_names: &BTreeSet<String>,
603 local_struct_names: &BTreeSet<String>,
604 local_extern_module_names: &BTreeSet<String>,
605) {
606 match arg {
607 crate::syntax::ast::CallArg::Expr(expr) => qualify_expr(
608 expr,
609 module_prefix,
610 local_function_names,
611 local_struct_names,
612 local_extern_module_names,
613 ),
614 crate::syntax::ast::CallArg::Spread(expr) => qualify_expr(
615 expr,
616 module_prefix,
617 local_function_names,
618 local_struct_names,
619 local_extern_module_names,
620 ),
621 crate::syntax::ast::CallArg::Type(ty) => qualify_type_expr(
622 ty,
623 module_prefix,
624 local_function_names,
625 local_struct_names,
626 local_extern_module_names,
627 ),
628 }
629}
630
631fn qualify_meta_block(
633 block: &mut MetaBlock,
634 module_prefix: &str,
635 local_function_names: &BTreeSet<String>,
636 local_struct_names: &BTreeSet<String>,
637 local_extern_module_names: &BTreeSet<String>,
638) {
639 for stmt in &mut block.statements {
640 match stmt {
641 crate::syntax::ast::MetaStmt::Let { value, .. } => qualify_meta_expr(
642 value,
643 module_prefix,
644 local_function_names,
645 local_struct_names,
646 local_extern_module_names,
647 ),
648 crate::syntax::ast::MetaStmt::Match { value, arms } => {
649 qualify_meta_expr(
650 value,
651 module_prefix,
652 local_function_names,
653 local_struct_names,
654 local_extern_module_names,
655 );
656 for arm in arms {
657 match &mut arm.pattern {
658 crate::syntax::ast::MetaMatchPattern::Wildcard => {}
659 crate::syntax::ast::MetaMatchPattern::Int(_)
660 | crate::syntax::ast::MetaMatchPattern::Bool(_)
661 | crate::syntax::ast::MetaMatchPattern::String(_) => {}
662 crate::syntax::ast::MetaMatchPattern::Quote(quoted) => {
663 qualify_quoted_code(
664 quoted,
665 module_prefix,
666 local_function_names,
667 local_struct_names,
668 local_extern_module_names,
669 );
670 }
671 crate::syntax::ast::MetaMatchPattern::Type(ty) => qualify_type_expr(
672 ty,
673 module_prefix,
674 local_function_names,
675 local_struct_names,
676 local_extern_module_names,
677 ),
678 }
679 qualify_meta_expr(
680 &mut arm.result,
681 module_prefix,
682 local_function_names,
683 local_struct_names,
684 local_extern_module_names,
685 );
686 }
687 }
688 crate::syntax::ast::MetaStmt::Meta { body } => qualify_meta_block(
689 body,
690 module_prefix,
691 local_function_names,
692 local_struct_names,
693 local_extern_module_names,
694 ),
695 crate::syntax::ast::MetaStmt::Expr { expr } => qualify_meta_expr(
696 expr,
697 module_prefix,
698 local_function_names,
699 local_struct_names,
700 local_extern_module_names,
701 ),
702 }
703 }
704}
705
706fn qualify_meta_expr(
708 expr: &mut MetaExpr,
709 module_prefix: &str,
710 local_function_names: &BTreeSet<String>,
711 local_struct_names: &BTreeSet<String>,
712 local_extern_module_names: &BTreeSet<String>,
713) {
714 match expr {
715 MetaExpr::Call { callee, args } => {
716 *callee = qualify_symbol_name(
717 callee,
718 module_prefix,
719 local_function_names,
720 local_struct_names,
721 local_extern_module_names,
722 );
723 for arg in args {
724 qualify_meta_expr(
725 arg,
726 module_prefix,
727 local_function_names,
728 local_struct_names,
729 local_extern_module_names,
730 );
731 }
732 }
733 MetaExpr::Type(ty) => qualify_type_expr(
734 ty,
735 module_prefix,
736 local_function_names,
737 local_struct_names,
738 local_extern_module_names,
739 ),
740 MetaExpr::BuildExpr(expr) => qualify_expr(
741 expr,
742 module_prefix,
743 local_function_names,
744 local_struct_names,
745 local_extern_module_names,
746 ),
747 MetaExpr::Quote(quoted) => qualify_quoted_code(
748 quoted,
749 module_prefix,
750 local_function_names,
751 local_struct_names,
752 local_extern_module_names,
753 ),
754 MetaExpr::Splice(inner) => qualify_meta_expr(
755 inner,
756 module_prefix,
757 local_function_names,
758 local_struct_names,
759 local_extern_module_names,
760 ),
761 MetaExpr::Ident(_) | MetaExpr::Int(_) | MetaExpr::Bool(_) | MetaExpr::String(_) => {}
762 }
763}
764
765fn qualify_quoted_code(
767 quoted: &mut QuotedCode,
768 module_prefix: &str,
769 local_function_names: &BTreeSet<String>,
770 local_struct_names: &BTreeSet<String>,
771 local_extern_module_names: &BTreeSet<String>,
772) {
773 match quoted {
774 QuotedCode::Expr(expr) => qualify_expr(
775 expr,
776 module_prefix,
777 local_function_names,
778 local_struct_names,
779 local_extern_module_names,
780 ),
781 QuotedCode::Type(ty) => qualify_type_expr(
782 ty,
783 module_prefix,
784 local_function_names,
785 local_struct_names,
786 local_extern_module_names,
787 ),
788 }
789}