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