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