1use std::collections::{HashMap, HashSet};
4use std::hash::{Hash, Hasher};
5use std::path::{Path, PathBuf};
6use std::sync::Arc;
7
8use async_recursion::async_recursion;
9use rexlang_ast::expr::{
10 Decl, DeclareFnDecl, Expr, FnDecl, ImportClause, ImportDecl, ImportPath, InstanceDecl, NameRef,
11 Pattern, Program, Symbol, TypeConstraint, TypeDecl, TypeExpr, Var, intern,
12};
13use rexlang_lexer::Token;
14use rexlang_parser::Parser as RexParser;
15use rexlang_typesystem::{Predicate, Type};
16use rexlang_util::{GasMeter, sha256_hex};
17use uuid::Uuid;
18
19use crate::Engine;
20use crate::{EngineError, Pointer};
21
22#[cfg(not(target_arch = "wasm32"))]
23mod filesystem;
24mod resolvers;
25mod system;
26mod types;
27
28#[cfg(not(target_arch = "wasm32"))]
29pub use filesystem::{default_local_resolver, include_resolver};
30#[cfg(all(not(target_arch = "wasm32"), feature = "github-imports"))]
31pub use resolvers::default_github_resolver;
32pub use resolvers::default_stdlib_resolver;
33pub use system::ResolverFn;
34pub use types::virtual_export_name;
35pub use types::{
36 CanonicalSymbol, ModuleExports, ModuleId, ModuleInstance, ModuleKey, ReplState, ResolveRequest,
37 ResolvedModule, SymbolKind,
38};
39
40pub(crate) use system::ModuleSystem;
41pub(crate) use types::module_key_for_module;
42
43use system::wrap_resolver;
44use types::{prefix_for_module, qualify};
45
46fn import_specifier(path: &ImportPath) -> String {
47 match path {
48 ImportPath::Local { segments, sha } => {
49 let base = segments
50 .iter()
51 .map(|s| s.as_ref())
52 .collect::<Vec<_>>()
53 .join(".");
54 if let Some(sha) = sha {
55 format!("{base}#{sha}")
56 } else {
57 base
58 }
59 }
60 ImportPath::Remote { url, sha } => {
61 if let Some(sha) = sha {
62 format!("{url}#{sha}")
63 } else {
64 url.clone()
65 }
66 }
67 }
68}
69
70fn spec_base_name(spec: &str) -> &str {
71 spec.split_once('#').map_or(spec, |(base, _)| base)
72}
73
74fn contains_import_alias(decls: &[Decl], alias: &Symbol) -> bool {
75 decls.iter().any(|decl| match decl {
76 Decl::Import(import_decl) => import_decl.alias == *alias,
77 _ => false,
78 })
79}
80
81fn default_import_decl(module_name: &str) -> ImportDecl {
82 ImportDecl {
83 span: rexlang_lexer::span::Span::default(),
84 is_pub: false,
85 path: ImportPath::Local {
86 segments: vec![intern(module_name)],
87 sha: None,
88 },
89 alias: intern(module_name),
90 clause: Some(ImportClause::All),
91 }
92}
93
94#[derive(Default)]
95struct ImportBindings {
96 alias_exports: HashMap<Symbol, ModuleExports>,
97 imported_values: HashMap<Symbol, CanonicalSymbol>,
98}
99
100fn add_import_bindings(
101 out: &mut ImportBindings,
102 import: &ImportDecl,
103 exports: &ModuleExports,
104 forbidden_locals: &HashSet<Symbol>,
105 existing_imported: Option<&HashSet<Symbol>>,
106) -> Result<(), EngineError> {
107 let module_name = import.alias.clone();
108 let mut bind_local = |local_name: Symbol, target: CanonicalSymbol| -> Result<(), EngineError> {
109 if forbidden_locals.contains(&local_name) {
110 return Err(crate::ModuleError::ImportNameConflictsWithLocal {
111 module: module_name.clone(),
112 name: local_name,
113 }
114 .into());
115 }
116 if let Some(existing) = existing_imported
117 && existing.contains(&local_name)
118 {
119 return Err(crate::ModuleError::DuplicateImportedName { name: local_name }.into());
120 }
121 if out.imported_values.contains_key(&local_name) {
122 return Err(crate::ModuleError::DuplicateImportedName { name: local_name }.into());
123 }
124 out.imported_values.insert(local_name, target);
125 Ok(())
126 };
127
128 match &import.clause {
129 None => {
130 out.alias_exports
131 .insert(import.alias.clone(), exports.clone());
132 Ok(())
133 }
134 Some(ImportClause::All) => {
135 for (export, target) in &exports.values {
136 bind_local(export.clone(), target.clone())?;
137 }
138 Ok(())
139 }
140 Some(ImportClause::Items(items)) => {
141 for item in items {
142 let Some(target) = exports.values.get(&item.name) else {
143 return Err(crate::ModuleError::MissingExport {
144 module: import.alias.clone(),
145 export: item.name.clone(),
146 }
147 .into());
148 };
149 let local_name = item.alias.clone().unwrap_or_else(|| item.name.clone());
150 bind_local(local_name, target.clone())?;
151 }
152 Ok(())
153 }
154 }
155}
156
157fn collect_local_renames(
158 program: &Program,
159 prefix: &str,
160) -> (
161 HashMap<Symbol, Symbol>,
162 HashMap<Symbol, Symbol>,
163 HashMap<Symbol, Symbol>,
164) {
165 let mut values = HashMap::new();
166 let mut types = HashMap::new();
167 let mut classes = HashMap::new();
168
169 for decl in &program.decls {
170 match decl {
171 Decl::Fn(fd) => {
172 values.insert(fd.name.name.clone(), qualify(prefix, &fd.name.name));
173 }
174 Decl::DeclareFn(df) => {
175 values.insert(df.name.name.clone(), qualify(prefix, &df.name.name));
176 }
177 Decl::Type(td) => {
178 types.insert(td.name.clone(), qualify(prefix, &td.name));
179 for variant in &td.variants {
180 values.insert(variant.name.clone(), qualify(prefix, &variant.name));
181 }
182 }
183 Decl::Class(cd) => {
184 classes.insert(cd.name.clone(), qualify(prefix, &cd.name));
185 }
186 Decl::Instance(..) | Decl::Import(..) => {}
187 }
188 }
189
190 (values, types, classes)
191}
192
193fn collect_pattern_bindings(pat: &Pattern, out: &mut Vec<Symbol>) {
194 match pat {
195 Pattern::Wildcard(..) => {}
196 Pattern::Var(v) => out.push(v.name.clone()),
197 Pattern::Named(_, _, args) => {
198 for arg in args {
199 collect_pattern_bindings(arg, out);
200 }
201 }
202 Pattern::Tuple(_, elems) | Pattern::List(_, elems) => {
203 for elem in elems {
204 collect_pattern_bindings(elem, out);
205 }
206 }
207 Pattern::Cons(_, head, tail) => {
208 collect_pattern_bindings(head, out);
209 collect_pattern_bindings(tail, out);
210 }
211 Pattern::Dict(_, fields) => {
212 for (_, pat) in fields {
213 collect_pattern_bindings(pat, out);
214 }
215 }
216 }
217}
218
219fn rename_type_expr(
220 ty: &TypeExpr,
221 type_renames: &HashMap<Symbol, Symbol>,
222 class_renames: &HashMap<Symbol, Symbol>,
223) -> TypeExpr {
224 match ty {
225 TypeExpr::Name(span, name) => {
226 let name_sym = name.to_dotted_symbol();
227 if let Some(new) = type_renames.get(&name_sym) {
228 TypeExpr::Name(*span, NameRef::Unqualified(new.clone()))
229 } else if let Some(new) = class_renames.get(&name_sym) {
230 TypeExpr::Name(*span, NameRef::Unqualified(new.clone()))
231 } else {
232 TypeExpr::Name(*span, name.clone())
233 }
234 }
235 TypeExpr::App(span, f, x) => TypeExpr::App(
236 *span,
237 Box::new(rename_type_expr(f, type_renames, class_renames)),
238 Box::new(rename_type_expr(x, type_renames, class_renames)),
239 ),
240 TypeExpr::Fun(span, a, b) => TypeExpr::Fun(
241 *span,
242 Box::new(rename_type_expr(a, type_renames, class_renames)),
243 Box::new(rename_type_expr(b, type_renames, class_renames)),
244 ),
245 TypeExpr::Tuple(span, elems) => TypeExpr::Tuple(
246 *span,
247 elems
248 .iter()
249 .map(|e| rename_type_expr(e, type_renames, class_renames))
250 .collect(),
251 ),
252 TypeExpr::Record(span, fields) => TypeExpr::Record(
253 *span,
254 fields
255 .iter()
256 .map(|(name, ty)| {
257 (
258 name.clone(),
259 rename_type_expr(ty, type_renames, class_renames),
260 )
261 })
262 .collect(),
263 ),
264 }
265}
266
267fn rename_constraints(
268 cs: &[TypeConstraint],
269 type_renames: &HashMap<Symbol, Symbol>,
270 class_renames: &HashMap<Symbol, Symbol>,
271) -> Vec<TypeConstraint> {
272 cs.iter()
273 .map(|c| TypeConstraint {
274 class: {
275 let class_sym = c.class.to_dotted_symbol();
276 class_renames
277 .get(&class_sym)
278 .cloned()
279 .map(NameRef::Unqualified)
280 .unwrap_or_else(|| c.class.clone())
281 },
282 typ: rename_type_expr(&c.typ, type_renames, class_renames),
283 })
284 .collect()
285}
286
287fn rename_pattern(pat: &Pattern, value_renames: &HashMap<Symbol, Symbol>) -> Pattern {
288 match pat {
289 Pattern::Wildcard(span) => Pattern::Wildcard(*span),
290 Pattern::Var(v) => Pattern::Var(v.clone()),
291 Pattern::Named(span, name, args) => Pattern::Named(
292 *span,
293 {
294 let name_sym = name.to_dotted_symbol();
295 value_renames
296 .get(&name_sym)
297 .cloned()
298 .map(NameRef::Unqualified)
299 .unwrap_or_else(|| name.clone())
300 },
301 args.iter()
302 .map(|p| rename_pattern(p, value_renames))
303 .collect(),
304 ),
305 Pattern::Tuple(span, elems) => Pattern::Tuple(
306 *span,
307 elems
308 .iter()
309 .map(|p| rename_pattern(p, value_renames))
310 .collect(),
311 ),
312 Pattern::List(span, elems) => Pattern::List(
313 *span,
314 elems
315 .iter()
316 .map(|p| rename_pattern(p, value_renames))
317 .collect(),
318 ),
319 Pattern::Cons(span, head, tail) => Pattern::Cons(
320 *span,
321 Box::new(rename_pattern(head, value_renames)),
322 Box::new(rename_pattern(tail, value_renames)),
323 ),
324 Pattern::Dict(span, fields) => Pattern::Dict(
325 *span,
326 fields
327 .iter()
328 .map(|(name, p)| (name.clone(), rename_pattern(p, value_renames)))
329 .collect(),
330 ),
331 }
332}
333
334fn rename_expr(
335 expr: &Expr,
336 bound: &mut HashSet<Symbol>,
337 value_renames: &HashMap<Symbol, Symbol>,
338 type_renames: &HashMap<Symbol, Symbol>,
339 class_renames: &HashMap<Symbol, Symbol>,
340) -> Expr {
341 match expr {
342 Expr::Bool(span, v) => Expr::Bool(*span, *v),
343 Expr::Uint(span, v) => Expr::Uint(*span, *v),
344 Expr::Int(span, v) => Expr::Int(*span, *v),
345 Expr::Float(span, v) => Expr::Float(*span, *v),
346 Expr::String(span, v) => Expr::String(*span, v.clone()),
347 Expr::Uuid(span, v) => Expr::Uuid(*span, *v),
348 Expr::DateTime(span, v) => Expr::DateTime(*span, *v),
349 Expr::Hole(span) => Expr::Hole(*span),
350 Expr::Tuple(span, elems) => Expr::Tuple(
351 *span,
352 elems
353 .iter()
354 .map(|e| {
355 Arc::new(rename_expr(
356 e,
357 bound,
358 value_renames,
359 type_renames,
360 class_renames,
361 ))
362 })
363 .collect(),
364 ),
365 Expr::List(span, elems) => Expr::List(
366 *span,
367 elems
368 .iter()
369 .map(|e| {
370 Arc::new(rename_expr(
371 e,
372 bound,
373 value_renames,
374 type_renames,
375 class_renames,
376 ))
377 })
378 .collect(),
379 ),
380 Expr::Dict(span, kvs) => Expr::Dict(
381 *span,
382 kvs.iter()
383 .map(|(k, v)| {
384 (
385 k.clone(),
386 Arc::new(rename_expr(
387 v,
388 bound,
389 value_renames,
390 type_renames,
391 class_renames,
392 )),
393 )
394 })
395 .collect(),
396 ),
397 Expr::RecordUpdate(span, base, updates) => Expr::RecordUpdate(
398 *span,
399 Arc::new(rename_expr(
400 base,
401 bound,
402 value_renames,
403 type_renames,
404 class_renames,
405 )),
406 updates
407 .iter()
408 .map(|(k, v)| {
409 (
410 k.clone(),
411 Arc::new(rename_expr(
412 v,
413 bound,
414 value_renames,
415 type_renames,
416 class_renames,
417 )),
418 )
419 })
420 .collect(),
421 ),
422 Expr::Var(v) => {
423 if bound.contains(&v.name) {
424 Expr::Var(v.clone())
425 } else if let Some(new) = value_renames.get(&v.name) {
426 Expr::Var(Var {
427 span: v.span,
428 name: new.clone(),
429 })
430 } else {
431 Expr::Var(v.clone())
432 }
433 }
434 Expr::App(span, f, x) => Expr::App(
435 *span,
436 Arc::new(rename_expr(
437 f,
438 bound,
439 value_renames,
440 type_renames,
441 class_renames,
442 )),
443 Arc::new(rename_expr(
444 x,
445 bound,
446 value_renames,
447 type_renames,
448 class_renames,
449 )),
450 ),
451 Expr::Project(span, base, field) => Expr::Project(
452 *span,
453 Arc::new(rename_expr(
454 base,
455 bound,
456 value_renames,
457 type_renames,
458 class_renames,
459 )),
460 field.clone(),
461 ),
462 Expr::Lam(span, scope, param, ann, constraints, body) => {
463 bound.insert(param.name.clone());
464 let out = Expr::Lam(
465 *span,
466 scope.clone(),
467 param.clone(),
468 ann.as_ref()
469 .map(|t| rename_type_expr(t, type_renames, class_renames)),
470 rename_constraints(constraints, type_renames, class_renames),
471 Arc::new(rename_expr(
472 body,
473 bound,
474 value_renames,
475 type_renames,
476 class_renames,
477 )),
478 );
479 bound.remove(¶m.name);
480 out
481 }
482 Expr::Let(span, var, ann, val, body) => {
483 let renamed_val = rename_expr(val, bound, value_renames, type_renames, class_renames);
484 bound.insert(var.name.clone());
485 let renamed_body = rename_expr(body, bound, value_renames, type_renames, class_renames);
486 bound.remove(&var.name);
487 Expr::Let(
488 *span,
489 var.clone(),
490 ann.as_ref()
491 .map(|t| rename_type_expr(t, type_renames, class_renames)),
492 Arc::new(renamed_val),
493 Arc::new(renamed_body),
494 )
495 }
496 Expr::LetRec(span, bindings, body) => {
497 let names: Vec<Symbol> = bindings
498 .iter()
499 .map(|(var, _, _)| var.name.clone())
500 .collect();
501 for name in &names {
502 bound.insert(name.clone());
503 }
504 let renamed_bindings = bindings
505 .iter()
506 .map(|(var, ann, def)| {
507 (
508 var.clone(),
509 ann.as_ref()
510 .map(|t| rename_type_expr(t, type_renames, class_renames)),
511 Arc::new(rename_expr(
512 def,
513 bound,
514 value_renames,
515 type_renames,
516 class_renames,
517 )),
518 )
519 })
520 .collect();
521 let renamed_body = Arc::new(rename_expr(
522 body,
523 bound,
524 value_renames,
525 type_renames,
526 class_renames,
527 ));
528 for name in &names {
529 bound.remove(name);
530 }
531 Expr::LetRec(*span, renamed_bindings, renamed_body)
532 }
533 Expr::Ite(span, c, t, e) => Expr::Ite(
534 *span,
535 Arc::new(rename_expr(
536 c,
537 bound,
538 value_renames,
539 type_renames,
540 class_renames,
541 )),
542 Arc::new(rename_expr(
543 t,
544 bound,
545 value_renames,
546 type_renames,
547 class_renames,
548 )),
549 Arc::new(rename_expr(
550 e,
551 bound,
552 value_renames,
553 type_renames,
554 class_renames,
555 )),
556 ),
557 Expr::Match(span, scrutinee, arms) => {
558 let scrutinee = Arc::new(rename_expr(
559 scrutinee,
560 bound,
561 value_renames,
562 type_renames,
563 class_renames,
564 ));
565 let mut renamed_arms = Vec::new();
566 for (pat, arm_expr) in arms {
567 let pat_renamed = rename_pattern(pat, value_renames);
568 let mut binds = Vec::new();
569 collect_pattern_bindings(&pat_renamed, &mut binds);
570 for b in &binds {
571 bound.insert(b.clone());
572 }
573 let arm_expr = Arc::new(rename_expr(
574 arm_expr,
575 bound,
576 value_renames,
577 type_renames,
578 class_renames,
579 ));
580 for b in &binds {
581 bound.remove(b);
582 }
583 renamed_arms.push((pat_renamed, arm_expr));
584 }
585 Expr::Match(*span, scrutinee, renamed_arms)
586 }
587 Expr::Ann(span, e, t) => Expr::Ann(
588 *span,
589 Arc::new(rename_expr(
590 e,
591 bound,
592 value_renames,
593 type_renames,
594 class_renames,
595 )),
596 rename_type_expr(t, type_renames, class_renames),
597 ),
598 }
599}
600
601fn qualify_program(program: &Program, prefix: &str) -> Program {
602 let (value_renames, type_renames, class_renames) = collect_local_renames(program, prefix);
603
604 let decls = program
605 .decls
606 .iter()
607 .filter_map(|decl| match decl {
608 Decl::Import(..) => None,
609 Decl::Type(td) => {
610 let name = type_renames
611 .get(&td.name)
612 .cloned()
613 .unwrap_or_else(|| td.name.clone());
614 let variants = td
615 .variants
616 .iter()
617 .map(|v| rexlang_ast::expr::TypeVariant {
618 name: value_renames
619 .get(&v.name)
620 .cloned()
621 .unwrap_or_else(|| v.name.clone()),
622 args: v
623 .args
624 .iter()
625 .map(|t| rename_type_expr(t, &type_renames, &class_renames))
626 .collect(),
627 })
628 .collect();
629 Some(Decl::Type(TypeDecl {
630 span: td.span,
631 is_pub: td.is_pub,
632 name,
633 params: td.params.clone(),
634 variants,
635 }))
636 }
637 Decl::Fn(fd) => {
638 let name_sym = value_renames
639 .get(&fd.name.name)
640 .cloned()
641 .unwrap_or_else(|| fd.name.name.clone());
642 let name = Var {
643 span: fd.name.span,
644 name: name_sym,
645 };
646 let params: Vec<(Var, TypeExpr)> = fd
647 .params
648 .iter()
649 .map(|(v, ann)| {
650 (
651 v.clone(),
652 rename_type_expr(ann, &type_renames, &class_renames),
653 )
654 })
655 .collect();
656 let ret = rename_type_expr(&fd.ret, &type_renames, &class_renames);
657 let constraints =
658 rename_constraints(&fd.constraints, &type_renames, &class_renames);
659 let mut bound = HashSet::new();
660 for (v, _) in ¶ms {
661 bound.insert(v.name.clone());
662 }
663 let body = Arc::new(rename_expr(
664 fd.body.as_ref(),
665 &mut bound,
666 &value_renames,
667 &type_renames,
668 &class_renames,
669 ));
670 Some(Decl::Fn(FnDecl {
671 span: fd.span,
672 is_pub: fd.is_pub,
673 name,
674 params,
675 ret,
676 constraints,
677 body,
678 }))
679 }
680 Decl::DeclareFn(df) => {
681 let name_sym = value_renames
682 .get(&df.name.name)
683 .cloned()
684 .unwrap_or_else(|| df.name.name.clone());
685 let name = Var {
686 span: df.name.span,
687 name: name_sym,
688 };
689 let params: Vec<(Var, TypeExpr)> = df
690 .params
691 .iter()
692 .map(|(v, ann)| {
693 (
694 v.clone(),
695 rename_type_expr(ann, &type_renames, &class_renames),
696 )
697 })
698 .collect();
699 let ret = rename_type_expr(&df.ret, &type_renames, &class_renames);
700 let constraints =
701 rename_constraints(&df.constraints, &type_renames, &class_renames);
702 Some(Decl::DeclareFn(DeclareFnDecl {
703 span: df.span,
704 is_pub: df.is_pub,
705 name,
706 params,
707 ret,
708 constraints,
709 }))
710 }
711 Decl::Class(cd) => {
712 let name = class_renames
713 .get(&cd.name)
714 .cloned()
715 .unwrap_or_else(|| cd.name.clone());
716 let supers = rename_constraints(&cd.supers, &type_renames, &class_renames);
717 let methods = cd
718 .methods
719 .iter()
720 .map(|m| rexlang_ast::expr::ClassMethodSig {
721 name: m.name.clone(),
722 typ: rename_type_expr(&m.typ, &type_renames, &class_renames),
723 })
724 .collect();
725 Some(Decl::Class(rexlang_ast::expr::ClassDecl {
726 span: cd.span,
727 is_pub: cd.is_pub,
728 name,
729 params: cd.params.clone(),
730 supers,
731 methods,
732 }))
733 }
734 Decl::Instance(id) => {
735 let class = class_renames
736 .get(&id.class)
737 .cloned()
738 .unwrap_or_else(|| id.class.clone());
739 let head = rename_type_expr(&id.head, &type_renames, &class_renames);
740 let context = rename_constraints(&id.context, &type_renames, &class_renames);
741 let mut methods = Vec::new();
742 for m in &id.methods {
743 let mut bound = HashSet::new();
744 let body = Arc::new(rename_expr(
745 m.body.as_ref(),
746 &mut bound,
747 &value_renames,
748 &type_renames,
749 &class_renames,
750 ));
751 methods.push(rexlang_ast::expr::InstanceMethodImpl {
752 name: m.name.clone(),
753 body,
754 });
755 }
756 Some(Decl::Instance(InstanceDecl {
757 span: id.span,
758 is_pub: id.is_pub,
759 class,
760 head,
761 context,
762 methods,
763 }))
764 }
765 })
766 .collect();
767
768 let mut bound = HashSet::new();
769 let expr = Arc::new(rename_expr(
770 program.expr.as_ref(),
771 &mut bound,
772 &value_renames,
773 &type_renames,
774 &class_renames,
775 ));
776
777 Program { decls, expr }
778}
779
780fn alias_is_visible(
781 name: &Symbol,
782 bound: &HashSet<Symbol>,
783 shadowed_values: Option<&HashSet<Symbol>>,
784) -> bool {
785 if bound.contains(name) {
786 return false;
787 }
788 match shadowed_values {
789 None => true,
790 Some(s) => !s.contains(name),
791 }
792}
793
794fn rewrite_import_uses_expr(
795 expr: &Expr,
796 bound: &mut HashSet<Symbol>,
797 aliases: &HashMap<Symbol, ModuleExports>,
798 imported_values: &HashMap<Symbol, CanonicalSymbol>,
799 shadowed_values: Option<&HashSet<Symbol>>,
800) -> Expr {
801 match expr {
802 Expr::Bool(span, v) => Expr::Bool(*span, *v),
803 Expr::Uint(span, v) => Expr::Uint(*span, *v),
804 Expr::Int(span, v) => Expr::Int(*span, *v),
805 Expr::Float(span, v) => Expr::Float(*span, *v),
806 Expr::String(span, v) => Expr::String(*span, v.clone()),
807 Expr::Uuid(span, v) => Expr::Uuid(*span, *v),
808 Expr::DateTime(span, v) => Expr::DateTime(*span, *v),
809 Expr::Hole(span) => Expr::Hole(*span),
810 Expr::Project(span, base, field) => {
811 if let Expr::Var(v) = base.as_ref()
812 && alias_is_visible(&v.name, bound, shadowed_values)
813 && let Some(exports) = aliases.get(&v.name)
814 && let Some(internal) = exports.values.get(field)
815 {
816 return Expr::Var(Var {
817 span: *span,
818 name: internal.symbol().clone(),
819 });
820 }
821 Expr::Project(
822 *span,
823 Arc::new(rewrite_import_uses_expr(
824 base,
825 bound,
826 aliases,
827 imported_values,
828 shadowed_values,
829 )),
830 field.clone(),
831 )
832 }
833 Expr::Var(v) => {
834 if alias_is_visible(&v.name, bound, shadowed_values)
835 && let Some(internal) = imported_values.get(&v.name)
836 {
837 Expr::Var(Var {
838 span: v.span,
839 name: internal.symbol().clone(),
840 })
841 } else {
842 Expr::Var(v.clone())
843 }
844 }
845 Expr::Lam(span, scope, param, ann, constraints, body) => {
846 let ann = ann
847 .as_ref()
848 .map(|t| rewrite_import_uses_type_expr(t, bound, aliases, shadowed_values));
849 let constraints = constraints
850 .iter()
851 .map(|c| TypeConstraint {
852 class: rewrite_import_uses_class_name(
853 &c.class,
854 bound,
855 aliases,
856 shadowed_values,
857 ),
858 typ: rewrite_import_uses_type_expr(&c.typ, bound, aliases, shadowed_values),
859 })
860 .collect();
861 bound.insert(param.name.clone());
862 let out = Expr::Lam(
863 *span,
864 scope.clone(),
865 param.clone(),
866 ann,
867 constraints,
868 Arc::new(rewrite_import_uses_expr(
869 body,
870 bound,
871 aliases,
872 imported_values,
873 shadowed_values,
874 )),
875 );
876 bound.remove(¶m.name);
877 out
878 }
879 Expr::Let(span, var, ann, val, body) => {
880 let val = Arc::new(rewrite_import_uses_expr(
881 val,
882 bound,
883 aliases,
884 imported_values,
885 shadowed_values,
886 ));
887 bound.insert(var.name.clone());
888 let body = Arc::new(rewrite_import_uses_expr(
889 body,
890 bound,
891 aliases,
892 imported_values,
893 shadowed_values,
894 ));
895 bound.remove(&var.name);
896 Expr::Let(
897 *span,
898 var.clone(),
899 ann.as_ref()
900 .map(|t| rewrite_import_uses_type_expr(t, bound, aliases, shadowed_values)),
901 val,
902 body,
903 )
904 }
905 Expr::LetRec(span, bindings, body) => {
906 let anns: Vec<Option<TypeExpr>> = bindings
907 .iter()
908 .map(|(_, ann, _)| {
909 ann.as_ref()
910 .map(|t| rewrite_import_uses_type_expr(t, bound, aliases, shadowed_values))
911 })
912 .collect();
913 let names: Vec<Symbol> = bindings
914 .iter()
915 .map(|(var, _, _)| var.name.clone())
916 .collect();
917 for name in &names {
918 bound.insert(name.clone());
919 }
920 let bindings = bindings
921 .iter()
922 .zip(anns)
923 .map(|((var, _ann, def), ann)| {
924 (
925 var.clone(),
926 ann,
927 Arc::new(rewrite_import_uses_expr(
928 def,
929 bound,
930 aliases,
931 imported_values,
932 shadowed_values,
933 )),
934 )
935 })
936 .collect();
937 let body = Arc::new(rewrite_import_uses_expr(
938 body,
939 bound,
940 aliases,
941 imported_values,
942 shadowed_values,
943 ));
944 for name in &names {
945 bound.remove(name);
946 }
947 Expr::LetRec(*span, bindings, body)
948 }
949 Expr::Match(span, scrutinee, arms) => {
950 let scrutinee = Arc::new(rewrite_import_uses_expr(
951 scrutinee,
952 bound,
953 aliases,
954 imported_values,
955 shadowed_values,
956 ));
957 let mut renamed_arms = Vec::new();
958 for (pat, arm_expr) in arms {
959 let pat = rewrite_import_uses_pattern(pat, imported_values);
960 let mut binds = Vec::new();
961 collect_pattern_bindings(&pat, &mut binds);
962 for b in &binds {
963 bound.insert(b.clone());
964 }
965 let arm_expr = Arc::new(rewrite_import_uses_expr(
966 arm_expr,
967 bound,
968 aliases,
969 imported_values,
970 shadowed_values,
971 ));
972 for b in &binds {
973 bound.remove(b);
974 }
975 renamed_arms.push((pat, arm_expr));
976 }
977 Expr::Match(*span, scrutinee, renamed_arms)
978 }
979 Expr::Tuple(span, elems) => Expr::Tuple(
980 *span,
981 elems
982 .iter()
983 .map(|e| {
984 Arc::new(rewrite_import_uses_expr(
985 e,
986 bound,
987 aliases,
988 imported_values,
989 shadowed_values,
990 ))
991 })
992 .collect(),
993 ),
994 Expr::List(span, elems) => Expr::List(
995 *span,
996 elems
997 .iter()
998 .map(|e| {
999 Arc::new(rewrite_import_uses_expr(
1000 e,
1001 bound,
1002 aliases,
1003 imported_values,
1004 shadowed_values,
1005 ))
1006 })
1007 .collect(),
1008 ),
1009 Expr::Dict(span, kvs) => Expr::Dict(
1010 *span,
1011 kvs.iter()
1012 .map(|(k, v)| {
1013 (
1014 k.clone(),
1015 Arc::new(rewrite_import_uses_expr(
1016 v,
1017 bound,
1018 aliases,
1019 imported_values,
1020 shadowed_values,
1021 )),
1022 )
1023 })
1024 .collect(),
1025 ),
1026 Expr::RecordUpdate(span, base, updates) => Expr::RecordUpdate(
1027 *span,
1028 Arc::new(rewrite_import_uses_expr(
1029 base,
1030 bound,
1031 aliases,
1032 imported_values,
1033 shadowed_values,
1034 )),
1035 updates
1036 .iter()
1037 .map(|(k, v)| {
1038 (
1039 k.clone(),
1040 Arc::new(rewrite_import_uses_expr(
1041 v,
1042 bound,
1043 aliases,
1044 imported_values,
1045 shadowed_values,
1046 )),
1047 )
1048 })
1049 .collect(),
1050 ),
1051 Expr::App(span, f, x) => Expr::App(
1052 *span,
1053 Arc::new(rewrite_import_uses_expr(
1054 f,
1055 bound,
1056 aliases,
1057 imported_values,
1058 shadowed_values,
1059 )),
1060 Arc::new(rewrite_import_uses_expr(
1061 x,
1062 bound,
1063 aliases,
1064 imported_values,
1065 shadowed_values,
1066 )),
1067 ),
1068 Expr::Ite(span, c, t, e) => Expr::Ite(
1069 *span,
1070 Arc::new(rewrite_import_uses_expr(
1071 c,
1072 bound,
1073 aliases,
1074 imported_values,
1075 shadowed_values,
1076 )),
1077 Arc::new(rewrite_import_uses_expr(
1078 t,
1079 bound,
1080 aliases,
1081 imported_values,
1082 shadowed_values,
1083 )),
1084 Arc::new(rewrite_import_uses_expr(
1085 e,
1086 bound,
1087 aliases,
1088 imported_values,
1089 shadowed_values,
1090 )),
1091 ),
1092 Expr::Ann(span, e, t) => Expr::Ann(
1093 *span,
1094 Arc::new(rewrite_import_uses_expr(
1095 e,
1096 bound,
1097 aliases,
1098 imported_values,
1099 shadowed_values,
1100 )),
1101 rewrite_import_uses_type_expr(t, bound, aliases, shadowed_values),
1102 ),
1103 }
1104}
1105
1106fn rewrite_import_uses_pattern(
1107 pat: &Pattern,
1108 imported_values: &HashMap<Symbol, CanonicalSymbol>,
1109) -> Pattern {
1110 match pat {
1111 Pattern::Wildcard(span) => Pattern::Wildcard(*span),
1112 Pattern::Var(v) => Pattern::Var(v.clone()),
1113 Pattern::Named(span, name, args) => {
1114 let name = imported_values
1115 .get(&name.to_dotted_symbol())
1116 .map(|c| NameRef::Unqualified(c.symbol().clone()))
1117 .unwrap_or_else(|| name.clone());
1118 let args = args
1119 .iter()
1120 .map(|p| rewrite_import_uses_pattern(p, imported_values))
1121 .collect();
1122 Pattern::Named(*span, name, args)
1123 }
1124 Pattern::Tuple(span, elems) => Pattern::Tuple(
1125 *span,
1126 elems
1127 .iter()
1128 .map(|p| rewrite_import_uses_pattern(p, imported_values))
1129 .collect(),
1130 ),
1131 Pattern::List(span, elems) => Pattern::List(
1132 *span,
1133 elems
1134 .iter()
1135 .map(|p| rewrite_import_uses_pattern(p, imported_values))
1136 .collect(),
1137 ),
1138 Pattern::Cons(span, head, tail) => Pattern::Cons(
1139 *span,
1140 Box::new(rewrite_import_uses_pattern(head, imported_values)),
1141 Box::new(rewrite_import_uses_pattern(tail, imported_values)),
1142 ),
1143 Pattern::Dict(span, fields) => Pattern::Dict(
1144 *span,
1145 fields
1146 .iter()
1147 .map(|(name, p)| {
1148 (
1149 name.clone(),
1150 rewrite_import_uses_pattern(p, imported_values),
1151 )
1152 })
1153 .collect(),
1154 ),
1155 }
1156}
1157
1158fn rewrite_import_uses_class_name(
1159 class: &NameRef,
1160 bound: &HashSet<Symbol>,
1161 aliases: &HashMap<Symbol, ModuleExports>,
1162 shadowed_values: Option<&HashSet<Symbol>>,
1163) -> NameRef {
1164 let Some((alias_sym, member_sym)) = qualified_alias_member(class) else {
1165 return class.clone();
1166 };
1167 if !alias_is_visible(alias_sym, bound, shadowed_values) {
1168 return class.clone();
1169 }
1170 let Some(exports) = aliases.get(alias_sym) else {
1171 return class.clone();
1172 };
1173 exports
1174 .classes
1175 .get(member_sym)
1176 .map(|s| s.symbol().clone())
1177 .map(NameRef::Unqualified)
1178 .unwrap_or_else(|| class.clone())
1179}
1180
1181fn qualified_alias_member(name: &NameRef) -> Option<(&Symbol, &Symbol)> {
1182 match name {
1183 NameRef::Qualified(_, segments) if segments.len() == 2 => {
1184 Some((&segments[0], &segments[1]))
1185 }
1186 _ => None,
1187 }
1188}
1189
1190fn rewrite_import_uses_type_expr(
1191 ty: &TypeExpr,
1192 bound: &HashSet<Symbol>,
1193 aliases: &HashMap<Symbol, ModuleExports>,
1194 shadowed_values: Option<&HashSet<Symbol>>,
1195) -> TypeExpr {
1196 match ty {
1197 TypeExpr::Name(span, name) => {
1198 let Some((alias_sym, member_sym)) = qualified_alias_member(name) else {
1199 return TypeExpr::Name(*span, name.clone());
1200 };
1201 if !alias_is_visible(alias_sym, bound, shadowed_values) {
1202 return TypeExpr::Name(*span, name.clone());
1203 }
1204 let Some(exports) = aliases.get(alias_sym) else {
1205 return TypeExpr::Name(*span, name.clone());
1206 };
1207 if let Some(new) = exports.types.get(member_sym) {
1208 TypeExpr::Name(*span, NameRef::Unqualified(new.symbol().clone()))
1209 } else if let Some(new) = exports.classes.get(member_sym) {
1210 TypeExpr::Name(*span, NameRef::Unqualified(new.symbol().clone()))
1211 } else {
1212 TypeExpr::Name(*span, name.clone())
1213 }
1214 }
1215 TypeExpr::App(span, f, x) => TypeExpr::App(
1216 *span,
1217 Box::new(rewrite_import_uses_type_expr(
1218 f,
1219 bound,
1220 aliases,
1221 shadowed_values,
1222 )),
1223 Box::new(rewrite_import_uses_type_expr(
1224 x,
1225 bound,
1226 aliases,
1227 shadowed_values,
1228 )),
1229 ),
1230 TypeExpr::Fun(span, a, b) => TypeExpr::Fun(
1231 *span,
1232 Box::new(rewrite_import_uses_type_expr(
1233 a,
1234 bound,
1235 aliases,
1236 shadowed_values,
1237 )),
1238 Box::new(rewrite_import_uses_type_expr(
1239 b,
1240 bound,
1241 aliases,
1242 shadowed_values,
1243 )),
1244 ),
1245 TypeExpr::Tuple(span, elems) => TypeExpr::Tuple(
1246 *span,
1247 elems
1248 .iter()
1249 .map(|e| rewrite_import_uses_type_expr(e, bound, aliases, shadowed_values))
1250 .collect(),
1251 ),
1252 TypeExpr::Record(span, fields) => TypeExpr::Record(
1253 *span,
1254 fields
1255 .iter()
1256 .map(|(name, ty)| {
1257 (
1258 name.clone(),
1259 rewrite_import_uses_type_expr(ty, bound, aliases, shadowed_values),
1260 )
1261 })
1262 .collect(),
1263 ),
1264 }
1265}
1266
1267fn rewrite_import_uses(
1268 program: &Program,
1269 aliases: &HashMap<Symbol, ModuleExports>,
1270 imported_values: &HashMap<Symbol, CanonicalSymbol>,
1271 shadowed_values: Option<&HashSet<Symbol>>,
1272) -> Program {
1273 let decl_bound = HashSet::new();
1274 let decls = program
1275 .decls
1276 .iter()
1277 .map(|decl| match decl {
1278 Decl::Fn(fd) => {
1279 let mut bound: HashSet<Symbol> =
1280 fd.params.iter().map(|(v, _)| v.name.clone()).collect();
1281 let body = Arc::new(rewrite_import_uses_expr(
1282 fd.body.as_ref(),
1283 &mut bound,
1284 aliases,
1285 imported_values,
1286 shadowed_values,
1287 ));
1288 Decl::Fn(FnDecl {
1289 span: fd.span,
1290 is_pub: fd.is_pub,
1291 name: fd.name.clone(),
1292 params: fd
1293 .params
1294 .iter()
1295 .map(|(v, t)| {
1296 (
1297 v.clone(),
1298 rewrite_import_uses_type_expr(
1299 t,
1300 &decl_bound,
1301 aliases,
1302 shadowed_values,
1303 ),
1304 )
1305 })
1306 .collect(),
1307 ret: rewrite_import_uses_type_expr(
1308 &fd.ret,
1309 &decl_bound,
1310 aliases,
1311 shadowed_values,
1312 ),
1313 constraints: fd
1314 .constraints
1315 .iter()
1316 .map(|c| TypeConstraint {
1317 class: rewrite_import_uses_class_name(
1318 &c.class,
1319 &decl_bound,
1320 aliases,
1321 shadowed_values,
1322 ),
1323 typ: rewrite_import_uses_type_expr(
1324 &c.typ,
1325 &decl_bound,
1326 aliases,
1327 shadowed_values,
1328 ),
1329 })
1330 .collect(),
1331 body,
1332 })
1333 }
1334 Decl::DeclareFn(df) => Decl::DeclareFn(DeclareFnDecl {
1335 span: df.span,
1336 is_pub: df.is_pub,
1337 name: df.name.clone(),
1338 params: df
1339 .params
1340 .iter()
1341 .map(|(v, t)| {
1342 (
1343 v.clone(),
1344 rewrite_import_uses_type_expr(t, &decl_bound, aliases, shadowed_values),
1345 )
1346 })
1347 .collect(),
1348 ret: rewrite_import_uses_type_expr(&df.ret, &decl_bound, aliases, shadowed_values),
1349 constraints: df
1350 .constraints
1351 .iter()
1352 .map(|c| TypeConstraint {
1353 class: rewrite_import_uses_class_name(
1354 &c.class,
1355 &decl_bound,
1356 aliases,
1357 shadowed_values,
1358 ),
1359 typ: rewrite_import_uses_type_expr(
1360 &c.typ,
1361 &decl_bound,
1362 aliases,
1363 shadowed_values,
1364 ),
1365 })
1366 .collect(),
1367 }),
1368 Decl::Type(td) => Decl::Type(TypeDecl {
1369 span: td.span,
1370 is_pub: td.is_pub,
1371 name: td.name.clone(),
1372 params: td.params.clone(),
1373 variants: td
1374 .variants
1375 .iter()
1376 .map(|v| rexlang_ast::expr::TypeVariant {
1377 name: v.name.clone(),
1378 args: v
1379 .args
1380 .iter()
1381 .map(|t| {
1382 rewrite_import_uses_type_expr(
1383 t,
1384 &decl_bound,
1385 aliases,
1386 shadowed_values,
1387 )
1388 })
1389 .collect(),
1390 })
1391 .collect(),
1392 }),
1393 Decl::Class(cd) => Decl::Class(rexlang_ast::expr::ClassDecl {
1394 span: cd.span,
1395 is_pub: cd.is_pub,
1396 name: cd.name.clone(),
1397 params: cd.params.clone(),
1398 supers: cd
1399 .supers
1400 .iter()
1401 .map(|c| TypeConstraint {
1402 class: rewrite_import_uses_class_name(
1403 &c.class,
1404 &decl_bound,
1405 aliases,
1406 shadowed_values,
1407 ),
1408 typ: rewrite_import_uses_type_expr(
1409 &c.typ,
1410 &decl_bound,
1411 aliases,
1412 shadowed_values,
1413 ),
1414 })
1415 .collect(),
1416 methods: cd
1417 .methods
1418 .iter()
1419 .map(|m| rexlang_ast::expr::ClassMethodSig {
1420 name: m.name.clone(),
1421 typ: rewrite_import_uses_type_expr(
1422 &m.typ,
1423 &decl_bound,
1424 aliases,
1425 shadowed_values,
1426 ),
1427 })
1428 .collect(),
1429 }),
1430 Decl::Instance(inst) => {
1431 let methods = inst
1432 .methods
1433 .iter()
1434 .map(|m| {
1435 let mut bound = HashSet::new();
1436 let body = Arc::new(rewrite_import_uses_expr(
1437 m.body.as_ref(),
1438 &mut bound,
1439 aliases,
1440 imported_values,
1441 shadowed_values,
1442 ));
1443 rexlang_ast::expr::InstanceMethodImpl {
1444 name: m.name.clone(),
1445 body,
1446 }
1447 })
1448 .collect();
1449 Decl::Instance(InstanceDecl {
1450 span: inst.span,
1451 is_pub: inst.is_pub,
1452 class: rewrite_import_uses_class_name(
1453 &NameRef::from_dotted(inst.class.as_ref()),
1454 &decl_bound,
1455 aliases,
1456 shadowed_values,
1457 )
1458 .to_dotted_symbol(),
1459 head: rewrite_import_uses_type_expr(
1460 &inst.head,
1461 &decl_bound,
1462 aliases,
1463 shadowed_values,
1464 ),
1465 context: inst
1466 .context
1467 .iter()
1468 .map(|c| TypeConstraint {
1469 class: rewrite_import_uses_class_name(
1470 &c.class,
1471 &decl_bound,
1472 aliases,
1473 shadowed_values,
1474 ),
1475 typ: rewrite_import_uses_type_expr(
1476 &c.typ,
1477 &decl_bound,
1478 aliases,
1479 shadowed_values,
1480 ),
1481 })
1482 .collect(),
1483 methods,
1484 })
1485 }
1486 other => other.clone(),
1487 })
1488 .collect();
1489
1490 let mut bound = HashSet::new();
1491 let expr = Arc::new(rewrite_import_uses_expr(
1492 program.expr.as_ref(),
1493 &mut bound,
1494 aliases,
1495 imported_values,
1496 shadowed_values,
1497 ));
1498 Program { decls, expr }
1499}
1500
1501fn validate_import_uses_expr(
1502 expr: &Expr,
1503 bound: &mut HashSet<Symbol>,
1504 aliases: &HashMap<Symbol, ModuleExports>,
1505 shadowed_values: Option<&HashSet<Symbol>>,
1506) -> Result<(), EngineError> {
1507 match expr {
1508 Expr::Project(_, base, field) => {
1509 if let Expr::Var(v) = base.as_ref()
1510 && alias_is_visible(&v.name, bound, shadowed_values)
1511 && let Some(exports) = aliases.get(&v.name)
1512 && !exports.values.contains_key(field)
1513 {
1514 return Err(crate::ModuleError::MissingExport {
1515 module: v.name.clone(),
1516 export: field.clone(),
1517 }
1518 .into());
1519 }
1520 validate_import_uses_expr(base, bound, aliases, shadowed_values)
1521 }
1522 Expr::Lam(_, _, param, ann, constraints, body) => {
1523 if let Some(ann) = ann {
1524 validate_import_uses_type_expr(ann, bound, aliases, shadowed_values)?;
1525 }
1526 for c in constraints {
1527 validate_import_uses_class_name(&c.class, bound, aliases, shadowed_values)?;
1528 validate_import_uses_type_expr(&c.typ, bound, aliases, shadowed_values)?;
1529 }
1530 bound.insert(param.name.clone());
1531 let res = validate_import_uses_expr(body, bound, aliases, shadowed_values);
1532 bound.remove(¶m.name);
1533 res
1534 }
1535 Expr::Let(_, var, ann, val, body) => {
1536 if let Some(ann) = ann {
1537 validate_import_uses_type_expr(ann, bound, aliases, shadowed_values)?;
1538 }
1539 validate_import_uses_expr(val, bound, aliases, shadowed_values)?;
1540 bound.insert(var.name.clone());
1541 let res = validate_import_uses_expr(body, bound, aliases, shadowed_values);
1542 bound.remove(&var.name);
1543 res
1544 }
1545 Expr::LetRec(_, bindings, body) => {
1546 for (_, ann, _) in bindings {
1547 if let Some(ann) = ann {
1548 validate_import_uses_type_expr(ann, bound, aliases, shadowed_values)?;
1549 }
1550 }
1551 let names: Vec<Symbol> = bindings
1552 .iter()
1553 .map(|(var, _, _)| var.name.clone())
1554 .collect();
1555 for name in &names {
1556 bound.insert(name.clone());
1557 }
1558 for (_, _ann, def) in bindings {
1559 validate_import_uses_expr(def, bound, aliases, shadowed_values)?;
1560 }
1561 let res = validate_import_uses_expr(body, bound, aliases, shadowed_values);
1562 for name in &names {
1563 bound.remove(name);
1564 }
1565 res
1566 }
1567 Expr::Match(_, scrutinee, arms) => {
1568 validate_import_uses_expr(scrutinee, bound, aliases, shadowed_values)?;
1569 for (pat, arm_expr) in arms {
1570 let mut binds = Vec::new();
1571 collect_pattern_bindings(pat, &mut binds);
1572 for b in &binds {
1573 bound.insert(b.clone());
1574 }
1575 let res = validate_import_uses_expr(arm_expr, bound, aliases, shadowed_values);
1576 for b in &binds {
1577 bound.remove(b);
1578 }
1579 res?;
1580 }
1581 Ok(())
1582 }
1583 Expr::Tuple(_, elems) | Expr::List(_, elems) => {
1584 for e in elems {
1585 validate_import_uses_expr(e, bound, aliases, shadowed_values)?;
1586 }
1587 Ok(())
1588 }
1589 Expr::Dict(_, kvs) => {
1590 for v in kvs.values() {
1591 validate_import_uses_expr(v, bound, aliases, shadowed_values)?;
1592 }
1593 Ok(())
1594 }
1595 Expr::RecordUpdate(_, base, updates) => {
1596 validate_import_uses_expr(base, bound, aliases, shadowed_values)?;
1597 for v in updates.values() {
1598 validate_import_uses_expr(v, bound, aliases, shadowed_values)?;
1599 }
1600 Ok(())
1601 }
1602 Expr::App(_, f, x) => {
1603 validate_import_uses_expr(f, bound, aliases, shadowed_values)?;
1604 validate_import_uses_expr(x, bound, aliases, shadowed_values)
1605 }
1606 Expr::Ite(_, c, t, e) => {
1607 validate_import_uses_expr(c, bound, aliases, shadowed_values)?;
1608 validate_import_uses_expr(t, bound, aliases, shadowed_values)?;
1609 validate_import_uses_expr(e, bound, aliases, shadowed_values)
1610 }
1611 Expr::Ann(_, e, t) => {
1612 validate_import_uses_expr(e, bound, aliases, shadowed_values)?;
1613 validate_import_uses_type_expr(t, bound, aliases, shadowed_values)
1614 }
1615 Expr::Var(..)
1616 | Expr::Bool(..)
1617 | Expr::Uint(..)
1618 | Expr::Int(..)
1619 | Expr::Float(..)
1620 | Expr::String(..)
1621 | Expr::Uuid(..)
1622 | Expr::DateTime(..)
1623 | Expr::Hole(..) => Ok(()),
1624 }
1625}
1626
1627fn validate_import_uses_class_name(
1628 class: &NameRef,
1629 bound: &HashSet<Symbol>,
1630 aliases: &HashMap<Symbol, ModuleExports>,
1631 shadowed_values: Option<&HashSet<Symbol>>,
1632) -> Result<(), EngineError> {
1633 let Some((alias_sym, member_sym)) = qualified_alias_member(class) else {
1634 return Ok(());
1635 };
1636 if !alias_is_visible(alias_sym, bound, shadowed_values) {
1637 return Ok(());
1638 }
1639 let Some(exports) = aliases.get(alias_sym) else {
1640 return Ok(());
1641 };
1642 if exports.classes.contains_key(member_sym) {
1643 return Ok(());
1644 }
1645 Err(crate::ModuleError::MissingExport {
1646 module: alias_sym.clone(),
1647 export: member_sym.clone(),
1648 }
1649 .into())
1650}
1651
1652fn validate_import_uses_type_expr(
1653 ty: &TypeExpr,
1654 bound: &HashSet<Symbol>,
1655 aliases: &HashMap<Symbol, ModuleExports>,
1656 shadowed_values: Option<&HashSet<Symbol>>,
1657) -> Result<(), EngineError> {
1658 match ty {
1659 TypeExpr::Name(_, name) => {
1660 let Some((alias_sym, member_sym)) = qualified_alias_member(name) else {
1661 return Ok(());
1662 };
1663 if !alias_is_visible(alias_sym, bound, shadowed_values) {
1664 return Ok(());
1665 }
1666 let Some(exports) = aliases.get(alias_sym) else {
1667 return Ok(());
1668 };
1669 if exports.types.contains_key(member_sym) || exports.classes.contains_key(member_sym) {
1670 Ok(())
1671 } else {
1672 Err(crate::ModuleError::MissingExport {
1673 module: alias_sym.clone(),
1674 export: member_sym.clone(),
1675 }
1676 .into())
1677 }
1678 }
1679 TypeExpr::App(_, f, x) => {
1680 validate_import_uses_type_expr(f, bound, aliases, shadowed_values)?;
1681 validate_import_uses_type_expr(x, bound, aliases, shadowed_values)
1682 }
1683 TypeExpr::Fun(_, a, b) => {
1684 validate_import_uses_type_expr(a, bound, aliases, shadowed_values)?;
1685 validate_import_uses_type_expr(b, bound, aliases, shadowed_values)
1686 }
1687 TypeExpr::Tuple(_, elems) => {
1688 for e in elems {
1689 validate_import_uses_type_expr(e, bound, aliases, shadowed_values)?;
1690 }
1691 Ok(())
1692 }
1693 TypeExpr::Record(_, fields) => {
1694 for (_, t) in fields {
1695 validate_import_uses_type_expr(t, bound, aliases, shadowed_values)?;
1696 }
1697 Ok(())
1698 }
1699 }
1700}
1701
1702fn validate_import_uses(
1703 program: &Program,
1704 aliases: &HashMap<Symbol, ModuleExports>,
1705 shadowed_values: Option<&HashSet<Symbol>>,
1706) -> Result<(), EngineError> {
1707 for decl in &program.decls {
1708 match decl {
1709 Decl::Fn(fd) => {
1710 for (_, t) in &fd.params {
1711 validate_import_uses_type_expr(t, &HashSet::new(), aliases, shadowed_values)?;
1712 }
1713 validate_import_uses_type_expr(&fd.ret, &HashSet::new(), aliases, shadowed_values)?;
1714 for c in &fd.constraints {
1715 validate_import_uses_class_name(
1716 &c.class,
1717 &HashSet::new(),
1718 aliases,
1719 shadowed_values,
1720 )?;
1721 validate_import_uses_type_expr(
1722 &c.typ,
1723 &HashSet::new(),
1724 aliases,
1725 shadowed_values,
1726 )?;
1727 }
1728 let mut bound: HashSet<Symbol> =
1729 fd.params.iter().map(|(v, _)| v.name.clone()).collect();
1730 validate_import_uses_expr(fd.body.as_ref(), &mut bound, aliases, shadowed_values)?;
1731 }
1732 Decl::DeclareFn(df) => {
1733 for (_, t) in &df.params {
1734 validate_import_uses_type_expr(t, &HashSet::new(), aliases, shadowed_values)?;
1735 }
1736 validate_import_uses_type_expr(&df.ret, &HashSet::new(), aliases, shadowed_values)?;
1737 for c in &df.constraints {
1738 validate_import_uses_class_name(
1739 &c.class,
1740 &HashSet::new(),
1741 aliases,
1742 shadowed_values,
1743 )?;
1744 validate_import_uses_type_expr(
1745 &c.typ,
1746 &HashSet::new(),
1747 aliases,
1748 shadowed_values,
1749 )?;
1750 }
1751 }
1752 Decl::Type(td) => {
1753 for v in &td.variants {
1754 for t in &v.args {
1755 validate_import_uses_type_expr(
1756 t,
1757 &HashSet::new(),
1758 aliases,
1759 shadowed_values,
1760 )?;
1761 }
1762 }
1763 }
1764 Decl::Class(cd) => {
1765 for c in &cd.supers {
1766 validate_import_uses_class_name(
1767 &c.class,
1768 &HashSet::new(),
1769 aliases,
1770 shadowed_values,
1771 )?;
1772 validate_import_uses_type_expr(
1773 &c.typ,
1774 &HashSet::new(),
1775 aliases,
1776 shadowed_values,
1777 )?;
1778 }
1779 for m in &cd.methods {
1780 validate_import_uses_type_expr(
1781 &m.typ,
1782 &HashSet::new(),
1783 aliases,
1784 shadowed_values,
1785 )?;
1786 }
1787 }
1788 Decl::Instance(inst) => {
1789 validate_import_uses_class_name(
1790 &NameRef::from_dotted(inst.class.as_ref()),
1791 &HashSet::new(),
1792 aliases,
1793 shadowed_values,
1794 )?;
1795 validate_import_uses_type_expr(
1796 &inst.head,
1797 &HashSet::new(),
1798 aliases,
1799 shadowed_values,
1800 )?;
1801 for c in &inst.context {
1802 validate_import_uses_class_name(
1803 &c.class,
1804 &HashSet::new(),
1805 aliases,
1806 shadowed_values,
1807 )?;
1808 validate_import_uses_type_expr(
1809 &c.typ,
1810 &HashSet::new(),
1811 aliases,
1812 shadowed_values,
1813 )?;
1814 }
1815 for m in &inst.methods {
1816 let mut bound = HashSet::new();
1817 validate_import_uses_expr(
1818 m.body.as_ref(),
1819 &mut bound,
1820 aliases,
1821 shadowed_values,
1822 )?;
1823 }
1824 }
1825 Decl::Import(..) => {}
1826 }
1827 }
1828 let mut bound = HashSet::new();
1829 validate_import_uses_expr(program.expr.as_ref(), &mut bound, aliases, shadowed_values)
1830}
1831
1832fn decl_value_names(decls: &[Decl]) -> HashSet<Symbol> {
1833 let mut out = HashSet::new();
1834 for decl in decls {
1835 match decl {
1836 Decl::Fn(fd) => {
1837 out.insert(fd.name.name.clone());
1838 }
1839 Decl::DeclareFn(df) => {
1840 out.insert(df.name.name.clone());
1841 }
1842 Decl::Type(td) => {
1843 for variant in &td.variants {
1844 out.insert(variant.name.clone());
1845 }
1846 }
1847 Decl::Class(..) | Decl::Instance(..) | Decl::Import(..) => {}
1848 }
1849 }
1850 out
1851}
1852
1853fn interface_decls_from_program(program: &Program) -> Vec<Decl> {
1854 let mut out = Vec::new();
1855 for decl in &program.decls {
1856 match decl {
1857 Decl::Fn(fd) if fd.is_pub => out.push(Decl::DeclareFn(DeclareFnDecl {
1858 span: fd.span,
1859 is_pub: fd.is_pub,
1860 name: fd.name.clone(),
1861 params: fd.params.clone(),
1862 ret: fd.ret.clone(),
1863 constraints: fd.constraints.clone(),
1864 })),
1865 Decl::Instance(..)
1866 | Decl::Import(..)
1867 | Decl::Fn(..)
1868 | Decl::DeclareFn(..)
1869 | Decl::Type(..)
1870 | Decl::Class(..) => {}
1871 }
1872 }
1873 out
1874}
1875
1876fn graph_imports_for_program(program: &Program, default_imports: &[String]) -> Vec<ImportDecl> {
1877 let mut out = Vec::new();
1878 for decl in &program.decls {
1879 if let Decl::Import(import_decl) = decl {
1880 out.push(import_decl.clone());
1881 }
1882 }
1883 for module_name in default_imports {
1884 let alias = intern(module_name);
1885 if contains_import_alias(&program.decls, &alias) {
1886 continue;
1887 }
1888 out.push(default_import_decl(module_name));
1889 }
1890 out
1891}
1892
1893fn tarjan_scc_module_ids(
1894 nodes: &[ModuleId],
1895 edges: &HashMap<ModuleId, Vec<ModuleId>>,
1896) -> Vec<Vec<ModuleId>> {
1897 #[derive(Default)]
1908 struct TarjanState {
1909 index: usize,
1910 index_of: HashMap<ModuleId, usize>,
1911 lowlink: HashMap<ModuleId, usize>,
1912 stack: Vec<ModuleId>,
1913 on_stack: HashSet<ModuleId>,
1914 components: Vec<Vec<ModuleId>>,
1915 }
1916
1917 fn strong_connect(
1918 v: &ModuleId,
1919 edges: &HashMap<ModuleId, Vec<ModuleId>>,
1920 st: &mut TarjanState,
1921 ) {
1922 st.index_of.insert(v.clone(), st.index);
1923 st.lowlink.insert(v.clone(), st.index);
1924 st.index += 1;
1925
1926 st.stack.push(v.clone());
1927 st.on_stack.insert(v.clone());
1928
1929 if let Some(neighbors) = edges.get(v) {
1930 for w in neighbors {
1931 if !st.index_of.contains_key(w) {
1932 strong_connect(w, edges, st);
1933 let lw = st.lowlink.get(w).copied();
1934 if let (Some(lw), Some(lv)) = (lw, st.lowlink.get_mut(v)) {
1935 *lv = (*lv).min(lw);
1936 }
1937 } else if st.on_stack.contains(w) {
1938 let iw = st.index_of.get(w).copied();
1939 if let (Some(iw), Some(lv)) = (iw, st.lowlink.get_mut(v)) {
1940 *lv = (*lv).min(iw);
1941 }
1942 }
1943 }
1944 }
1945
1946 let is_root = st.lowlink.get(v) == st.index_of.get(v);
1948 if is_root {
1949 let mut component = Vec::new();
1950 loop {
1951 let Some(w) = st.stack.pop() else {
1952 break;
1953 };
1954 st.on_stack.remove(&w);
1955 component.push(w.clone());
1956 if &w == v {
1957 break;
1958 }
1959 }
1960 st.components.push(component);
1961 }
1962 }
1963
1964 let mut st = TarjanState::default();
1965 for node in nodes {
1966 if !st.index_of.contains_key(node) {
1967 strong_connect(node, edges, &mut st);
1968 }
1969 }
1970 st.components
1971}
1972
1973fn exports_from_program(program: &Program, prefix: &str, module_id: &ModuleId) -> ModuleExports {
1974 let (value_renames, type_renames, class_renames) = collect_local_renames(program, prefix);
1975 let module_key = module_key_for_module(module_id);
1976
1977 let mut values = HashMap::new();
1978 let mut types = HashMap::new();
1979 let mut classes = HashMap::new();
1980
1981 for decl in &program.decls {
1982 match decl {
1983 Decl::Fn(fd) if fd.is_pub => {
1984 if let Some(internal) = value_renames.get(&fd.name.name) {
1985 values.insert(
1986 fd.name.name.clone(),
1987 CanonicalSymbol::from_symbol(
1988 module_key,
1989 SymbolKind::Value,
1990 fd.name.name.clone(),
1991 internal.clone(),
1992 ),
1993 );
1994 }
1995 }
1996 Decl::DeclareFn(df) if df.is_pub => {
1997 if let Some(internal) = value_renames.get(&df.name.name) {
1998 values.insert(
1999 df.name.name.clone(),
2000 CanonicalSymbol::from_symbol(
2001 module_key,
2002 SymbolKind::Value,
2003 df.name.name.clone(),
2004 internal.clone(),
2005 ),
2006 );
2007 }
2008 }
2009 Decl::Type(td) if td.is_pub => {
2010 if let Some(internal) = type_renames.get(&td.name) {
2011 types.insert(
2012 td.name.clone(),
2013 CanonicalSymbol::from_symbol(
2014 module_key,
2015 SymbolKind::Type,
2016 td.name.clone(),
2017 internal.clone(),
2018 ),
2019 );
2020 }
2021 for variant in &td.variants {
2022 if let Some(internal) = value_renames.get(&variant.name) {
2023 values.insert(
2024 variant.name.clone(),
2025 CanonicalSymbol::from_symbol(
2026 module_key,
2027 SymbolKind::Value,
2028 variant.name.clone(),
2029 internal.clone(),
2030 ),
2031 );
2032 }
2033 }
2034 }
2035 Decl::Class(cd) if cd.is_pub => {
2036 if let Some(internal) = class_renames.get(&cd.name) {
2037 classes.insert(
2038 cd.name.clone(),
2039 CanonicalSymbol::from_symbol(
2040 module_key,
2041 SymbolKind::Class,
2042 cd.name.clone(),
2043 internal.clone(),
2044 ),
2045 );
2046 }
2047 }
2048 Decl::Instance(..)
2049 | Decl::Import(..)
2050 | Decl::Fn(..)
2051 | Decl::DeclareFn(..)
2052 | Decl::Type(..)
2053 | Decl::Class(..) => {}
2054 }
2055 }
2056
2057 ModuleExports {
2058 values,
2059 types,
2060 classes,
2061 }
2062}
2063
2064fn parse_program_from_source(
2065 source: &str,
2066 context: Option<&ModuleId>,
2067 gas: Option<&mut GasMeter>,
2068) -> Result<Program, EngineError> {
2069 let tokens = Token::tokenize(source).map_err(|e| match context {
2070 Some(id) => EngineError::from(crate::ModuleError::LexInModule {
2071 module: id.clone(),
2072 source: e,
2073 }),
2074 None => EngineError::from(crate::ModuleError::Lex { source: e }),
2075 })?;
2076 let mut parser = RexParser::new(tokens);
2077 let program = match gas {
2078 Some(gas) => parser.parse_program(gas),
2079 None => parser.parse_program(&mut GasMeter::default()),
2080 }
2081 .map_err(|errs| match context {
2082 Some(id) => EngineError::from(crate::ModuleError::ParseInModule {
2083 module: id.clone(),
2084 errors: errs,
2085 }),
2086 None => EngineError::from(crate::ModuleError::Parse { errors: errs }),
2087 })?;
2088 if let Some(module) = context
2089 && !matches!(program.expr.as_ref(), Expr::Tuple(_, elems) if elems.is_empty())
2090 {
2091 return Err(crate::ModuleError::TopLevelExprInModule {
2092 module: module.clone(),
2093 }
2094 .into());
2095 }
2096 Ok(program)
2097}
2098
2099impl<State> Engine<State>
2100where
2101 State: Clone + Send + Sync + 'static,
2102{
2103 fn source_fingerprint(source: &str) -> String {
2104 sha256_hex(source.as_bytes())
2105 }
2106
2107 fn refresh_if_stale(&mut self, resolved: &ResolvedModule) -> Result<String, EngineError> {
2108 let next = Self::source_fingerprint(&resolved.source);
2109 if let Some(prev) = self.module_source_fingerprints.get(&resolved.id)
2110 && prev != &next
2111 {
2112 self.invalidate_module_caches(&resolved.id)?;
2113 }
2114 Ok(next)
2115 }
2116
2117 fn remove_type_level_symbols_for_module_interface(&mut self, decls: &[Decl]) {
2118 for decl in decls {
2119 match decl {
2120 Decl::Fn(fd) => {
2121 self.type_system.env.remove(&fd.name.name);
2122 self.type_system.declared_values.remove(&fd.name.name);
2123 }
2124 Decl::DeclareFn(df) => {
2125 self.type_system.env.remove(&df.name.name);
2126 self.type_system.declared_values.remove(&df.name.name);
2127 }
2128 Decl::Type(td) => {
2129 self.type_system.adts.remove(&td.name);
2130 for variant in &td.variants {
2131 self.type_system.env.remove(&variant.name);
2132 self.type_system.declared_values.remove(&variant.name);
2133 }
2134 }
2135 Decl::Class(cd) => {
2136 self.type_system.classes.classes.remove(&cd.name);
2137 self.type_system.classes.instances.remove(&cd.name);
2138 self.type_system.class_info.remove(&cd.name);
2139 for method in &cd.methods {
2140 self.type_system.env.remove(&method.name);
2141 self.type_system.class_methods.remove(&method.name);
2142 }
2143 }
2144 Decl::Import(..) | Decl::Instance(..) => {}
2145 }
2146 }
2147 }
2148
2149 fn invalidate_module_caches(&mut self, id: &ModuleId) -> Result<(), EngineError> {
2150 if let Some(prev_interface) = self.module_interface_cache.get(id).cloned() {
2151 self.remove_type_level_symbols_for_module_interface(&prev_interface);
2152 }
2153 self.modules.invalidate(id)?;
2154 self.module_exports_cache.remove(id);
2155 self.module_interface_cache.remove(id);
2156 self.module_sources.remove(id);
2157 self.module_source_fingerprints.remove(id);
2158 self.published_cycle_interfaces.remove(id);
2159 Ok(())
2160 }
2161
2162 fn load_module_types_via_scc(
2163 &mut self,
2164 root: ResolvedModule,
2165 gas: &mut GasMeter,
2166 loaded: &mut HashMap<ModuleId, ModuleExports>,
2167 loading: &mut HashSet<ModuleId>,
2168 ) -> Result<ModuleExports, EngineError> {
2169 #[derive(Clone)]
2170 struct PendingModule {
2171 resolved: ResolvedModule,
2172 program: Program,
2173 prefix: String,
2174 }
2175
2176 if let Some(exports) = loaded.get(&root.id)
2177 && !loading.contains(&root.id)
2178 {
2179 return Ok(exports.clone());
2180 }
2181
2182 let mut pending: HashMap<ModuleId, PendingModule> = HashMap::new();
2183 let mut edges: HashMap<ModuleId, Vec<ModuleId>> = HashMap::new();
2184 let mut stack = vec![root.clone()];
2185
2186 while let Some(resolved) = stack.pop() {
2187 let fingerprint = self.refresh_if_stale(&resolved)?;
2188 if pending.contains_key(&resolved.id) {
2189 continue;
2190 }
2191 if loaded.contains_key(&resolved.id) && !loading.contains(&resolved.id) {
2192 continue;
2193 }
2194
2195 let prefix = prefix_for_module(&resolved.id);
2196 let program =
2197 parse_program_from_source(&resolved.source, Some(&resolved.id), Some(&mut *gas))?;
2198 let exports = exports_from_program(&program, &prefix, &resolved.id);
2199 loaded.insert(resolved.id.clone(), exports);
2200 loading.insert(resolved.id.clone());
2201 self.module_sources
2202 .insert(resolved.id.clone(), resolved.source.clone());
2203
2204 let imports = graph_imports_for_program(&program, self.default_imports());
2205 for import_decl in imports {
2206 let spec = import_specifier(&import_decl.path);
2207 if self.virtual_module_exports(spec_base_name(&spec)).is_some() {
2208 continue;
2209 }
2210 let imported = self.modules.resolve(ResolveRequest {
2211 module_name: spec,
2212 importer: Some(resolved.id.clone()),
2213 })?;
2214 edges
2215 .entry(resolved.id.clone())
2216 .or_default()
2217 .push(imported.id.clone());
2218 if (loading.contains(&imported.id) || !loaded.contains_key(&imported.id))
2219 && !pending.contains_key(&imported.id)
2220 {
2221 stack.push(imported);
2222 }
2223 }
2224
2225 let module_id = resolved.id.clone();
2226 pending.insert(
2227 module_id.clone(),
2228 PendingModule {
2229 resolved,
2230 program,
2231 prefix,
2232 },
2233 );
2234 self.module_source_fingerprints
2235 .insert(module_id, fingerprint);
2236 }
2237
2238 if pending.is_empty() {
2239 return loaded.get(&root.id).cloned().ok_or_else(|| {
2240 EngineError::Internal("missing module exports after SCC load".into())
2241 });
2242 }
2243
2244 let pending_ids: Vec<ModuleId> = pending.keys().cloned().collect();
2245 let sccs = tarjan_scc_module_ids(&pending_ids, &edges);
2246
2247 for component in sccs {
2250 for module_id in &component {
2251 let node = pending
2252 .get(module_id)
2253 .ok_or_else(|| EngineError::Internal("missing pending module node".into()))?;
2254 let rewritten = self.rewrite_program_with_imports(
2255 &node.program,
2256 Some(node.resolved.id.clone()),
2257 &node.prefix,
2258 gas,
2259 loaded,
2260 loading,
2261 )?;
2262 self.inject_decls(&rewritten.decls)?;
2263 }
2264 for module_id in component {
2265 loading.remove(&module_id);
2266 }
2267 }
2268
2269 loaded
2270 .get(&root.id)
2271 .cloned()
2272 .ok_or_else(|| EngineError::Internal("missing root exports after SCC load".into()))
2273 }
2274
2275 fn ensure_cycle_interfaces_published(
2276 &mut self,
2277 module_id: &ModuleId,
2278 ) -> Result<(), EngineError> {
2279 if self.published_cycle_interfaces.contains(module_id) {
2280 return Ok(());
2281 }
2282 let Some(decls) = self.module_interface_cache.get(module_id).cloned() else {
2283 return Ok(());
2284 };
2285 self.inject_decls(&decls)?;
2286 self.publish_runtime_interfaces(&decls)?;
2287 self.published_cycle_interfaces.insert(module_id.clone());
2288 Ok(())
2289 }
2290
2291 fn publish_runtime_interfaces(&mut self, decls: &[Decl]) -> Result<(), EngineError> {
2292 let mut signatures = Vec::new();
2293 for decl in decls {
2294 let Decl::DeclareFn(df) = decl else {
2295 continue;
2296 };
2297 signatures.push(df.clone());
2298 }
2299 self.publish_runtime_decl_interfaces(&signatures)
2300 }
2301
2302 #[async_recursion]
2303 async fn resolve_module_exports_from_import_decl_async(
2304 &mut self,
2305 import_decl: &ImportDecl,
2306 importer: Option<ModuleId>,
2307 gas: &mut GasMeter,
2308 ) -> Result<ModuleExports, EngineError> {
2309 let spec = import_specifier(&import_decl.path);
2310 if let Some(exports) = self.virtual_module_exports(spec_base_name(&spec)) {
2311 return Ok(exports);
2312 }
2313 let imported = self.modules.resolve(ResolveRequest {
2314 module_name: spec,
2315 importer,
2316 })?;
2317 self.refresh_if_stale(&imported)?;
2318 if let Some(exports) = self.module_exports_cache.get(&imported.id).cloned() {
2319 self.ensure_cycle_interfaces_published(&imported.id)?;
2320 return Ok(exports);
2321 }
2322 let inst = self.load_module_from_resolved(imported, gas).await?;
2323 Ok(inst.exports)
2324 }
2325
2326 async fn add_default_import_bindings(
2327 &mut self,
2328 bindings: &mut ImportBindings,
2329 decls: &[Decl],
2330 importer: Option<ModuleId>,
2331 forbidden_locals: &HashSet<Symbol>,
2332 existing_imported: Option<&HashSet<Symbol>>,
2333 gas: &mut GasMeter,
2334 ) -> Result<(), EngineError> {
2335 let existing_names: HashSet<Symbol> = existing_imported.cloned().unwrap_or_default();
2336 let default_imports = self.default_imports().to_vec();
2337 for module_name in default_imports {
2338 let alias = intern(&module_name);
2339 if contains_import_alias(decls, &alias) {
2340 continue;
2341 }
2342 let import_decl = default_import_decl(&module_name);
2343 let exports = self
2344 .resolve_module_exports_from_import_decl_async(&import_decl, importer.clone(), gas)
2345 .await?;
2346 for (local, target) in exports.values {
2347 if !forbidden_locals.contains(&local)
2348 && !existing_names.contains(&local)
2349 && !bindings.imported_values.contains_key(&local)
2350 {
2351 bindings.imported_values.insert(local, target);
2352 }
2353 }
2354 }
2355 Ok(())
2356 }
2357
2358 pub fn add_resolver<F>(&mut self, name: impl Into<String>, f: F)
2359 where
2360 F: Fn(ResolveRequest) -> Result<Option<ResolvedModule>, EngineError>
2361 + Send
2362 + Sync
2363 + 'static,
2364 {
2365 self.modules.add_resolver(name, wrap_resolver(f));
2366 }
2367
2368 pub fn add_default_resolvers(&mut self) {
2369 self.modules
2370 .add_resolver("stdlib", default_stdlib_resolver());
2371
2372 #[cfg(not(target_arch = "wasm32"))]
2373 self.modules.add_resolver("local", default_local_resolver());
2374
2375 #[cfg(all(not(target_arch = "wasm32"), feature = "github-imports"))]
2376 {
2377 self.modules
2378 .add_resolver("remote", default_github_resolver());
2379 }
2380 }
2381
2382 #[cfg(not(target_arch = "wasm32"))]
2383 pub fn add_include_resolver(&mut self, root: impl AsRef<Path>) -> Result<(), EngineError> {
2384 let canon =
2385 root.as_ref()
2386 .canonicalize()
2387 .map_err(|e| crate::ModuleError::InvalidIncludeRoot {
2388 path: root.as_ref().to_path_buf(),
2389 source: e,
2390 })?;
2391 self.modules.add_resolver(
2392 format!("include:{}", canon.display()),
2393 include_resolver(canon),
2394 );
2395 Ok(())
2396 }
2397
2398 #[cfg(target_arch = "wasm32")]
2399 pub fn add_include_resolver(&mut self, _root: impl AsRef<Path>) -> Result<(), EngineError> {
2400 Err(EngineError::UnsupportedExpr)
2401 }
2402
2403 #[async_recursion]
2404 async fn import_bindings_for_decls(
2405 &mut self,
2406 decls: &[Decl],
2407 importer: Option<ModuleId>,
2408 forbidden_locals: &HashSet<Symbol>,
2409 existing_imported: Option<&HashSet<Symbol>>,
2410 gas: &mut GasMeter,
2411 ) -> Result<ImportBindings, EngineError> {
2412 let mut bindings = ImportBindings::default();
2413 for decl in decls {
2414 let Decl::Import(import_decl) = decl else {
2415 continue;
2416 };
2417 let exports = self
2418 .resolve_module_exports_from_import_decl_async(import_decl, importer.clone(), gas)
2419 .await?;
2420 add_import_bindings(
2421 &mut bindings,
2422 import_decl,
2423 &exports,
2424 forbidden_locals,
2425 existing_imported,
2426 )?;
2427 }
2428 self.add_default_import_bindings(
2429 &mut bindings,
2430 decls,
2431 importer,
2432 forbidden_locals,
2433 existing_imported,
2434 gas,
2435 )
2436 .await?;
2437 Ok(bindings)
2438 }
2439
2440 #[async_recursion]
2441 async fn load_module_from_resolved(
2442 &mut self,
2443 resolved: ResolvedModule,
2444 gas: &mut GasMeter,
2445 ) -> Result<ModuleInstance, EngineError> {
2446 let source_fingerprint = self.refresh_if_stale(&resolved)?;
2447 if let Some(inst) = self.modules.cached(&resolved.id)? {
2448 return Ok(inst);
2449 }
2450
2451 self.modules.mark_loading(&resolved.id)?;
2452
2453 let prefix = prefix_for_module(&resolved.id);
2454 let program = parse_program_from_source(&resolved.source, Some(&resolved.id), Some(gas))?;
2455 self.module_sources
2456 .insert(resolved.id.clone(), resolved.source.clone());
2457 let exports = exports_from_program(&program, &prefix, &resolved.id);
2458 self.module_exports_cache
2459 .insert(resolved.id.clone(), exports.clone());
2460 let qualified = qualify_program(&program, &prefix);
2461 let interfaces = interface_decls_from_program(&qualified);
2462 self.module_interface_cache
2463 .insert(resolved.id.clone(), interfaces);
2464
2465 let local_values = decl_value_names(&program.decls);
2467 let import_bindings = self
2468 .import_bindings_for_decls(
2469 &program.decls,
2470 Some(resolved.id.clone()),
2471 &local_values,
2472 None,
2473 gas,
2474 )
2475 .await?;
2476
2477 validate_import_uses(&qualified, &import_bindings.alias_exports, None)?;
2479 let rewritten = rewrite_import_uses(
2480 &qualified,
2481 &import_bindings.alias_exports,
2482 &import_bindings.imported_values,
2483 None,
2484 );
2485
2486 self.inject_decls(&rewritten.decls)?;
2487 let init_value = self.heap.alloc_tuple(vec![])?;
2488 let init_type = Type::tuple(vec![]);
2489
2490 let inst = ModuleInstance {
2491 id: resolved.id.clone(),
2492 exports,
2493 init_value,
2494 init_type,
2495 source_fingerprint: Some(source_fingerprint.clone()),
2496 };
2497 self.modules.store_loaded(inst.clone())?;
2498 self.module_source_fingerprints
2499 .insert(resolved.id.clone(), source_fingerprint);
2500 Ok(inst)
2501 }
2502
2503 fn load_module_types_from_resolved(
2504 &mut self,
2505 resolved: ResolvedModule,
2506 gas: &mut GasMeter,
2507 loaded: &mut HashMap<ModuleId, ModuleExports>,
2508 loading: &mut HashSet<ModuleId>,
2509 ) -> Result<ModuleExports, EngineError> {
2510 if let Some(exports) = loaded.get(&resolved.id) {
2511 return Ok(exports.clone());
2512 }
2513
2514 if loading.contains(&resolved.id)
2515 && let Some(exports) = loaded.get(&resolved.id)
2516 {
2517 return Ok(exports.clone());
2518 }
2519 self.load_module_types_via_scc(resolved, gas, loaded, loading)
2520 }
2521
2522 fn resolve_module_exports_for_rewrite(
2523 &mut self,
2524 import_decl: &ImportDecl,
2525 importer: Option<ModuleId>,
2526 gas: &mut GasMeter,
2527 loaded: &mut HashMap<ModuleId, ModuleExports>,
2528 loading: &mut HashSet<ModuleId>,
2529 ) -> Result<ModuleExports, EngineError> {
2530 let spec = import_specifier(&import_decl.path);
2531 if let Some(exports) = self.virtual_module_exports(spec_base_name(&spec)) {
2532 return Ok(exports);
2533 }
2534 let imported = self.modules.resolve(ResolveRequest {
2535 module_name: spec,
2536 importer,
2537 })?;
2538 self.refresh_if_stale(&imported)?;
2539 self.load_module_types_from_resolved(imported, gas, loaded, loading)
2540 }
2541
2542 fn rewrite_program_with_imports(
2543 &mut self,
2544 program: &Program,
2545 importer: Option<ModuleId>,
2546 prefix: &str,
2547 gas: &mut GasMeter,
2548 loaded: &mut HashMap<ModuleId, ModuleExports>,
2549 loading: &mut HashSet<ModuleId>,
2550 ) -> Result<Program, EngineError> {
2551 let mut bindings = ImportBindings::default();
2552 let local_values = decl_value_names(&program.decls);
2553 for decl in &program.decls {
2554 let Decl::Import(import_decl) = decl else {
2555 continue;
2556 };
2557 let exports = self.resolve_module_exports_for_rewrite(
2558 import_decl,
2559 importer.clone(),
2560 gas,
2561 loaded,
2562 loading,
2563 )?;
2564 add_import_bindings(&mut bindings, import_decl, &exports, &local_values, None)?;
2565 }
2566
2567 let default_imports = self.default_imports().to_vec();
2568 for module_name in default_imports {
2569 let alias = intern(&module_name);
2570 if contains_import_alias(&program.decls, &alias) {
2571 continue;
2572 }
2573 let import_decl = default_import_decl(&module_name);
2574 let exports = self.resolve_module_exports_for_rewrite(
2575 &import_decl,
2576 importer.clone(),
2577 gas,
2578 loaded,
2579 loading,
2580 )?;
2581 for (local, target) in exports.values {
2582 if !local_values.contains(&local) && !bindings.imported_values.contains_key(&local)
2583 {
2584 bindings.imported_values.insert(local, target);
2585 }
2586 }
2587 }
2588
2589 let qualified = qualify_program(program, prefix);
2590 validate_import_uses(&qualified, &bindings.alias_exports, None)?;
2591 Ok(rewrite_import_uses(
2592 &qualified,
2593 &bindings.alias_exports,
2594 &bindings.imported_values,
2595 None,
2596 ))
2597 }
2598
2599 fn read_local_module_bytes(&self, path: &Path) -> Result<(ModuleId, Vec<u8>), EngineError> {
2600 let canon = path
2601 .canonicalize()
2602 .map_err(|e| crate::ModuleError::InvalidModulePath {
2603 path: path.to_path_buf(),
2604 source: e,
2605 })?;
2606 let bytes = std::fs::read(&canon).map_err(|e| crate::ModuleError::ReadFailed {
2607 path: canon.clone(),
2608 source: e,
2609 })?;
2610 Ok((ModuleId::Local { path: canon }, bytes))
2611 }
2612
2613 fn decode_local_module_source(
2614 &self,
2615 id: &ModuleId,
2616 bytes: Vec<u8>,
2617 ) -> Result<String, EngineError> {
2618 let path = match id {
2619 ModuleId::Local { path, .. } => path.clone(),
2620 other => {
2621 return Err(EngineError::Internal(format!(
2622 "decode_local_module_source called with non-local module id {other}"
2623 )));
2624 }
2625 };
2626 String::from_utf8(bytes).map_err(|e| {
2627 crate::ModuleError::NotUtf8 {
2628 kind: "local",
2629 path,
2630 source: e,
2631 }
2632 .into()
2633 })
2634 }
2635
2636 pub fn infer_module_file(
2637 &mut self,
2638 path: impl AsRef<Path>,
2639 gas: &mut GasMeter,
2640 ) -> Result<(Vec<Predicate>, Type), EngineError> {
2641 let (id, bytes) = self.read_local_module_bytes(path.as_ref())?;
2642 let source = self.decode_local_module_source(&id, bytes)?;
2643 self.infer_module_source(ResolvedModule { id, source }, gas)
2644 }
2645
2646 fn infer_module_source(
2647 &mut self,
2648 resolved: ResolvedModule,
2649 gas: &mut GasMeter,
2650 ) -> Result<(Vec<Predicate>, Type), EngineError> {
2651 let mut loaded: HashMap<ModuleId, ModuleExports> = HashMap::new();
2652 let mut loading: HashSet<ModuleId> = HashSet::new();
2653
2654 loading.insert(resolved.id.clone());
2655
2656 let prefix = prefix_for_module(&resolved.id);
2657 let program =
2658 parse_program_from_source(&resolved.source, Some(&resolved.id), Some(&mut *gas))?;
2659
2660 let rewritten = self.rewrite_program_with_imports(
2661 &program,
2662 Some(resolved.id.clone()),
2663 &prefix,
2664 gas,
2665 &mut loaded,
2666 &mut loading,
2667 )?;
2668 self.inject_decls(&rewritten.decls)?;
2669
2670 let (preds, ty) = self.infer_type(rewritten.expr.as_ref(), gas)?;
2671
2672 let exports = exports_from_program(&program, &prefix, &resolved.id);
2673 loaded.insert(resolved.id.clone(), exports);
2674 loading.remove(&resolved.id);
2675
2676 Ok((preds, ty))
2677 }
2678
2679 pub fn infer_snippet(
2680 &mut self,
2681 source: &str,
2682 gas: &mut GasMeter,
2683 ) -> Result<(Vec<Predicate>, Type), EngineError> {
2684 self.infer_snippet_with_gas_and_importer(source, gas, None)
2685 }
2686
2687 pub fn infer_snippet_at(
2688 &mut self,
2689 source: &str,
2690 importer_path: impl AsRef<Path>,
2691 gas: &mut GasMeter,
2692 ) -> Result<(Vec<Predicate>, Type), EngineError> {
2693 let path = importer_path.as_ref().to_path_buf();
2694 self.infer_snippet_with_gas_and_importer(source, gas, Some(path))
2695 }
2696
2697 fn infer_snippet_with_gas_and_importer(
2698 &mut self,
2699 source: &str,
2700 gas: &mut GasMeter,
2701 importer_path: Option<PathBuf>,
2702 ) -> Result<(Vec<Predicate>, Type), EngineError> {
2703 let program = parse_program_from_source(source, None, Some(&mut *gas))?;
2704
2705 let importer = importer_path.map(|p| ModuleId::Local { path: p });
2706
2707 let mut loaded: HashMap<ModuleId, ModuleExports> = HashMap::new();
2708 let mut loading: HashSet<ModuleId> = HashSet::new();
2709
2710 let prefix = format!("@snippet{}", Uuid::new_v4());
2711 let rewritten = self.rewrite_program_with_imports(
2712 &program,
2713 importer,
2714 &prefix,
2715 gas,
2716 &mut loaded,
2717 &mut loading,
2718 )?;
2719 self.inject_decls(&rewritten.decls)?;
2720 self.infer_type(rewritten.expr.as_ref(), gas)
2721 }
2722
2723 pub async fn eval_module_file(
2724 &mut self,
2725 path: impl AsRef<Path>,
2726 gas: &mut GasMeter,
2727 ) -> Result<(Pointer, Type), EngineError> {
2728 let (id, bytes) = self.read_local_module_bytes(path.as_ref())?;
2729 let source_fingerprint = sha256_hex(&bytes);
2730 if let Some(inst) = self.modules.cached(&id)? {
2731 if inst.source_fingerprint.as_deref() == Some(source_fingerprint.as_str()) {
2732 return Ok((inst.init_value, inst.init_type));
2733 }
2734 self.invalidate_module_caches(&id)?;
2737 }
2738 let source = self.decode_local_module_source(&id, bytes)?;
2739 let inst = self
2740 .load_module_from_resolved(ResolvedModule { id, source }, gas)
2741 .await?;
2742 Ok((inst.init_value, inst.init_type))
2743 }
2744
2745 pub async fn eval_module_source(
2746 &mut self,
2747 source: &str,
2748 gas: &mut GasMeter,
2749 ) -> Result<(Pointer, Type), EngineError> {
2750 let mut hasher = std::collections::hash_map::DefaultHasher::new();
2751 source.hash(&mut hasher);
2752 let id = ModuleId::Virtual(format!("<inline:{:016x}>", hasher.finish()));
2753 if let Some(inst) = self.modules.cached(&id)? {
2754 return Ok((inst.init_value, inst.init_type));
2755 }
2756 let inst = self
2757 .load_module_from_resolved(
2758 ResolvedModule {
2759 id,
2760 source: source.to_string(),
2761 },
2762 gas,
2763 )
2764 .await?;
2765 Ok((inst.init_value, inst.init_type))
2766 }
2767
2768 pub async fn eval_snippet(
2769 &mut self,
2770 source: &str,
2771 gas: &mut GasMeter,
2772 ) -> Result<(Pointer, Type), EngineError> {
2773 self.eval_snippet_with_gas_and_importer(source, gas, None)
2774 .await
2775 }
2776
2777 pub async fn eval_repl_program(
2778 &mut self,
2779 program: &Program,
2780 state: &mut ReplState,
2781 gas: &mut GasMeter,
2782 ) -> Result<(Pointer, Type), EngineError> {
2783 let importer = state
2784 .importer_path
2785 .as_ref()
2786 .map(|p| ModuleId::Local { path: p.clone() });
2787
2788 let mut local_values = state.defined_values.clone();
2789 local_values.extend(decl_value_names(&program.decls));
2790 let existing_imported: HashSet<Symbol> = state.imported_values.keys().cloned().collect();
2791 let import_bindings = self
2792 .import_bindings_for_decls(
2793 &program.decls,
2794 importer.clone(),
2795 &local_values,
2796 Some(&existing_imported),
2797 gas,
2798 )
2799 .await?;
2800 state.alias_exports.extend(import_bindings.alias_exports);
2801 state
2802 .imported_values
2803 .extend(import_bindings.imported_values);
2804
2805 let mut shadowed_values = state.defined_values.clone();
2806 shadowed_values.extend(decl_value_names(&program.decls));
2807
2808 validate_import_uses(program, &state.alias_exports, Some(&shadowed_values))?;
2809 let rewritten = rewrite_import_uses(
2810 program,
2811 &state.alias_exports,
2812 &state.imported_values,
2813 Some(&shadowed_values),
2814 );
2815
2816 self.inject_decls(&rewritten.decls)?;
2817 state
2818 .defined_values
2819 .extend(decl_value_names(&program.decls));
2820 self.eval(rewritten.expr.as_ref(), gas).await
2821 }
2822
2823 pub async fn eval_snippet_at(
2825 &mut self,
2826 source: &str,
2827 importer_path: impl AsRef<Path>,
2828 gas: &mut GasMeter,
2829 ) -> Result<(Pointer, Type), EngineError> {
2830 let path = importer_path.as_ref().to_path_buf();
2831 self.eval_snippet_with_gas_and_importer(source, gas, Some(path))
2832 .await
2833 }
2834
2835 async fn eval_snippet_with_gas_and_importer(
2836 &mut self,
2837 source: &str,
2838 gas: &mut GasMeter,
2839 importer_path: Option<PathBuf>,
2840 ) -> Result<(Pointer, Type), EngineError> {
2841 let program = parse_program_from_source(source, None, Some(&mut *gas))?;
2842
2843 let importer = importer_path.map(|p| ModuleId::Local { path: p });
2844
2845 let local_values = decl_value_names(&program.decls);
2846 let import_bindings = self
2847 .import_bindings_for_decls(&program.decls, importer.clone(), &local_values, None, gas)
2848 .await?;
2849
2850 let prefix = format!("@snippet{}", Uuid::new_v4());
2851 let qualified = qualify_program(&program, &prefix);
2852 validate_import_uses(&qualified, &import_bindings.alias_exports, None)?;
2853 let rewritten = rewrite_import_uses(
2854 &qualified,
2855 &import_bindings.alias_exports,
2856 &import_bindings.imported_values,
2857 None,
2858 );
2859
2860 self.inject_decls(&rewritten.decls)?;
2861 self.eval(rewritten.expr.as_ref(), gas).await
2862 }
2863}