1use std::collections::{BTreeMap, HashMap, HashSet};
4use std::fmt::Write as _;
5use std::future::Future;
6use std::hash::{Hash, Hasher};
7use std::sync::{Arc, Mutex};
8
9use async_recursion::async_recursion;
10use futures::{FutureExt, future::BoxFuture, pin_mut};
11use rexlang_ast::expr::{
12 ClassDecl, Decl, DeclareFnDecl, Expr, FnDecl, InstanceDecl, Pattern, Scope, Symbol, TypeDecl,
13 sym, sym_eq,
14};
15use rexlang_lexer::span::Span;
16use rexlang_typesystem::{
17 AdtDecl, BuiltinTypeId, CollectAdtsError, Instance, Predicate, PreparedInstanceDecl, Scheme,
18 Subst, Type, TypeError, TypeKind, TypeSystem, TypeVarSupply, TypedExpr, TypedExprKind, Types,
19 compose_subst, entails, instantiate, unify,
20};
21use rexlang_util::GasMeter;
22
23use crate::libraries::{
24 CanonicalSymbol, Library, LibraryExports, LibraryId, LibrarySystem, ResolveRequest,
25 ResolvedLibrary, SymbolKind, library_key_for_library, virtual_export_name,
26};
27use crate::prelude::{
28 inject_boolean_ops, inject_equality_ops, inject_json_primops, inject_list_builtins,
29 inject_numeric_ops, inject_option_result_builtins, inject_order_ops, inject_prelude_adts,
30 inject_show_ops,
31};
32use crate::value::{Closure, Heap, Pointer, Value, list_to_vec};
33use crate::{
34 CancellationToken, EngineError, Env, FromPointer, IntoPointer, RexType, evaluator::EvaluatorRef,
35};
36
37pub trait RexDefault<State>
38where
39 State: Clone + Send + Sync + 'static,
40{
41 fn rex_default(engine: &Engine<State>) -> Result<Pointer, EngineError>;
42}
43
44pub const ROOT_LIBRARY_NAME: &str = "__root__";
45pub const PRELUDE_LIBRARY_NAME: &str = "Prelude";
46
47#[derive(Clone, Debug, PartialEq, Eq)]
48pub enum PreludeMode {
49 Enabled,
50 Disabled,
51}
52
53#[derive(Clone, Debug)]
54pub struct EngineOptions {
55 pub prelude: PreludeMode,
56 pub default_imports: Vec<String>,
57}
58
59impl Default for EngineOptions {
60 fn default() -> Self {
61 Self {
62 prelude: PreludeMode::Enabled,
63 default_imports: vec![PRELUDE_LIBRARY_NAME.to_string()],
64 }
65 }
66}
67
68pub trait RexAdt: RexType {
70 fn rex_adt_decl<State: Clone + Send + Sync + 'static>(
71 engine: &mut Engine<State>,
72 ) -> Result<AdtDecl, EngineError>;
73
74 fn inject_rex<State: Clone + Send + Sync + 'static>(
75 engine: &mut Engine<State>,
76 ) -> Result<(), EngineError> {
77 let adt = Self::rex_adt_decl(engine)?;
78 engine.inject_adt(adt)
79 }
80}
81
82pub(crate) fn check_runtime_cancelled<State: Clone + Send + Sync + 'static>(
83 runtime: &RuntimeSnapshot<State>,
84) -> Result<(), EngineError> {
85 if runtime.cancel.is_cancelled() {
86 Err(EngineError::Cancelled)
87 } else {
88 Ok(())
89 }
90}
91
92fn alloc_uint_literal_as<State: Clone + Send + Sync + 'static>(
93 engine: &RuntimeSnapshot<State>,
94 value: u64,
95 typ: &Type,
96) -> Result<Pointer, EngineError> {
97 match typ.as_ref() {
98 TypeKind::Var(_) => {
99 engine
100 .heap
101 .alloc_i32(i32::try_from(value).map_err(|_| EngineError::NativeType {
102 expected: "i32".into(),
103 got: value.to_string(),
104 })?)
105 }
106 TypeKind::Con(tc) => match tc.builtin_id {
107 Some(BuiltinTypeId::U8) => {
108 engine
109 .heap
110 .alloc_u8(u8::try_from(value).map_err(|_| EngineError::NativeType {
111 expected: "u8".into(),
112 got: value.to_string(),
113 })?)
114 }
115 Some(BuiltinTypeId::U16) => {
116 engine.heap.alloc_u16(u16::try_from(value).map_err(|_| {
117 EngineError::NativeType {
118 expected: "u16".into(),
119 got: value.to_string(),
120 }
121 })?)
122 }
123 Some(BuiltinTypeId::U32) => {
124 engine.heap.alloc_u32(u32::try_from(value).map_err(|_| {
125 EngineError::NativeType {
126 expected: "u32".into(),
127 got: value.to_string(),
128 }
129 })?)
130 }
131 Some(BuiltinTypeId::U64) => engine.heap.alloc_u64(value),
132 Some(BuiltinTypeId::I8) => {
133 engine
134 .heap
135 .alloc_i8(i8::try_from(value).map_err(|_| EngineError::NativeType {
136 expected: "i8".into(),
137 got: value.to_string(),
138 })?)
139 }
140 Some(BuiltinTypeId::I16) => {
141 engine.heap.alloc_i16(i16::try_from(value).map_err(|_| {
142 EngineError::NativeType {
143 expected: "i16".into(),
144 got: value.to_string(),
145 }
146 })?)
147 }
148 Some(BuiltinTypeId::I32) => {
149 engine.heap.alloc_i32(i32::try_from(value).map_err(|_| {
150 EngineError::NativeType {
151 expected: "i32".into(),
152 got: value.to_string(),
153 }
154 })?)
155 }
156 Some(BuiltinTypeId::I64) => {
157 engine.heap.alloc_i64(i64::try_from(value).map_err(|_| {
158 EngineError::NativeType {
159 expected: "i64".into(),
160 got: value.to_string(),
161 }
162 })?)
163 }
164 _ => Err(EngineError::NativeType {
165 expected: "integral".into(),
166 got: typ.to_string(),
167 }),
168 },
169 _ => Err(EngineError::NativeType {
170 expected: "integral".into(),
171 got: typ.to_string(),
172 }),
173 }
174}
175
176fn alloc_int_literal_as<State: Clone + Send + Sync + 'static>(
177 engine: &RuntimeSnapshot<State>,
178 value: i64,
179 typ: &Type,
180) -> Result<Pointer, EngineError> {
181 match typ.as_ref() {
182 TypeKind::Var(_) => {
183 engine
184 .heap
185 .alloc_i32(i32::try_from(value).map_err(|_| EngineError::NativeType {
186 expected: "i32".into(),
187 got: value.to_string(),
188 })?)
189 }
190 TypeKind::Con(tc) => match tc.builtin_id {
191 Some(BuiltinTypeId::I8) => {
192 engine
193 .heap
194 .alloc_i8(i8::try_from(value).map_err(|_| EngineError::NativeType {
195 expected: "i8".into(),
196 got: value.to_string(),
197 })?)
198 }
199 Some(BuiltinTypeId::I16) => {
200 engine.heap.alloc_i16(i16::try_from(value).map_err(|_| {
201 EngineError::NativeType {
202 expected: "i16".into(),
203 got: value.to_string(),
204 }
205 })?)
206 }
207 Some(BuiltinTypeId::I32) => {
208 engine.heap.alloc_i32(i32::try_from(value).map_err(|_| {
209 EngineError::NativeType {
210 expected: "i32".into(),
211 got: value.to_string(),
212 }
213 })?)
214 }
215 Some(BuiltinTypeId::I64) => engine.heap.alloc_i64(value),
216 Some(BuiltinTypeId::U8) => {
217 engine
218 .heap
219 .alloc_u8(u8::try_from(value).map_err(|_| EngineError::NativeType {
220 expected: "u8".into(),
221 got: value.to_string(),
222 })?)
223 }
224 Some(BuiltinTypeId::U16) => {
225 engine.heap.alloc_u16(u16::try_from(value).map_err(|_| {
226 EngineError::NativeType {
227 expected: "u16".into(),
228 got: value.to_string(),
229 }
230 })?)
231 }
232 Some(BuiltinTypeId::U32) => {
233 engine.heap.alloc_u32(u32::try_from(value).map_err(|_| {
234 EngineError::NativeType {
235 expected: "u32".into(),
236 got: value.to_string(),
237 }
238 })?)
239 }
240 Some(BuiltinTypeId::U64) => {
241 engine.heap.alloc_u64(u64::try_from(value).map_err(|_| {
242 EngineError::NativeType {
243 expected: "u64".into(),
244 got: value.to_string(),
245 }
246 })?)
247 }
248 _ => Err(EngineError::NativeType {
249 expected: "integral".into(),
250 got: typ.to_string(),
251 }),
252 },
253 _ => Err(EngineError::NativeType {
254 expected: "integral".into(),
255 got: typ.to_string(),
256 }),
257 }
258}
259
260pub(crate) fn type_head_is_var(typ: &Type) -> bool {
261 let mut cur = typ;
262 while let TypeKind::App(head, _) = cur.as_ref() {
263 cur = head;
264 }
265 matches!(cur.as_ref(), TypeKind::Var(..))
266}
267
268fn sanitize_type_name_for_symbol(typ: &Type) -> String {
269 typ.to_string()
270 .chars()
271 .map(|ch| if ch.is_ascii_alphanumeric() { ch } else { '_' })
272 .collect()
273}
274
275pub type NativeFuture<'a> = BoxFuture<'a, Result<Pointer, EngineError>>;
276type NativeId = u64;
277pub(crate) const RUNTIME_LINK_ABI_VERSION: u32 = 1;
278pub type SyncNativeCallable<State> = Arc<
279 dyn for<'a> Fn(EvaluatorRef<'a, State>, &'a Type, &'a [Pointer]) -> Result<Pointer, EngineError>
280 + Send
281 + Sync
282 + 'static,
283>;
284pub type AsyncNativeCallable<State> = Arc<
285 dyn for<'a> Fn(EvaluatorRef<'a, State>, Type, &'a [Pointer]) -> NativeFuture<'a>
286 + Send
287 + Sync
288 + 'static,
289>;
290pub type AsyncNativeCallableCancellable<State> = Arc<
291 dyn for<'a> Fn(
292 EvaluatorRef<'a, State>,
293 CancellationToken,
294 Type,
295 &'a [Pointer],
296 ) -> NativeFuture<'a>
297 + Send
298 + Sync
299 + 'static,
300>;
301
302type ExportInjector<State> =
303 Box<dyn FnOnce(&mut Engine<State>, &str) -> Result<(), EngineError> + Send + 'static>;
304
305struct NativeRegistration<State: Clone + Send + Sync + 'static> {
306 scheme: Scheme,
307 arity: usize,
308 callable: NativeCallable<State>,
309 gas_cost: u64,
310}
311
312impl<State: Clone + Send + Sync + 'static> NativeRegistration<State> {
313 fn sync(scheme: Scheme, arity: usize, func: SyncNativeCallable<State>, gas_cost: u64) -> Self {
314 Self {
315 scheme,
316 arity,
317 callable: NativeCallable::Sync(func),
318 gas_cost,
319 }
320 }
321
322 fn r#async(
323 scheme: Scheme,
324 arity: usize,
325 func: AsyncNativeCallable<State>,
326 gas_cost: u64,
327 ) -> Self {
328 Self {
329 scheme,
330 arity,
331 callable: NativeCallable::Async(func),
332 gas_cost,
333 }
334 }
335
336 fn async_cancellable(
337 scheme: Scheme,
338 arity: usize,
339 func: AsyncNativeCallableCancellable<State>,
340 gas_cost: u64,
341 ) -> Self {
342 Self {
343 scheme,
344 arity,
345 callable: NativeCallable::AsyncCancellable(func),
346 gas_cost,
347 }
348 }
349}
350
351pub trait Handler<State: Clone + Send + Sync + 'static, Sig>: Send + Sync + 'static {
352 fn declaration(export_name: &str) -> String;
353 fn declaration_for(&self, export_name: &str) -> String {
354 Self::declaration(export_name)
355 }
356 fn inject(self, engine: &mut Engine<State>, export_name: &str) -> Result<(), EngineError>;
357}
358
359pub trait AsyncHandler<State: Clone + Send + Sync + 'static, Sig>: Send + Sync + 'static {
360 fn declaration(export_name: &str) -> String;
361 fn declaration_for(&self, export_name: &str) -> String {
362 Self::declaration(export_name)
363 }
364 fn inject_async(self, engine: &mut Engine<State>, export_name: &str)
365 -> Result<(), EngineError>;
366}
367
368#[derive(Debug, Clone, Copy)]
369struct NativeCallableSig;
370
371#[derive(Debug, Clone, Copy)]
372struct AsyncNativeCallableSig;
373
374pub struct Export<State: Clone + Send + Sync + 'static> {
375 pub name: String,
376 declaration: String,
377 injector: ExportInjector<State>,
378}
379
380impl<State> Export<State>
381where
382 State: Clone + Send + Sync + 'static,
383{
384 fn from_injector(
385 name: impl Into<String>,
386 declaration: String,
387 injector: ExportInjector<State>,
388 ) -> Result<Self, EngineError> {
389 let name = name.into();
390 if name.trim().is_empty() {
391 return Err(EngineError::Internal("export name cannot be empty".into()));
392 }
393 let normalized = normalize_name(&name).to_string();
394 Ok(Self {
395 name: normalized,
396 declaration,
397 injector,
398 })
399 }
400
401 pub fn from_handler<Sig, H>(name: impl Into<String>, handler: H) -> Result<Self, EngineError>
402 where
403 H: Handler<State, Sig>,
404 {
405 let name = name.into();
406 let normalized = normalize_name(&name).to_string();
407 let declaration = handler.declaration_for(&normalized);
408 let injector: ExportInjector<State> =
409 Box::new(move |engine, qualified_name| handler.inject(engine, qualified_name));
410 Self::from_injector(name, declaration, injector)
411 }
412
413 pub fn from_async_handler<Sig, H>(
414 name: impl Into<String>,
415 handler: H,
416 ) -> Result<Self, EngineError>
417 where
418 H: AsyncHandler<State, Sig>,
419 {
420 let name = name.into();
421 let normalized = normalize_name(&name).to_string();
422 let declaration = handler.declaration_for(&normalized);
423 let injector: ExportInjector<State> =
424 Box::new(move |engine, qualified_name| handler.inject_async(engine, qualified_name));
425 Self::from_injector(name, declaration, injector)
426 }
427
428 pub fn from_native<F>(
429 name: impl Into<String>,
430 scheme: Scheme,
431 arity: usize,
432 handler: F,
433 ) -> Result<Self, EngineError>
434 where
435 F: for<'a> Fn(
436 EvaluatorRef<'a, State>,
437 &'a Type,
438 &'a [Pointer],
439 ) -> Result<Pointer, EngineError>
440 + Send
441 + Sync
442 + 'static,
443 {
444 validate_native_export_scheme(&scheme, arity)?;
445 let handler = Arc::new(handler);
446 let func: SyncNativeCallable<State> =
447 Arc::new(move |engine, typ: &Type, args: &[Pointer]| handler(engine, typ, args));
448 Self::from_handler::<NativeCallableSig, _>(name, (scheme, arity, func))
449 }
450
451 pub fn from_native_async<F>(
452 name: impl Into<String>,
453 scheme: Scheme,
454 arity: usize,
455 handler: F,
456 ) -> Result<Self, EngineError>
457 where
458 F: for<'a> Fn(EvaluatorRef<'a, State>, Type, Vec<Pointer>) -> NativeFuture<'a>
459 + Send
460 + Sync
461 + 'static,
462 {
463 validate_native_export_scheme(&scheme, arity)?;
464 let handler = Arc::new(handler);
465 let func: AsyncNativeCallable<State> = Arc::new(move |engine, typ, args| {
466 let args = args.to_vec();
467 let handler = Arc::clone(&handler);
468 handler(engine, typ, args)
469 });
470 Self::from_async_handler::<AsyncNativeCallableSig, _>(name, (scheme, arity, func))
471 }
472}
473
474fn declaration_type_string(arg_types: &[Type], ret: Type) -> String {
475 if arg_types.is_empty() {
476 return ret.to_string();
477 }
478 let mut out = ret.to_string();
479 for arg in arg_types.iter().rev() {
480 out = format!("{arg} -> {out}");
481 }
482 out
483}
484
485fn declaration_line(export_name: &str, arg_types: &[Type], ret: Type) -> String {
486 format!(
487 "pub declare fn {export_name} {}",
488 declaration_type_string(arg_types, ret)
489 )
490}
491
492fn declaration_line_from_scheme(export_name: &str, scheme: &Scheme) -> String {
493 let mut out = format!("pub declare fn {export_name} : {}", scheme.typ);
494 if !scheme.preds.is_empty() {
495 let preds = scheme
496 .preds
497 .iter()
498 .map(|p| format!("{} {}", p.class, p.typ))
499 .collect::<Vec<_>>()
500 .join(", ");
501 out.push_str(" where ");
502 out.push_str(&preds);
503 }
504 out
505}
506
507fn library_local_type_names_from_declarations(declarations: &[String]) -> HashSet<Symbol> {
508 let mut out = HashSet::new();
509 for declaration in declarations {
510 let mut s = declaration.trim_start();
511 if let Some(rest) = s.strip_prefix("pub ") {
512 s = rest.trim_start();
513 }
514 let Some(rest) = s.strip_prefix("type ") else {
515 continue;
516 };
517 let name: String = rest
518 .chars()
519 .take_while(|c| c.is_ascii_alphanumeric() || *c == '_')
520 .collect();
521 if !name.is_empty() {
522 out.insert(sym(&name));
523 }
524 }
525 out
526}
527
528fn qualify_library_type_refs(
529 typ: &Type,
530 library_name: &str,
531 local_type_names: &HashSet<Symbol>,
532) -> Type {
533 match typ.as_ref() {
534 TypeKind::Con(tc) => {
535 if local_type_names.contains(&tc.name) {
536 Type::con(
537 virtual_export_name(library_name, tc.name.as_ref()),
538 tc.arity,
539 )
540 } else {
541 typ.clone()
542 }
543 }
544 TypeKind::App(f, x) => Type::app(
545 qualify_library_type_refs(f, library_name, local_type_names),
546 qualify_library_type_refs(x, library_name, local_type_names),
547 ),
548 TypeKind::Fun(a, b) => Type::fun(
549 qualify_library_type_refs(a, library_name, local_type_names),
550 qualify_library_type_refs(b, library_name, local_type_names),
551 ),
552 TypeKind::Tuple(elems) => Type::tuple(
553 elems
554 .iter()
555 .map(|t| qualify_library_type_refs(t, library_name, local_type_names))
556 .collect(),
557 ),
558 TypeKind::Record(fields) => Type::new(TypeKind::Record(
559 fields
560 .iter()
561 .map(|(k, v)| {
562 (
563 k.clone(),
564 qualify_library_type_refs(v, library_name, local_type_names),
565 )
566 })
567 .collect(),
568 )),
569 TypeKind::Var(_) => typ.clone(),
570 }
571}
572
573fn qualify_library_scheme_refs(
574 scheme: &Scheme,
575 library_name: &str,
576 local_type_names: &HashSet<Symbol>,
577) -> Scheme {
578 let typ = qualify_library_type_refs(&scheme.typ, library_name, local_type_names);
579 let preds = scheme
580 .preds
581 .iter()
582 .map(|pred| {
583 Predicate::new(
584 pred.class.clone(),
585 qualify_library_type_refs(&pred.typ, library_name, local_type_names),
586 )
587 })
588 .collect();
589 Scheme::new(scheme.vars.clone(), preds, typ)
590}
591
592pub fn collect_adts_error_to_engine(err: CollectAdtsError) -> EngineError {
610 let details = err
611 .conflicts
612 .into_iter()
613 .map(|conflict| {
614 let defs = conflict
615 .definitions
616 .iter()
617 .map(ToString::to_string)
618 .collect::<Vec<_>>()
619 .join(", ");
620 format!("{}: [{defs}]", conflict.name)
621 })
622 .collect::<Vec<_>>()
623 .join("; ");
624 EngineError::Custom(format!(
625 "conflicting ADT definitions discovered in input types: {details}"
626 ))
627}
628
629fn native_export_arg_types(
630 scheme: &Scheme,
631 arity: usize,
632) -> Result<(Vec<Type>, Type), EngineError> {
633 let mut args = Vec::with_capacity(arity);
634 let mut rest = scheme.typ.clone();
635 for _ in 0..arity {
636 let Some((arg, tail)) = split_fun(&rest) else {
637 return Err(EngineError::Internal(format!(
638 "native export type `{}` does not accept {arity} argument(s)",
639 scheme.typ
640 )));
641 };
642 args.push(arg);
643 rest = tail;
644 }
645 Ok((args, rest))
646}
647
648fn validate_native_export_scheme(scheme: &Scheme, arity: usize) -> Result<(), EngineError> {
649 let _ = native_export_arg_types(scheme, arity)?;
650 Ok(())
651}
652
653macro_rules! define_handler_impl {
654 ([] ; $arity:literal ; $sig:ty) => {
655 impl<State, F, R> Handler<State, $sig> for F
656 where
657 State: Clone + Send + Sync + 'static,
658 F: for<'a> Fn(&'a State) -> Result<R, EngineError> + Send + Sync + 'static,
659 R: IntoPointer + RexType,
660 {
661 fn declaration(export_name: &str) -> String {
662 declaration_line(export_name, &[], R::rex_type())
663 }
664
665 fn inject(
666 self,
667 engine: &mut Engine<State>,
668 export_name: &str,
669 ) -> Result<(), EngineError> {
670 let name_sym = normalize_name(export_name);
671 let func: SyncNativeCallable<State> = Arc::new(
672 move |engine, _: &Type, args: &[Pointer]| {
673 if args.len() != $arity {
674 return Err(EngineError::NativeArity {
675 name: name_sym.clone(),
676 expected: $arity,
677 got: args.len(),
678 });
679 }
680 let value = self(engine.state.as_ref())?;
681 value.into_pointer(&engine.heap)
682 },
683 );
684 let scheme = Scheme::new(vec![], vec![], R::rex_type());
685 let registration = NativeRegistration::sync(scheme, $arity, func, 0);
686 engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
687 }
688 }
689
690 };
691 ([ $(($arg_ty:ident, $arg_name:ident, $idx:tt)),+ ] ; $arity:literal ; $sig:ty) => {
692 impl<State, F, R, $($arg_ty),+> Handler<State, $sig> for F
693 where
694 State: Clone + Send + Sync + 'static,
695 F: for<'a> Fn(&'a State, $($arg_ty),+) -> Result<R, EngineError> + Send + Sync + 'static,
696 R: IntoPointer + RexType,
697 $($arg_ty: FromPointer + RexType),+
698 {
699 fn declaration(export_name: &str) -> String {
700 let args = vec![$($arg_ty::rex_type()),+];
701 declaration_line(export_name, &args, R::rex_type())
702 }
703
704 fn inject(
705 self,
706 engine: &mut Engine<State>,
707 export_name: &str,
708 ) -> Result<(), EngineError> {
709 let name_sym = normalize_name(export_name);
710 let func: SyncNativeCallable<State> = Arc::new(
711 move |engine, _: &Type, args: &[Pointer]| {
712 if args.len() != $arity {
713 return Err(EngineError::NativeArity {
714 name: name_sym.clone(),
715 expected: $arity,
716 got: args.len(),
717 });
718 }
719 $(let $arg_name = $arg_ty::from_pointer(&engine.heap, &args[$idx])?;)*
720 let value = self(engine.state.as_ref(), $($arg_name),+)?;
721 value.into_pointer(&engine.heap)
722 },
723 );
724 let typ = native_fn_type!($($arg_ty),+ ; R);
725 let scheme = Scheme::new(vec![], vec![], typ);
726 let registration = NativeRegistration::sync(scheme, $arity, func, 0);
727 engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
728 }
729 }
730
731 };
732}
733
734impl<State> Handler<State, NativeCallableSig> for (Scheme, usize, SyncNativeCallable<State>)
735where
736 State: Clone + Send + Sync + 'static,
737{
738 fn declaration(_export_name: &str) -> String {
739 unreachable!("native callable handlers use declaration_for")
740 }
741
742 fn declaration_for(&self, export_name: &str) -> String {
743 let (scheme, _, _) = self;
744 declaration_line_from_scheme(export_name, scheme)
745 }
746
747 fn inject(self, engine: &mut Engine<State>, export_name: &str) -> Result<(), EngineError> {
748 let (scheme, arity, func) = self;
749 validate_native_export_scheme(&scheme, arity)?;
750 let registration = NativeRegistration::sync(scheme, arity, func, 0);
751 engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
752 }
753}
754
755macro_rules! define_async_handler_impl {
756 ([] ; $arity:literal ; $sig:ty) => {
757 impl<State, F, Fut, R> AsyncHandler<State, $sig> for F
758 where
759 State: Clone + Send + Sync + 'static,
760 F: for<'a> Fn(&'a State) -> Fut + Send + Sync + 'static,
761 Fut: Future<Output = Result<R, EngineError>> + Send + 'static,
762 R: IntoPointer + RexType,
763 {
764 fn declaration(export_name: &str) -> String {
765 declaration_line(export_name, &[], R::rex_type())
766 }
767
768 fn inject_async(
769 self,
770 engine: &mut Engine<State>,
771 export_name: &str,
772 ) -> Result<(), EngineError> {
773 let f = Arc::new(self);
774 let name_sym = normalize_name(export_name);
775 let func: AsyncNativeCallable<State> = Arc::new(
776 move |engine, _: Type, args: &[Pointer]| -> NativeFuture<'_> {
777 let f = Arc::clone(&f);
778 let name_sym = name_sym.clone();
779 async move {
780 if args.len() != $arity {
781 return Err(EngineError::NativeArity {
782 name: name_sym.clone(),
783 expected: $arity,
784 got: args.len(),
785 });
786 }
787 let value = f(engine.state.as_ref()).await?;
788 value.into_pointer(&engine.heap)
789 }
790 .boxed()
791 },
792 );
793 let scheme = Scheme::new(vec![], vec![], R::rex_type());
794 let registration = NativeRegistration::r#async(scheme, $arity, func, 0);
795 engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
796 }
797 }
798 };
799 ([ $(($arg_ty:ident, $arg_name:ident, $idx:tt)),+ ] ; $arity:literal ; $sig:ty) => {
800 impl<State, F, Fut, R, $($arg_ty),+> AsyncHandler<State, $sig> for F
801 where
802 State: Clone + Send + Sync + 'static,
803 F: for<'a> Fn(&'a State, $($arg_ty),+) -> Fut + Send + Sync + 'static,
804 Fut: Future<Output = Result<R, EngineError>> + Send + 'static,
805 R: IntoPointer + RexType,
806 $($arg_ty: FromPointer + RexType),+
807 {
808 fn declaration(export_name: &str) -> String {
809 let args = vec![$($arg_ty::rex_type()),+];
810 declaration_line(export_name, &args, R::rex_type())
811 }
812
813 fn inject_async(
814 self,
815 engine: &mut Engine<State>,
816 export_name: &str,
817 ) -> Result<(), EngineError> {
818 let f = Arc::new(self);
819 let name_sym = normalize_name(export_name);
820 let func: AsyncNativeCallable<State> = Arc::new(
821 move |engine, _: Type, args: &[Pointer]| -> NativeFuture<'_> {
822 let f = Arc::clone(&f);
823 let name_sym = name_sym.clone();
824 async move {
825 if args.len() != $arity {
826 return Err(EngineError::NativeArity {
827 name: name_sym.clone(),
828 expected: $arity,
829 got: args.len(),
830 });
831 }
832 $(let $arg_name = $arg_ty::from_pointer(&engine.heap, &args[$idx])?;)*
833 let value = f(engine.state.as_ref(), $($arg_name),+).await?;
834 value.into_pointer(&engine.heap)
835 }
836 .boxed()
837 },
838 );
839 let typ = native_fn_type!($($arg_ty),+ ; R);
840 let scheme = Scheme::new(vec![], vec![], typ);
841 let registration = NativeRegistration::r#async(scheme, $arity, func, 0);
842 engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
843 }
844 }
845 };
846}
847
848impl<State> AsyncHandler<State, AsyncNativeCallableSig>
849 for (Scheme, usize, AsyncNativeCallable<State>)
850where
851 State: Clone + Send + Sync + 'static,
852{
853 fn declaration(_export_name: &str) -> String {
854 unreachable!("native async callable handlers use declaration_for")
855 }
856
857 fn declaration_for(&self, export_name: &str) -> String {
858 let (scheme, _, _) = self;
859 declaration_line_from_scheme(export_name, scheme)
860 }
861
862 fn inject_async(
863 self,
864 engine: &mut Engine<State>,
865 export_name: &str,
866 ) -> Result<(), EngineError> {
867 let (scheme, arity, func) = self;
868 validate_native_export_scheme(&scheme, arity)?;
869 let registration = NativeRegistration::r#async(scheme, arity, func, 0);
870 engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
871 }
872}
873
874#[derive(Clone)]
875pub(crate) enum NativeCallable<State: Clone + Send + Sync + 'static> {
876 Sync(SyncNativeCallable<State>),
877 Async(AsyncNativeCallable<State>),
878 AsyncCancellable(AsyncNativeCallableCancellable<State>),
879}
880
881impl<State: Clone + Send + Sync + 'static> PartialEq for NativeCallable<State> {
882 fn eq(&self, _other: &NativeCallable<State>) -> bool {
883 false
884 }
885}
886
887impl<State: Clone + Send + Sync + 'static> std::fmt::Debug for NativeCallable<State> {
888 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
889 match self {
890 NativeCallable::Sync(_) => write!(f, "Sync"),
891 NativeCallable::Async(_) => write!(f, "Async"),
892 NativeCallable::AsyncCancellable(_) => write!(f, "AsyncCancellable"),
893 }
894 }
895}
896
897impl<State: Clone + Send + Sync + 'static> NativeCallable<State> {
898 pub(crate) async fn call(
899 &self,
900 runtime: &RuntimeSnapshot<State>,
901 typ: Type,
902 args: &[Pointer],
903 ) -> Result<Pointer, EngineError> {
904 let token = runtime.cancel.clone();
905 if token.is_cancelled() {
906 return Err(EngineError::Cancelled);
907 }
908
909 match self {
910 NativeCallable::Sync(f) => (f)(EvaluatorRef::new(runtime), &typ, args),
911 NativeCallable::Async(f) => {
912 let call_fut = (f)(EvaluatorRef::new(runtime), typ, args).fuse();
913 let cancel_fut = token.cancelled().fuse();
914 pin_mut!(call_fut, cancel_fut);
915 futures::select! {
916 _ = cancel_fut => Err(EngineError::Cancelled),
917 res = call_fut => {
918 if token.is_cancelled() {
919 Err(EngineError::Cancelled)
920 } else {
921 res
922 }
923 },
924 }
925 }
926 NativeCallable::AsyncCancellable(f) => {
927 let call_fut = (f)(EvaluatorRef::new(runtime), token.clone(), typ, args).fuse();
928 let cancel_fut = token.cancelled().fuse();
929 pin_mut!(call_fut, cancel_fut);
930 futures::select! {
931 _ = cancel_fut => Err(EngineError::Cancelled),
932 res = call_fut => {
933 if token.is_cancelled() {
934 Err(EngineError::Cancelled)
935 } else {
936 res
937 }
938 },
939 }
940 }
941 }
942 }
943}
944
945#[derive(Clone, Debug, PartialEq)]
946pub struct NativeFn {
947 native_id: NativeId,
948 name: Symbol,
949 arity: usize,
950 typ: Type,
951 gas_cost: u64,
952 applied: Vec<Pointer>,
953 applied_types: Vec<Type>,
954}
955
956impl NativeFn {
957 fn new(native_id: NativeId, name: Symbol, arity: usize, typ: Type, gas_cost: u64) -> Self {
958 Self {
959 native_id,
960 name,
961 arity,
962 typ,
963 gas_cost,
964 applied: Vec::new(),
965 applied_types: Vec::new(),
966 }
967 }
968
969 pub(crate) fn from_parts(
970 native_id: NativeId,
971 name: Symbol,
972 arity: usize,
973 typ: Type,
974 gas_cost: u64,
975 applied: Vec<Pointer>,
976 applied_types: Vec<Type>,
977 ) -> Self {
978 Self {
979 native_id,
980 name,
981 arity,
982 typ,
983 gas_cost,
984 applied,
985 applied_types,
986 }
987 }
988
989 pub(crate) fn into_parts(
990 self,
991 ) -> (NativeId, Symbol, usize, Type, u64, Vec<Pointer>, Vec<Type>) {
992 (
993 self.native_id,
994 self.name,
995 self.arity,
996 self.typ,
997 self.gas_cost,
998 self.applied,
999 self.applied_types,
1000 )
1001 }
1002
1003 pub(crate) fn name(&self) -> &Symbol {
1004 &self.name
1005 }
1006
1007 pub(crate) fn is_zero_unapplied(&self) -> bool {
1008 self.arity == 0 && self.applied.is_empty()
1009 }
1010
1011 pub(crate) async fn call_zero<State: Clone + Send + Sync + 'static>(
1012 &self,
1013 runtime: &RuntimeSnapshot<State>,
1014 gas: &mut GasMeter,
1015 ) -> Result<Pointer, EngineError> {
1016 let amount = gas
1017 .costs
1018 .native_call_base
1019 .saturating_add(self.gas_cost)
1020 .saturating_add(gas.costs.native_call_per_arg.saturating_mul(0));
1021 gas.charge(amount)?;
1022 if self.arity != 0 {
1023 return Err(EngineError::NativeArity {
1024 name: self.name.clone(),
1025 expected: self.arity,
1026 got: 0,
1027 });
1028 }
1029 runtime
1030 .native_callable(self.native_id)?
1031 .call(runtime, self.typ.clone(), &[])
1032 .await
1033 }
1034
1035 async fn apply<State: Clone + Send + Sync + 'static>(
1036 mut self,
1037 runtime: &RuntimeSnapshot<State>,
1038 arg: Pointer,
1039 arg_type: Option<&Type>,
1040 gas: &mut GasMeter,
1041 ) -> Result<Pointer, EngineError> {
1042 if self.arity == 0 {
1045 return Err(EngineError::NativeArity {
1046 name: self.name,
1047 expected: 0,
1048 got: 1,
1049 });
1050 }
1051 let (arg_ty, rest_ty) =
1052 split_fun(&self.typ).ok_or_else(|| EngineError::NotCallable(self.typ.to_string()))?;
1053 let actual_ty = resolve_arg_type(&runtime.heap, arg_type, &arg)?;
1054 let subst = unify(&arg_ty, &actual_ty).map_err(|_| EngineError::NativeType {
1055 expected: arg_ty.to_string(),
1056 got: actual_ty.to_string(),
1057 })?;
1058 self.typ = rest_ty.apply(&subst);
1059 self.applied.push(arg);
1060 self.applied_types.push(actual_ty);
1061 if is_function_type(&self.typ) {
1062 let NativeFn {
1063 native_id,
1064 name,
1065 arity,
1066 typ,
1067 gas_cost,
1068 applied,
1069 applied_types,
1070 } = self;
1071 return runtime.heap.alloc_native(
1072 native_id,
1073 name,
1074 arity,
1075 typ,
1076 gas_cost,
1077 applied,
1078 applied_types,
1079 );
1080 }
1081
1082 let mut full_ty = self.typ.clone();
1083 for arg_ty in self.applied_types.iter().rev() {
1084 full_ty = Type::fun(arg_ty.clone(), full_ty);
1085 }
1086
1087 let amount = gas
1088 .costs
1089 .native_call_base
1090 .saturating_add(self.gas_cost)
1091 .saturating_add(
1092 gas.costs
1093 .native_call_per_arg
1094 .saturating_mul(self.applied.len() as u64),
1095 );
1096 gas.charge(amount)?;
1097 runtime
1098 .native_callable(self.native_id)?
1099 .call(runtime, full_ty, &self.applied)
1100 .await
1101 }
1102}
1103
1104#[derive(Clone, Debug, PartialEq)]
1105pub struct OverloadedFn {
1106 name: Symbol,
1107 typ: Type,
1108 applied: Vec<Pointer>,
1109 applied_types: Vec<Type>,
1110}
1111
1112impl OverloadedFn {
1113 pub(crate) fn new(name: Symbol, typ: Type) -> Self {
1114 Self {
1115 name,
1116 typ,
1117 applied: Vec::new(),
1118 applied_types: Vec::new(),
1119 }
1120 }
1121
1122 pub(crate) fn from_parts(
1123 name: Symbol,
1124 typ: Type,
1125 applied: Vec<Pointer>,
1126 applied_types: Vec<Type>,
1127 ) -> Self {
1128 Self {
1129 name,
1130 typ,
1131 applied,
1132 applied_types,
1133 }
1134 }
1135
1136 pub(crate) fn name(&self) -> &Symbol {
1137 &self.name
1138 }
1139
1140 pub(crate) fn into_parts(self) -> (Symbol, Type, Vec<Pointer>, Vec<Type>) {
1141 (self.name, self.typ, self.applied, self.applied_types)
1142 }
1143
1144 async fn apply<State: Clone + Send + Sync + 'static>(
1145 mut self,
1146 runtime: &RuntimeSnapshot<State>,
1147 arg: Pointer,
1148 func_type: Option<&Type>,
1149 arg_type: Option<&Type>,
1150 gas: &mut GasMeter,
1151 ) -> Result<Pointer, EngineError> {
1152 if let Some(expected) = func_type {
1153 let subst = unify(&self.typ, expected).map_err(|_| EngineError::NativeType {
1154 expected: self.typ.to_string(),
1155 got: expected.to_string(),
1156 })?;
1157 self.typ = self.typ.apply(&subst);
1158 }
1159 let (arg_ty, rest_ty) =
1160 split_fun(&self.typ).ok_or_else(|| EngineError::NotCallable(self.typ.to_string()))?;
1161 let actual_ty = resolve_arg_type(&runtime.heap, arg_type, &arg)?;
1162 let subst = unify(&arg_ty, &actual_ty).map_err(|_| EngineError::NativeType {
1163 expected: arg_ty.to_string(),
1164 got: actual_ty.to_string(),
1165 })?;
1166 let rest_ty = rest_ty.apply(&subst);
1167 self.applied.push(arg);
1168 self.applied_types.push(actual_ty);
1169 if is_function_type(&rest_ty) {
1170 return runtime.heap.alloc_overloaded(
1171 self.name,
1172 rest_ty,
1173 self.applied,
1174 self.applied_types,
1175 );
1176 }
1177 let mut full_ty = rest_ty;
1178 for arg_ty in self.applied_types.iter().rev() {
1179 full_ty = Type::fun(arg_ty.clone(), full_ty);
1180 }
1181 if runtime.type_system.class_methods.contains_key(&self.name) {
1182 let mut func = EvaluatorRef::new(runtime)
1183 .resolve_class_method(&self.name, &full_ty, gas)
1184 .await?;
1185 let mut cur_ty = full_ty;
1186 for (applied, applied_ty) in self.applied.into_iter().zip(self.applied_types.iter()) {
1187 let (arg_ty, rest_ty) = split_fun(&cur_ty)
1188 .ok_or_else(|| EngineError::NotCallable(cur_ty.to_string()))?;
1189 let subst = unify(&arg_ty, applied_ty).map_err(|_| EngineError::NativeType {
1190 expected: arg_ty.to_string(),
1191 got: applied_ty.to_string(),
1192 })?;
1193 let rest_ty = rest_ty.apply(&subst);
1194 func = apply(runtime, func, applied, Some(&cur_ty), Some(applied_ty), gas).await?;
1195 cur_ty = rest_ty;
1196 }
1197 return Ok(func);
1198 }
1199
1200 let imp = EvaluatorRef::new(runtime).resolve_native_impl(self.name.as_ref(), &full_ty)?;
1201 let amount = gas
1202 .costs
1203 .native_call_base
1204 .saturating_add(imp.gas_cost)
1205 .saturating_add(
1206 gas.costs
1207 .native_call_per_arg
1208 .saturating_mul(self.applied.len() as u64),
1209 );
1210 gas.charge(amount)?;
1211 imp.func.call(runtime, full_ty, &self.applied).await
1212 }
1213}
1214
1215#[derive(Clone)]
1216pub(crate) struct NativeImpl<State: Clone + Send + Sync + 'static> {
1217 id: NativeId,
1218 name: Symbol,
1219 arity: usize,
1220 scheme: Scheme,
1221 pub(crate) func: NativeCallable<State>,
1222 gas_cost: u64,
1223}
1224
1225impl<State: Clone + Send + Sync + 'static> NativeImpl<State> {
1226 pub(crate) fn to_native_fn(&self, typ: Type) -> NativeFn {
1227 NativeFn::new(self.id, self.name.clone(), self.arity, typ, self.gas_cost)
1228 }
1229}
1230
1231#[derive(Clone)]
1232pub(crate) struct NativeRegistry<State: Clone + Send + Sync + 'static> {
1233 next_id: NativeId,
1234 entries: HashMap<Symbol, Vec<NativeImpl<State>>>,
1235 by_id: HashMap<NativeId, NativeImpl<State>>,
1236}
1237
1238impl<State: Clone + Send + Sync + 'static> NativeRegistry<State> {
1239 fn insert(
1240 &mut self,
1241 name: Symbol,
1242 arity: usize,
1243 scheme: Scheme,
1244 func: NativeCallable<State>,
1245 gas_cost: u64,
1246 ) -> Result<(), EngineError> {
1247 let entry = self.entries.entry(name.clone()).or_default();
1248 if entry.iter().any(|existing| existing.scheme == scheme) {
1249 return Err(EngineError::DuplicateImpl {
1250 name,
1251 typ: scheme.typ.to_string(),
1252 });
1253 }
1254 let id = self.next_id;
1255 self.next_id = self.next_id.saturating_add(1);
1256 let imp = NativeImpl::<State> {
1257 id,
1258 name: name.clone(),
1259 arity,
1260 scheme,
1261 func,
1262 gas_cost,
1263 };
1264 self.by_id.insert(id, imp.clone());
1265 entry.push(imp);
1266 Ok(())
1267 }
1268
1269 pub(crate) fn get(&self, name: &Symbol) -> Option<&[NativeImpl<State>]> {
1270 self.entries.get(name).map(|v| v.as_slice())
1271 }
1272
1273 pub(crate) fn has_name(&self, name: &Symbol) -> bool {
1274 self.entries.contains_key(name)
1275 }
1276
1277 fn by_id(&self, id: NativeId) -> Option<&NativeImpl<State>> {
1278 self.by_id.get(&id)
1279 }
1280}
1281
1282impl<State: Clone + Send + Sync + 'static> Default for NativeRegistry<State> {
1283 fn default() -> Self {
1284 Self {
1285 next_id: 0,
1286 entries: HashMap::new(),
1287 by_id: HashMap::new(),
1288 }
1289 }
1290}
1291
1292#[derive(Clone)]
1293pub(crate) struct TypeclassInstance {
1294 head: Type,
1295 def_env: Env,
1296 methods: HashMap<Symbol, Arc<TypedExpr>>,
1297}
1298
1299#[derive(Default, Clone)]
1300pub(crate) struct TypeclassRegistry {
1301 entries: HashMap<Symbol, Vec<TypeclassInstance>>,
1302}
1303
1304impl TypeclassRegistry {
1305 fn insert(
1306 &mut self,
1307 class: Symbol,
1308 head: Type,
1309 def_env: Env,
1310 methods: HashMap<Symbol, Arc<TypedExpr>>,
1311 ) -> Result<(), EngineError> {
1312 let entry = self.entries.entry(class.clone()).or_default();
1313 for existing in entry.iter() {
1314 if unify(&existing.head, &head).is_ok() {
1315 return Err(EngineError::DuplicateTypeclassImpl {
1316 class,
1317 typ: head.to_string(),
1318 });
1319 }
1320 }
1321 entry.push(TypeclassInstance {
1322 head,
1323 def_env,
1324 methods,
1325 });
1326 Ok(())
1327 }
1328
1329 pub(crate) fn resolve(
1330 &self,
1331 class: &Symbol,
1332 method: &Symbol,
1333 param_type: &Type,
1334 ) -> Result<(Env, Arc<TypedExpr>, Subst), EngineError> {
1335 let instances =
1336 self.entries
1337 .get(class)
1338 .ok_or_else(|| EngineError::MissingTypeclassImpl {
1339 class: class.clone(),
1340 typ: param_type.to_string(),
1341 })?;
1342
1343 let mut matches = Vec::new();
1344 for inst in instances {
1345 if let Ok(s) = unify(&inst.head, param_type) {
1346 matches.push((inst, s));
1347 }
1348 }
1349 match matches.len() {
1350 0 => Err(EngineError::MissingTypeclassImpl {
1351 class: class.clone(),
1352 typ: param_type.to_string(),
1353 }),
1354 1 => {
1355 let (inst, s) = matches.remove(0);
1356 let typed =
1357 inst.methods
1358 .get(method)
1359 .ok_or_else(|| EngineError::MissingTypeclassImpl {
1360 class: class.clone(),
1361 typ: param_type.to_string(),
1362 })?;
1363 Ok((inst.def_env.clone(), typed.clone(), s))
1364 }
1365 _ => Err(EngineError::AmbiguousTypeclassImpl {
1366 class: class.clone(),
1367 typ: param_type.to_string(),
1368 }),
1369 }
1370 }
1371}
1372
1373pub struct Engine<State = ()>
1374where
1375 State: Clone + Send + Sync + 'static,
1376{
1377 pub state: Arc<State>,
1378 env: Env,
1379 natives: NativeRegistry<State>,
1380 typeclasses: TypeclassRegistry,
1381 pub type_system: TypeSystem,
1382 typeclass_cache: Arc<Mutex<HashMap<(Symbol, Type), Pointer>>>,
1383 pub(crate) modules: LibrarySystem,
1384 injected_libraries: HashSet<String>,
1385 pub(crate) library_exports_cache: HashMap<LibraryId, LibraryExports>,
1386 pub(crate) library_interface_cache: HashMap<LibraryId, Vec<Decl>>,
1387 pub(crate) library_sources: HashMap<LibraryId, String>,
1388 pub(crate) library_source_fingerprints: HashMap<LibraryId, String>,
1389 pub(crate) published_cycle_interfaces: HashSet<LibraryId>,
1390 default_imports: Vec<String>,
1391 virtual_libraries: HashMap<String, LibraryExports>,
1392 library_local_type_names: HashMap<String, HashSet<Symbol>>,
1393 registration_library_context: Option<String>,
1394 cancel: CancellationToken,
1395 pub heap: Heap,
1396}
1397
1398#[derive(Clone)]
1399pub struct CompiledProgram {
1400 pub externs: CompiledExterns,
1401 link_contract: RuntimeLinkContract,
1402 pub(crate) env: Env,
1403 pub(crate) expr: Arc<TypedExpr>,
1404}
1405
1406impl CompiledProgram {
1407 pub(crate) fn new(
1408 externs: CompiledExterns,
1409 link_contract: RuntimeLinkContract,
1410 env: Env,
1411 expr: TypedExpr,
1412 ) -> Self {
1413 Self {
1414 externs,
1415 link_contract,
1416 env,
1417 expr: Arc::new(expr),
1418 }
1419 }
1420
1421 pub fn result_type(&self) -> &Type {
1422 &self.expr.typ
1423 }
1424
1425 pub fn externs(&self) -> &CompiledExterns {
1426 &self.externs
1427 }
1428
1429 pub fn link_contract(&self) -> &RuntimeLinkContract {
1430 &self.link_contract
1431 }
1432
1433 pub fn link_fingerprint(&self) -> u64 {
1434 self.link_contract.fingerprint()
1435 }
1436
1437 pub fn storage_boundary(&self) -> CompiledProgramBoundary {
1438 CompiledProgramBoundary {
1439 contains_prepared_expr: true,
1440 captures_process_local_env: true,
1441 serializable: false,
1442 }
1443 }
1444}
1445
1446#[derive(Clone, Debug, Default, PartialEq, Eq)]
1447pub struct CompiledExterns {
1448 pub natives: Vec<Symbol>,
1449 pub class_methods: Vec<Symbol>,
1450}
1451
1452impl CompiledExterns {
1453 pub fn is_empty(&self) -> bool {
1454 self.natives.is_empty() && self.class_methods.is_empty()
1455 }
1456
1457 pub fn fingerprint(&self) -> u64 {
1458 let mut hasher = std::collections::hash_map::DefaultHasher::new();
1459 "natives".hash(&mut hasher);
1460 self.natives.hash(&mut hasher);
1461 "class_methods".hash(&mut hasher);
1462 self.class_methods.hash(&mut hasher);
1463 hasher.finish()
1464 }
1465
1466 pub fn compatibility_with(&self, capabilities: &RuntimeCapabilities) -> RuntimeCompatibility {
1467 let natives = capabilities.natives.iter().cloned().collect::<HashSet<_>>();
1468 let class_methods = capabilities
1469 .class_methods
1470 .iter()
1471 .cloned()
1472 .collect::<HashSet<_>>();
1473
1474 RuntimeCompatibility {
1475 expected_abi_version: capabilities.abi_version,
1476 actual_abi_version: capabilities.abi_version,
1477 missing_natives: self
1478 .natives
1479 .iter()
1480 .filter(|name| !natives.contains(*name))
1481 .cloned()
1482 .collect(),
1483 incompatible_natives: Vec::new(),
1484 missing_class_methods: self
1485 .class_methods
1486 .iter()
1487 .filter(|name| !class_methods.contains(*name))
1488 .cloned()
1489 .collect(),
1490 incompatible_class_methods: Vec::new(),
1491 }
1492 }
1493}
1494
1495#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1496pub struct NativeRequirement {
1497 pub name: Symbol,
1498 pub typ: Type,
1499}
1500
1501#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1502pub struct ClassMethodRequirement {
1503 pub name: Symbol,
1504 pub typ: Type,
1505}
1506
1507#[derive(Clone, Debug, PartialEq, Eq)]
1508pub struct RuntimeLinkContract {
1509 pub abi_version: u32,
1510 pub natives: Vec<NativeRequirement>,
1511 pub class_methods: Vec<ClassMethodRequirement>,
1512}
1513
1514impl RuntimeLinkContract {
1515 pub fn fingerprint(&self) -> u64 {
1516 let mut hasher = std::collections::hash_map::DefaultHasher::new();
1517 self.abi_version.hash(&mut hasher);
1518 self.natives.hash(&mut hasher);
1519 self.class_methods.hash(&mut hasher);
1520 hasher.finish()
1521 }
1522}
1523
1524#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1525pub struct CompiledProgramBoundary {
1526 pub contains_prepared_expr: bool,
1527 pub captures_process_local_env: bool,
1528 pub serializable: bool,
1529}
1530
1531#[derive(Clone, Debug, PartialEq)]
1532pub struct RuntimeCapabilities {
1533 pub abi_version: u32,
1534 pub natives: Vec<Symbol>,
1535 pub class_methods: Vec<Symbol>,
1536 pub(crate) native_impls: HashMap<Symbol, Vec<NativeCapability>>,
1537 pub(crate) class_method_impls: HashMap<Symbol, ClassMethodCapability>,
1538}
1539
1540impl RuntimeCapabilities {
1541 pub fn fingerprint(&self) -> u64 {
1542 let mut hasher = std::collections::hash_map::DefaultHasher::new();
1543 self.abi_version.hash(&mut hasher);
1544 "natives".hash(&mut hasher);
1545 self.natives.hash(&mut hasher);
1546 "class_methods".hash(&mut hasher);
1547 self.class_methods.hash(&mut hasher);
1548 hasher.finish()
1549 }
1550}
1551
1552#[derive(Clone, Debug, PartialEq)]
1553pub struct NativeCapability {
1554 pub name: Symbol,
1555 pub arity: usize,
1556 pub scheme: Scheme,
1557}
1558
1559#[derive(Clone, Debug, PartialEq)]
1560pub struct ClassMethodCapability {
1561 pub name: Symbol,
1562 pub scheme: Scheme,
1563}
1564
1565#[derive(Clone, Debug, PartialEq, Eq)]
1566pub struct RuntimeCompatibility {
1567 pub expected_abi_version: u32,
1568 pub actual_abi_version: u32,
1569 pub missing_natives: Vec<Symbol>,
1570 pub incompatible_natives: Vec<Symbol>,
1571 pub missing_class_methods: Vec<Symbol>,
1572 pub incompatible_class_methods: Vec<Symbol>,
1573}
1574
1575impl RuntimeCompatibility {
1576 pub fn is_compatible(&self) -> bool {
1577 self.expected_abi_version == self.actual_abi_version
1578 && self.missing_natives.is_empty()
1579 && self.incompatible_natives.is_empty()
1580 && self.missing_class_methods.is_empty()
1581 && self.incompatible_class_methods.is_empty()
1582 }
1583}
1584
1585#[derive(Clone)]
1586pub struct RuntimeSnapshot<State = ()>
1587where
1588 State: Clone + Send + Sync + 'static,
1589{
1590 pub state: Arc<State>,
1591 pub(crate) env: Env,
1592 pub(crate) natives: NativeRegistry<State>,
1593 pub(crate) typeclasses: TypeclassRegistry,
1594 pub(crate) type_system: TypeSystem,
1595 pub(crate) typeclass_cache: Arc<Mutex<HashMap<(Symbol, Type), Pointer>>>,
1596 pub(crate) cancel: CancellationToken,
1597 pub heap: Heap,
1598}
1599
1600impl<State> Clone for Engine<State>
1601where
1602 State: Clone + Send + Sync + 'static,
1603{
1604 fn clone(&self) -> Self {
1605 Self {
1606 state: Arc::clone(&self.state),
1607 env: self.env.clone(),
1608 natives: self.natives.clone(),
1609 typeclasses: self.typeclasses.clone(),
1610 type_system: self.type_system.clone(),
1611 typeclass_cache: Arc::clone(&self.typeclass_cache),
1612 modules: self.modules.clone(),
1613 injected_libraries: self.injected_libraries.clone(),
1614 library_exports_cache: self.library_exports_cache.clone(),
1615 library_interface_cache: self.library_interface_cache.clone(),
1616 library_sources: self.library_sources.clone(),
1617 library_source_fingerprints: self.library_source_fingerprints.clone(),
1618 published_cycle_interfaces: self.published_cycle_interfaces.clone(),
1619 default_imports: self.default_imports.clone(),
1620 virtual_libraries: self.virtual_libraries.clone(),
1621 library_local_type_names: self.library_local_type_names.clone(),
1622 registration_library_context: self.registration_library_context.clone(),
1623 cancel: self.cancel.clone(),
1624 heap: self.heap.clone(),
1625 }
1626 }
1627}
1628
1629impl<State> Default for Engine<State>
1630where
1631 State: Clone + Send + Sync + 'static + Default,
1632{
1633 fn default() -> Self {
1634 Self::new(State::default())
1635 }
1636}
1637
1638macro_rules! native_fn_type {
1639 (; $ret:ident) => {
1640 $ret::rex_type()
1641 };
1642 ($arg_ty:ident $(, $rest:ident)* ; $ret:ident) => {
1643 Type::fun($arg_ty::rex_type(), native_fn_type!($($rest),* ; $ret))
1644 };
1645}
1646
1647define_handler_impl!([] ; 0 ; fn() -> R);
1648define_handler_impl!([(A, a, 0)] ; 1 ; fn(A) -> R);
1649define_handler_impl!([(A, a, 0), (B, b, 1)] ; 2 ; fn(A, B) -> R);
1650define_handler_impl!([(A, a, 0), (B, b, 1), (C, c, 2)] ; 3 ; fn(A, B, C) -> R);
1651define_handler_impl!(
1652 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3)] ; 4 ; fn(A, B, C, D) -> R
1653);
1654define_handler_impl!(
1655 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4)] ; 5 ; fn(A, B, C, D, E) -> R
1656);
1657define_handler_impl!(
1658 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5)] ; 6 ; fn(A, B, C, D, E, G) -> R
1659);
1660define_handler_impl!(
1661 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6)] ; 7 ; fn(A, B, C, D, E, G, H) -> R
1662);
1663define_handler_impl!(
1664 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6), (I, i, 7)] ; 8 ; fn(A, B, C, D, E, G, H, I) -> R
1665);
1666
1667define_async_handler_impl!([] ; 0 ; fn() -> R);
1668define_async_handler_impl!([(A, a, 0)] ; 1 ; fn(A) -> R);
1669define_async_handler_impl!([(A, a, 0), (B, b, 1)] ; 2 ; fn(A, B) -> R);
1670define_async_handler_impl!([(A, a, 0), (B, b, 1), (C, c, 2)] ; 3 ; fn(A, B, C) -> R);
1671define_async_handler_impl!(
1672 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3)] ; 4 ; fn(A, B, C, D) -> R
1673);
1674define_async_handler_impl!(
1675 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4)] ; 5 ; fn(A, B, C, D, E) -> R
1676);
1677define_async_handler_impl!(
1678 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5)] ; 6 ; fn(A, B, C, D, E, G) -> R
1679);
1680define_async_handler_impl!(
1681 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6)] ; 7 ; fn(A, B, C, D, E, G, H) -> R
1682);
1683define_async_handler_impl!(
1684 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6), (I, i, 7)] ; 8 ; fn(A, B, C, D, E, G, H, I) -> R
1685);
1686
1687impl<State> Engine<State>
1688where
1689 State: Clone + Send + Sync + 'static,
1690{
1691 pub(crate) fn env_snapshot(&self) -> Env {
1692 self.env.clone()
1693 }
1694
1695 pub(crate) fn has_native_name(&self, name: &Symbol) -> bool {
1696 self.natives.has_name(name)
1697 }
1698
1699 pub(crate) fn runtime_snapshot(&self) -> RuntimeSnapshot<State> {
1700 RuntimeSnapshot {
1701 state: Arc::clone(&self.state),
1702 env: self.env.clone(),
1703 natives: self.natives.clone(),
1704 typeclasses: self.typeclasses.clone(),
1705 type_system: self.type_system.clone(),
1706 typeclass_cache: Arc::clone(&self.typeclass_cache),
1707 cancel: self.cancel.clone(),
1708 heap: self.heap.clone(),
1709 }
1710 }
1711
1712 pub(crate) fn runtime_capabilities_snapshot(&self) -> RuntimeCapabilities {
1713 let mut natives = self.natives.entries.keys().cloned().collect::<Vec<_>>();
1714 let mut class_methods = self
1715 .type_system
1716 .class_methods
1717 .keys()
1718 .cloned()
1719 .collect::<Vec<_>>();
1720 let mut native_impls = HashMap::new();
1721 for (name, impls) in &self.natives.entries {
1722 let mut caps = impls
1723 .iter()
1724 .map(|imp| NativeCapability {
1725 name: name.clone(),
1726 arity: imp.arity,
1727 scheme: imp.scheme.clone(),
1728 })
1729 .collect::<Vec<_>>();
1730 caps.sort_by(|a, b| {
1731 a.arity
1732 .cmp(&b.arity)
1733 .then_with(|| a.scheme.typ.to_string().cmp(&b.scheme.typ.to_string()))
1734 });
1735 native_impls.insert(name.clone(), caps);
1736 }
1737 let mut class_method_impls = HashMap::new();
1738 for (name, info) in &self.type_system.class_methods {
1739 class_method_impls.insert(
1740 name.clone(),
1741 ClassMethodCapability {
1742 name: name.clone(),
1743 scheme: info.scheme.clone(),
1744 },
1745 );
1746 }
1747 natives.sort();
1748 class_methods.sort();
1749 RuntimeCapabilities {
1750 abi_version: RUNTIME_LINK_ABI_VERSION,
1751 natives,
1752 class_methods,
1753 native_impls,
1754 class_method_impls,
1755 }
1756 }
1757
1758 pub fn new(state: State) -> Self {
1759 Self {
1760 state: Arc::new(state),
1761 env: Env::new(),
1762 natives: NativeRegistry::<State>::default(),
1763 typeclasses: TypeclassRegistry::default(),
1764 type_system: TypeSystem::new(),
1765 typeclass_cache: Arc::new(Mutex::new(HashMap::new())),
1766 modules: LibrarySystem::default(),
1767 injected_libraries: HashSet::new(),
1768 library_exports_cache: HashMap::new(),
1769 library_interface_cache: HashMap::new(),
1770 library_sources: HashMap::new(),
1771 library_source_fingerprints: HashMap::new(),
1772 published_cycle_interfaces: HashSet::new(),
1773 default_imports: Vec::new(),
1774 virtual_libraries: HashMap::new(),
1775 library_local_type_names: HashMap::new(),
1776 registration_library_context: None,
1777 cancel: CancellationToken::new(),
1778 heap: Heap::new(),
1779 }
1780 }
1781
1782 pub fn with_prelude(state: State) -> Result<Self, EngineError> {
1783 Self::with_options(state, EngineOptions::default())
1784 }
1785
1786 pub fn with_options(state: State, options: EngineOptions) -> Result<Self, EngineError> {
1787 let type_system = match options.prelude {
1788 PreludeMode::Enabled => TypeSystem::with_prelude()?,
1789 PreludeMode::Disabled => TypeSystem::new(),
1790 };
1791 let mut engine = Engine {
1792 state: Arc::new(state),
1793 env: Env::new(),
1794 natives: NativeRegistry::<State>::default(),
1795 typeclasses: TypeclassRegistry::default(),
1796 type_system,
1797 typeclass_cache: Arc::new(Mutex::new(HashMap::new())),
1798 modules: LibrarySystem::default(),
1799 injected_libraries: HashSet::new(),
1800 library_exports_cache: HashMap::new(),
1801 library_interface_cache: HashMap::new(),
1802 library_sources: HashMap::new(),
1803 library_source_fingerprints: HashMap::new(),
1804 published_cycle_interfaces: HashSet::new(),
1805 default_imports: options.default_imports,
1806 virtual_libraries: HashMap::new(),
1807 library_local_type_names: HashMap::new(),
1808 registration_library_context: None,
1809 cancel: CancellationToken::new(),
1810 heap: Heap::new(),
1811 };
1812 if matches!(options.prelude, PreludeMode::Enabled) {
1813 engine.inject_prelude()?;
1814 engine.inject_prelude_virtual_module()?;
1815 }
1816 Ok(engine)
1817 }
1818
1819 pub fn into_heap(self) -> Heap {
1820 self.heap
1821 }
1822
1823 pub fn inject_tracing_log_functions(&mut self) -> Result<(), EngineError> {
1828 let string = Type::builtin(BuiltinTypeId::String);
1829
1830 let make_scheme = |engine: &mut Engine<State>| {
1831 let a_tv = engine.type_system.supply.fresh(Some("a".into()));
1832 let a = Type::var(a_tv.clone());
1833 Scheme::new(
1834 vec![a_tv],
1835 vec![Predicate::new("Show", a.clone())],
1836 Type::fun(a, string.clone()),
1837 )
1838 };
1839
1840 let debug_scheme = make_scheme(self);
1841 self.inject_tracing_log_function_with_scheme("debug", debug_scheme, |s| {
1842 tracing::debug!("{s}")
1843 })?;
1844 let info_scheme = make_scheme(self);
1845 self.inject_tracing_log_function_with_scheme("info", info_scheme, |s| {
1846 tracing::info!("{s}")
1847 })?;
1848 let warn_scheme = make_scheme(self);
1849 self.inject_tracing_log_function_with_scheme("warn", warn_scheme, |s| {
1850 tracing::warn!("{s}")
1851 })?;
1852 let error_scheme = make_scheme(self);
1853 self.inject_tracing_log_function_with_scheme("error", error_scheme, |s| {
1854 tracing::error!("{s}")
1855 })?;
1856 Ok(())
1857 }
1858
1859 pub fn inject_tracing_log_function(
1860 &mut self,
1861 name: &str,
1862 log: fn(&str),
1863 ) -> Result<(), EngineError> {
1864 let string = Type::builtin(BuiltinTypeId::String);
1865 let a_tv = self.type_system.supply.fresh(Some("a".into()));
1866 let a = Type::var(a_tv.clone());
1867 let scheme = Scheme::new(
1868 vec![a_tv],
1869 vec![Predicate::new("Show", a.clone())],
1870 Type::fun(a, string),
1871 );
1872 self.inject_tracing_log_function_with_scheme(name, scheme, log)
1873 }
1874
1875 fn inject_tracing_log_function_with_scheme(
1876 &mut self,
1877 name: &str,
1878 scheme: Scheme,
1879 log: fn(&str),
1880 ) -> Result<(), EngineError> {
1881 let name_sym = sym(name);
1882 self.export_native_async(name, scheme, 1, move |engine, call_type, args| {
1883 let name_sym = name_sym.clone();
1884 async move {
1885 if args.len() != 1 {
1886 return Err(EngineError::NativeArity {
1887 name: name_sym.clone(),
1888 expected: 1,
1889 got: args.len(),
1890 });
1891 }
1892
1893 let (arg_ty, _ret_ty) = split_fun(&call_type)
1894 .ok_or_else(|| EngineError::NotCallable(call_type.to_string()))?;
1895 let show_ty = Type::fun(arg_ty.clone(), Type::builtin(BuiltinTypeId::String));
1896 let mut gas = GasMeter::default();
1897 let show_ptr = engine
1898 .resolve_class_method(&sym("show"), &show_ty, &mut gas)
1899 .await?;
1900 let rendered_ptr = apply(
1901 &engine,
1902 show_ptr,
1903 args[0],
1904 Some(&show_ty),
1905 Some(&arg_ty),
1906 &mut gas,
1907 )
1908 .await?;
1909 let message = engine.heap.pointer_as_string(&rendered_ptr)?;
1910
1911 log(&message);
1912 engine.heap.alloc_string(message)
1913 }
1914 .boxed()
1915 })
1916 }
1917
1918 pub fn cancellation_token(&self) -> CancellationToken {
1919 self.cancel.clone()
1920 }
1921
1922 pub fn set_default_imports(&mut self, imports: Vec<String>) {
1923 self.default_imports = imports;
1924 }
1925
1926 pub fn default_imports(&self) -> &[String] {
1927 &self.default_imports
1928 }
1929
1930 pub fn registry_markdown(&self) -> String {
1953 fn library_anchor(id: &LibraryId) -> String {
1954 let raw = format!("library-{id}").to_ascii_lowercase();
1955 let mut out = String::with_capacity(raw.len());
1956 let mut prev_dash = false;
1957 for ch in raw.chars() {
1958 let keep = ch.is_ascii_alphanumeric();
1959 let mapped = if keep { ch } else { '-' };
1960 if mapped == '-' {
1961 if prev_dash {
1962 continue;
1963 }
1964 prev_dash = true;
1965 } else {
1966 prev_dash = false;
1967 }
1968 out.push(mapped);
1969 }
1970 out.trim_matches('-').to_string()
1971 }
1972
1973 fn symbol_list(symbols: &[Symbol]) -> String {
1974 if symbols.is_empty() {
1975 "(none)".to_string()
1976 } else {
1977 symbols
1978 .iter()
1979 .map(|s| format!("`{s}`"))
1980 .collect::<Vec<_>>()
1981 .join(", ")
1982 }
1983 }
1984
1985 let mut out = String::new();
1986 let _ = writeln!(&mut out, "# Engine Registry");
1987 let _ = writeln!(&mut out);
1988 let mut library_ids: BTreeMap<String, LibraryId> = BTreeMap::new();
1989 for id in self.library_exports_cache.keys() {
1990 library_ids.insert(id.to_string(), id.clone());
1991 }
1992 for id in self.library_sources.keys() {
1993 library_ids.insert(id.to_string(), id.clone());
1994 }
1995 for library_name in self.virtual_libraries.keys() {
1996 let id = LibraryId::Virtual(library_name.clone());
1997 library_ids.insert(id.to_string(), id);
1998 }
1999 for library_name in &self.injected_libraries {
2000 let id = LibraryId::Virtual(library_name.clone());
2001 library_ids.insert(id.to_string(), id);
2002 }
2003
2004 let _ = writeln!(&mut out, "## Summary");
2005 let env_value_count = self.type_system.env.values.size();
2006 let native_impl_count: usize = self.natives.entries.values().map(Vec::len).sum();
2007 let class_count = self.type_system.classes.classes.len();
2008 let class_instance_count: usize = self
2009 .type_system
2010 .classes
2011 .instances
2012 .values()
2013 .map(Vec::len)
2014 .sum();
2015 let _ = writeln!(&mut out, "- Libraries (all kinds): {}", library_ids.len());
2016 let _ = writeln!(
2017 &mut out,
2018 "- Injected libraries: {}",
2019 self.injected_libraries.len()
2020 );
2021 let _ = writeln!(
2022 &mut out,
2023 "- Virtual libraries: {}",
2024 self.virtual_libraries.len()
2025 );
2026 let _ = writeln!(&mut out, "- ADTs: {}", self.type_system.adts.len());
2027 let _ = writeln!(
2028 &mut out,
2029 "- Values/functions in type env: {env_value_count}"
2030 );
2031 let _ = writeln!(&mut out, "- Type classes: {class_count}");
2032 let _ = writeln!(&mut out, "- Type class instances: {class_instance_count}");
2033 let _ = writeln!(&mut out, "- Native implementations: {native_impl_count}");
2034 let _ = writeln!(&mut out);
2035
2036 let _ = writeln!(&mut out, "## Library Index");
2037 if library_ids.is_empty() {
2038 let _ = writeln!(&mut out, "_No libraries registered._");
2039 } else {
2040 for (display, id) in &library_ids {
2041 let anchor = library_anchor(id);
2042 let _ = writeln!(&mut out, "- [`{display}`](#{anchor})");
2043 }
2044 }
2045 let _ = writeln!(&mut out);
2046
2047 let _ = writeln!(&mut out, "## Libraries");
2048 if library_ids.is_empty() {
2049 let _ = writeln!(&mut out, "_No libraries registered._");
2050 let _ = writeln!(&mut out);
2051 } else {
2052 for (display, id) in library_ids {
2053 let anchor = library_anchor(&id);
2054 let _ = writeln!(&mut out, "<a id=\"{anchor}\"></a>");
2055 let _ = writeln!(&mut out, "### `{display}`");
2056 if let Some(source) = self.library_sources.get(&id) {
2057 if source.trim().is_empty() {
2058 let _ = writeln!(&mut out, "_Module source is empty._");
2059 } else {
2060 let _ = writeln!(&mut out, "```rex");
2061 let _ = writeln!(&mut out, "{}", source.trim_end());
2062 let _ = writeln!(&mut out, "```");
2063 }
2064 } else {
2065 let _ = writeln!(&mut out, "_No captured source for this library._");
2066 }
2067
2068 let exports = self.library_exports_cache.get(&id).or_else(|| match &id {
2069 LibraryId::Virtual(name) => self.virtual_libraries.get(name),
2070 _ => None,
2071 });
2072 if let Some(exports) = exports {
2073 let mut values: Vec<Symbol> = exports.values.keys().cloned().collect();
2074 let mut types: Vec<Symbol> = exports.types.keys().cloned().collect();
2075 let mut classes: Vec<Symbol> = exports.classes.keys().cloned().collect();
2076 values.sort();
2077 types.sort();
2078 classes.sort();
2079 let _ = writeln!(&mut out, "- Values: {}", symbol_list(&values));
2080 let _ = writeln!(&mut out, "- Types: {}", symbol_list(&types));
2081 let _ = writeln!(&mut out, "- Classes: {}", symbol_list(&classes));
2082 } else {
2083 let _ = writeln!(&mut out, "- Exports: (none cached)");
2084 }
2085 let _ = writeln!(&mut out);
2086 }
2087 }
2088
2089 let _ = writeln!(&mut out, "## ADTs");
2090 if self.type_system.adts.is_empty() {
2091 let _ = writeln!(&mut out, "_No ADTs registered._");
2092 let _ = writeln!(&mut out);
2093 } else {
2094 let mut adts: Vec<&AdtDecl> = self.type_system.adts.values().collect();
2095 adts.sort_by(|a, b| a.name.cmp(&b.name));
2096 for adt in adts {
2097 let params = if adt.params.is_empty() {
2098 "(none)".to_string()
2099 } else {
2100 adt.params
2101 .iter()
2102 .map(|p| format!("`{}`", p.name))
2103 .collect::<Vec<_>>()
2104 .join(", ")
2105 };
2106 let _ = writeln!(&mut out, "### `{}`", adt.name);
2107 let _ = writeln!(&mut out, "- Parameters: {params}");
2108 if adt.variants.is_empty() {
2109 let _ = writeln!(&mut out, "- Variants: (none)");
2110 } else {
2111 let mut variants = adt.variants.clone();
2112 variants.sort_by(|a, b| a.name.cmp(&b.name));
2113 let _ = writeln!(&mut out, "- Variants:");
2114 for variant in variants {
2115 if variant.args.is_empty() {
2116 let _ = writeln!(&mut out, " - `{}`", variant.name);
2117 } else {
2118 let args = variant
2119 .args
2120 .iter()
2121 .map(ToString::to_string)
2122 .collect::<Vec<_>>()
2123 .join(", ");
2124 let _ = writeln!(&mut out, " - `{}`({args})", variant.name);
2125 }
2126 }
2127 }
2128 let _ = writeln!(&mut out);
2129 }
2130 }
2131
2132 let _ = writeln!(&mut out, "## Functions and Values");
2133 if self.type_system.env.values.is_empty() {
2134 let _ = writeln!(&mut out, "_No values registered._");
2135 let _ = writeln!(&mut out);
2136 } else {
2137 let mut names: Vec<Symbol> = self
2138 .type_system
2139 .env
2140 .values
2141 .iter()
2142 .map(|(name, _)| name.clone())
2143 .collect();
2144 names.sort();
2145 for name in names {
2146 if let Some(schemes) = self.type_system.env.lookup(&name) {
2147 let mut scheme_strs: Vec<String> =
2148 schemes.iter().map(|s| s.typ.to_string()).collect();
2149 scheme_strs.sort();
2150 scheme_strs.dedup();
2151 let joined = scheme_strs
2152 .into_iter()
2153 .map(|s| format!("`{s}`"))
2154 .collect::<Vec<_>>()
2155 .join(", ");
2156 let _ = writeln!(&mut out, "- `{name}`: {joined}");
2157 }
2158 }
2159 let _ = writeln!(&mut out);
2160 }
2161
2162 let _ = writeln!(&mut out, "## Type Classes");
2163 if self.type_system.classes.classes.is_empty() {
2164 let _ = writeln!(&mut out, "_No type classes registered._");
2165 let _ = writeln!(&mut out);
2166 } else {
2167 let mut class_names: Vec<Symbol> =
2168 self.type_system.classes.classes.keys().cloned().collect();
2169 class_names.sort();
2170 for class_name in class_names {
2171 let supers = self.type_system.classes.supers_of(&class_name);
2172 let mut supers_sorted = supers;
2173 supers_sorted.sort();
2174 let _ = writeln!(&mut out, "### `{class_name}`");
2175 let _ = writeln!(&mut out, "- Superclasses: {}", symbol_list(&supers_sorted));
2176
2177 let mut methods: Vec<(Symbol, String)> = self
2178 .type_system
2179 .class_methods
2180 .iter()
2181 .filter(|(_, info)| info.class == class_name)
2182 .map(|(name, info)| (name.clone(), info.scheme.typ.to_string()))
2183 .collect();
2184 methods.sort_by(|a, b| a.0.cmp(&b.0));
2185 if methods.is_empty() {
2186 let _ = writeln!(&mut out, "- Methods: (none)");
2187 } else {
2188 let _ = writeln!(&mut out, "- Methods:");
2189 for (method, scheme) in methods {
2190 let _ = writeln!(&mut out, " - `{method}`: `{scheme}`");
2191 }
2192 }
2193
2194 let mut instances = self
2195 .type_system
2196 .classes
2197 .instances
2198 .get(&class_name)
2199 .cloned()
2200 .unwrap_or_default();
2201 instances.sort_by(|a, b| a.head.typ.to_string().cmp(&b.head.typ.to_string()));
2202 if instances.is_empty() {
2203 let _ = writeln!(&mut out, "- Instances: (none)");
2204 } else {
2205 let _ = writeln!(&mut out, "- Instances:");
2206 for instance in instances {
2207 let ctx = if instance.context.is_empty() {
2208 String::new()
2209 } else {
2210 let mut parts: Vec<String> = instance
2211 .context
2212 .iter()
2213 .map(|pred| format!("{} {}", pred.class, pred.typ))
2214 .collect();
2215 parts.sort();
2216 format!("({}) => ", parts.join(", "))
2217 };
2218 let _ = writeln!(
2219 &mut out,
2220 " - `{}{} {}`",
2221 ctx, instance.head.class, instance.head.typ
2222 );
2223 }
2224 }
2225 let _ = writeln!(&mut out);
2226 }
2227 }
2228
2229 let _ = writeln!(&mut out, "## Native Implementations");
2230 if self.natives.entries.is_empty() {
2231 let _ = writeln!(&mut out, "_No native implementations registered._");
2232 } else {
2233 let mut native_names: Vec<Symbol> = self.natives.entries.keys().cloned().collect();
2234 native_names.sort();
2235 for name in native_names {
2236 if let Some(impls) = self.natives.get(&name) {
2237 let mut rows: Vec<(usize, String, u64)> = impls
2238 .iter()
2239 .map(|imp| (imp.arity, imp.scheme.typ.to_string(), imp.gas_cost))
2240 .collect();
2241 rows.sort_by(|a, b| a.1.cmp(&b.1));
2242 let _ = writeln!(&mut out, "### `{name}`");
2243 for (arity, typ, gas_cost) in rows {
2244 let _ = writeln!(
2245 &mut out,
2246 "- arity `{arity}`, gas `{gas_cost}`, type `{typ}`"
2247 );
2248 }
2249 let _ = writeln!(&mut out);
2250 }
2251 }
2252 }
2253
2254 out
2255 }
2256
2257 pub fn cancel(&self) {
2258 self.cancel.cancel();
2259 }
2260
2261 pub fn inject_library(&mut self, library: Library<State>) -> Result<(), EngineError> {
2262 let library_name = library.name.trim().to_string();
2263 if library_name.is_empty() {
2264 return Err(EngineError::Internal("library name cannot be empty".into()));
2265 }
2266 if self.injected_libraries.contains(&library_name) {
2267 return Err(EngineError::Internal(format!(
2268 "library `{library_name}` already injected"
2269 )));
2270 }
2271
2272 let mut source = String::new();
2273 for declaration in &library.declarations {
2274 source.push_str(declaration);
2275 source.push('\n');
2276 }
2277 for export in &library.exports {
2278 source.push_str(&export.declaration);
2279 source.push('\n');
2280 }
2281 self.library_sources
2282 .insert(LibraryId::Virtual(library_name.clone()), source.clone());
2283
2284 let local_type_names = library_local_type_names_from_declarations(&library.declarations);
2285 self.library_local_type_names
2286 .insert(library_name.clone(), local_type_names);
2287
2288 for export in library.exports {
2289 self.inject_library_export(&library_name, export)?;
2290 }
2291
2292 let resolver_module_name = library_name.clone();
2293 let resolver_source = source.clone();
2294 self.add_resolver(
2295 format!("injected:{library_name}"),
2296 move |req: ResolveRequest| {
2297 let requested = req
2298 .library_name
2299 .split_once('#')
2300 .map(|(base, _)| base)
2301 .unwrap_or(req.library_name.as_str());
2302 if requested != resolver_module_name {
2303 return Ok(None);
2304 }
2305 Ok(Some(ResolvedLibrary {
2306 id: LibraryId::Virtual(resolver_module_name.clone()),
2307 source: resolver_source.clone(),
2308 }))
2309 },
2310 );
2311
2312 self.injected_libraries.insert(library_name);
2313 Ok(())
2314 }
2315
2316 fn library_export_symbol(library_name: &str, export_name: &str) -> String {
2317 if library_name == ROOT_LIBRARY_NAME {
2318 normalize_name(export_name).to_string()
2319 } else {
2320 virtual_export_name(library_name, export_name)
2321 }
2322 }
2323
2324 fn inject_library_export(
2325 &mut self,
2326 library_name: &str,
2327 export: Export<State>,
2328 ) -> Result<(), EngineError> {
2329 let Export {
2330 name,
2331 declaration: _,
2332 injector,
2333 } = export;
2334 let qualified_name = Self::library_export_symbol(library_name, &name);
2335 let previous_context = self.registration_library_context.clone();
2336 self.registration_library_context = if library_name == ROOT_LIBRARY_NAME {
2337 None
2338 } else {
2339 Some(library_name.to_string())
2340 };
2341 let result = injector(self, &qualified_name);
2342 self.registration_library_context = previous_context;
2343 result
2344 }
2345
2346 fn inject_root_export(&mut self, export: Export<State>) -> Result<(), EngineError> {
2347 self.inject_library_export(ROOT_LIBRARY_NAME, export)
2348 }
2349
2350 fn register_native_registration(
2351 &mut self,
2352 library_name: &str,
2353 export_name: &str,
2354 registration: NativeRegistration<State>,
2355 ) -> Result<(), EngineError> {
2356 let NativeRegistration {
2357 mut scheme,
2358 arity,
2359 callable,
2360 gas_cost,
2361 } = registration;
2362 let scheme_module = if library_name == ROOT_LIBRARY_NAME {
2363 self.registration_library_context
2364 .as_deref()
2365 .unwrap_or(ROOT_LIBRARY_NAME)
2366 } else {
2367 library_name
2368 };
2369 if scheme_module != ROOT_LIBRARY_NAME
2370 && let Some(local_type_names) = self.library_local_type_names.get(scheme_module)
2371 {
2372 scheme = qualify_library_scheme_refs(&scheme, scheme_module, local_type_names);
2373 }
2374 let name = normalize_name(&Self::library_export_symbol(library_name, export_name));
2375 self.register_native(name, scheme, arity, callable, gas_cost)
2376 }
2377
2378 pub fn export<Sig, H>(&mut self, name: impl Into<String>, handler: H) -> Result<(), EngineError>
2379 where
2380 H: Handler<State, Sig>,
2381 {
2382 self.inject_root_export(Export::from_handler(name, handler)?)
2383 }
2384
2385 pub fn export_async<Sig, H>(
2386 &mut self,
2387 name: impl Into<String>,
2388 handler: H,
2389 ) -> Result<(), EngineError>
2390 where
2391 H: AsyncHandler<State, Sig>,
2392 {
2393 self.inject_root_export(Export::from_async_handler(name, handler)?)
2394 }
2395
2396 pub fn export_native<F>(
2397 &mut self,
2398 name: impl Into<String>,
2399 scheme: Scheme,
2400 arity: usize,
2401 handler: F,
2402 ) -> Result<(), EngineError>
2403 where
2404 F: for<'a> Fn(
2405 EvaluatorRef<'a, State>,
2406 &'a Type,
2407 &'a [Pointer],
2408 ) -> Result<Pointer, EngineError>
2409 + Send
2410 + Sync
2411 + 'static,
2412 {
2413 self.export_native_with_gas_cost(name, scheme, arity, 0, handler)
2414 }
2415
2416 pub fn inject_rex_default_instance<T>(&mut self) -> Result<(), EngineError>
2417 where
2418 T: RexType + RexDefault<State>,
2419 {
2420 let class = sym("Default");
2421 let method = sym("default");
2422 let head_ty = T::rex_type();
2423
2424 if !self.type_system.class_methods.contains_key(&method) {
2425 return Err(EngineError::UnknownVar(method));
2426 }
2427 if !head_ty.ftv().is_empty() {
2428 return Err(EngineError::UnsupportedExpr);
2429 }
2430
2431 if let Some(instances) = self.type_system.classes.instances.get(&class)
2432 && instances
2433 .iter()
2434 .any(|existing| unify(&existing.head.typ, &head_ty).is_ok())
2435 {
2436 return Err(EngineError::DuplicateTypeclassImpl {
2437 class,
2438 typ: head_ty.to_string(),
2439 });
2440 }
2441
2442 let native_name = format!(
2443 "__rex_default_for_{}",
2444 sanitize_type_name_for_symbol(&head_ty)
2445 );
2446 let native_scheme = Scheme::new(vec![], vec![], head_ty.clone());
2447 let engine_for_default = self.clone();
2448 self.export_native(
2449 native_name.clone(),
2450 native_scheme,
2451 0,
2452 move |engine, _, _| {
2453 let _ = engine;
2454 T::rex_default(&engine_for_default)
2455 },
2456 )?;
2457
2458 self.type_system.inject_instance(
2459 "Default",
2460 Instance::new(vec![], Predicate::new(class.clone(), head_ty.clone())),
2461 );
2462
2463 let mut methods: HashMap<Symbol, Arc<TypedExpr>> = HashMap::new();
2464 methods.insert(
2465 method.clone(),
2466 Arc::new(TypedExpr::new(
2467 head_ty.clone(),
2468 TypedExprKind::Var {
2469 name: sym(&native_name),
2470 overloads: vec![],
2471 },
2472 )),
2473 );
2474
2475 self.typeclasses
2476 .insert(class, head_ty, self.env.clone(), methods)?;
2477
2478 Ok(())
2479 }
2480
2481 pub fn export_native_async<F>(
2482 &mut self,
2483 name: impl Into<String>,
2484 scheme: Scheme,
2485 arity: usize,
2486 handler: F,
2487 ) -> Result<(), EngineError>
2488 where
2489 F: for<'a> Fn(EvaluatorRef<'a, State>, Type, Vec<Pointer>) -> NativeFuture<'a>
2490 + Send
2491 + Sync
2492 + 'static,
2493 {
2494 self.export_native_async_with_gas_cost(name, scheme, arity, 0, handler)
2495 }
2496
2497 pub fn export_value<V: IntoPointer + RexType>(
2498 &mut self,
2499 name: &str,
2500 value: V,
2501 ) -> Result<(), EngineError> {
2502 let typ = V::rex_type();
2503 let value = value.into_pointer(&self.heap)?;
2504 let func: SyncNativeCallable<State> =
2505 Arc::new(move |_engine, _: &Type, _args: &[Pointer]| Ok(value));
2506 let scheme = Scheme::new(vec![], vec![], typ);
2507 let registration = NativeRegistration::sync(scheme, 0, func, 0);
2508 self.register_native_registration(ROOT_LIBRARY_NAME, name, registration)
2509 }
2510
2511 pub fn export_value_typed(
2512 &mut self,
2513 name: &str,
2514 typ: Type,
2515 value: Value,
2516 ) -> Result<(), EngineError> {
2517 let value = self.heap.alloc_value(value)?;
2518 let func: SyncNativeCallable<State> =
2519 Arc::new(move |_engine, _: &Type, _args: &[Pointer]| Ok(value));
2520 let scheme = Scheme::new(vec![], vec![], typ);
2521 let registration = NativeRegistration::sync(scheme, 0, func, 0);
2522 self.register_native_registration(ROOT_LIBRARY_NAME, name, registration)
2523 }
2524
2525 pub fn export_native_with_gas_cost<F>(
2526 &mut self,
2527 name: impl Into<String>,
2528 scheme: Scheme,
2529 arity: usize,
2530 gas_cost: u64,
2531 handler: F,
2532 ) -> Result<(), EngineError>
2533 where
2534 F: for<'a> Fn(
2535 EvaluatorRef<'a, State>,
2536 &'a Type,
2537 &'a [Pointer],
2538 ) -> Result<Pointer, EngineError>
2539 + Send
2540 + Sync
2541 + 'static,
2542 {
2543 validate_native_export_scheme(&scheme, arity)?;
2544 let name = name.into();
2545 let handler = Arc::new(handler);
2546 let func: SyncNativeCallable<State> =
2547 Arc::new(move |engine, typ: &Type, args: &[Pointer]| handler(engine, typ, args));
2548 let registration = NativeRegistration::sync(scheme, arity, func, gas_cost);
2549 self.register_native_registration(ROOT_LIBRARY_NAME, &name, registration)
2550 }
2551
2552 pub fn export_native_async_with_gas_cost<F>(
2553 &mut self,
2554 name: impl Into<String>,
2555 scheme: Scheme,
2556 arity: usize,
2557 gas_cost: u64,
2558 handler: F,
2559 ) -> Result<(), EngineError>
2560 where
2561 F: for<'a> Fn(EvaluatorRef<'a, State>, Type, Vec<Pointer>) -> NativeFuture<'a>
2562 + Send
2563 + Sync
2564 + 'static,
2565 {
2566 validate_native_export_scheme(&scheme, arity)?;
2567 let name = name.into();
2568 let handler = Arc::new(handler);
2569 let func: AsyncNativeCallable<State> = Arc::new(move |engine, typ, args| {
2570 let handler = Arc::clone(&handler);
2571 handler(engine, typ, args.to_vec())
2572 });
2573 let registration = NativeRegistration::r#async(scheme, arity, func, gas_cost);
2574 self.register_native_registration(ROOT_LIBRARY_NAME, &name, registration)
2575 }
2576
2577 pub fn export_native_async_cancellable<F>(
2578 &mut self,
2579 name: impl Into<String>,
2580 scheme: Scheme,
2581 arity: usize,
2582 handler: F,
2583 ) -> Result<(), EngineError>
2584 where
2585 F: for<'a> Fn(
2586 EvaluatorRef<'a, State>,
2587 CancellationToken,
2588 Type,
2589 &'a [Pointer],
2590 ) -> NativeFuture<'a>
2591 + Send
2592 + Sync
2593 + 'static,
2594 {
2595 self.export_native_async_cancellable_with_gas_cost(name, scheme, arity, 0, handler)
2596 }
2597
2598 pub fn export_native_async_cancellable_with_gas_cost<F>(
2599 &mut self,
2600 name: impl Into<String>,
2601 scheme: Scheme,
2602 arity: usize,
2603 gas_cost: u64,
2604 handler: F,
2605 ) -> Result<(), EngineError>
2606 where
2607 F: for<'a> Fn(
2608 EvaluatorRef<'a, State>,
2609 CancellationToken,
2610 Type,
2611 &'a [Pointer],
2612 ) -> NativeFuture<'a>
2613 + Send
2614 + Sync
2615 + 'static,
2616 {
2617 validate_native_export_scheme(&scheme, arity)?;
2618 let name = name.into();
2619 let handler = Arc::new(handler);
2620 let func: AsyncNativeCallableCancellable<State> =
2621 Arc::new(move |engine, token, typ, args| handler(engine, token, typ, args));
2622 let registration = NativeRegistration::async_cancellable(scheme, arity, func, gas_cost);
2623 self.register_native_registration(ROOT_LIBRARY_NAME, &name, registration)
2624 }
2625
2626 pub fn adt_decl(&mut self, name: &str, params: &[&str]) -> AdtDecl {
2627 let name_sym = sym(name);
2628 let param_syms: Vec<Symbol> = params.iter().map(|p| sym(p)).collect();
2629 AdtDecl::new(&name_sym, ¶m_syms, &mut self.type_system.supply)
2630 }
2631
2632 pub fn adt_decl_from_type(&mut self, typ: &Type) -> Result<AdtDecl, EngineError> {
2639 let (name, arity, args) = type_head_and_args(typ)?;
2640 let param_names: Vec<String> = if args.is_empty() {
2641 (0..arity).map(|i| format!("t{i}")).collect()
2642 } else {
2643 let mut names = Vec::with_capacity(args.len());
2644 for arg in args {
2645 match arg.as_ref() {
2646 TypeKind::Var(tv) => {
2647 let name = tv
2648 .name
2649 .as_ref()
2650 .map(|s| s.to_string())
2651 .unwrap_or_else(|| format!("t{}", tv.id));
2652 names.push(name);
2653 }
2654 _ => {
2655 return Err(EngineError::Custom(format!(
2656 "cannot infer ADT params from `{typ}`: expected type variables, got `{arg}`"
2657 )));
2658 }
2659 }
2660 }
2661 names
2662 };
2663 let param_refs: Vec<&str> = param_names.iter().map(|s| s.as_str()).collect();
2664 Ok(self.adt_decl(name.as_ref(), ¶m_refs))
2665 }
2666
2667 pub fn adt_decl_from_type_with_params(
2669 &mut self,
2670 typ: &Type,
2671 params: &[&str],
2672 ) -> Result<AdtDecl, EngineError> {
2673 let (name, arity, _args) = type_head_and_args(typ)?;
2674 if arity != params.len() {
2675 return Err(EngineError::Custom(format!(
2676 "type `{}` expects {} parameters, got {}",
2677 name,
2678 arity,
2679 params.len()
2680 )));
2681 }
2682 Ok(self.adt_decl(name.as_ref(), params))
2683 }
2684
2685 pub fn inject_adt(&mut self, adt: AdtDecl) -> Result<(), EngineError> {
2686 self.type_system.inject_adt(&adt);
2689 for (ctor, scheme) in adt.constructor_schemes() {
2690 let ctor_name = ctor.clone();
2691 let func = Arc::new(
2692 move |engine: EvaluatorRef<'_, State>, _: &Type, args: &[Pointer]| {
2693 engine.heap.alloc_adt(ctor_name.clone(), args.to_vec())
2694 },
2695 );
2696 let arity = type_arity(&scheme.typ);
2697 self.register_native(ctor, scheme, arity, NativeCallable::Sync(func), 0)?;
2698 }
2699 Ok(())
2700 }
2701
2702 pub fn inject_type_decl(&mut self, decl: &TypeDecl) -> Result<(), EngineError> {
2703 let adt = self
2704 .type_system
2705 .adt_from_decl(decl)
2706 .map_err(EngineError::Type)?;
2707 self.inject_adt(adt)
2708 }
2709
2710 pub fn inject_class_decl(&mut self, decl: &ClassDecl) -> Result<(), EngineError> {
2711 self.type_system
2712 .inject_class_decl(decl)
2713 .map_err(EngineError::Type)
2714 }
2715
2716 pub fn inject_instance_decl(&mut self, decl: &InstanceDecl) -> Result<(), EngineError> {
2717 let prepared = self
2718 .type_system
2719 .inject_instance_decl(decl)
2720 .map_err(EngineError::Type)?;
2721 self.register_typeclass_instance(decl, &prepared)
2722 }
2723
2724 pub fn inject_fn_decl(&mut self, decl: &FnDecl) -> Result<(), EngineError> {
2725 self.inject_fn_decls(std::slice::from_ref(decl))
2726 }
2727
2728 pub fn inject_fn_decls(&mut self, decls: &[FnDecl]) -> Result<(), EngineError> {
2729 if decls.is_empty() {
2730 return Ok(());
2731 }
2732
2733 self.type_system
2735 .inject_fn_decls(decls)
2736 .map_err(EngineError::Type)?;
2737
2738 let mut env_rec = self.env.clone();
2740 let mut slots = Vec::with_capacity(decls.len());
2741 for decl in decls {
2742 if let Some(existing) = env_rec.get(&decl.name.name) {
2743 slots.push(existing);
2744 } else {
2745 let placeholder = self.heap.alloc_uninitialized(decl.name.name.clone())?;
2746 env_rec = env_rec.extend(decl.name.name.clone(), placeholder);
2747 slots.push(placeholder);
2748 }
2749 }
2750
2751 let saved_env = self.env.clone();
2752 self.env = env_rec.clone();
2753
2754 let result: Result<(), EngineError> = (|| {
2755 for (decl, slot) in decls.iter().zip(slots.iter()) {
2756 let mut lam_body = decl.body.clone();
2757 for (idx, (param, ann)) in decl.params.iter().enumerate().rev() {
2758 let lam_constraints = if idx == 0 {
2759 decl.constraints.clone()
2760 } else {
2761 Vec::new()
2762 };
2763 let span = param.span;
2764 lam_body = Arc::new(Expr::Lam(
2765 span,
2766 Scope::new_sync(),
2767 param.clone(),
2768 Some(ann.clone()),
2769 lam_constraints,
2770 lam_body,
2771 ));
2772 }
2773
2774 let typed = self.type_check_expr(lam_body.as_ref())?;
2775 let (param_ty, _ret_ty) = split_fun(&typed.typ)
2776 .ok_or_else(|| EngineError::NotCallable(typed.typ.to_string()))?;
2777 let TypedExprKind::Lam { param, body } = &typed.kind else {
2778 return Err(EngineError::Internal(
2779 "fn declaration did not lower to lambda".into(),
2780 ));
2781 };
2782 let ptr = self.heap.alloc_closure(
2783 self.env.clone(),
2784 param.clone(),
2785 param_ty,
2786 typed.typ.clone(),
2787 Arc::new(body.as_ref().clone()),
2788 )?;
2789 let value = self.heap.get(&ptr)?;
2790 self.heap.overwrite(slot, value.as_ref().clone())?;
2791 }
2792 Ok(())
2793 })();
2794
2795 if result.is_err() {
2796 self.env = saved_env;
2797 return result;
2798 }
2799
2800 self.env = env_rec;
2801 Ok(())
2802 }
2803
2804 pub fn inject_decls(&mut self, decls: &[Decl]) -> Result<(), EngineError> {
2805 let mut pending_fns: Vec<FnDecl> = Vec::new();
2806 for decl in decls {
2807 if let Decl::Fn(fd) = decl {
2808 pending_fns.push(fd.clone());
2809 continue;
2810 }
2811 if !pending_fns.is_empty() {
2812 self.inject_fn_decls(&pending_fns)?;
2813 pending_fns.clear();
2814 }
2815
2816 match decl {
2817 Decl::Type(ty) => self.inject_type_decl(ty)?,
2818 Decl::Class(class_decl) => self.inject_class_decl(class_decl)?,
2819 Decl::Instance(inst_decl) => self.inject_instance_decl(inst_decl)?,
2820 Decl::Fn(..) => {}
2821 Decl::DeclareFn(df) => {
2822 self.type_system
2823 .inject_declare_fn_decl(df)
2824 .map_err(EngineError::Type)?;
2825 }
2826 Decl::Import(..) => {}
2827 }
2828 }
2829 if !pending_fns.is_empty() {
2830 self.inject_fn_decls(&pending_fns)?;
2831 }
2832 Ok(())
2833 }
2834
2835 pub(crate) fn publish_runtime_decl_interfaces(
2836 &mut self,
2837 decls: &[DeclareFnDecl],
2838 ) -> Result<(), EngineError> {
2839 for df in decls {
2840 if self.env.get(&df.name.name).is_some() {
2841 continue;
2842 }
2843 let placeholder = self.heap.alloc_uninitialized(df.name.name.clone())?;
2844 self.env = self.env.extend(df.name.name.clone(), placeholder);
2845 }
2846 Ok(())
2847 }
2848
2849 pub fn inject_class(&mut self, name: &str, supers: Vec<String>) {
2850 let supers = supers.into_iter().map(|s| sym(&s)).collect();
2851 self.type_system.inject_class(name, supers);
2852 }
2853
2854 pub fn inject_instance(&mut self, class: &str, inst: Instance) {
2855 self.type_system.inject_instance(class, inst);
2856 }
2857
2858 fn inject_prelude(&mut self) -> Result<(), EngineError> {
2859 inject_prelude_adts(self)?;
2860 inject_equality_ops(self)?;
2861 inject_order_ops(self)?;
2862 inject_show_ops(self)?;
2863 inject_boolean_ops(self)?;
2864 inject_numeric_ops(self)?;
2865 inject_list_builtins(self)?;
2866 inject_option_result_builtins(self)?;
2867 inject_json_primops(self)?;
2868 self.register_prelude_typeclass_instances()?;
2869 Ok(())
2870 }
2871
2872 fn inject_prelude_virtual_module(&mut self) -> Result<(), EngineError> {
2873 if self.virtual_libraries.contains_key(PRELUDE_LIBRARY_NAME) {
2874 return Ok(());
2875 }
2876
2877 let module_key =
2878 library_key_for_library(&LibraryId::Virtual(PRELUDE_LIBRARY_NAME.to_string()));
2879 let mut values: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
2880 for (name, _) in self.type_system.env.values.iter() {
2881 if !name.as_ref().starts_with("@m") {
2882 values.insert(
2883 name.clone(),
2884 CanonicalSymbol::from_symbol(
2885 module_key,
2886 SymbolKind::Value,
2887 name.clone(),
2888 name.clone(),
2889 ),
2890 );
2891 }
2892 }
2893
2894 let mut types: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
2895 for name in self.type_system.adts.keys() {
2896 if !name.as_ref().starts_with("@m") {
2897 types.insert(
2898 name.clone(),
2899 CanonicalSymbol::from_symbol(
2900 module_key,
2901 SymbolKind::Type,
2902 name.clone(),
2903 name.clone(),
2904 ),
2905 );
2906 }
2907 }
2908
2909 let mut classes: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
2910 for name in self.type_system.class_info.keys() {
2911 if !name.as_ref().starts_with("@m") {
2912 classes.insert(
2913 name.clone(),
2914 CanonicalSymbol::from_symbol(
2915 module_key,
2916 SymbolKind::Class,
2917 name.clone(),
2918 name.clone(),
2919 ),
2920 );
2921 }
2922 }
2923
2924 self.virtual_libraries.insert(
2925 PRELUDE_LIBRARY_NAME.to_string(),
2926 LibraryExports {
2927 values,
2928 types,
2929 classes,
2930 },
2931 );
2932 Ok(())
2933 }
2934
2935 pub(crate) fn virtual_library_exports(&self, library_name: &str) -> Option<LibraryExports> {
2936 self.virtual_libraries.get(library_name).cloned()
2937 }
2938
2939 fn register_prelude_typeclass_instances(&mut self) -> Result<(), EngineError> {
2940 let program =
2944 rexlang_typesystem::prelude_typeclasses_program().map_err(EngineError::Type)?;
2945 for decl in program.decls.iter() {
2946 let Decl::Instance(inst_decl) = decl else {
2947 continue;
2948 };
2949 if inst_decl.methods.is_empty() {
2950 continue;
2951 }
2952 let prepared = self
2953 .type_system
2954 .prepare_instance_decl(inst_decl)
2955 .map_err(EngineError::Type)?;
2956 self.register_typeclass_instance(inst_decl, &prepared)?;
2957 }
2958 Ok(())
2959 }
2960
2961 fn register_native(
2962 &mut self,
2963 name: Symbol,
2964 scheme: Scheme,
2965 arity: usize,
2966 func: NativeCallable<State>,
2967 gas_cost: u64,
2968 ) -> Result<(), EngineError> {
2969 let expected = type_arity(&scheme.typ);
2970 if expected != arity {
2971 return Err(EngineError::NativeArity {
2972 name: name.clone(),
2973 expected,
2974 got: arity,
2975 });
2976 }
2977 self.register_type_scheme(&name, &scheme)?;
2978 self.natives.insert(name, arity, scheme, func, gas_cost)
2979 }
2980
2981 fn register_type_scheme(
2982 &mut self,
2983 name: &Symbol,
2984 injected: &Scheme,
2985 ) -> Result<(), EngineError> {
2986 let schemes = self.type_system.env.lookup(name);
2987 match schemes {
2988 None => {
2989 self.type_system.add_value(name.as_ref(), injected.clone());
2990 Ok(())
2991 }
2992 Some(schemes) => {
2993 let has_poly = schemes
2994 .iter()
2995 .any(|s| !s.vars.is_empty() || !s.preds.is_empty());
2996 if has_poly {
2997 for existing in schemes {
2998 if scheme_accepts(&self.type_system, existing, &injected.typ)? {
2999 return Ok(());
3000 }
3001 }
3002 Err(EngineError::InvalidInjection {
3003 name: name.clone(),
3004 typ: injected.typ.to_string(),
3005 })
3006 } else {
3007 if schemes.iter().any(|s| s == injected) {
3008 return Ok(());
3009 }
3010 self.type_system
3011 .add_overload(name.as_ref(), injected.clone());
3012 Ok(())
3013 }
3014 }
3015 }
3016 }
3017
3018 pub(crate) fn infer_type(
3019 &mut self,
3020 expr: &Expr,
3021 gas: &mut GasMeter,
3022 ) -> Result<(Vec<Predicate>, Type), EngineError> {
3023 self.type_system
3024 .infer_with_gas(expr, gas)
3025 .map_err(EngineError::Type)
3026 }
3027
3028 fn type_check_expr(&mut self, expr: &Expr) -> Result<TypedExpr, EngineError> {
3029 type_check_engine(self, expr)
3030 }
3031
3032 fn check_natives(&self, expr: &TypedExpr) -> Result<(), EngineError> {
3033 check_natives_in_engine(self, expr)
3034 }
3035
3036 fn register_typeclass_instance(
3037 &mut self,
3038 decl: &InstanceDecl,
3039 prepared: &PreparedInstanceDecl,
3040 ) -> Result<(), EngineError> {
3041 let mut methods: HashMap<Symbol, Arc<TypedExpr>> = HashMap::new();
3042 for method in &decl.methods {
3043 let typed = self
3044 .type_system
3045 .typecheck_instance_method(prepared, method)
3046 .map_err(EngineError::Type)?;
3047 self.check_natives(&typed)?;
3048 methods.insert(method.name.clone(), Arc::new(typed));
3049 }
3050
3051 self.typeclasses.insert(
3052 prepared.class.clone(),
3053 prepared.head.clone(),
3054 self.env.clone(),
3055 methods,
3056 )?;
3057 Ok(())
3058 }
3059
3060 pub(crate) fn lookup_scheme(&self, name: &Symbol) -> Result<Scheme, EngineError> {
3061 let schemes = self
3062 .type_system
3063 .env
3064 .lookup(name)
3065 .ok_or_else(|| EngineError::UnknownVar(name.clone()))?;
3066 if schemes.len() != 1 {
3067 return Err(EngineError::AmbiguousOverload { name: name.clone() });
3068 }
3069 Ok(schemes[0].clone())
3070 }
3071}
3072
3073pub(crate) fn type_check_engine<State>(
3074 engine: &mut Engine<State>,
3075 expr: &Expr,
3076) -> Result<TypedExpr, EngineError>
3077where
3078 State: Clone + Send + Sync + 'static,
3079{
3080 if let Some(span) = first_hole_span(expr) {
3081 return Err(EngineError::Type(TypeError::Spanned {
3082 span,
3083 error: Box::new(TypeError::UnsupportedExpr(
3084 "typed hole `?` must be filled before evaluation",
3085 )),
3086 }));
3087 }
3088 let (typed, preds, _ty) = engine.type_system.infer_typed(expr)?;
3089 let (typed, preds) = default_ambiguous_types(engine, typed, preds)?;
3090 check_predicates_in_engine(engine, &preds)?;
3091 check_natives_in_engine(engine, &typed)?;
3092 Ok(typed)
3093}
3094
3095fn check_predicates_in_engine<State>(
3096 engine: &Engine<State>,
3097 preds: &[Predicate],
3098) -> Result<(), EngineError>
3099where
3100 State: Clone + Send + Sync + 'static,
3101{
3102 for pred in preds {
3103 if pred.typ.ftv().is_empty() {
3104 let ok = entails(&engine.type_system.classes, &[], pred)?;
3105 if !ok {
3106 return Err(EngineError::Type(TypeError::NoInstance(
3107 pred.class.clone(),
3108 pred.typ.to_string(),
3109 )));
3110 }
3111 }
3112 }
3113 Ok(())
3114}
3115
3116fn check_natives_in_engine<State>(
3117 engine: &Engine<State>,
3118 expr: &TypedExpr,
3119) -> Result<(), EngineError>
3120where
3121 State: Clone + Send + Sync + 'static,
3122{
3123 enum Frame<'b> {
3124 Expr(&'b TypedExpr),
3125 Push(Symbol),
3126 PushMany(Vec<Symbol>),
3127 Pop(usize),
3128 }
3129
3130 let mut bound: Vec<Symbol> = Vec::new();
3131 let mut stack = vec![Frame::Expr(expr)];
3132 while let Some(frame) = stack.pop() {
3133 match frame {
3134 Frame::Expr(expr) => match &expr.kind {
3135 TypedExprKind::Var { name, overloads } => {
3136 if bound.iter().any(|n| n == name) {
3137 continue;
3138 }
3139 if !engine.natives.has_name(name) {
3140 if engine.env.get(name).is_some() {
3141 continue;
3142 }
3143 if engine.type_system.class_methods.contains_key(name) {
3144 continue;
3145 }
3146 return Err(EngineError::UnknownVar(name.clone()));
3147 }
3148 if !overloads.is_empty()
3149 && expr.typ.ftv().is_empty()
3150 && !overloads.iter().any(|t| unify(t, &expr.typ).is_ok())
3151 {
3152 return Err(EngineError::MissingImpl {
3153 name: name.clone(),
3154 typ: expr.typ.to_string(),
3155 });
3156 }
3157 if expr.typ.ftv().is_empty()
3158 && !has_native_impl_in_engine(engine, name, &expr.typ)
3159 {
3160 return Err(EngineError::MissingImpl {
3161 name: name.clone(),
3162 typ: expr.typ.to_string(),
3163 });
3164 }
3165 }
3166 TypedExprKind::Tuple(elems) | TypedExprKind::List(elems) => {
3167 for elem in elems.iter().rev() {
3168 stack.push(Frame::Expr(elem));
3169 }
3170 }
3171 TypedExprKind::Dict(kvs) => {
3172 for v in kvs.values().rev() {
3173 stack.push(Frame::Expr(v));
3174 }
3175 }
3176 TypedExprKind::RecordUpdate { base, updates } => {
3177 for v in updates.values().rev() {
3178 stack.push(Frame::Expr(v));
3179 }
3180 stack.push(Frame::Expr(base));
3181 }
3182 TypedExprKind::App(f, x) => {
3183 stack.push(Frame::Expr(x));
3184 stack.push(Frame::Expr(f));
3185 }
3186 TypedExprKind::Project { expr, .. } => stack.push(Frame::Expr(expr)),
3187 TypedExprKind::Lam { param, body } => {
3188 stack.push(Frame::Pop(1));
3189 stack.push(Frame::Expr(body));
3190 stack.push(Frame::Push(param.clone()));
3191 }
3192 TypedExprKind::Let { name, def, body } => {
3193 stack.push(Frame::Pop(1));
3194 stack.push(Frame::Expr(body));
3195 stack.push(Frame::Push(name.clone()));
3196 stack.push(Frame::Expr(def));
3197 }
3198 TypedExprKind::LetRec { bindings, body } => {
3199 if !bindings.is_empty() {
3200 stack.push(Frame::Pop(bindings.len()));
3201 stack.push(Frame::Expr(body));
3202 for (_, def) in bindings.iter().rev() {
3203 stack.push(Frame::Expr(def));
3204 }
3205 stack.push(Frame::PushMany(
3206 bindings.iter().map(|(name, _)| name.clone()).collect(),
3207 ));
3208 } else {
3209 stack.push(Frame::Expr(body));
3210 }
3211 }
3212 TypedExprKind::Ite {
3213 cond,
3214 then_expr,
3215 else_expr,
3216 } => {
3217 stack.push(Frame::Expr(else_expr));
3218 stack.push(Frame::Expr(then_expr));
3219 stack.push(Frame::Expr(cond));
3220 }
3221 TypedExprKind::Match { scrutinee, arms } => {
3222 for (pat, arm_expr) in arms.iter().rev() {
3223 let mut bindings = Vec::new();
3224 collect_pattern_bindings(pat, &mut bindings);
3225 let count = bindings.len();
3226 if count != 0 {
3227 stack.push(Frame::Pop(count));
3228 stack.push(Frame::Expr(arm_expr));
3229 stack.push(Frame::PushMany(bindings));
3230 } else {
3231 stack.push(Frame::Expr(arm_expr));
3232 }
3233 }
3234 stack.push(Frame::Expr(scrutinee));
3235 }
3236 TypedExprKind::Bool(..)
3237 | TypedExprKind::Uint(..)
3238 | TypedExprKind::Int(..)
3239 | TypedExprKind::Float(..)
3240 | TypedExprKind::String(..)
3241 | TypedExprKind::Uuid(..)
3242 | TypedExprKind::DateTime(..) => {}
3243 TypedExprKind::Hole => return Err(EngineError::UnsupportedExpr),
3244 },
3245 Frame::Push(sym) => bound.push(sym),
3246 Frame::PushMany(syms) => bound.extend(syms),
3247 Frame::Pop(count) => bound.truncate(bound.len().saturating_sub(count)),
3248 }
3249 }
3250 Ok(())
3251}
3252
3253fn has_native_impl_in_engine<State>(engine: &Engine<State>, name: &str, typ: &Type) -> bool
3254where
3255 State: Clone + Send + Sync + 'static,
3256{
3257 let sym_name = sym(name);
3258 engine
3259 .natives
3260 .get(&sym_name)
3261 .map(|impls| impls.iter().any(|imp| impl_matches_type(imp, typ)))
3262 .unwrap_or(false)
3263}
3264
3265impl<State> RuntimeSnapshot<State>
3266where
3267 State: Clone + Send + Sync + 'static,
3268{
3269 fn native_callable(&self, id: NativeId) -> Result<NativeCallable<State>, EngineError> {
3270 self.natives
3271 .by_id(id)
3272 .map(|imp| imp.func.clone())
3273 .ok_or_else(|| EngineError::Internal(format!("unknown native id: {id}")))
3274 }
3275}
3276
3277fn first_hole_span(expr: &Expr) -> Option<Span> {
3278 match expr {
3279 Expr::Hole(span) => Some(*span),
3280 Expr::App(_, f, x) => first_hole_span(f).or_else(|| first_hole_span(x)),
3281 Expr::Project(_, base, _) => first_hole_span(base),
3282 Expr::Lam(_, _scope, _param, _ann, _constraints, body) => first_hole_span(body),
3283 Expr::Let(_, _var, _ann, def, body) => {
3284 first_hole_span(def).or_else(|| first_hole_span(body))
3285 }
3286 Expr::LetRec(_, bindings, body) => {
3287 for (_var, _ann, def) in bindings {
3288 if let Some(span) = first_hole_span(def) {
3289 return Some(span);
3290 }
3291 }
3292 first_hole_span(body)
3293 }
3294 Expr::Ite(_, cond, then_expr, else_expr) => first_hole_span(cond)
3295 .or_else(|| first_hole_span(then_expr))
3296 .or_else(|| first_hole_span(else_expr)),
3297 Expr::Match(_, scrutinee, arms) => {
3298 if let Some(span) = first_hole_span(scrutinee) {
3299 return Some(span);
3300 }
3301 for (_pat, arm) in arms {
3302 if let Some(span) = first_hole_span(arm) {
3303 return Some(span);
3304 }
3305 }
3306 None
3307 }
3308 Expr::Ann(_, inner, _) => first_hole_span(inner),
3309 Expr::Tuple(_, elems) | Expr::List(_, elems) => {
3310 for elem in elems {
3311 if let Some(span) = first_hole_span(elem) {
3312 return Some(span);
3313 }
3314 }
3315 None
3316 }
3317 Expr::Dict(_, kvs) => {
3318 for value in kvs.values() {
3319 if let Some(span) = first_hole_span(value) {
3320 return Some(span);
3321 }
3322 }
3323 None
3324 }
3325 Expr::RecordUpdate(_, base, kvs) => {
3326 if let Some(span) = first_hole_span(base) {
3327 return Some(span);
3328 }
3329 for value in kvs.values() {
3330 if let Some(span) = first_hole_span(value) {
3331 return Some(span);
3332 }
3333 }
3334 None
3335 }
3336 Expr::Bool(..)
3337 | Expr::Uint(..)
3338 | Expr::Int(..)
3339 | Expr::Float(..)
3340 | Expr::String(..)
3341 | Expr::Uuid(..)
3342 | Expr::DateTime(..)
3343 | Expr::Var(..) => None,
3344 }
3345}
3346
3347fn normalize_name(name: &str) -> Symbol {
3348 if let Some(stripped) = name.strip_prefix('(').and_then(|s| s.strip_suffix(')')) {
3349 let ok = stripped
3350 .chars()
3351 .all(|c| !c.is_alphanumeric() && c != '_' && !c.is_whitespace());
3352 if ok {
3353 return sym(stripped);
3354 }
3355 }
3356 sym(name)
3357}
3358
3359fn default_ambiguous_types<State: Clone + Send + Sync + 'static>(
3360 engine: &Engine<State>,
3361 typed: TypedExpr,
3362 mut preds: Vec<Predicate>,
3363) -> Result<(TypedExpr, Vec<Predicate>), EngineError> {
3364 let mut candidates = Vec::new();
3365 collect_default_candidates(&typed, &mut candidates);
3366 for ty in [
3367 Type::builtin(BuiltinTypeId::F32),
3368 Type::builtin(BuiltinTypeId::I32),
3369 Type::builtin(BuiltinTypeId::String),
3370 ] {
3371 push_unique_type(&mut candidates, ty);
3372 }
3373
3374 let mut subst = Subst::new_sync();
3375 loop {
3376 let vars: Vec<_> = preds.ftv().into_iter().collect();
3377 let mut progress = false;
3378 for tv in vars {
3379 if subst.get(&tv).is_some() {
3380 continue;
3381 }
3382 let mut relevant = Vec::new();
3383 let mut simple = true;
3384 for pred in &preds {
3385 if pred.typ.ftv().contains(&tv) {
3386 if !defaultable_class(&pred.class) {
3387 simple = false;
3388 break;
3389 }
3390 match pred.typ.as_ref() {
3391 TypeKind::Var(v) if v.id == tv => relevant.push(pred.clone()),
3392 _ => {
3393 simple = false;
3394 break;
3395 }
3396 }
3397 }
3398 }
3399 if !simple || relevant.is_empty() {
3400 continue;
3401 }
3402 if let Some(choice) = choose_default_type(engine, &relevant, &candidates)? {
3403 let mut next = Subst::new_sync();
3404 next = next.insert(tv, choice.clone());
3405 preds = preds.apply(&next);
3406 subst = compose_subst(next, subst);
3407 progress = true;
3408 }
3409 }
3410 if !progress {
3411 break;
3412 }
3413 }
3414 Ok((typed.apply(&subst), preds))
3415}
3416
3417fn defaultable_class(class: &Symbol) -> bool {
3418 matches!(
3419 class.as_ref(),
3420 "AdditiveMonoid" | "MultiplicativeMonoid" | "AdditiveGroup" | "Ring" | "Field" | "Integral"
3421 )
3422}
3423
3424fn collect_default_candidates(expr: &TypedExpr, out: &mut Vec<Type>) {
3425 let mut stack: Vec<&TypedExpr> = vec![expr];
3426 while let Some(expr) = stack.pop() {
3427 if expr.typ.ftv().is_empty()
3428 && let TypeKind::Con(tc) = expr.typ.as_ref()
3429 && tc.arity == 0
3430 {
3431 push_unique_type(out, expr.typ.clone());
3432 }
3433
3434 match &expr.kind {
3435 TypedExprKind::Tuple(elems) | TypedExprKind::List(elems) => {
3436 for elem in elems.iter().rev() {
3437 stack.push(elem);
3438 }
3439 }
3440 TypedExprKind::Dict(kvs) => {
3441 for value in kvs.values().rev() {
3442 stack.push(value);
3443 }
3444 }
3445 TypedExprKind::RecordUpdate { base, updates } => {
3446 for value in updates.values().rev() {
3447 stack.push(value);
3448 }
3449 stack.push(base);
3450 }
3451 TypedExprKind::App(f, x) => {
3452 stack.push(x);
3453 stack.push(f);
3454 }
3455 TypedExprKind::Project { expr, .. } => stack.push(expr),
3456 TypedExprKind::Lam { body, .. } => stack.push(body),
3457 TypedExprKind::Let { def, body, .. } => {
3458 stack.push(body);
3459 stack.push(def);
3460 }
3461 TypedExprKind::LetRec { bindings, body } => {
3462 stack.push(body);
3463 for (_, def) in bindings.iter().rev() {
3464 stack.push(def);
3465 }
3466 }
3467 TypedExprKind::Ite {
3468 cond,
3469 then_expr,
3470 else_expr,
3471 } => {
3472 stack.push(else_expr);
3473 stack.push(then_expr);
3474 stack.push(cond);
3475 }
3476 TypedExprKind::Match { scrutinee, arms } => {
3477 for (_, expr) in arms.iter().rev() {
3478 stack.push(expr);
3479 }
3480 stack.push(scrutinee);
3481 }
3482 TypedExprKind::Var { .. }
3483 | TypedExprKind::Bool(..)
3484 | TypedExprKind::Uint(..)
3485 | TypedExprKind::Int(..)
3486 | TypedExprKind::Float(..)
3487 | TypedExprKind::String(..)
3488 | TypedExprKind::Uuid(..)
3489 | TypedExprKind::DateTime(..)
3490 | TypedExprKind::Hole => {}
3491 }
3492 }
3493}
3494
3495fn push_unique_type(out: &mut Vec<Type>, typ: Type) {
3496 if !out.iter().any(|t| t == &typ) {
3497 out.push(typ);
3498 }
3499}
3500
3501fn choose_default_type<State: Clone + Send + Sync + 'static>(
3502 engine: &Engine<State>,
3503 preds: &[Predicate],
3504 candidates: &[Type],
3505) -> Result<Option<Type>, EngineError> {
3506 for candidate in candidates {
3507 let mut ok = true;
3508 for pred in preds {
3509 let test = Predicate::new(pred.class.clone(), candidate.clone());
3510 if !entails(&engine.type_system.classes, &[], &test)? {
3511 ok = false;
3512 break;
3513 }
3514 }
3515 if ok {
3516 return Ok(Some(candidate.clone()));
3517 }
3518 }
3519 Ok(None)
3520}
3521
3522fn scheme_accepts(ts: &TypeSystem, scheme: &Scheme, typ: &Type) -> Result<bool, EngineError> {
3523 let mut supply = TypeVarSupply::new();
3524 let (preds, scheme_ty) = instantiate(scheme, &mut supply);
3525 let subst = match unify(&scheme_ty, typ) {
3526 Ok(s) => s,
3527 Err(_) => return Ok(false),
3528 };
3529 let preds = preds.apply(&subst);
3530 for pred in preds {
3531 if pred.typ.ftv().is_empty() {
3532 let ok = entails(&ts.classes, &[], &pred)?;
3533 if !ok {
3534 return Ok(false);
3535 }
3536 }
3537 }
3538 Ok(true)
3539}
3540
3541pub(crate) fn is_function_type(typ: &Type) -> bool {
3542 matches!(typ.as_ref(), TypeKind::Fun(..))
3543}
3544
3545pub(crate) fn collect_pattern_bindings(pat: &Pattern, out: &mut Vec<Symbol>) {
3546 match pat {
3547 Pattern::Wildcard(..) => {}
3548 Pattern::Var(var) => out.push(var.name.clone()),
3549 Pattern::Named(_, _, ps) => {
3550 for p in ps {
3551 collect_pattern_bindings(p, out);
3552 }
3553 }
3554 Pattern::Tuple(_, ps) => {
3555 for p in ps {
3556 collect_pattern_bindings(p, out);
3557 }
3558 }
3559 Pattern::List(_, ps) => {
3560 for p in ps {
3561 collect_pattern_bindings(p, out);
3562 }
3563 }
3564 Pattern::Cons(_, head, tail) => {
3565 collect_pattern_bindings(head, out);
3566 collect_pattern_bindings(tail, out);
3567 }
3568 Pattern::Dict(_, fields) => {
3569 for (_key, pat) in fields {
3570 collect_pattern_bindings(pat, out);
3571 }
3572 }
3573 }
3574}
3575
3576fn type_head_and_args(typ: &Type) -> Result<(Symbol, usize, Vec<Type>), EngineError> {
3577 let mut args = Vec::new();
3578 let mut head = typ;
3579 while let TypeKind::App(f, arg) = head.as_ref() {
3580 args.push(arg.clone());
3581 head = f;
3582 }
3583 args.reverse();
3584
3585 let TypeKind::Con(con) = head.as_ref() else {
3586 return Err(EngineError::Custom(format!(
3587 "cannot build ADT declaration from non-constructor type `{typ}`"
3588 )));
3589 };
3590 if !args.is_empty() && args.len() != con.arity {
3591 return Err(EngineError::Custom(format!(
3592 "constructor `{}` expected {} type arguments but got {} in `{typ}`",
3593 con.name,
3594 con.arity,
3595 args.len()
3596 )));
3597 }
3598 Ok((con.name.clone(), con.arity, args))
3599}
3600
3601fn type_arity(typ: &Type) -> usize {
3602 let mut count = 0;
3603 let mut cur = typ;
3604 while let TypeKind::Fun(_, next) = cur.as_ref() {
3605 count += 1;
3606 cur = next;
3607 }
3608 count
3609}
3610
3611fn split_fun(typ: &Type) -> Option<(Type, Type)> {
3612 match typ.as_ref() {
3613 TypeKind::Fun(a, b) => Some((a.clone(), b.clone())),
3614 _ => None,
3615 }
3616}
3617
3618pub(crate) fn impl_matches_type<State: Clone + Send + Sync + 'static>(
3619 imp: &NativeImpl<State>,
3620 typ: &Type,
3621) -> bool {
3622 let mut supply = TypeVarSupply::new();
3623 let (_preds, scheme_ty) = instantiate(&imp.scheme, &mut supply);
3624 unify(&scheme_ty, typ).is_ok()
3625}
3626
3627pub(crate) fn native_capability_matches_requirement(
3628 capability: &NativeCapability,
3629 requirement: &NativeRequirement,
3630) -> bool {
3631 let mut supply = TypeVarSupply::new();
3632 let (_preds, scheme_ty) = instantiate(&capability.scheme, &mut supply);
3633 capability.name == requirement.name
3634 && capability.arity == type_arity(&requirement.typ)
3635 && unify(&scheme_ty, &requirement.typ).is_ok()
3636}
3637
3638pub(crate) fn class_method_capability_matches_requirement(
3639 capability: &ClassMethodCapability,
3640 requirement: &ClassMethodRequirement,
3641) -> bool {
3642 let mut supply = TypeVarSupply::new();
3643 let (_preds, scheme_ty) = instantiate(&capability.scheme, &mut supply);
3644 capability.name == requirement.name && unify(&scheme_ty, &requirement.typ).is_ok()
3645}
3646
3647fn value_type(heap: &Heap, value: &Value) -> Result<Type, EngineError> {
3648 let pointer_type = |pointer: &Pointer| -> Result<Type, EngineError> {
3649 let value = heap.get(pointer)?;
3650 value_type(heap, value.as_ref())
3651 };
3652
3653 match value {
3654 Value::Bool(..) => Ok(Type::builtin(BuiltinTypeId::Bool)),
3655 Value::U8(..) => Ok(Type::builtin(BuiltinTypeId::U8)),
3656 Value::U16(..) => Ok(Type::builtin(BuiltinTypeId::U16)),
3657 Value::U32(..) => Ok(Type::builtin(BuiltinTypeId::U32)),
3658 Value::U64(..) => Ok(Type::builtin(BuiltinTypeId::U64)),
3659 Value::I8(..) => Ok(Type::builtin(BuiltinTypeId::I8)),
3660 Value::I16(..) => Ok(Type::builtin(BuiltinTypeId::I16)),
3661 Value::I32(..) => Ok(Type::builtin(BuiltinTypeId::I32)),
3662 Value::I64(..) => Ok(Type::builtin(BuiltinTypeId::I64)),
3663 Value::F32(..) => Ok(Type::builtin(BuiltinTypeId::F32)),
3664 Value::F64(..) => Ok(Type::builtin(BuiltinTypeId::F64)),
3665 Value::String(..) => Ok(Type::builtin(BuiltinTypeId::String)),
3666 Value::Uuid(..) => Ok(Type::builtin(BuiltinTypeId::Uuid)),
3667 Value::DateTime(..) => Ok(Type::builtin(BuiltinTypeId::DateTime)),
3668 Value::Tuple(elems) => {
3669 let mut tys = Vec::with_capacity(elems.len());
3670 for elem in elems {
3671 tys.push(pointer_type(elem)?);
3672 }
3673 Ok(Type::tuple(tys))
3674 }
3675 Value::Array(elems) => {
3676 let first = elems
3677 .first()
3678 .ok_or_else(|| EngineError::UnknownType(sym("array")))?;
3679 let elem_ty = pointer_type(first)?;
3680 for elem in elems.iter().skip(1) {
3681 let ty = pointer_type(elem)?;
3682 if ty != elem_ty {
3683 return Err(EngineError::NativeType {
3684 expected: elem_ty.to_string(),
3685 got: ty.to_string(),
3686 });
3687 }
3688 }
3689 Ok(Type::app(Type::builtin(BuiltinTypeId::Array), elem_ty))
3690 }
3691 Value::Dict(map) => {
3692 let first = map
3693 .values()
3694 .next()
3695 .ok_or_else(|| EngineError::UnknownType(sym("dict")))?;
3696 let elem_ty = pointer_type(first)?;
3697 for val in map.values().skip(1) {
3698 let ty = pointer_type(val)?;
3699 if ty != elem_ty {
3700 return Err(EngineError::NativeType {
3701 expected: elem_ty.to_string(),
3702 got: ty.to_string(),
3703 });
3704 }
3705 }
3706 Ok(Type::app(Type::builtin(BuiltinTypeId::Dict), elem_ty))
3707 }
3708 Value::Adt(tag, args) if sym_eq(tag, "Some") && args.len() == 1 => {
3709 let inner = pointer_type(&args[0])?;
3710 Ok(Type::app(Type::builtin(BuiltinTypeId::Option), inner))
3711 }
3712 Value::Adt(tag, args) if sym_eq(tag, "None") && args.is_empty() => {
3713 Err(EngineError::UnknownType(sym("option")))
3714 }
3715 Value::Adt(tag, args) if (sym_eq(tag, "Ok") || sym_eq(tag, "Err")) && args.len() == 1 => {
3716 Err(EngineError::UnknownType(sym("result")))
3717 }
3718 Value::Adt(tag, args)
3719 if (sym_eq(tag, "Empty") || sym_eq(tag, "Cons")) && args.len() <= 2 =>
3720 {
3721 let elems = list_to_vec(heap, value)?;
3722 let first = elems
3723 .first()
3724 .ok_or_else(|| EngineError::UnknownType(sym("list")))?;
3725 let elem_ty = pointer_type(first)?;
3726 for elem in elems.iter().skip(1) {
3727 let ty = pointer_type(elem)?;
3728 if ty != elem_ty {
3729 return Err(EngineError::NativeType {
3730 expected: elem_ty.to_string(),
3731 got: ty.to_string(),
3732 });
3733 }
3734 }
3735 Ok(Type::app(Type::builtin(BuiltinTypeId::List), elem_ty))
3736 }
3737 Value::Adt(tag, _args) => Err(EngineError::UnknownType(tag.clone())),
3738 Value::Uninitialized(..) => Err(EngineError::UnknownType(sym("uninitialized"))),
3739 Value::Closure(..) => Err(EngineError::UnknownType(sym("closure"))),
3740 Value::Native(..) => Err(EngineError::UnknownType(sym("native"))),
3741 Value::Overloaded(..) => Err(EngineError::UnknownType(sym("overloaded"))),
3742 }
3743}
3744
3745fn resolve_arg_type(
3746 heap: &Heap,
3747 arg_type: Option<&Type>,
3748 arg: &Pointer,
3749) -> Result<Type, EngineError> {
3750 let infer_from_value = |ty_hint: Option<&Type>| -> Result<Type, EngineError> {
3751 let value = heap.get(arg)?;
3752 match ty_hint {
3753 Some(ty) => match value_type(heap, value.as_ref()) {
3754 Ok(val_ty) if val_ty.ftv().is_empty() => Ok(val_ty),
3755 _ => Ok(ty.clone()),
3756 },
3757 None => value_type(heap, value.as_ref()),
3758 }
3759 };
3760 match arg_type {
3761 Some(ty) if ty.ftv().is_empty() => Ok(ty.clone()),
3762 Some(ty) => infer_from_value(Some(ty)),
3763 None => infer_from_value(None),
3764 }
3765}
3766
3767pub(crate) fn binary_arg_types(typ: &Type) -> Result<(Type, Type), EngineError> {
3768 let (lhs, rest) = split_fun(typ).ok_or_else(|| EngineError::NativeType {
3769 expected: "binary function".into(),
3770 got: typ.to_string(),
3771 })?;
3772 let (rhs, _res) = split_fun(&rest).ok_or_else(|| EngineError::NativeType {
3773 expected: "binary function".into(),
3774 got: typ.to_string(),
3775 })?;
3776 Ok((lhs, rhs))
3777}
3778
3779fn project_pointer(heap: &Heap, field: &Symbol, pointer: &Pointer) -> Result<Pointer, EngineError> {
3780 let value = heap.get(pointer)?;
3781 if let Ok(index) = field.as_ref().parse::<usize>() {
3782 return match value.as_ref() {
3783 Value::Tuple(items) => {
3784 items
3785 .get(index)
3786 .cloned()
3787 .ok_or_else(|| EngineError::UnknownField {
3788 field: field.clone(),
3789 value: "tuple".into(),
3790 })
3791 }
3792 _ => Err(EngineError::UnknownField {
3793 field: field.clone(),
3794 value: heap.type_name(pointer)?.into(),
3795 }),
3796 };
3797 }
3798 match value.as_ref() {
3799 Value::Adt(_, args) if args.len() == 1 => {
3800 let inner = heap.get(&args[0])?;
3801 match inner.as_ref() {
3802 Value::Dict(map) => {
3803 map.get(field)
3804 .cloned()
3805 .ok_or_else(|| EngineError::UnknownField {
3806 field: field.clone(),
3807 value: "record".into(),
3808 })
3809 }
3810 _ => Err(EngineError::UnknownField {
3811 field: field.clone(),
3812 value: heap.type_name(&args[0])?.into(),
3813 }),
3814 }
3815 }
3816 _ => Err(EngineError::UnknownField {
3817 field: field.clone(),
3818 value: heap.type_name(pointer)?.into(),
3819 }),
3820 }
3821}
3822
3823#[async_recursion]
3824pub(crate) async fn eval_typed_expr<State>(
3825 runtime: &RuntimeSnapshot<State>,
3826 env: &Env,
3827 expr: &TypedExpr,
3828 gas: &mut GasMeter,
3829) -> Result<Pointer, EngineError>
3830where
3831 State: Clone + Send + Sync + 'static,
3832{
3833 check_runtime_cancelled(runtime)?;
3834 let mut env = env.clone();
3835 let mut cur = expr;
3836 loop {
3837 check_runtime_cancelled(runtime)?;
3838 match &cur.kind {
3839 TypedExprKind::Let { name, def, body } => {
3840 gas.charge(gas.costs.eval_node)?;
3841 let ptr = eval_typed_expr(runtime, &env, def, gas).await?;
3842 env = env.extend(name.clone(), ptr);
3843 cur = body;
3844 }
3845 _ => break,
3846 }
3847 }
3848
3849 gas.charge(gas.costs.eval_node)?;
3850 match &cur.kind {
3851 TypedExprKind::Bool(v) => runtime.heap.alloc_bool(*v),
3852 TypedExprKind::Uint(v) => alloc_uint_literal_as(runtime, *v, &cur.typ),
3853 TypedExprKind::Int(v) => alloc_int_literal_as(runtime, *v, &cur.typ),
3854 TypedExprKind::Float(v) => runtime.heap.alloc_f32(*v as f32),
3855 TypedExprKind::String(v) => runtime.heap.alloc_string(v.clone()),
3856 TypedExprKind::Uuid(v) => runtime.heap.alloc_uuid(*v),
3857 TypedExprKind::DateTime(v) => runtime.heap.alloc_datetime(*v),
3858 TypedExprKind::Hole => Err(EngineError::UnsupportedExpr),
3859 TypedExprKind::Tuple(elems) => {
3860 let mut values = Vec::with_capacity(elems.len());
3861 for elem in elems {
3862 check_runtime_cancelled(runtime)?;
3863 values.push(eval_typed_expr(runtime, &env, elem, gas).await?);
3864 }
3865 runtime.heap.alloc_tuple(values)
3866 }
3867 TypedExprKind::List(elems) => {
3868 let mut values = Vec::with_capacity(elems.len());
3869 for elem in elems {
3870 check_runtime_cancelled(runtime)?;
3871 values.push(eval_typed_expr(runtime, &env, elem, gas).await?);
3872 }
3873 let mut list = runtime.heap.alloc_adt(sym("Empty"), vec![])?;
3874 for value in values.into_iter().rev() {
3875 list = runtime.heap.alloc_adt(sym("Cons"), vec![value, list])?;
3876 }
3877 Ok(list)
3878 }
3879 TypedExprKind::Dict(kvs) => {
3880 let mut out = BTreeMap::new();
3881 for (k, v) in kvs {
3882 check_runtime_cancelled(runtime)?;
3883 out.insert(k.clone(), eval_typed_expr(runtime, &env, v, gas).await?);
3884 }
3885 runtime.heap.alloc_dict(out)
3886 }
3887 TypedExprKind::RecordUpdate { base, updates } => {
3888 let base_ptr = eval_typed_expr(runtime, &env, base, gas).await?;
3889 let mut update_vals = BTreeMap::new();
3890 for (k, v) in updates {
3891 check_runtime_cancelled(runtime)?;
3892 update_vals.insert(k.clone(), eval_typed_expr(runtime, &env, v, gas).await?);
3893 }
3894
3895 let base_val = runtime.heap.get(&base_ptr)?;
3896 match base_val.as_ref() {
3897 Value::Dict(map) => {
3898 let mut map = map.clone();
3899 for (k, v) in update_vals {
3900 gas.charge(gas.costs.eval_record_update_field)?;
3901 map.insert(k, v);
3902 }
3903 runtime.heap.alloc_dict(map)
3904 }
3905 Value::Adt(tag, args) if args.len() == 1 => {
3906 let inner = runtime.heap.get(&args[0])?;
3907 match inner.as_ref() {
3908 Value::Dict(map) => {
3909 let mut out = map.clone();
3910 for (k, v) in update_vals {
3911 gas.charge(gas.costs.eval_record_update_field)?;
3912 out.insert(k, v);
3913 }
3914 let dict = runtime.heap.alloc_dict(out)?;
3915 runtime.heap.alloc_adt(tag.clone(), vec![dict])
3916 }
3917 _ => Err(EngineError::UnsupportedExpr),
3918 }
3919 }
3920 _ => Err(EngineError::UnsupportedExpr),
3921 }
3922 }
3923 TypedExprKind::Var { name, .. } => {
3924 if let Some(ptr) = env.get(name) {
3925 let value = runtime.heap.get(&ptr)?;
3926 match value.as_ref() {
3927 Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
3928 native.call_zero(runtime, gas).await
3929 }
3930 _ => Ok(ptr),
3931 }
3932 } else if runtime.type_system.class_methods.contains_key(name) {
3933 EvaluatorRef::new(runtime)
3934 .resolve_class_method(name, &cur.typ, gas)
3935 .await
3936 } else {
3937 let value =
3938 EvaluatorRef::new(runtime).resolve_native(name.as_ref(), &cur.typ, gas)?;
3939 match runtime.heap.get(&value)?.as_ref() {
3940 Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
3941 native.call_zero(runtime, gas).await
3942 }
3943 _ => Ok(value),
3944 }
3945 }
3946 }
3947 TypedExprKind::App(..) => {
3948 let mut spine: Vec<(Type, &TypedExpr)> = Vec::new();
3949 let mut head = cur;
3950 while let TypedExprKind::App(f, x) = &head.kind {
3951 check_runtime_cancelled(runtime)?;
3952 spine.push((f.typ.clone(), x.as_ref()));
3953 head = f.as_ref();
3954 }
3955 spine.reverse();
3956
3957 let mut func = eval_typed_expr(runtime, &env, head, gas).await?;
3958 for (func_type, arg_expr) in spine {
3959 check_runtime_cancelled(runtime)?;
3960 gas.charge(gas.costs.eval_app_step)?;
3961 let arg = eval_typed_expr(runtime, &env, arg_expr, gas).await?;
3962 func = apply(
3963 runtime,
3964 func,
3965 arg,
3966 Some(&func_type),
3967 Some(&arg_expr.typ),
3968 gas,
3969 )
3970 .await?;
3971 }
3972 Ok(func)
3973 }
3974 TypedExprKind::Project { expr, field } => {
3975 let value = eval_typed_expr(runtime, &env, expr, gas).await?;
3976 project_pointer(&runtime.heap, field, &value)
3977 }
3978 TypedExprKind::Lam { param, body } => {
3979 let param_ty = split_fun(&expr.typ)
3980 .map(|(arg, _)| arg)
3981 .ok_or_else(|| EngineError::NotCallable(expr.typ.to_string()))?;
3982 runtime.heap.alloc_closure(
3983 env.clone(),
3984 param.clone(),
3985 param_ty,
3986 expr.typ.clone(),
3987 Arc::new(body.as_ref().clone()),
3988 )
3989 }
3990 TypedExprKind::LetRec { bindings, body } => {
3991 let mut env_rec = env.clone();
3992 let mut slots = Vec::with_capacity(bindings.len());
3993 for (name, _) in bindings {
3994 let placeholder = runtime.heap.alloc_uninitialized(name.clone())?;
3995 env_rec = env_rec.extend(name.clone(), placeholder);
3996 slots.push(placeholder);
3997 }
3998
3999 for ((_, def), slot) in bindings.iter().zip(slots.iter()) {
4000 check_runtime_cancelled(runtime)?;
4001 gas.charge(gas.costs.eval_node)?;
4002 let def_ptr = eval_typed_expr(runtime, &env_rec, def, gas).await?;
4003 let def_value = runtime.heap.get(&def_ptr)?;
4004 runtime.heap.overwrite(slot, def_value.as_ref().clone())?;
4005 }
4006
4007 eval_typed_expr(runtime, &env_rec, body, gas).await
4008 }
4009 TypedExprKind::Ite {
4010 cond,
4011 then_expr,
4012 else_expr,
4013 } => {
4014 let cond_ptr = eval_typed_expr(runtime, &env, cond, gas).await?;
4015 match runtime.heap.pointer_as_bool(&cond_ptr) {
4016 Ok(true) => eval_typed_expr(runtime, &env, then_expr, gas).await,
4017 Ok(false) => eval_typed_expr(runtime, &env, else_expr, gas).await,
4018 Err(EngineError::NativeType { got, .. }) => Err(EngineError::ExpectedBool(got)),
4019 Err(err) => Err(err),
4020 }
4021 }
4022 TypedExprKind::Match { scrutinee, arms } => {
4023 let value = eval_typed_expr(runtime, &env, scrutinee, gas).await?;
4024 for (pat, expr) in arms {
4025 check_runtime_cancelled(runtime)?;
4026 gas.charge(gas.costs.eval_match_arm)?;
4027 if let Some(bindings) = match_pattern_ptr(&runtime.heap, pat, &value) {
4028 let env = env.extend_many(bindings);
4029 return eval_typed_expr(runtime, &env, expr, gas).await;
4030 }
4031 }
4032 Err(EngineError::MatchFailure)
4033 }
4034 TypedExprKind::Let { .. } => {
4035 unreachable!("let chain handled in eval_typed_expr loop")
4036 }
4037 }
4038}
4039
4040#[async_recursion]
4041pub(crate) async fn apply<State>(
4042 runtime: &RuntimeSnapshot<State>,
4043 func: Pointer,
4044 arg: Pointer,
4045 func_type: Option<&Type>,
4046 arg_type: Option<&Type>,
4047 gas: &mut GasMeter,
4048) -> Result<Pointer, EngineError>
4049where
4050 State: Clone + Send + Sync + 'static,
4051{
4052 let func_value = runtime.heap.get(&func)?.as_ref().clone();
4053 match func_value {
4054 Value::Closure(Closure {
4055 env,
4056 param,
4057 param_ty,
4058 typ,
4059 body,
4060 }) => {
4061 let mut subst = Subst::new_sync();
4062 if let Some(expected) = func_type {
4063 let s_fun = unify(&typ, expected).map_err(|_| EngineError::NativeType {
4064 expected: typ.to_string(),
4065 got: expected.to_string(),
4066 })?;
4067 subst = compose_subst(s_fun, subst);
4068 }
4069 let actual_ty = resolve_arg_type(&runtime.heap, arg_type, &arg)?;
4070 let param_ty = param_ty.apply(&subst);
4071 let s_arg = unify(¶m_ty, &actual_ty).map_err(|_| EngineError::NativeType {
4072 expected: param_ty.to_string(),
4073 got: actual_ty.to_string(),
4074 })?;
4075 subst = compose_subst(s_arg, subst);
4076 let env = env.extend(param, arg);
4077 let body = body.apply(&subst);
4078 eval_typed_expr(runtime, &env, &body, gas).await
4079 }
4080 Value::Native(native) => native.apply(runtime, arg, arg_type, gas).await,
4081 Value::Overloaded(over) => over.apply(runtime, arg, func_type, arg_type, gas).await,
4082 _ => Err(EngineError::NotCallable(
4083 runtime.heap.type_name(&func)?.into(),
4084 )),
4085 }
4086}
4087
4088fn match_pattern_ptr(
4089 heap: &Heap,
4090 pat: &Pattern,
4091 value: &Pointer,
4092) -> Option<HashMap<Symbol, Pointer>> {
4093 match pat {
4094 Pattern::Wildcard(..) => Some(HashMap::new()),
4095 Pattern::Var(var) => {
4096 let mut bindings = HashMap::new();
4097 bindings.insert(var.name.clone(), *value);
4098 Some(bindings)
4099 }
4100 Pattern::Named(_, name, ps) => {
4101 let v = heap.get(value).ok()?;
4102 match v.as_ref() {
4103 Value::Adt(vname, args)
4104 if vname == &name.to_dotted_symbol() && args.len() == ps.len() =>
4105 {
4106 match_patterns(heap, ps, args)
4107 }
4108 _ => None,
4109 }
4110 }
4111 Pattern::Tuple(_, ps) => {
4112 let v = heap.get(value).ok()?;
4113 match v.as_ref() {
4114 Value::Tuple(xs) if xs.len() == ps.len() => match_patterns(heap, ps, xs),
4115 _ => None,
4116 }
4117 }
4118 Pattern::List(_, ps) => {
4119 let v = heap.get(value).ok()?;
4120 let values = list_to_vec(heap, v.as_ref()).ok()?;
4121 if values.len() == ps.len() {
4122 match_patterns(heap, ps, &values)
4123 } else {
4124 None
4125 }
4126 }
4127 Pattern::Cons(_, head, tail) => {
4128 let v = heap.get(value).ok()?;
4129 match v.as_ref() {
4130 Value::Adt(tag, args) if sym_eq(tag, "Cons") && args.len() == 2 => {
4131 let mut left = match_pattern_ptr(heap, head, &args[0])?;
4132 let right = match_pattern_ptr(heap, tail, &args[1])?;
4133 left.extend(right);
4134 Some(left)
4135 }
4136 _ => None,
4137 }
4138 }
4139 Pattern::Dict(_, fields) => {
4140 let v = heap.get(value).ok()?;
4141 match v.as_ref() {
4142 Value::Dict(map) => {
4143 let mut bindings = HashMap::new();
4144 for (key, pat) in fields {
4145 let v = map.get(key)?;
4146 let sub = match_pattern_ptr(heap, pat, v)?;
4147 bindings.extend(sub);
4148 }
4149 Some(bindings)
4150 }
4151 _ => None,
4152 }
4153 }
4154 }
4155}
4156
4157fn match_patterns(
4158 heap: &Heap,
4159 patterns: &[Pattern],
4160 values: &[Pointer],
4161) -> Option<HashMap<Symbol, Pointer>> {
4162 let mut bindings = HashMap::new();
4163 for (p, v) in patterns.iter().zip(values.iter()) {
4164 let sub = match_pattern_ptr(heap, p, v)?;
4165 bindings.extend(sub);
4166 }
4167 Some(bindings)
4168}