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 collect_adts_in_types, compose_subst, entails, instantiate, unify,
19};
20use rexlang_util::GasMeter;
21
22use crate::modules::{
23 CanonicalSymbol, ModuleExports, ModuleId, ModuleSystem, ResolveRequest, ResolvedModule,
24 SymbolKind, module_key_for_module, 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_MODULE_NAME: &str = "__root__";
42pub const PRELUDE_MODULE_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_MODULE_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
462pub struct Module<State: Clone + Send + Sync + 'static> {
463 pub name: String,
464 declarations: Vec<String>,
465 exports: Vec<Export<State>>,
466}
467
468impl<State> Module<State>
469where
470 State: Clone + Send + Sync + 'static,
471{
472 pub fn new(name: impl Into<String>) -> Self {
473 Self {
474 name: name.into(),
475 declarations: Vec::new(),
476 exports: Vec::new(),
477 }
478 }
479
480 pub fn add_declaration(&mut self, declaration: impl Into<String>) -> Result<(), EngineError> {
484 let declaration = declaration.into();
485 if declaration.trim().is_empty() {
486 return Err(EngineError::Internal(
487 "module declaration cannot be empty".into(),
488 ));
489 }
490 self.declarations.push(declaration);
491 Ok(())
492 }
493
494 pub fn add_adt_decl(&mut self, adt: AdtDecl) -> Result<(), EngineError> {
496 self.add_declaration(adt_declaration_line(&adt))
497 }
498
499 pub fn add_adt_decls_from_types(
522 &mut self,
523 engine: &mut Engine<State>,
524 types: Vec<Type>,
525 ) -> Result<(), EngineError> {
526 let adts = collect_adts_in_types(types).map_err(collect_adts_error_to_engine)?;
527 for typ in adts {
528 let adt = engine.adt_decl_from_type(&typ)?;
529 self.add_adt_decl(adt)?;
530 }
531 Ok(())
532 }
533
534 pub fn inject_rex_adt<T>(&mut self, engine: &mut Engine<State>) -> Result<(), EngineError>
536 where
537 T: RexAdt,
538 {
539 let adt = T::rex_adt_decl(engine)?;
540 self.add_adt_decl(adt)
541 }
542
543 pub fn add_export(&mut self, export: Export<State>) {
544 self.exports.push(export);
545 }
546
547 pub fn export<Sig, H>(&mut self, name: impl Into<String>, handler: H) -> Result<(), EngineError>
548 where
549 H: Handler<State, Sig>,
550 {
551 self.exports.push(Export::from_handler(name, handler)?);
552 Ok(())
553 }
554
555 pub fn export_async<Sig, H>(
556 &mut self,
557 name: impl Into<String>,
558 handler: H,
559 ) -> Result<(), EngineError>
560 where
561 H: AsyncHandler<State, Sig>,
562 {
563 self.exports
564 .push(Export::from_async_handler(name, handler)?);
565 Ok(())
566 }
567
568 pub fn export_native<F>(
569 &mut self,
570 name: impl Into<String>,
571 scheme: Scheme,
572 arity: usize,
573 handler: F,
574 ) -> Result<(), EngineError>
575 where
576 F: for<'a> Fn(&'a Engine<State>, &'a Type, &'a [Pointer]) -> Result<Pointer, EngineError>
577 + Send
578 + Sync
579 + 'static,
580 {
581 self.exports
582 .push(Export::from_native(name, scheme, arity, handler)?);
583 Ok(())
584 }
585
586 pub fn export_native_async<F>(
587 &mut self,
588 name: impl Into<String>,
589 scheme: Scheme,
590 arity: usize,
591 handler: F,
592 ) -> Result<(), EngineError>
593 where
594 F: for<'a> Fn(&'a Engine<State>, Type, Vec<Pointer>) -> NativeFuture<'a>
595 + Send
596 + Sync
597 + 'static,
598 {
599 self.exports
600 .push(Export::from_native_async(name, scheme, arity, handler)?);
601 Ok(())
602 }
603}
604
605fn declaration_type_string(arg_types: &[Type], ret: Type) -> String {
606 if arg_types.is_empty() {
607 return ret.to_string();
608 }
609 let mut out = ret.to_string();
610 for arg in arg_types.iter().rev() {
611 out = format!("{arg} -> {out}");
612 }
613 out
614}
615
616fn declaration_line(export_name: &str, arg_types: &[Type], ret: Type) -> String {
617 format!(
618 "pub declare fn {export_name} {}",
619 declaration_type_string(arg_types, ret)
620 )
621}
622
623fn declaration_line_from_scheme(export_name: &str, scheme: &Scheme) -> String {
624 let mut out = format!("pub declare fn {export_name} : {}", scheme.typ);
625 if !scheme.preds.is_empty() {
626 let preds = scheme
627 .preds
628 .iter()
629 .map(|p| format!("{} {}", p.class, p.typ))
630 .collect::<Vec<_>>()
631 .join(", ");
632 out.push_str(" where ");
633 out.push_str(&preds);
634 }
635 out
636}
637
638fn adt_variant_arg_string(typ: &Type) -> String {
639 match typ.as_ref() {
640 TypeKind::Fun(..) => format!("({typ})"),
641 _ => typ.to_string(),
642 }
643}
644
645fn module_local_type_names_from_declarations(declarations: &[String]) -> HashSet<Symbol> {
646 let mut out = HashSet::new();
647 for declaration in declarations {
648 let mut s = declaration.trim_start();
649 if let Some(rest) = s.strip_prefix("pub ") {
650 s = rest.trim_start();
651 }
652 let Some(rest) = s.strip_prefix("type ") else {
653 continue;
654 };
655 let name: String = rest
656 .chars()
657 .take_while(|c| c.is_ascii_alphanumeric() || *c == '_')
658 .collect();
659 if !name.is_empty() {
660 out.insert(sym(&name));
661 }
662 }
663 out
664}
665
666fn qualify_module_type_refs(
667 typ: &Type,
668 module_name: &str,
669 local_type_names: &HashSet<Symbol>,
670) -> Type {
671 match typ.as_ref() {
672 TypeKind::Con(tc) => {
673 if local_type_names.contains(&tc.name) {
674 Type::con(virtual_export_name(module_name, tc.name.as_ref()), tc.arity)
675 } else {
676 typ.clone()
677 }
678 }
679 TypeKind::App(f, x) => Type::app(
680 qualify_module_type_refs(f, module_name, local_type_names),
681 qualify_module_type_refs(x, module_name, local_type_names),
682 ),
683 TypeKind::Fun(a, b) => Type::fun(
684 qualify_module_type_refs(a, module_name, local_type_names),
685 qualify_module_type_refs(b, module_name, local_type_names),
686 ),
687 TypeKind::Tuple(elems) => Type::tuple(
688 elems
689 .iter()
690 .map(|t| qualify_module_type_refs(t, module_name, local_type_names))
691 .collect(),
692 ),
693 TypeKind::Record(fields) => Type::new(TypeKind::Record(
694 fields
695 .iter()
696 .map(|(k, v)| {
697 (
698 k.clone(),
699 qualify_module_type_refs(v, module_name, local_type_names),
700 )
701 })
702 .collect(),
703 )),
704 TypeKind::Var(_) => typ.clone(),
705 }
706}
707
708fn qualify_module_scheme_refs(
709 scheme: &Scheme,
710 module_name: &str,
711 local_type_names: &HashSet<Symbol>,
712) -> Scheme {
713 let typ = qualify_module_type_refs(&scheme.typ, module_name, local_type_names);
714 let preds = scheme
715 .preds
716 .iter()
717 .map(|pred| {
718 Predicate::new(
719 pred.class.clone(),
720 qualify_module_type_refs(&pred.typ, module_name, local_type_names),
721 )
722 })
723 .collect();
724 Scheme::new(scheme.vars.clone(), preds, typ)
725}
726
727fn adt_declaration_line(adt: &AdtDecl) -> String {
728 let head = if adt.params.is_empty() {
729 adt.name.to_string()
730 } else {
731 let params = adt
732 .params
733 .iter()
734 .map(|p| p.name.to_string())
735 .collect::<Vec<_>>()
736 .join(" ");
737 format!("{} {}", adt.name, params)
738 };
739 let variants = adt
740 .variants
741 .iter()
742 .map(|variant| {
743 if variant.args.is_empty() {
744 variant.name.to_string()
745 } else {
746 let args = variant
747 .args
748 .iter()
749 .map(adt_variant_arg_string)
750 .collect::<Vec<_>>()
751 .join(" ");
752 format!("{} {}", variant.name, args)
753 }
754 })
755 .collect::<Vec<_>>()
756 .join(" | ");
757 format!("pub type {head} = {variants}")
758}
759
760pub fn collect_adts_error_to_engine(err: CollectAdtsError) -> EngineError {
778 let details = err
779 .conflicts
780 .into_iter()
781 .map(|conflict| {
782 let defs = conflict
783 .definitions
784 .iter()
785 .map(ToString::to_string)
786 .collect::<Vec<_>>()
787 .join(", ");
788 format!("{}: [{defs}]", conflict.name)
789 })
790 .collect::<Vec<_>>()
791 .join("; ");
792 EngineError::Custom(format!(
793 "conflicting ADT definitions discovered in input types: {details}"
794 ))
795}
796
797fn native_export_arg_types(
798 scheme: &Scheme,
799 arity: usize,
800) -> Result<(Vec<Type>, Type), EngineError> {
801 let mut args = Vec::with_capacity(arity);
802 let mut rest = scheme.typ.clone();
803 for _ in 0..arity {
804 let Some((arg, tail)) = split_fun(&rest) else {
805 return Err(EngineError::Internal(format!(
806 "native export type `{}` does not accept {arity} argument(s)",
807 scheme.typ
808 )));
809 };
810 args.push(arg);
811 rest = tail;
812 }
813 Ok((args, rest))
814}
815
816fn validate_native_export_scheme(scheme: &Scheme, arity: usize) -> Result<(), EngineError> {
817 let _ = native_export_arg_types(scheme, arity)?;
818 Ok(())
819}
820
821macro_rules! define_handler_impl {
822 ([] ; $arity:literal ; $sig:ty) => {
823 impl<State, F, R> Handler<State, $sig> for F
824 where
825 State: Clone + Send + Sync + 'static,
826 F: for<'a> Fn(&'a State) -> Result<R, EngineError> + Send + Sync + 'static,
827 R: IntoPointer + RexType,
828 {
829 fn declaration(export_name: &str) -> String {
830 declaration_line(export_name, &[], R::rex_type())
831 }
832
833 fn inject(
834 self,
835 engine: &mut Engine<State>,
836 export_name: &str,
837 ) -> Result<(), EngineError> {
838 let name_sym = normalize_name(export_name);
839 let func: SyncNativeCallable<State> = Arc::new(
840 move |engine: &Engine<State>, _: &Type, args: &[Pointer]| {
841 if args.len() != $arity {
842 return Err(EngineError::NativeArity {
843 name: name_sym.clone(),
844 expected: $arity,
845 got: args.len(),
846 });
847 }
848 let value = self(engine.state.as_ref())?;
849 value.into_pointer(&engine.heap)
850 },
851 );
852 let scheme = Scheme::new(vec![], vec![], R::rex_type());
853 let registration = NativeRegistration::sync(scheme, $arity, func, 0);
854 engine.register_native_registration(ROOT_MODULE_NAME, export_name, registration)
855 }
856 }
857
858 };
859 ([ $(($arg_ty:ident, $arg_name:ident, $idx:tt)),+ ] ; $arity:literal ; $sig:ty) => {
860 impl<State, F, R, $($arg_ty),+> Handler<State, $sig> for F
861 where
862 State: Clone + Send + Sync + 'static,
863 F: for<'a> Fn(&'a State, $($arg_ty),+) -> Result<R, EngineError> + Send + Sync + 'static,
864 R: IntoPointer + RexType,
865 $($arg_ty: FromPointer + RexType),+
866 {
867 fn declaration(export_name: &str) -> String {
868 let args = vec![$($arg_ty::rex_type()),+];
869 declaration_line(export_name, &args, R::rex_type())
870 }
871
872 fn inject(
873 self,
874 engine: &mut Engine<State>,
875 export_name: &str,
876 ) -> Result<(), EngineError> {
877 let name_sym = normalize_name(export_name);
878 let func: SyncNativeCallable<State> = Arc::new(
879 move |engine: &Engine<State>, _: &Type, args: &[Pointer]| {
880 if args.len() != $arity {
881 return Err(EngineError::NativeArity {
882 name: name_sym.clone(),
883 expected: $arity,
884 got: args.len(),
885 });
886 }
887 $(let $arg_name = $arg_ty::from_pointer(&engine.heap, &args[$idx])?;)*
888 let value = self(engine.state.as_ref(), $($arg_name),+)?;
889 value.into_pointer(&engine.heap)
890 },
891 );
892 let typ = native_fn_type!($($arg_ty),+ ; R);
893 let scheme = Scheme::new(vec![], vec![], typ);
894 let registration = NativeRegistration::sync(scheme, $arity, func, 0);
895 engine.register_native_registration(ROOT_MODULE_NAME, export_name, registration)
896 }
897 }
898
899 };
900}
901
902impl<State> Handler<State, NativeCallableSig> for (Scheme, usize, SyncNativeCallable<State>)
903where
904 State: Clone + Send + Sync + 'static,
905{
906 fn declaration(_export_name: &str) -> String {
907 unreachable!("native callable handlers use declaration_for")
908 }
909
910 fn declaration_for(&self, export_name: &str) -> String {
911 let (scheme, _, _) = self;
912 declaration_line_from_scheme(export_name, scheme)
913 }
914
915 fn inject(self, engine: &mut Engine<State>, export_name: &str) -> Result<(), EngineError> {
916 let (scheme, arity, func) = self;
917 validate_native_export_scheme(&scheme, arity)?;
918 let registration = NativeRegistration::sync(scheme, arity, func, 0);
919 engine.register_native_registration(ROOT_MODULE_NAME, export_name, registration)
920 }
921}
922
923macro_rules! define_async_handler_impl {
924 ([] ; $arity:literal ; $sig:ty) => {
925 impl<State, F, Fut, R> AsyncHandler<State, $sig> for F
926 where
927 State: Clone + Send + Sync + 'static,
928 F: for<'a> Fn(&'a State) -> Fut + Send + Sync + 'static,
929 Fut: Future<Output = Result<R, EngineError>> + Send + 'static,
930 R: IntoPointer + RexType,
931 {
932 fn declaration(export_name: &str) -> String {
933 declaration_line(export_name, &[], R::rex_type())
934 }
935
936 fn inject_async(
937 self,
938 engine: &mut Engine<State>,
939 export_name: &str,
940 ) -> Result<(), EngineError> {
941 let f = Arc::new(self);
942 let name_sym = normalize_name(export_name);
943 let func: AsyncNativeCallable<State> = Arc::new(
944 move |engine: &Engine<State>, _: Type, args: &[Pointer]| -> NativeFuture<'_> {
945 let f = Arc::clone(&f);
946 let name_sym = name_sym.clone();
947 async move {
948 if args.len() != $arity {
949 return Err(EngineError::NativeArity {
950 name: name_sym.clone(),
951 expected: $arity,
952 got: args.len(),
953 });
954 }
955 let value = f(engine.state.as_ref()).await?;
956 value.into_pointer(&engine.heap)
957 }
958 .boxed()
959 },
960 );
961 let scheme = Scheme::new(vec![], vec![], R::rex_type());
962 let registration = NativeRegistration::r#async(scheme, $arity, func, 0);
963 engine.register_native_registration(ROOT_MODULE_NAME, export_name, registration)
964 }
965 }
966 };
967 ([ $(($arg_ty:ident, $arg_name:ident, $idx:tt)),+ ] ; $arity:literal ; $sig:ty) => {
968 impl<State, F, Fut, R, $($arg_ty),+> AsyncHandler<State, $sig> for F
969 where
970 State: Clone + Send + Sync + 'static,
971 F: for<'a> Fn(&'a State, $($arg_ty),+) -> Fut + Send + Sync + 'static,
972 Fut: Future<Output = Result<R, EngineError>> + Send + 'static,
973 R: IntoPointer + RexType,
974 $($arg_ty: FromPointer + RexType),+
975 {
976 fn declaration(export_name: &str) -> String {
977 let args = vec![$($arg_ty::rex_type()),+];
978 declaration_line(export_name, &args, R::rex_type())
979 }
980
981 fn inject_async(
982 self,
983 engine: &mut Engine<State>,
984 export_name: &str,
985 ) -> Result<(), EngineError> {
986 let f = Arc::new(self);
987 let name_sym = normalize_name(export_name);
988 let func: AsyncNativeCallable<State> = Arc::new(
989 move |engine: &Engine<State>, _: Type, args: &[Pointer]| -> NativeFuture<'_> {
990 let f = Arc::clone(&f);
991 let name_sym = name_sym.clone();
992 async move {
993 if args.len() != $arity {
994 return Err(EngineError::NativeArity {
995 name: name_sym.clone(),
996 expected: $arity,
997 got: args.len(),
998 });
999 }
1000 $(let $arg_name = $arg_ty::from_pointer(&engine.heap, &args[$idx])?;)*
1001 let value = f(engine.state.as_ref(), $($arg_name),+).await?;
1002 value.into_pointer(&engine.heap)
1003 }
1004 .boxed()
1005 },
1006 );
1007 let typ = native_fn_type!($($arg_ty),+ ; R);
1008 let scheme = Scheme::new(vec![], vec![], typ);
1009 let registration = NativeRegistration::r#async(scheme, $arity, func, 0);
1010 engine.register_native_registration(ROOT_MODULE_NAME, export_name, registration)
1011 }
1012 }
1013 };
1014}
1015
1016impl<State> AsyncHandler<State, AsyncNativeCallableSig>
1017 for (Scheme, usize, AsyncNativeCallable<State>)
1018where
1019 State: Clone + Send + Sync + 'static,
1020{
1021 fn declaration(_export_name: &str) -> String {
1022 unreachable!("native async callable handlers use declaration_for")
1023 }
1024
1025 fn declaration_for(&self, export_name: &str) -> String {
1026 let (scheme, _, _) = self;
1027 declaration_line_from_scheme(export_name, scheme)
1028 }
1029
1030 fn inject_async(
1031 self,
1032 engine: &mut Engine<State>,
1033 export_name: &str,
1034 ) -> Result<(), EngineError> {
1035 let (scheme, arity, func) = self;
1036 validate_native_export_scheme(&scheme, arity)?;
1037 let registration = NativeRegistration::r#async(scheme, arity, func, 0);
1038 engine.register_native_registration(ROOT_MODULE_NAME, export_name, registration)
1039 }
1040}
1041
1042#[derive(Clone)]
1043pub(crate) enum NativeCallable<State: Clone + Send + Sync + 'static> {
1044 Sync(SyncNativeCallable<State>),
1045 Async(AsyncNativeCallable<State>),
1046 AsyncCancellable(AsyncNativeCallableCancellable<State>),
1047}
1048
1049impl<State: Clone + Send + Sync + 'static> PartialEq for NativeCallable<State> {
1050 fn eq(&self, _other: &NativeCallable<State>) -> bool {
1051 false
1052 }
1053}
1054
1055impl<State: Clone + Send + Sync + 'static> std::fmt::Debug for NativeCallable<State> {
1056 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
1057 match self {
1058 NativeCallable::Sync(_) => write!(f, "Sync"),
1059 NativeCallable::Async(_) => write!(f, "Async"),
1060 NativeCallable::AsyncCancellable(_) => write!(f, "AsyncCancellable"),
1061 }
1062 }
1063}
1064
1065impl<State: Clone + Send + Sync + 'static> NativeCallable<State> {
1066 async fn call(
1067 &self,
1068 engine: &Engine<State>,
1069 typ: Type,
1070 args: &[Pointer],
1071 ) -> Result<Pointer, EngineError> {
1072 let token = engine.cancellation_token();
1073 if token.is_cancelled() {
1074 return Err(EngineError::Cancelled);
1075 }
1076
1077 match self {
1078 NativeCallable::Sync(f) => (f)(engine, &typ, args),
1079 NativeCallable::Async(f) => {
1080 let call_fut = (f)(engine, typ, args).fuse();
1081 let cancel_fut = token.cancelled().fuse();
1082 pin_mut!(call_fut, cancel_fut);
1083 futures::select! {
1084 _ = cancel_fut => Err(EngineError::Cancelled),
1085 res = call_fut => {
1086 if token.is_cancelled() {
1087 Err(EngineError::Cancelled)
1088 } else {
1089 res
1090 }
1091 },
1092 }
1093 }
1094 NativeCallable::AsyncCancellable(f) => {
1095 let call_fut = (f)(engine, token.clone(), typ, args).fuse();
1096 let cancel_fut = token.cancelled().fuse();
1097 pin_mut!(call_fut, cancel_fut);
1098 futures::select! {
1099 _ = cancel_fut => Err(EngineError::Cancelled),
1100 res = call_fut => {
1101 if token.is_cancelled() {
1102 Err(EngineError::Cancelled)
1103 } else {
1104 res
1105 }
1106 },
1107 }
1108 }
1109 }
1110 }
1111}
1112
1113#[derive(Clone, Debug, PartialEq)]
1114pub struct NativeFn {
1115 native_id: NativeId,
1116 name: Symbol,
1117 arity: usize,
1118 typ: Type,
1119 gas_cost: u64,
1120 applied: Vec<Pointer>,
1121 applied_types: Vec<Type>,
1122}
1123
1124impl NativeFn {
1125 fn new(native_id: NativeId, name: Symbol, arity: usize, typ: Type, gas_cost: u64) -> Self {
1126 Self {
1127 native_id,
1128 name,
1129 arity,
1130 typ,
1131 gas_cost,
1132 applied: Vec::new(),
1133 applied_types: Vec::new(),
1134 }
1135 }
1136
1137 pub(crate) fn from_parts(
1138 native_id: NativeId,
1139 name: Symbol,
1140 arity: usize,
1141 typ: Type,
1142 gas_cost: u64,
1143 applied: Vec<Pointer>,
1144 applied_types: Vec<Type>,
1145 ) -> Self {
1146 Self {
1147 native_id,
1148 name,
1149 arity,
1150 typ,
1151 gas_cost,
1152 applied,
1153 applied_types,
1154 }
1155 }
1156
1157 pub(crate) fn name(&self) -> &Symbol {
1158 &self.name
1159 }
1160
1161 async fn call_zero<State: Clone + Send + Sync + 'static>(
1162 &self,
1163 engine: &Engine<State>,
1164 gas: &mut GasMeter,
1165 ) -> Result<Pointer, EngineError> {
1166 let amount = gas
1167 .costs
1168 .native_call_base
1169 .saturating_add(self.gas_cost)
1170 .saturating_add(gas.costs.native_call_per_arg.saturating_mul(0));
1171 gas.charge(amount)?;
1172 if self.arity != 0 {
1173 return Err(EngineError::NativeArity {
1174 name: self.name.clone(),
1175 expected: self.arity,
1176 got: 0,
1177 });
1178 }
1179 engine
1180 .native_callable(self.native_id)?
1181 .call(engine, self.typ.clone(), &[])
1182 .await
1183 }
1184
1185 async fn apply<State: Clone + Send + Sync + 'static>(
1186 mut self,
1187 engine: &Engine<State>,
1188 arg: Pointer,
1189 arg_type: Option<&Type>,
1190 gas: &mut GasMeter,
1191 ) -> Result<Pointer, EngineError> {
1192 if self.arity == 0 {
1195 return Err(EngineError::NativeArity {
1196 name: self.name,
1197 expected: 0,
1198 got: 1,
1199 });
1200 }
1201 let (arg_ty, rest_ty) =
1202 split_fun(&self.typ).ok_or_else(|| EngineError::NotCallable(self.typ.to_string()))?;
1203 let actual_ty = resolve_arg_type(&engine.heap, arg_type, &arg)?;
1204 let subst = unify(&arg_ty, &actual_ty).map_err(|_| EngineError::NativeType {
1205 expected: arg_ty.to_string(),
1206 got: actual_ty.to_string(),
1207 })?;
1208 self.typ = rest_ty.apply(&subst);
1209 self.applied.push(arg);
1210 self.applied_types.push(actual_ty);
1211 if is_function_type(&self.typ) {
1212 let NativeFn {
1213 native_id,
1214 name,
1215 arity,
1216 typ,
1217 gas_cost,
1218 applied,
1219 applied_types,
1220 } = self;
1221 return engine.heap.alloc_native(
1222 native_id,
1223 name,
1224 arity,
1225 typ,
1226 gas_cost,
1227 applied,
1228 applied_types,
1229 );
1230 }
1231
1232 let mut full_ty = self.typ.clone();
1233 for arg_ty in self.applied_types.iter().rev() {
1234 full_ty = Type::fun(arg_ty.clone(), full_ty);
1235 }
1236
1237 let amount = gas
1238 .costs
1239 .native_call_base
1240 .saturating_add(self.gas_cost)
1241 .saturating_add(
1242 gas.costs
1243 .native_call_per_arg
1244 .saturating_mul(self.applied.len() as u64),
1245 );
1246 gas.charge(amount)?;
1247 engine
1248 .native_callable(self.native_id)?
1249 .call(engine, full_ty, &self.applied)
1250 .await
1251 }
1252}
1253
1254#[derive(Clone, Debug, PartialEq)]
1255pub struct OverloadedFn {
1256 name: Symbol,
1257 typ: Type,
1258 applied: Vec<Pointer>,
1259 applied_types: Vec<Type>,
1260}
1261
1262impl OverloadedFn {
1263 pub(crate) fn new(name: Symbol, typ: Type) -> Self {
1264 Self {
1265 name,
1266 typ,
1267 applied: Vec::new(),
1268 applied_types: Vec::new(),
1269 }
1270 }
1271
1272 pub(crate) fn from_parts(
1273 name: Symbol,
1274 typ: Type,
1275 applied: Vec<Pointer>,
1276 applied_types: Vec<Type>,
1277 ) -> Self {
1278 Self {
1279 name,
1280 typ,
1281 applied,
1282 applied_types,
1283 }
1284 }
1285
1286 pub(crate) fn name(&self) -> &Symbol {
1287 &self.name
1288 }
1289
1290 pub(crate) fn into_parts(self) -> (Symbol, Type, Vec<Pointer>, Vec<Type>) {
1291 (self.name, self.typ, self.applied, self.applied_types)
1292 }
1293
1294 async fn apply<State: Clone + Send + Sync + 'static>(
1295 mut self,
1296 engine: &Engine<State>,
1297 arg: Pointer,
1298 func_type: Option<&Type>,
1299 arg_type: Option<&Type>,
1300 gas: &mut GasMeter,
1301 ) -> Result<Pointer, EngineError> {
1302 if let Some(expected) = func_type {
1303 let subst = unify(&self.typ, expected).map_err(|_| EngineError::NativeType {
1304 expected: self.typ.to_string(),
1305 got: expected.to_string(),
1306 })?;
1307 self.typ = self.typ.apply(&subst);
1308 }
1309 let (arg_ty, rest_ty) =
1310 split_fun(&self.typ).ok_or_else(|| EngineError::NotCallable(self.typ.to_string()))?;
1311 let actual_ty = resolve_arg_type(&engine.heap, arg_type, &arg)?;
1312 let subst = unify(&arg_ty, &actual_ty).map_err(|_| EngineError::NativeType {
1313 expected: arg_ty.to_string(),
1314 got: actual_ty.to_string(),
1315 })?;
1316 let rest_ty = rest_ty.apply(&subst);
1317 self.applied.push(arg);
1318 self.applied_types.push(actual_ty);
1319 if is_function_type(&rest_ty) {
1320 return engine.heap.alloc_overloaded(
1321 self.name,
1322 rest_ty,
1323 self.applied,
1324 self.applied_types,
1325 );
1326 }
1327 let mut full_ty = rest_ty;
1328 for arg_ty in self.applied_types.iter().rev() {
1329 full_ty = Type::fun(arg_ty.clone(), full_ty);
1330 }
1331 if engine.type_system.class_methods.contains_key(&self.name) {
1332 let mut func = engine
1333 .resolve_class_method(&self.name, &full_ty, gas)
1334 .await?;
1335 let mut cur_ty = full_ty;
1336 for (applied, applied_ty) in self.applied.into_iter().zip(self.applied_types.iter()) {
1337 let (arg_ty, rest_ty) = split_fun(&cur_ty)
1338 .ok_or_else(|| EngineError::NotCallable(cur_ty.to_string()))?;
1339 let subst = unify(&arg_ty, applied_ty).map_err(|_| EngineError::NativeType {
1340 expected: arg_ty.to_string(),
1341 got: applied_ty.to_string(),
1342 })?;
1343 let rest_ty = rest_ty.apply(&subst);
1344 func = apply(engine, func, applied, Some(&cur_ty), Some(applied_ty), gas).await?;
1345 cur_ty = rest_ty;
1346 }
1347 return Ok(func);
1348 }
1349
1350 let imp = engine.resolve_native_impl(self.name.as_ref(), &full_ty)?;
1351 let amount = gas
1352 .costs
1353 .native_call_base
1354 .saturating_add(imp.gas_cost)
1355 .saturating_add(
1356 gas.costs
1357 .native_call_per_arg
1358 .saturating_mul(self.applied.len() as u64),
1359 );
1360 gas.charge(amount)?;
1361 imp.func.call(engine, full_ty, &self.applied).await
1362 }
1363}
1364
1365#[derive(Clone)]
1366struct NativeImpl<State: Clone + Send + Sync + 'static> {
1367 id: NativeId,
1368 name: Symbol,
1369 arity: usize,
1370 scheme: Scheme,
1371 func: NativeCallable<State>,
1372 gas_cost: u64,
1373}
1374
1375impl<State: Clone + Send + Sync + 'static> NativeImpl<State> {
1376 fn to_native_fn(&self, typ: Type) -> NativeFn {
1377 NativeFn::new(self.id, self.name.clone(), self.arity, typ, self.gas_cost)
1378 }
1379}
1380
1381#[derive(Clone)]
1382struct NativeRegistry<State: Clone + Send + Sync + 'static> {
1383 next_id: NativeId,
1384 entries: HashMap<Symbol, Vec<NativeImpl<State>>>,
1385 by_id: HashMap<NativeId, NativeImpl<State>>,
1386}
1387
1388impl<State: Clone + Send + Sync + 'static> NativeRegistry<State> {
1389 fn insert(
1390 &mut self,
1391 name: Symbol,
1392 arity: usize,
1393 scheme: Scheme,
1394 func: NativeCallable<State>,
1395 gas_cost: u64,
1396 ) -> Result<(), EngineError> {
1397 let entry = self.entries.entry(name.clone()).or_default();
1398 if entry.iter().any(|existing| existing.scheme == scheme) {
1399 return Err(EngineError::DuplicateImpl {
1400 name,
1401 typ: scheme.typ.to_string(),
1402 });
1403 }
1404 let id = self.next_id;
1405 self.next_id = self.next_id.saturating_add(1);
1406 let imp = NativeImpl::<State> {
1407 id,
1408 name: name.clone(),
1409 arity,
1410 scheme,
1411 func,
1412 gas_cost,
1413 };
1414 self.by_id.insert(id, imp.clone());
1415 entry.push(imp);
1416 Ok(())
1417 }
1418
1419 fn get(&self, name: &Symbol) -> Option<&[NativeImpl<State>]> {
1420 self.entries.get(name).map(|v| v.as_slice())
1421 }
1422
1423 fn has_name(&self, name: &Symbol) -> bool {
1424 self.entries.contains_key(name)
1425 }
1426
1427 fn by_id(&self, id: NativeId) -> Option<&NativeImpl<State>> {
1428 self.by_id.get(&id)
1429 }
1430}
1431
1432impl<State: Clone + Send + Sync + 'static> Default for NativeRegistry<State> {
1433 fn default() -> Self {
1434 Self {
1435 next_id: 0,
1436 entries: HashMap::new(),
1437 by_id: HashMap::new(),
1438 }
1439 }
1440}
1441
1442#[derive(Clone)]
1443struct TypeclassInstance {
1444 head: Type,
1445 def_env: Env,
1446 methods: HashMap<Symbol, Arc<TypedExpr>>,
1447}
1448
1449#[derive(Default, Clone)]
1450struct TypeclassRegistry {
1451 entries: HashMap<Symbol, Vec<TypeclassInstance>>,
1452}
1453
1454impl TypeclassRegistry {
1455 fn insert(
1456 &mut self,
1457 class: Symbol,
1458 head: Type,
1459 def_env: Env,
1460 methods: HashMap<Symbol, Arc<TypedExpr>>,
1461 ) -> Result<(), EngineError> {
1462 let entry = self.entries.entry(class.clone()).or_default();
1463 for existing in entry.iter() {
1464 if unify(&existing.head, &head).is_ok() {
1465 return Err(EngineError::DuplicateTypeclassImpl {
1466 class,
1467 typ: head.to_string(),
1468 });
1469 }
1470 }
1471 entry.push(TypeclassInstance {
1472 head,
1473 def_env,
1474 methods,
1475 });
1476 Ok(())
1477 }
1478
1479 fn resolve(
1480 &self,
1481 class: &Symbol,
1482 method: &Symbol,
1483 param_type: &Type,
1484 ) -> Result<(Env, Arc<TypedExpr>, Subst), EngineError> {
1485 let instances =
1486 self.entries
1487 .get(class)
1488 .ok_or_else(|| EngineError::MissingTypeclassImpl {
1489 class: class.clone(),
1490 typ: param_type.to_string(),
1491 })?;
1492
1493 let mut matches = Vec::new();
1494 for inst in instances {
1495 if let Ok(s) = unify(&inst.head, param_type) {
1496 matches.push((inst, s));
1497 }
1498 }
1499 match matches.len() {
1500 0 => Err(EngineError::MissingTypeclassImpl {
1501 class: class.clone(),
1502 typ: param_type.to_string(),
1503 }),
1504 1 => {
1505 let (inst, s) = matches.remove(0);
1506 let typed =
1507 inst.methods
1508 .get(method)
1509 .ok_or_else(|| EngineError::MissingTypeclassImpl {
1510 class: class.clone(),
1511 typ: param_type.to_string(),
1512 })?;
1513 Ok((inst.def_env.clone(), typed.clone(), s))
1514 }
1515 _ => Err(EngineError::AmbiguousTypeclassImpl {
1516 class: class.clone(),
1517 typ: param_type.to_string(),
1518 }),
1519 }
1520 }
1521}
1522
1523pub struct Engine<State = ()>
1524where
1525 State: Clone + Send + Sync + 'static,
1526{
1527 pub state: Arc<State>,
1528 env: Env,
1529 natives: NativeRegistry<State>,
1530 typeclasses: TypeclassRegistry,
1531 pub type_system: TypeSystem,
1532 typeclass_cache: Arc<Mutex<HashMap<(Symbol, Type), Pointer>>>,
1533 pub(crate) modules: ModuleSystem,
1534 injected_modules: HashSet<String>,
1535 pub(crate) module_exports_cache: HashMap<ModuleId, ModuleExports>,
1536 pub(crate) module_interface_cache: HashMap<ModuleId, Vec<Decl>>,
1537 pub(crate) module_sources: HashMap<ModuleId, String>,
1538 pub(crate) module_source_fingerprints: HashMap<ModuleId, String>,
1539 pub(crate) published_cycle_interfaces: HashSet<ModuleId>,
1540 default_imports: Vec<String>,
1541 virtual_modules: HashMap<String, ModuleExports>,
1542 module_local_type_names: HashMap<String, HashSet<Symbol>>,
1543 registration_module_context: Option<String>,
1544 cancel: CancellationToken,
1545 pub heap: Heap,
1546}
1547
1548impl<State> Default for Engine<State>
1549where
1550 State: Clone + Send + Sync + 'static + Default,
1551{
1552 fn default() -> Self {
1553 Self::new(State::default())
1554 }
1555}
1556
1557macro_rules! native_fn_type {
1558 (; $ret:ident) => {
1559 $ret::rex_type()
1560 };
1561 ($arg_ty:ident $(, $rest:ident)* ; $ret:ident) => {
1562 Type::fun($arg_ty::rex_type(), native_fn_type!($($rest),* ; $ret))
1563 };
1564}
1565
1566define_handler_impl!([] ; 0 ; fn() -> R);
1567define_handler_impl!([(A, a, 0)] ; 1 ; fn(A) -> R);
1568define_handler_impl!([(A, a, 0), (B, b, 1)] ; 2 ; fn(A, B) -> R);
1569define_handler_impl!([(A, a, 0), (B, b, 1), (C, c, 2)] ; 3 ; fn(A, B, C) -> R);
1570define_handler_impl!(
1571 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3)] ; 4 ; fn(A, B, C, D) -> R
1572);
1573define_handler_impl!(
1574 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4)] ; 5 ; fn(A, B, C, D, E) -> R
1575);
1576define_handler_impl!(
1577 [(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
1578);
1579define_handler_impl!(
1580 [(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
1581);
1582define_handler_impl!(
1583 [(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
1584);
1585
1586define_async_handler_impl!([] ; 0 ; fn() -> R);
1587define_async_handler_impl!([(A, a, 0)] ; 1 ; fn(A) -> R);
1588define_async_handler_impl!([(A, a, 0), (B, b, 1)] ; 2 ; fn(A, B) -> R);
1589define_async_handler_impl!([(A, a, 0), (B, b, 1), (C, c, 2)] ; 3 ; fn(A, B, C) -> R);
1590define_async_handler_impl!(
1591 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3)] ; 4 ; fn(A, B, C, D) -> R
1592);
1593define_async_handler_impl!(
1594 [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4)] ; 5 ; fn(A, B, C, D, E) -> R
1595);
1596define_async_handler_impl!(
1597 [(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
1598);
1599define_async_handler_impl!(
1600 [(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
1601);
1602define_async_handler_impl!(
1603 [(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
1604);
1605
1606impl<State> Engine<State>
1607where
1608 State: Clone + Send + Sync + 'static,
1609{
1610 pub fn new(state: State) -> Self {
1611 Self {
1612 state: Arc::new(state),
1613 env: Env::new(),
1614 natives: NativeRegistry::<State>::default(),
1615 typeclasses: TypeclassRegistry::default(),
1616 type_system: TypeSystem::new(),
1617 typeclass_cache: Arc::new(Mutex::new(HashMap::new())),
1618 modules: ModuleSystem::default(),
1619 injected_modules: HashSet::new(),
1620 module_exports_cache: HashMap::new(),
1621 module_interface_cache: HashMap::new(),
1622 module_sources: HashMap::new(),
1623 module_source_fingerprints: HashMap::new(),
1624 published_cycle_interfaces: HashSet::new(),
1625 default_imports: Vec::new(),
1626 virtual_modules: HashMap::new(),
1627 module_local_type_names: HashMap::new(),
1628 registration_module_context: None,
1629 cancel: CancellationToken::new(),
1630 heap: Heap::new(),
1631 }
1632 }
1633
1634 pub fn with_prelude(state: State) -> Result<Self, EngineError> {
1635 Self::with_options(state, EngineOptions::default())
1636 }
1637
1638 pub fn with_options(state: State, options: EngineOptions) -> Result<Self, EngineError> {
1639 let type_system = match options.prelude {
1640 PreludeMode::Enabled => TypeSystem::with_prelude()?,
1641 PreludeMode::Disabled => TypeSystem::new(),
1642 };
1643 let mut engine = Engine {
1644 state: Arc::new(state),
1645 env: Env::new(),
1646 natives: NativeRegistry::<State>::default(),
1647 typeclasses: TypeclassRegistry::default(),
1648 type_system,
1649 typeclass_cache: Arc::new(Mutex::new(HashMap::new())),
1650 modules: ModuleSystem::default(),
1651 injected_modules: HashSet::new(),
1652 module_exports_cache: HashMap::new(),
1653 module_interface_cache: HashMap::new(),
1654 module_sources: HashMap::new(),
1655 module_source_fingerprints: HashMap::new(),
1656 published_cycle_interfaces: HashSet::new(),
1657 default_imports: options.default_imports,
1658 virtual_modules: HashMap::new(),
1659 module_local_type_names: HashMap::new(),
1660 registration_module_context: None,
1661 cancel: CancellationToken::new(),
1662 heap: Heap::new(),
1663 };
1664 if matches!(options.prelude, PreludeMode::Enabled) {
1665 engine.inject_prelude()?;
1666 engine.inject_prelude_virtual_module()?;
1667 }
1668 Ok(engine)
1669 }
1670
1671 pub fn into_heap(self) -> Heap {
1672 self.heap
1673 }
1674
1675 pub fn inject_tracing_log_functions(&mut self) -> Result<(), EngineError> {
1680 let string = Type::builtin(BuiltinTypeId::String);
1681
1682 let make_scheme = |engine: &mut Engine<State>| {
1683 let a_tv = engine.type_system.supply.fresh(Some("a".into()));
1684 let a = Type::var(a_tv.clone());
1685 Scheme::new(
1686 vec![a_tv],
1687 vec![Predicate::new("Show", a.clone())],
1688 Type::fun(a, string.clone()),
1689 )
1690 };
1691
1692 let debug_scheme = make_scheme(self);
1693 self.inject_tracing_log_function_with_scheme("debug", debug_scheme, |s| {
1694 tracing::debug!("{s}")
1695 })?;
1696 let info_scheme = make_scheme(self);
1697 self.inject_tracing_log_function_with_scheme("info", info_scheme, |s| {
1698 tracing::info!("{s}")
1699 })?;
1700 let warn_scheme = make_scheme(self);
1701 self.inject_tracing_log_function_with_scheme("warn", warn_scheme, |s| {
1702 tracing::warn!("{s}")
1703 })?;
1704 let error_scheme = make_scheme(self);
1705 self.inject_tracing_log_function_with_scheme("error", error_scheme, |s| {
1706 tracing::error!("{s}")
1707 })?;
1708 Ok(())
1709 }
1710
1711 pub fn inject_tracing_log_function(
1712 &mut self,
1713 name: &str,
1714 log: fn(&str),
1715 ) -> Result<(), EngineError> {
1716 let string = Type::builtin(BuiltinTypeId::String);
1717 let a_tv = self.type_system.supply.fresh(Some("a".into()));
1718 let a = Type::var(a_tv.clone());
1719 let scheme = Scheme::new(
1720 vec![a_tv],
1721 vec![Predicate::new("Show", a.clone())],
1722 Type::fun(a, string),
1723 );
1724 self.inject_tracing_log_function_with_scheme(name, scheme, log)
1725 }
1726
1727 fn inject_tracing_log_function_with_scheme(
1728 &mut self,
1729 name: &str,
1730 scheme: Scheme,
1731 log: fn(&str),
1732 ) -> Result<(), EngineError> {
1733 let name_sym = sym(name);
1734 self.export_native_async(name, scheme, 1, move |engine, call_type, args| {
1735 let name_sym = name_sym.clone();
1736 async move {
1737 if args.len() != 1 {
1738 return Err(EngineError::NativeArity {
1739 name: name_sym.clone(),
1740 expected: 1,
1741 got: args.len(),
1742 });
1743 }
1744
1745 let (arg_ty, _ret_ty) = split_fun(&call_type)
1746 .ok_or_else(|| EngineError::NotCallable(call_type.to_string()))?;
1747 let show_ty = Type::fun(arg_ty.clone(), Type::builtin(BuiltinTypeId::String));
1748 let mut gas = GasMeter::default();
1749 let show_ptr = engine
1750 .resolve_class_method(&sym("show"), &show_ty, &mut gas)
1751 .await?;
1752 let rendered_ptr = apply(
1753 engine,
1754 show_ptr,
1755 args[0],
1756 Some(&show_ty),
1757 Some(&arg_ty),
1758 &mut gas,
1759 )
1760 .await?;
1761 let message = engine.heap.pointer_as_string(&rendered_ptr)?;
1762
1763 log(&message);
1764 engine.heap.alloc_string(message)
1765 }
1766 .boxed()
1767 })
1768 }
1769
1770 pub fn cancellation_token(&self) -> CancellationToken {
1771 self.cancel.clone()
1772 }
1773
1774 pub fn set_default_imports(&mut self, imports: Vec<String>) {
1775 self.default_imports = imports;
1776 }
1777
1778 pub fn default_imports(&self) -> &[String] {
1779 &self.default_imports
1780 }
1781
1782 pub fn registry_markdown(&self) -> String {
1805 fn module_anchor(id: &ModuleId) -> String {
1806 let raw = format!("module-{id}").to_ascii_lowercase();
1807 let mut out = String::with_capacity(raw.len());
1808 let mut prev_dash = false;
1809 for ch in raw.chars() {
1810 let keep = ch.is_ascii_alphanumeric();
1811 let mapped = if keep { ch } else { '-' };
1812 if mapped == '-' {
1813 if prev_dash {
1814 continue;
1815 }
1816 prev_dash = true;
1817 } else {
1818 prev_dash = false;
1819 }
1820 out.push(mapped);
1821 }
1822 out.trim_matches('-').to_string()
1823 }
1824
1825 fn symbol_list(symbols: &[Symbol]) -> String {
1826 if symbols.is_empty() {
1827 "(none)".to_string()
1828 } else {
1829 symbols
1830 .iter()
1831 .map(|s| format!("`{s}`"))
1832 .collect::<Vec<_>>()
1833 .join(", ")
1834 }
1835 }
1836
1837 let mut out = String::new();
1838 let _ = writeln!(&mut out, "# Engine Registry");
1839 let _ = writeln!(&mut out);
1840 let mut module_ids: BTreeMap<String, ModuleId> = BTreeMap::new();
1841 for id in self.module_exports_cache.keys() {
1842 module_ids.insert(id.to_string(), id.clone());
1843 }
1844 for id in self.module_sources.keys() {
1845 module_ids.insert(id.to_string(), id.clone());
1846 }
1847 for module_name in self.virtual_modules.keys() {
1848 let id = ModuleId::Virtual(module_name.clone());
1849 module_ids.insert(id.to_string(), id);
1850 }
1851 for module_name in &self.injected_modules {
1852 let id = ModuleId::Virtual(module_name.clone());
1853 module_ids.insert(id.to_string(), id);
1854 }
1855
1856 let _ = writeln!(&mut out, "## Summary");
1857 let env_value_count = self.type_system.env.values.size();
1858 let native_impl_count: usize = self.natives.entries.values().map(Vec::len).sum();
1859 let class_count = self.type_system.classes.classes.len();
1860 let class_instance_count: usize = self
1861 .type_system
1862 .classes
1863 .instances
1864 .values()
1865 .map(Vec::len)
1866 .sum();
1867 let _ = writeln!(&mut out, "- Modules (all kinds): {}", module_ids.len());
1868 let _ = writeln!(
1869 &mut out,
1870 "- Injected modules: {}",
1871 self.injected_modules.len()
1872 );
1873 let _ = writeln!(
1874 &mut out,
1875 "- Virtual modules: {}",
1876 self.virtual_modules.len()
1877 );
1878 let _ = writeln!(&mut out, "- ADTs: {}", self.type_system.adts.len());
1879 let _ = writeln!(
1880 &mut out,
1881 "- Values/functions in type env: {env_value_count}"
1882 );
1883 let _ = writeln!(&mut out, "- Type classes: {class_count}");
1884 let _ = writeln!(&mut out, "- Type class instances: {class_instance_count}");
1885 let _ = writeln!(&mut out, "- Native implementations: {native_impl_count}");
1886 let _ = writeln!(&mut out);
1887
1888 let _ = writeln!(&mut out, "## Module Index");
1889 if module_ids.is_empty() {
1890 let _ = writeln!(&mut out, "_No modules registered._");
1891 } else {
1892 for (display, id) in &module_ids {
1893 let anchor = module_anchor(id);
1894 let _ = writeln!(&mut out, "- [`{display}`](#{anchor})");
1895 }
1896 }
1897 let _ = writeln!(&mut out);
1898
1899 let _ = writeln!(&mut out, "## Modules");
1900 if module_ids.is_empty() {
1901 let _ = writeln!(&mut out, "_No modules registered._");
1902 let _ = writeln!(&mut out);
1903 } else {
1904 for (display, id) in module_ids {
1905 let anchor = module_anchor(&id);
1906 let _ = writeln!(&mut out, "<a id=\"{anchor}\"></a>");
1907 let _ = writeln!(&mut out, "### `{display}`");
1908 if let Some(source) = self.module_sources.get(&id) {
1909 if source.trim().is_empty() {
1910 let _ = writeln!(&mut out, "_Module source is empty._");
1911 } else {
1912 let _ = writeln!(&mut out, "```rex");
1913 let _ = writeln!(&mut out, "{}", source.trim_end());
1914 let _ = writeln!(&mut out, "```");
1915 }
1916 } else {
1917 let _ = writeln!(&mut out, "_No captured source for this module._");
1918 }
1919
1920 let exports = self.module_exports_cache.get(&id).or_else(|| match &id {
1921 ModuleId::Virtual(name) => self.virtual_modules.get(name),
1922 _ => None,
1923 });
1924 if let Some(exports) = exports {
1925 let mut values: Vec<Symbol> = exports.values.keys().cloned().collect();
1926 let mut types: Vec<Symbol> = exports.types.keys().cloned().collect();
1927 let mut classes: Vec<Symbol> = exports.classes.keys().cloned().collect();
1928 values.sort();
1929 types.sort();
1930 classes.sort();
1931 let _ = writeln!(&mut out, "- Values: {}", symbol_list(&values));
1932 let _ = writeln!(&mut out, "- Types: {}", symbol_list(&types));
1933 let _ = writeln!(&mut out, "- Classes: {}", symbol_list(&classes));
1934 } else {
1935 let _ = writeln!(&mut out, "- Exports: (none cached)");
1936 }
1937 let _ = writeln!(&mut out);
1938 }
1939 }
1940
1941 let _ = writeln!(&mut out, "## ADTs");
1942 if self.type_system.adts.is_empty() {
1943 let _ = writeln!(&mut out, "_No ADTs registered._");
1944 let _ = writeln!(&mut out);
1945 } else {
1946 let mut adts: Vec<&AdtDecl> = self.type_system.adts.values().collect();
1947 adts.sort_by(|a, b| a.name.cmp(&b.name));
1948 for adt in adts {
1949 let params = if adt.params.is_empty() {
1950 "(none)".to_string()
1951 } else {
1952 adt.params
1953 .iter()
1954 .map(|p| format!("`{}`", p.name))
1955 .collect::<Vec<_>>()
1956 .join(", ")
1957 };
1958 let _ = writeln!(&mut out, "### `{}`", adt.name);
1959 let _ = writeln!(&mut out, "- Parameters: {params}");
1960 if adt.variants.is_empty() {
1961 let _ = writeln!(&mut out, "- Variants: (none)");
1962 } else {
1963 let mut variants = adt.variants.clone();
1964 variants.sort_by(|a, b| a.name.cmp(&b.name));
1965 let _ = writeln!(&mut out, "- Variants:");
1966 for variant in variants {
1967 if variant.args.is_empty() {
1968 let _ = writeln!(&mut out, " - `{}`", variant.name);
1969 } else {
1970 let args = variant
1971 .args
1972 .iter()
1973 .map(ToString::to_string)
1974 .collect::<Vec<_>>()
1975 .join(", ");
1976 let _ = writeln!(&mut out, " - `{}`({args})", variant.name);
1977 }
1978 }
1979 }
1980 let _ = writeln!(&mut out);
1981 }
1982 }
1983
1984 let _ = writeln!(&mut out, "## Functions and Values");
1985 if self.type_system.env.values.is_empty() {
1986 let _ = writeln!(&mut out, "_No values registered._");
1987 let _ = writeln!(&mut out);
1988 } else {
1989 let mut names: Vec<Symbol> = self
1990 .type_system
1991 .env
1992 .values
1993 .iter()
1994 .map(|(name, _)| name.clone())
1995 .collect();
1996 names.sort();
1997 for name in names {
1998 if let Some(schemes) = self.type_system.env.lookup(&name) {
1999 let mut scheme_strs: Vec<String> =
2000 schemes.iter().map(|s| s.typ.to_string()).collect();
2001 scheme_strs.sort();
2002 scheme_strs.dedup();
2003 let joined = scheme_strs
2004 .into_iter()
2005 .map(|s| format!("`{s}`"))
2006 .collect::<Vec<_>>()
2007 .join(", ");
2008 let _ = writeln!(&mut out, "- `{name}`: {joined}");
2009 }
2010 }
2011 let _ = writeln!(&mut out);
2012 }
2013
2014 let _ = writeln!(&mut out, "## Type Classes");
2015 if self.type_system.classes.classes.is_empty() {
2016 let _ = writeln!(&mut out, "_No type classes registered._");
2017 let _ = writeln!(&mut out);
2018 } else {
2019 let mut class_names: Vec<Symbol> =
2020 self.type_system.classes.classes.keys().cloned().collect();
2021 class_names.sort();
2022 for class_name in class_names {
2023 let supers = self.type_system.classes.supers_of(&class_name);
2024 let mut supers_sorted = supers;
2025 supers_sorted.sort();
2026 let _ = writeln!(&mut out, "### `{class_name}`");
2027 let _ = writeln!(&mut out, "- Superclasses: {}", symbol_list(&supers_sorted));
2028
2029 let mut methods: Vec<(Symbol, String)> = self
2030 .type_system
2031 .class_methods
2032 .iter()
2033 .filter(|(_, info)| info.class == class_name)
2034 .map(|(name, info)| (name.clone(), info.scheme.typ.to_string()))
2035 .collect();
2036 methods.sort_by(|a, b| a.0.cmp(&b.0));
2037 if methods.is_empty() {
2038 let _ = writeln!(&mut out, "- Methods: (none)");
2039 } else {
2040 let _ = writeln!(&mut out, "- Methods:");
2041 for (method, scheme) in methods {
2042 let _ = writeln!(&mut out, " - `{method}`: `{scheme}`");
2043 }
2044 }
2045
2046 let mut instances = self
2047 .type_system
2048 .classes
2049 .instances
2050 .get(&class_name)
2051 .cloned()
2052 .unwrap_or_default();
2053 instances.sort_by(|a, b| a.head.typ.to_string().cmp(&b.head.typ.to_string()));
2054 if instances.is_empty() {
2055 let _ = writeln!(&mut out, "- Instances: (none)");
2056 } else {
2057 let _ = writeln!(&mut out, "- Instances:");
2058 for instance in instances {
2059 let ctx = if instance.context.is_empty() {
2060 String::new()
2061 } else {
2062 let mut parts: Vec<String> = instance
2063 .context
2064 .iter()
2065 .map(|pred| format!("{} {}", pred.class, pred.typ))
2066 .collect();
2067 parts.sort();
2068 format!("({}) => ", parts.join(", "))
2069 };
2070 let _ = writeln!(
2071 &mut out,
2072 " - `{}{} {}`",
2073 ctx, instance.head.class, instance.head.typ
2074 );
2075 }
2076 }
2077 let _ = writeln!(&mut out);
2078 }
2079 }
2080
2081 let _ = writeln!(&mut out, "## Native Implementations");
2082 if self.natives.entries.is_empty() {
2083 let _ = writeln!(&mut out, "_No native implementations registered._");
2084 } else {
2085 let mut native_names: Vec<Symbol> = self.natives.entries.keys().cloned().collect();
2086 native_names.sort();
2087 for name in native_names {
2088 if let Some(impls) = self.natives.get(&name) {
2089 let mut rows: Vec<(usize, String, u64)> = impls
2090 .iter()
2091 .map(|imp| (imp.arity, imp.scheme.typ.to_string(), imp.gas_cost))
2092 .collect();
2093 rows.sort_by(|a, b| a.1.cmp(&b.1));
2094 let _ = writeln!(&mut out, "### `{name}`");
2095 for (arity, typ, gas_cost) in rows {
2096 let _ = writeln!(
2097 &mut out,
2098 "- arity `{arity}`, gas `{gas_cost}`, type `{typ}`"
2099 );
2100 }
2101 let _ = writeln!(&mut out);
2102 }
2103 }
2104 }
2105
2106 out
2107 }
2108
2109 pub fn cancel(&self) {
2110 self.cancel.cancel();
2111 }
2112
2113 pub fn inject_module(&mut self, module: Module<State>) -> Result<(), EngineError> {
2114 let module_name = module.name.trim().to_string();
2115 if module_name.is_empty() {
2116 return Err(EngineError::Internal("module name cannot be empty".into()));
2117 }
2118 if self.injected_modules.contains(&module_name) {
2119 return Err(EngineError::Internal(format!(
2120 "module `{module_name}` already injected"
2121 )));
2122 }
2123
2124 let mut source = String::new();
2125 for declaration in &module.declarations {
2126 source.push_str(declaration);
2127 source.push('\n');
2128 }
2129 for export in &module.exports {
2130 source.push_str(&export.declaration);
2131 source.push('\n');
2132 }
2133 self.module_sources
2134 .insert(ModuleId::Virtual(module_name.clone()), source.clone());
2135
2136 let local_type_names = module_local_type_names_from_declarations(&module.declarations);
2137 self.module_local_type_names
2138 .insert(module_name.clone(), local_type_names);
2139
2140 for export in module.exports {
2141 self.inject_module_export(&module_name, export)?;
2142 }
2143
2144 let resolver_module_name = module_name.clone();
2145 let resolver_source = source.clone();
2146 self.add_resolver(
2147 format!("injected:{module_name}"),
2148 move |req: ResolveRequest| {
2149 let requested = req
2150 .module_name
2151 .split_once('#')
2152 .map(|(base, _)| base)
2153 .unwrap_or(req.module_name.as_str());
2154 if requested != resolver_module_name {
2155 return Ok(None);
2156 }
2157 Ok(Some(ResolvedModule {
2158 id: ModuleId::Virtual(resolver_module_name.clone()),
2159 source: resolver_source.clone(),
2160 }))
2161 },
2162 );
2163
2164 self.injected_modules.insert(module_name);
2165 Ok(())
2166 }
2167
2168 fn module_export_symbol(module_name: &str, export_name: &str) -> String {
2169 if module_name == ROOT_MODULE_NAME {
2170 normalize_name(export_name).to_string()
2171 } else {
2172 virtual_export_name(module_name, export_name)
2173 }
2174 }
2175
2176 fn inject_module_export(
2177 &mut self,
2178 module_name: &str,
2179 export: Export<State>,
2180 ) -> Result<(), EngineError> {
2181 let Export {
2182 name,
2183 declaration: _,
2184 injector,
2185 } = export;
2186 let qualified_name = Self::module_export_symbol(module_name, &name);
2187 let previous_context = self.registration_module_context.clone();
2188 self.registration_module_context = if module_name == ROOT_MODULE_NAME {
2189 None
2190 } else {
2191 Some(module_name.to_string())
2192 };
2193 let result = injector(self, &qualified_name);
2194 self.registration_module_context = previous_context;
2195 result
2196 }
2197
2198 fn inject_root_export(&mut self, export: Export<State>) -> Result<(), EngineError> {
2199 self.inject_module_export(ROOT_MODULE_NAME, export)
2200 }
2201
2202 fn register_native_registration(
2203 &mut self,
2204 module_name: &str,
2205 export_name: &str,
2206 registration: NativeRegistration<State>,
2207 ) -> Result<(), EngineError> {
2208 let NativeRegistration {
2209 mut scheme,
2210 arity,
2211 callable,
2212 gas_cost,
2213 } = registration;
2214 let scheme_module = if module_name == ROOT_MODULE_NAME {
2215 self.registration_module_context
2216 .as_deref()
2217 .unwrap_or(ROOT_MODULE_NAME)
2218 } else {
2219 module_name
2220 };
2221 if scheme_module != ROOT_MODULE_NAME
2222 && let Some(local_type_names) = self.module_local_type_names.get(scheme_module)
2223 {
2224 scheme = qualify_module_scheme_refs(&scheme, scheme_module, local_type_names);
2225 }
2226 let name = normalize_name(&Self::module_export_symbol(module_name, export_name));
2227 self.register_native(name, scheme, arity, callable, gas_cost)
2228 }
2229
2230 pub fn export<Sig, H>(&mut self, name: impl Into<String>, handler: H) -> Result<(), EngineError>
2231 where
2232 H: Handler<State, Sig>,
2233 {
2234 self.inject_root_export(Export::from_handler(name, handler)?)
2235 }
2236
2237 pub fn export_async<Sig, H>(
2238 &mut self,
2239 name: impl Into<String>,
2240 handler: H,
2241 ) -> Result<(), EngineError>
2242 where
2243 H: AsyncHandler<State, Sig>,
2244 {
2245 self.inject_root_export(Export::from_async_handler(name, handler)?)
2246 }
2247
2248 pub fn export_native<F>(
2249 &mut self,
2250 name: impl Into<String>,
2251 scheme: Scheme,
2252 arity: usize,
2253 handler: F,
2254 ) -> Result<(), EngineError>
2255 where
2256 F: for<'a> Fn(&'a Engine<State>, &'a Type, &'a [Pointer]) -> Result<Pointer, EngineError>
2257 + Send
2258 + Sync
2259 + 'static,
2260 {
2261 self.export_native_with_gas_cost(name, scheme, arity, 0, handler)
2262 }
2263
2264 pub fn inject_rex_default_instance<T>(&mut self) -> Result<(), EngineError>
2265 where
2266 T: RexType + RexDefault<State>,
2267 {
2268 let class = sym("Default");
2269 let method = sym("default");
2270 let head_ty = T::rex_type();
2271
2272 if !self.type_system.class_methods.contains_key(&method) {
2273 return Err(EngineError::UnknownVar(method));
2274 }
2275 if !head_ty.ftv().is_empty() {
2276 return Err(EngineError::UnsupportedExpr);
2277 }
2278
2279 if let Some(instances) = self.type_system.classes.instances.get(&class)
2280 && instances
2281 .iter()
2282 .any(|existing| unify(&existing.head.typ, &head_ty).is_ok())
2283 {
2284 return Err(EngineError::DuplicateTypeclassImpl {
2285 class,
2286 typ: head_ty.to_string(),
2287 });
2288 }
2289
2290 let native_name = format!(
2291 "__rex_default_for_{}",
2292 sanitize_type_name_for_symbol(&head_ty)
2293 );
2294 let native_scheme = Scheme::new(vec![], vec![], head_ty.clone());
2295 self.export_native(native_name.clone(), native_scheme, 0, |engine, _, _| {
2296 T::rex_default(engine)
2297 })?;
2298
2299 self.type_system.inject_instance(
2300 "Default",
2301 Instance::new(vec![], Predicate::new(class.clone(), head_ty.clone())),
2302 );
2303
2304 let mut methods: HashMap<Symbol, Arc<TypedExpr>> = HashMap::new();
2305 methods.insert(
2306 method.clone(),
2307 Arc::new(TypedExpr::new(
2308 head_ty.clone(),
2309 TypedExprKind::Var {
2310 name: sym(&native_name),
2311 overloads: vec![],
2312 },
2313 )),
2314 );
2315
2316 self.typeclasses
2317 .insert(class, head_ty, self.env.clone(), methods)?;
2318
2319 Ok(())
2320 }
2321
2322 pub fn export_native_async<F>(
2323 &mut self,
2324 name: impl Into<String>,
2325 scheme: Scheme,
2326 arity: usize,
2327 handler: F,
2328 ) -> Result<(), EngineError>
2329 where
2330 F: for<'a> Fn(&'a Engine<State>, Type, Vec<Pointer>) -> NativeFuture<'a>
2331 + Send
2332 + Sync
2333 + 'static,
2334 {
2335 self.export_native_async_with_gas_cost(name, scheme, arity, 0, handler)
2336 }
2337
2338 pub fn export_value<V: IntoPointer + RexType>(
2339 &mut self,
2340 name: &str,
2341 value: V,
2342 ) -> Result<(), EngineError> {
2343 let typ = V::rex_type();
2344 let value = value.into_pointer(&self.heap)?;
2345 let func: SyncNativeCallable<State> =
2346 Arc::new(move |_engine: &Engine<State>, _: &Type, _args: &[Pointer]| Ok(value));
2347 let scheme = Scheme::new(vec![], vec![], typ);
2348 let registration = NativeRegistration::sync(scheme, 0, func, 0);
2349 self.register_native_registration(ROOT_MODULE_NAME, name, registration)
2350 }
2351
2352 pub fn export_value_typed(
2353 &mut self,
2354 name: &str,
2355 typ: Type,
2356 value: Value,
2357 ) -> Result<(), EngineError> {
2358 let value = self.heap.alloc_value(value)?;
2359 let func: SyncNativeCallable<State> =
2360 Arc::new(move |_engine: &Engine<State>, _: &Type, _args: &[Pointer]| Ok(value));
2361 let scheme = Scheme::new(vec![], vec![], typ);
2362 let registration = NativeRegistration::sync(scheme, 0, func, 0);
2363 self.register_native_registration(ROOT_MODULE_NAME, name, registration)
2364 }
2365
2366 pub fn export_native_with_gas_cost<F>(
2367 &mut self,
2368 name: impl Into<String>,
2369 scheme: Scheme,
2370 arity: usize,
2371 gas_cost: u64,
2372 handler: F,
2373 ) -> Result<(), EngineError>
2374 where
2375 F: for<'a> Fn(&'a Engine<State>, &'a Type, &'a [Pointer]) -> Result<Pointer, EngineError>
2376 + Send
2377 + Sync
2378 + 'static,
2379 {
2380 validate_native_export_scheme(&scheme, arity)?;
2381 let name = name.into();
2382 let handler = Arc::new(handler);
2383 let func: SyncNativeCallable<State> = Arc::new(
2384 move |engine: &Engine<State>, typ: &Type, args: &[Pointer]| handler(engine, typ, args),
2385 );
2386 let registration = NativeRegistration::sync(scheme, arity, func, gas_cost);
2387 self.register_native_registration(ROOT_MODULE_NAME, &name, registration)
2388 }
2389
2390 pub fn export_native_async_with_gas_cost<F>(
2391 &mut self,
2392 name: impl Into<String>,
2393 scheme: Scheme,
2394 arity: usize,
2395 gas_cost: u64,
2396 handler: F,
2397 ) -> Result<(), EngineError>
2398 where
2399 F: for<'a> Fn(&'a Engine<State>, Type, Vec<Pointer>) -> NativeFuture<'a>
2400 + Send
2401 + Sync
2402 + 'static,
2403 {
2404 validate_native_export_scheme(&scheme, arity)?;
2405 let name = name.into();
2406 let handler = Arc::new(handler);
2407 let func: AsyncNativeCallable<State> = Arc::new(move |engine, typ, args| {
2408 let handler = Arc::clone(&handler);
2409 handler(engine, typ, args.to_vec())
2410 });
2411 let registration = NativeRegistration::r#async(scheme, arity, func, gas_cost);
2412 self.register_native_registration(ROOT_MODULE_NAME, &name, registration)
2413 }
2414
2415 pub fn export_native_async_cancellable<F>(
2416 &mut self,
2417 name: impl Into<String>,
2418 scheme: Scheme,
2419 arity: usize,
2420 handler: F,
2421 ) -> Result<(), EngineError>
2422 where
2423 F: for<'a> Fn(
2424 &'a Engine<State>,
2425 CancellationToken,
2426 Type,
2427 &'a [Pointer],
2428 ) -> NativeFuture<'a>
2429 + Send
2430 + Sync
2431 + 'static,
2432 {
2433 self.export_native_async_cancellable_with_gas_cost(name, scheme, arity, 0, handler)
2434 }
2435
2436 pub fn export_native_async_cancellable_with_gas_cost<F>(
2437 &mut self,
2438 name: impl Into<String>,
2439 scheme: Scheme,
2440 arity: usize,
2441 gas_cost: u64,
2442 handler: F,
2443 ) -> Result<(), EngineError>
2444 where
2445 F: for<'a> Fn(
2446 &'a Engine<State>,
2447 CancellationToken,
2448 Type,
2449 &'a [Pointer],
2450 ) -> NativeFuture<'a>
2451 + Send
2452 + Sync
2453 + 'static,
2454 {
2455 validate_native_export_scheme(&scheme, arity)?;
2456 let name = name.into();
2457 let handler = Arc::new(handler);
2458 let func: AsyncNativeCallableCancellable<State> =
2459 Arc::new(move |engine, token, typ, args| handler(engine, token, typ, args));
2460 let registration = NativeRegistration::async_cancellable(scheme, arity, func, gas_cost);
2461 self.register_native_registration(ROOT_MODULE_NAME, &name, registration)
2462 }
2463
2464 pub fn adt_decl(&mut self, name: &str, params: &[&str]) -> AdtDecl {
2465 let name_sym = sym(name);
2466 let param_syms: Vec<Symbol> = params.iter().map(|p| sym(p)).collect();
2467 AdtDecl::new(&name_sym, ¶m_syms, &mut self.type_system.supply)
2468 }
2469
2470 pub fn adt_decl_from_type(&mut self, typ: &Type) -> Result<AdtDecl, EngineError> {
2477 let (name, arity, args) = type_head_and_args(typ)?;
2478 let param_names: Vec<String> = if args.is_empty() {
2479 (0..arity).map(|i| format!("t{i}")).collect()
2480 } else {
2481 let mut names = Vec::with_capacity(args.len());
2482 for arg in args {
2483 match arg.as_ref() {
2484 TypeKind::Var(tv) => {
2485 let name = tv
2486 .name
2487 .as_ref()
2488 .map(|s| s.to_string())
2489 .unwrap_or_else(|| format!("t{}", tv.id));
2490 names.push(name);
2491 }
2492 _ => {
2493 return Err(EngineError::Custom(format!(
2494 "cannot infer ADT params from `{typ}`: expected type variables, got `{arg}`"
2495 )));
2496 }
2497 }
2498 }
2499 names
2500 };
2501 let param_refs: Vec<&str> = param_names.iter().map(|s| s.as_str()).collect();
2502 Ok(self.adt_decl(name.as_ref(), ¶m_refs))
2503 }
2504
2505 pub fn adt_decl_from_type_with_params(
2507 &mut self,
2508 typ: &Type,
2509 params: &[&str],
2510 ) -> Result<AdtDecl, EngineError> {
2511 let (name, arity, _args) = type_head_and_args(typ)?;
2512 if arity != params.len() {
2513 return Err(EngineError::Custom(format!(
2514 "type `{}` expects {} parameters, got {}",
2515 name,
2516 arity,
2517 params.len()
2518 )));
2519 }
2520 Ok(self.adt_decl(name.as_ref(), params))
2521 }
2522
2523 pub fn inject_adt(&mut self, adt: AdtDecl) -> Result<(), EngineError> {
2524 self.type_system.inject_adt(&adt);
2527 for (ctor, scheme) in adt.constructor_schemes() {
2528 let ctor_name = ctor.clone();
2529 let func = Arc::new(move |engine: &Engine<State>, _: &Type, args: &[Pointer]| {
2530 engine.heap.alloc_adt(ctor_name.clone(), args.to_vec())
2531 });
2532 let arity = type_arity(&scheme.typ);
2533 self.register_native(ctor, scheme, arity, NativeCallable::Sync(func), 0)?;
2534 }
2535 Ok(())
2536 }
2537
2538 pub fn inject_type_decl(&mut self, decl: &TypeDecl) -> Result<(), EngineError> {
2539 let adt = self
2540 .type_system
2541 .adt_from_decl(decl)
2542 .map_err(EngineError::Type)?;
2543 self.inject_adt(adt)
2544 }
2545
2546 pub fn inject_class_decl(&mut self, decl: &ClassDecl) -> Result<(), EngineError> {
2547 self.type_system
2548 .inject_class_decl(decl)
2549 .map_err(EngineError::Type)
2550 }
2551
2552 pub fn inject_instance_decl(&mut self, decl: &InstanceDecl) -> Result<(), EngineError> {
2553 let prepared = self
2554 .type_system
2555 .inject_instance_decl(decl)
2556 .map_err(EngineError::Type)?;
2557 self.register_typeclass_instance(decl, &prepared)
2558 }
2559
2560 pub fn inject_fn_decl(&mut self, decl: &FnDecl) -> Result<(), EngineError> {
2561 self.inject_fn_decls(std::slice::from_ref(decl))
2562 }
2563
2564 pub fn inject_fn_decls(&mut self, decls: &[FnDecl]) -> Result<(), EngineError> {
2565 if decls.is_empty() {
2566 return Ok(());
2567 }
2568
2569 self.type_system
2571 .inject_fn_decls(decls)
2572 .map_err(EngineError::Type)?;
2573
2574 let mut env_rec = self.env.clone();
2576 let mut slots = Vec::with_capacity(decls.len());
2577 for decl in decls {
2578 if let Some(existing) = env_rec.get(&decl.name.name) {
2579 slots.push(existing);
2580 } else {
2581 let placeholder = self.heap.alloc_uninitialized(decl.name.name.clone())?;
2582 env_rec = env_rec.extend(decl.name.name.clone(), placeholder);
2583 slots.push(placeholder);
2584 }
2585 }
2586
2587 let saved_env = self.env.clone();
2588 self.env = env_rec.clone();
2589
2590 let result: Result<(), EngineError> = (|| {
2591 for (decl, slot) in decls.iter().zip(slots.iter()) {
2592 let mut lam_body = decl.body.clone();
2593 for (idx, (param, ann)) in decl.params.iter().enumerate().rev() {
2594 let lam_constraints = if idx == 0 {
2595 decl.constraints.clone()
2596 } else {
2597 Vec::new()
2598 };
2599 let span = param.span;
2600 lam_body = Arc::new(Expr::Lam(
2601 span,
2602 Scope::new_sync(),
2603 param.clone(),
2604 Some(ann.clone()),
2605 lam_constraints,
2606 lam_body,
2607 ));
2608 }
2609
2610 let typed = self.type_check(lam_body.as_ref())?;
2611 let (param_ty, _ret_ty) = split_fun(&typed.typ)
2612 .ok_or_else(|| EngineError::NotCallable(typed.typ.to_string()))?;
2613 let TypedExprKind::Lam { param, body } = &typed.kind else {
2614 return Err(EngineError::Internal(
2615 "fn declaration did not lower to lambda".into(),
2616 ));
2617 };
2618 let ptr = self.heap.alloc_closure(
2619 self.env.clone(),
2620 param.clone(),
2621 param_ty,
2622 typed.typ.clone(),
2623 Arc::new(body.as_ref().clone()),
2624 )?;
2625 let value = self.heap.get(&ptr)?;
2626 self.heap.overwrite(slot, value.as_ref().clone())?;
2627 }
2628 Ok(())
2629 })();
2630
2631 if result.is_err() {
2632 self.env = saved_env;
2633 return result;
2634 }
2635
2636 self.env = env_rec;
2637 Ok(())
2638 }
2639
2640 pub fn inject_decls(&mut self, decls: &[Decl]) -> Result<(), EngineError> {
2641 let mut pending_fns: Vec<FnDecl> = Vec::new();
2642 for decl in decls {
2643 if let Decl::Fn(fd) = decl {
2644 pending_fns.push(fd.clone());
2645 continue;
2646 }
2647 if !pending_fns.is_empty() {
2648 self.inject_fn_decls(&pending_fns)?;
2649 pending_fns.clear();
2650 }
2651
2652 match decl {
2653 Decl::Type(ty) => self.inject_type_decl(ty)?,
2654 Decl::Class(class_decl) => self.inject_class_decl(class_decl)?,
2655 Decl::Instance(inst_decl) => self.inject_instance_decl(inst_decl)?,
2656 Decl::Fn(..) => {}
2657 Decl::DeclareFn(df) => {
2658 self.type_system
2659 .inject_declare_fn_decl(df)
2660 .map_err(EngineError::Type)?;
2661 }
2662 Decl::Import(..) => {}
2663 }
2664 }
2665 if !pending_fns.is_empty() {
2666 self.inject_fn_decls(&pending_fns)?;
2667 }
2668 Ok(())
2669 }
2670
2671 pub(crate) fn publish_runtime_decl_interfaces(
2672 &mut self,
2673 decls: &[DeclareFnDecl],
2674 ) -> Result<(), EngineError> {
2675 for df in decls {
2676 if self.env.get(&df.name.name).is_some() {
2677 continue;
2678 }
2679 let placeholder = self.heap.alloc_uninitialized(df.name.name.clone())?;
2680 self.env = self.env.extend(df.name.name.clone(), placeholder);
2681 }
2682 Ok(())
2683 }
2684
2685 pub fn inject_class(&mut self, name: &str, supers: Vec<String>) {
2686 let supers = supers.into_iter().map(|s| sym(&s)).collect();
2687 self.type_system.inject_class(name, supers);
2688 }
2689
2690 pub fn inject_instance(&mut self, class: &str, inst: Instance) {
2691 self.type_system.inject_instance(class, inst);
2692 }
2693
2694 pub async fn eval(
2695 &mut self,
2696 expr: &Expr,
2697 gas: &mut GasMeter,
2698 ) -> Result<(Pointer, Type), EngineError> {
2699 check_cancelled(self)?;
2700 let typed = self.type_check(expr)?;
2701 let typ = typed.typ.clone();
2702 let value = eval_typed_expr(self, &self.env, &typed, gas).await?;
2703 Ok((value, typ))
2704 }
2705
2706 fn inject_prelude(&mut self) -> Result<(), EngineError> {
2707 inject_prelude_adts(self)?;
2708 inject_equality_ops(self)?;
2709 inject_order_ops(self)?;
2710 inject_show_ops(self)?;
2711 inject_boolean_ops(self)?;
2712 inject_numeric_ops(self)?;
2713 inject_list_builtins(self)?;
2714 inject_option_result_builtins(self)?;
2715 inject_json_primops(self)?;
2716 self.register_prelude_typeclass_instances()?;
2717 Ok(())
2718 }
2719
2720 fn inject_prelude_virtual_module(&mut self) -> Result<(), EngineError> {
2721 if self.virtual_modules.contains_key(PRELUDE_MODULE_NAME) {
2722 return Ok(());
2723 }
2724
2725 let module_key = module_key_for_module(&ModuleId::Virtual(PRELUDE_MODULE_NAME.to_string()));
2726 let mut values: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
2727 for (name, _) in self.type_system.env.values.iter() {
2728 if !name.as_ref().starts_with("@m") {
2729 values.insert(
2730 name.clone(),
2731 CanonicalSymbol::from_symbol(
2732 module_key,
2733 SymbolKind::Value,
2734 name.clone(),
2735 name.clone(),
2736 ),
2737 );
2738 }
2739 }
2740
2741 let mut types: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
2742 for name in self.type_system.adts.keys() {
2743 if !name.as_ref().starts_with("@m") {
2744 types.insert(
2745 name.clone(),
2746 CanonicalSymbol::from_symbol(
2747 module_key,
2748 SymbolKind::Type,
2749 name.clone(),
2750 name.clone(),
2751 ),
2752 );
2753 }
2754 }
2755
2756 let mut classes: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
2757 for name in self.type_system.class_info.keys() {
2758 if !name.as_ref().starts_with("@m") {
2759 classes.insert(
2760 name.clone(),
2761 CanonicalSymbol::from_symbol(
2762 module_key,
2763 SymbolKind::Class,
2764 name.clone(),
2765 name.clone(),
2766 ),
2767 );
2768 }
2769 }
2770
2771 self.virtual_modules.insert(
2772 PRELUDE_MODULE_NAME.to_string(),
2773 ModuleExports {
2774 values,
2775 types,
2776 classes,
2777 },
2778 );
2779 Ok(())
2780 }
2781
2782 pub(crate) fn virtual_module_exports(&self, module_name: &str) -> Option<ModuleExports> {
2783 self.virtual_modules.get(module_name).cloned()
2784 }
2785
2786 fn register_prelude_typeclass_instances(&mut self) -> Result<(), EngineError> {
2787 let program =
2791 rexlang_typesystem::prelude_typeclasses_program().map_err(EngineError::Type)?;
2792 for decl in program.decls.iter() {
2793 let Decl::Instance(inst_decl) = decl else {
2794 continue;
2795 };
2796 if inst_decl.methods.is_empty() {
2797 continue;
2798 }
2799 let prepared = self
2800 .type_system
2801 .prepare_instance_decl(inst_decl)
2802 .map_err(EngineError::Type)?;
2803 self.register_typeclass_instance(inst_decl, &prepared)?;
2804 }
2805 Ok(())
2806 }
2807
2808 fn register_native(
2809 &mut self,
2810 name: Symbol,
2811 scheme: Scheme,
2812 arity: usize,
2813 func: NativeCallable<State>,
2814 gas_cost: u64,
2815 ) -> Result<(), EngineError> {
2816 let expected = type_arity(&scheme.typ);
2817 if expected != arity {
2818 return Err(EngineError::NativeArity {
2819 name: name.clone(),
2820 expected,
2821 got: arity,
2822 });
2823 }
2824 self.register_type_scheme(&name, &scheme)?;
2825 self.natives.insert(name, arity, scheme, func, gas_cost)
2826 }
2827
2828 fn register_type_scheme(
2829 &mut self,
2830 name: &Symbol,
2831 injected: &Scheme,
2832 ) -> Result<(), EngineError> {
2833 let schemes = self.type_system.env.lookup(name);
2834 match schemes {
2835 None => {
2836 self.type_system.add_value(name.as_ref(), injected.clone());
2837 Ok(())
2838 }
2839 Some(schemes) => {
2840 let has_poly = schemes
2841 .iter()
2842 .any(|s| !s.vars.is_empty() || !s.preds.is_empty());
2843 if has_poly {
2844 for existing in schemes {
2845 if scheme_accepts(&self.type_system, existing, &injected.typ)? {
2846 return Ok(());
2847 }
2848 }
2849 Err(EngineError::InvalidInjection {
2850 name: name.clone(),
2851 typ: injected.typ.to_string(),
2852 })
2853 } else {
2854 if schemes.iter().any(|s| s == injected) {
2855 return Ok(());
2856 }
2857 self.type_system
2858 .add_overload(name.as_ref(), injected.clone());
2859 Ok(())
2860 }
2861 }
2862 }
2863 }
2864
2865 fn type_check(&mut self, expr: &Expr) -> Result<TypedExpr, EngineError> {
2866 if let Some(span) = first_hole_span(expr) {
2867 return Err(EngineError::Type(TypeError::Spanned {
2868 span,
2869 error: Box::new(TypeError::UnsupportedExpr(
2870 "typed hole `?` must be filled before evaluation",
2871 )),
2872 }));
2873 }
2874 let (typed, preds, _ty) = self.type_system.infer_typed(expr)?;
2875 let (typed, preds) = default_ambiguous_types(self, typed, preds)?;
2876 self.check_predicates(&preds)?;
2877 self.check_natives(&typed)?;
2878 Ok(typed)
2879 }
2880
2881 pub(crate) fn infer_type(
2882 &mut self,
2883 expr: &Expr,
2884 gas: &mut GasMeter,
2885 ) -> Result<(Vec<Predicate>, Type), EngineError> {
2886 self.type_system
2887 .infer_with_gas(expr, gas)
2888 .map_err(EngineError::Type)
2889 }
2890
2891 fn check_predicates(&self, preds: &[Predicate]) -> Result<(), EngineError> {
2892 for pred in preds {
2893 if pred.typ.ftv().is_empty() {
2894 let ok = entails(&self.type_system.classes, &[], pred)?;
2895 if !ok {
2896 return Err(EngineError::Type(TypeError::NoInstance(
2897 pred.class.clone(),
2898 pred.typ.to_string(),
2899 )));
2900 }
2901 }
2902 }
2903 Ok(())
2904 }
2905
2906 fn check_natives(&self, expr: &TypedExpr) -> Result<(), EngineError> {
2907 enum Frame<'a> {
2908 Expr(&'a TypedExpr),
2909 Push(Symbol),
2910 PushMany(Vec<Symbol>),
2911 Pop(usize),
2912 }
2913
2914 let mut bound: Vec<Symbol> = Vec::new();
2915 let mut stack = vec![Frame::Expr(expr)];
2916 while let Some(frame) = stack.pop() {
2917 match frame {
2918 Frame::Expr(expr) => match &expr.kind {
2919 TypedExprKind::Var { name, overloads } => {
2920 if bound.iter().any(|n| n == name) {
2921 continue;
2922 }
2923 if !self.natives.has_name(name) {
2924 if self.env.get(name).is_some() {
2925 continue;
2926 }
2927 if self.type_system.class_methods.contains_key(name) {
2928 continue;
2929 }
2930 return Err(EngineError::UnknownVar(name.clone()));
2931 }
2932 if !overloads.is_empty()
2933 && expr.typ.ftv().is_empty()
2934 && !overloads.iter().any(|t| unify(t, &expr.typ).is_ok())
2935 {
2936 return Err(EngineError::MissingImpl {
2937 name: name.clone(),
2938 typ: expr.typ.to_string(),
2939 });
2940 }
2941 if expr.typ.ftv().is_empty() && !self.has_impl(name, &expr.typ) {
2942 return Err(EngineError::MissingImpl {
2943 name: name.clone(),
2944 typ: expr.typ.to_string(),
2945 });
2946 }
2947 }
2948 TypedExprKind::Tuple(elems) | TypedExprKind::List(elems) => {
2949 for elem in elems.iter().rev() {
2950 stack.push(Frame::Expr(elem));
2951 }
2952 }
2953 TypedExprKind::Dict(kvs) => {
2954 for v in kvs.values().rev() {
2955 stack.push(Frame::Expr(v));
2956 }
2957 }
2958 TypedExprKind::RecordUpdate { base, updates } => {
2959 for v in updates.values().rev() {
2960 stack.push(Frame::Expr(v));
2961 }
2962 stack.push(Frame::Expr(base));
2963 }
2964 TypedExprKind::App(f, x) => {
2965 stack.push(Frame::Expr(x));
2967 stack.push(Frame::Expr(f));
2968 }
2969 TypedExprKind::Project { expr, .. } => {
2970 stack.push(Frame::Expr(expr));
2971 }
2972 TypedExprKind::Lam { param, body } => {
2973 stack.push(Frame::Pop(1));
2974 stack.push(Frame::Expr(body));
2975 stack.push(Frame::Push(param.clone()));
2976 }
2977 TypedExprKind::Let { name, def, body } => {
2978 stack.push(Frame::Pop(1));
2979 stack.push(Frame::Expr(body));
2980 stack.push(Frame::Push(name.clone()));
2981 stack.push(Frame::Expr(def));
2982 }
2983 TypedExprKind::LetRec { bindings, body } => {
2984 if !bindings.is_empty() {
2985 stack.push(Frame::Pop(bindings.len()));
2986 stack.push(Frame::Expr(body));
2987 for (_, def) in bindings.iter().rev() {
2988 stack.push(Frame::Expr(def));
2989 }
2990 stack.push(Frame::PushMany(
2991 bindings.iter().map(|(name, _)| name.clone()).collect(),
2992 ));
2993 } else {
2994 stack.push(Frame::Expr(body));
2995 }
2996 }
2997 TypedExprKind::Ite {
2998 cond,
2999 then_expr,
3000 else_expr,
3001 } => {
3002 stack.push(Frame::Expr(else_expr));
3003 stack.push(Frame::Expr(then_expr));
3004 stack.push(Frame::Expr(cond));
3005 }
3006 TypedExprKind::Match { scrutinee, arms } => {
3007 for (pat, arm_expr) in arms.iter().rev() {
3008 let mut bindings = Vec::new();
3009 collect_pattern_bindings(pat, &mut bindings);
3010 let count = bindings.len();
3011 if count != 0 {
3012 stack.push(Frame::Pop(count));
3013 stack.push(Frame::Expr(arm_expr));
3014 stack.push(Frame::PushMany(bindings));
3015 } else {
3016 stack.push(Frame::Expr(arm_expr));
3017 }
3018 }
3019 stack.push(Frame::Expr(scrutinee));
3020 }
3021 TypedExprKind::Bool(..)
3022 | TypedExprKind::Uint(..)
3023 | TypedExprKind::Int(..)
3024 | TypedExprKind::Float(..)
3025 | TypedExprKind::String(..)
3026 | TypedExprKind::Uuid(..)
3027 | TypedExprKind::DateTime(..) => {}
3028 TypedExprKind::Hole => return Err(EngineError::UnsupportedExpr),
3029 },
3030 Frame::Push(sym) => bound.push(sym),
3031 Frame::PushMany(syms) => bound.extend(syms),
3032 Frame::Pop(count) => {
3033 bound.truncate(bound.len().saturating_sub(count));
3034 }
3035 }
3036 }
3037 Ok(())
3038 }
3039
3040 fn register_typeclass_instance(
3041 &mut self,
3042 decl: &InstanceDecl,
3043 prepared: &PreparedInstanceDecl,
3044 ) -> Result<(), EngineError> {
3045 let mut methods: HashMap<Symbol, Arc<TypedExpr>> = HashMap::new();
3046 for method in &decl.methods {
3047 let typed = self
3048 .type_system
3049 .typecheck_instance_method(prepared, method)
3050 .map_err(EngineError::Type)?;
3051 self.check_natives(&typed)?;
3052 methods.insert(method.name.clone(), Arc::new(typed));
3053 }
3054
3055 self.typeclasses.insert(
3056 prepared.class.clone(),
3057 prepared.head.clone(),
3058 self.env.clone(),
3059 methods,
3060 )?;
3061 Ok(())
3062 }
3063
3064 fn resolve_typeclass_method_impl(
3065 &self,
3066 name: &Symbol,
3067 call_type: &Type,
3068 ) -> Result<(Env, Arc<TypedExpr>, Subst), EngineError> {
3069 let info = self
3070 .type_system
3071 .class_methods
3072 .get(name)
3073 .ok_or_else(|| EngineError::UnknownVar(name.clone()))?;
3074
3075 let s_method = unify(&info.scheme.typ, call_type).map_err(EngineError::Type)?;
3076 let class_pred = info
3077 .scheme
3078 .preds
3079 .iter()
3080 .find(|p| p.class == info.class)
3081 .ok_or(EngineError::Type(TypeError::UnsupportedExpr(
3082 "method scheme missing class predicate",
3083 )))?;
3084 let param_type = class_pred.typ.apply(&s_method);
3085 if type_head_is_var(¶m_type) {
3086 return Err(EngineError::AmbiguousOverload { name: name.clone() });
3087 }
3088
3089 self.typeclasses.resolve(&info.class, name, ¶m_type)
3090 }
3091
3092 fn cached_class_method(&self, name: &Symbol, typ: &Type) -> Option<Pointer> {
3093 if !typ.ftv().is_empty() {
3094 return None;
3095 }
3096 let cache = self.typeclass_cache.lock().ok()?;
3097 cache.get(&(name.clone(), typ.clone())).cloned()
3098 }
3099
3100 fn insert_cached_class_method(&self, name: &Symbol, typ: &Type, pointer: &Pointer) {
3101 if typ.ftv().is_empty()
3102 && let Ok(mut cache) = self.typeclass_cache.lock()
3103 {
3104 cache.insert((name.clone(), typ.clone()), *pointer);
3105 }
3106 }
3107
3108 fn resolve_class_method_plan(
3109 &self,
3110 name: &Symbol,
3111 typ: &Type,
3112 ) -> Result<Result<(Env, TypedExpr), Pointer>, EngineError> {
3113 let (def_env, typed, s) = match self.resolve_typeclass_method_impl(name, typ) {
3114 Ok(res) => res,
3115 Err(EngineError::AmbiguousOverload { .. }) if is_function_type(typ) => {
3116 let (name, typ, applied, applied_types) =
3117 OverloadedFn::new(name.clone(), typ.clone()).into_parts();
3118 let pointer = self
3119 .heap
3120 .alloc_overloaded(name, typ, applied, applied_types)?;
3121 return Ok(Err(pointer));
3122 }
3123 Err(err) => return Err(err),
3124 };
3125 let specialized = typed.as_ref().apply(&s);
3126 Ok(Ok((def_env, specialized)))
3127 }
3128
3129 async fn resolve_class_method(
3130 &self,
3131 name: &Symbol,
3132 typ: &Type,
3133 gas: &mut GasMeter,
3134 ) -> Result<Pointer, EngineError> {
3135 if let Some(pointer) = self.cached_class_method(name, typ) {
3136 return Ok(pointer);
3137 }
3138
3139 let pointer = match self.resolve_class_method_plan(name, typ)? {
3140 Ok((def_env, specialized)) => {
3141 eval_typed_expr(self, &def_env, &specialized, gas).await?
3142 }
3143 Err(pointer) => pointer,
3144 };
3145
3146 if typ.ftv().is_empty() {
3147 self.insert_cached_class_method(name, typ, &pointer);
3148 }
3149 Ok(pointer)
3150 }
3151
3152 pub(crate) async fn resolve_global(
3153 &self,
3154 name: &Symbol,
3155 typ: &Type,
3156 ) -> Result<Pointer, EngineError> {
3157 if let Some(ptr) = self.env.get(name) {
3158 let value = self.heap.get(&ptr)?;
3159 match value.as_ref() {
3160 Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
3161 let mut gas = GasMeter::default();
3162 native.call_zero(self, &mut gas).await
3163 }
3164 _ => Ok(ptr),
3165 }
3166 } else if self.type_system.class_methods.contains_key(name) {
3167 let mut gas = GasMeter::default();
3168 self.resolve_class_method(name, typ, &mut gas).await
3169 } else {
3170 let mut gas = GasMeter::default();
3171 let pointer = self.resolve_native(name.as_ref(), typ, &mut gas)?;
3172 let value = self.heap.get(&pointer)?;
3173 match value.as_ref() {
3174 Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
3175 let mut gas = GasMeter::default();
3176 native.call_zero(self, &mut gas).await
3177 }
3178 _ => Ok(pointer),
3179 }
3180 }
3181 }
3182
3183 pub(crate) fn lookup_scheme(&self, name: &Symbol) -> Result<Scheme, EngineError> {
3184 let schemes = self
3185 .type_system
3186 .env
3187 .lookup(name)
3188 .ok_or_else(|| EngineError::UnknownVar(name.clone()))?;
3189 if schemes.len() != 1 {
3190 return Err(EngineError::AmbiguousOverload { name: name.clone() });
3191 }
3192 Ok(schemes[0].clone())
3193 }
3194
3195 fn has_impl(&self, name: &str, typ: &Type) -> bool {
3196 let sym_name = sym(name);
3197 self.natives
3198 .get(&sym_name)
3199 .map(|impls| impls.iter().any(|imp| impl_matches_type(imp, typ)))
3200 .unwrap_or(false)
3201 }
3202
3203 fn resolve_native_impl(
3204 &self,
3205 name: &str,
3206 typ: &Type,
3207 ) -> Result<NativeImpl<State>, EngineError> {
3208 let sym_name = sym(name);
3209 let impls = self
3210 .natives
3211 .get(&sym_name)
3212 .ok_or_else(|| EngineError::UnknownVar(sym_name.clone()))?;
3213 let matches: Vec<NativeImpl<State>> = impls
3214 .iter()
3215 .filter(|imp| impl_matches_type(imp, typ))
3216 .cloned()
3217 .collect();
3218 match matches.len() {
3219 0 => Err(EngineError::MissingImpl {
3220 name: sym_name.clone(),
3221 typ: typ.to_string(),
3222 }),
3223 1 => Ok(matches[0].clone()),
3224 _ => Err(EngineError::AmbiguousImpl {
3225 name: sym_name,
3226 typ: typ.to_string(),
3227 }),
3228 }
3229 }
3230
3231 fn native_callable(&self, id: NativeId) -> Result<NativeCallable<State>, EngineError> {
3232 self.natives
3233 .by_id(id)
3234 .map(|imp| imp.func.clone())
3235 .ok_or_else(|| EngineError::Internal(format!("unknown native id: {id}")))
3236 }
3237
3238 pub(crate) async fn call_native_impl(
3239 &self,
3240 name: &str,
3241 typ: &Type,
3242 args: &[Pointer],
3243 ) -> Result<Pointer, EngineError> {
3244 let imp = self.resolve_native_impl(name, typ)?;
3245 imp.func.call(self, typ.clone(), args).await
3246 }
3247
3248 fn resolve_native(
3249 &self,
3250 name: &str,
3251 typ: &Type,
3252 _gas: &mut GasMeter,
3253 ) -> Result<Pointer, EngineError> {
3254 let sym_name = sym(name);
3255 let impls = self
3256 .natives
3257 .get(&sym_name)
3258 .ok_or_else(|| EngineError::UnknownVar(sym_name.clone()))?;
3259 let matches: Vec<NativeImpl<State>> = impls
3260 .iter()
3261 .filter(|imp| impl_matches_type(imp, typ))
3262 .cloned()
3263 .collect();
3264 match matches.len() {
3265 0 => Err(EngineError::MissingImpl {
3266 name: sym_name.clone(),
3267 typ: typ.to_string(),
3268 }),
3269 1 => {
3270 let imp = matches[0].clone();
3271 let NativeFn {
3272 native_id,
3273 name,
3274 arity,
3275 typ,
3276 gas_cost,
3277 applied,
3278 applied_types,
3279 } = imp.to_native_fn(typ.clone());
3280 self.heap.alloc_native(
3281 native_id,
3282 name,
3283 arity,
3284 typ,
3285 gas_cost,
3286 applied,
3287 applied_types,
3288 )
3289 }
3290 _ => {
3291 if typ.ftv().is_empty() {
3292 Err(EngineError::AmbiguousImpl {
3293 name: sym_name.clone(),
3294 typ: typ.to_string(),
3295 })
3296 } else if is_function_type(typ) {
3297 let (name, typ, applied, applied_types) =
3298 OverloadedFn::new(sym_name.clone(), typ.clone()).into_parts();
3299 self.heap
3300 .alloc_overloaded(name, typ, applied, applied_types)
3301 } else {
3302 Err(EngineError::AmbiguousOverload { name: sym_name })
3303 }
3304 }
3305 }
3306 }
3307}
3308
3309fn first_hole_span(expr: &Expr) -> Option<Span> {
3310 match expr {
3311 Expr::Hole(span) => Some(*span),
3312 Expr::App(_, f, x) => first_hole_span(f).or_else(|| first_hole_span(x)),
3313 Expr::Project(_, base, _) => first_hole_span(base),
3314 Expr::Lam(_, _scope, _param, _ann, _constraints, body) => first_hole_span(body),
3315 Expr::Let(_, _var, _ann, def, body) => {
3316 first_hole_span(def).or_else(|| first_hole_span(body))
3317 }
3318 Expr::LetRec(_, bindings, body) => {
3319 for (_var, _ann, def) in bindings {
3320 if let Some(span) = first_hole_span(def) {
3321 return Some(span);
3322 }
3323 }
3324 first_hole_span(body)
3325 }
3326 Expr::Ite(_, cond, then_expr, else_expr) => first_hole_span(cond)
3327 .or_else(|| first_hole_span(then_expr))
3328 .or_else(|| first_hole_span(else_expr)),
3329 Expr::Match(_, scrutinee, arms) => {
3330 if let Some(span) = first_hole_span(scrutinee) {
3331 return Some(span);
3332 }
3333 for (_pat, arm) in arms {
3334 if let Some(span) = first_hole_span(arm) {
3335 return Some(span);
3336 }
3337 }
3338 None
3339 }
3340 Expr::Ann(_, inner, _) => first_hole_span(inner),
3341 Expr::Tuple(_, elems) | Expr::List(_, elems) => {
3342 for elem in elems {
3343 if let Some(span) = first_hole_span(elem) {
3344 return Some(span);
3345 }
3346 }
3347 None
3348 }
3349 Expr::Dict(_, kvs) => {
3350 for value in kvs.values() {
3351 if let Some(span) = first_hole_span(value) {
3352 return Some(span);
3353 }
3354 }
3355 None
3356 }
3357 Expr::RecordUpdate(_, base, kvs) => {
3358 if let Some(span) = first_hole_span(base) {
3359 return Some(span);
3360 }
3361 for value in kvs.values() {
3362 if let Some(span) = first_hole_span(value) {
3363 return Some(span);
3364 }
3365 }
3366 None
3367 }
3368 Expr::Bool(..)
3369 | Expr::Uint(..)
3370 | Expr::Int(..)
3371 | Expr::Float(..)
3372 | Expr::String(..)
3373 | Expr::Uuid(..)
3374 | Expr::DateTime(..)
3375 | Expr::Var(..) => None,
3376 }
3377}
3378
3379fn normalize_name(name: &str) -> Symbol {
3380 if let Some(stripped) = name.strip_prefix('(').and_then(|s| s.strip_suffix(')')) {
3381 let ok = stripped
3382 .chars()
3383 .all(|c| !c.is_alphanumeric() && c != '_' && !c.is_whitespace());
3384 if ok {
3385 return sym(stripped);
3386 }
3387 }
3388 sym(name)
3389}
3390
3391fn default_ambiguous_types<State: Clone + Send + Sync + 'static>(
3392 engine: &Engine<State>,
3393 typed: TypedExpr,
3394 mut preds: Vec<Predicate>,
3395) -> Result<(TypedExpr, Vec<Predicate>), EngineError> {
3396 let mut candidates = Vec::new();
3397 collect_default_candidates(&typed, &mut candidates);
3398 for ty in [
3399 Type::builtin(BuiltinTypeId::F32),
3400 Type::builtin(BuiltinTypeId::I32),
3401 Type::builtin(BuiltinTypeId::String),
3402 ] {
3403 push_unique_type(&mut candidates, ty);
3404 }
3405
3406 let mut subst = Subst::new_sync();
3407 loop {
3408 let vars: Vec<_> = preds.ftv().into_iter().collect();
3409 let mut progress = false;
3410 for tv in vars {
3411 if subst.get(&tv).is_some() {
3412 continue;
3413 }
3414 let mut relevant = Vec::new();
3415 let mut simple = true;
3416 for pred in &preds {
3417 if pred.typ.ftv().contains(&tv) {
3418 if !defaultable_class(&pred.class) {
3419 simple = false;
3420 break;
3421 }
3422 match pred.typ.as_ref() {
3423 TypeKind::Var(v) if v.id == tv => relevant.push(pred.clone()),
3424 _ => {
3425 simple = false;
3426 break;
3427 }
3428 }
3429 }
3430 }
3431 if !simple || relevant.is_empty() {
3432 continue;
3433 }
3434 if let Some(choice) = choose_default_type(engine, &relevant, &candidates)? {
3435 let mut next = Subst::new_sync();
3436 next = next.insert(tv, choice.clone());
3437 preds = preds.apply(&next);
3438 subst = compose_subst(next, subst);
3439 progress = true;
3440 }
3441 }
3442 if !progress {
3443 break;
3444 }
3445 }
3446 Ok((typed.apply(&subst), preds))
3447}
3448
3449fn defaultable_class(class: &Symbol) -> bool {
3450 matches!(
3451 class.as_ref(),
3452 "AdditiveMonoid" | "MultiplicativeMonoid" | "AdditiveGroup" | "Ring" | "Field" | "Integral"
3453 )
3454}
3455
3456fn collect_default_candidates(expr: &TypedExpr, out: &mut Vec<Type>) {
3457 let mut stack: Vec<&TypedExpr> = vec![expr];
3458 while let Some(expr) = stack.pop() {
3459 if expr.typ.ftv().is_empty()
3460 && let TypeKind::Con(tc) = expr.typ.as_ref()
3461 && tc.arity == 0
3462 {
3463 push_unique_type(out, expr.typ.clone());
3464 }
3465
3466 match &expr.kind {
3467 TypedExprKind::Tuple(elems) | TypedExprKind::List(elems) => {
3468 for elem in elems.iter().rev() {
3469 stack.push(elem);
3470 }
3471 }
3472 TypedExprKind::Dict(kvs) => {
3473 for value in kvs.values().rev() {
3474 stack.push(value);
3475 }
3476 }
3477 TypedExprKind::RecordUpdate { base, updates } => {
3478 for value in updates.values().rev() {
3479 stack.push(value);
3480 }
3481 stack.push(base);
3482 }
3483 TypedExprKind::App(f, x) => {
3484 stack.push(x);
3485 stack.push(f);
3486 }
3487 TypedExprKind::Project { expr, .. } => stack.push(expr),
3488 TypedExprKind::Lam { body, .. } => stack.push(body),
3489 TypedExprKind::Let { def, body, .. } => {
3490 stack.push(body);
3491 stack.push(def);
3492 }
3493 TypedExprKind::LetRec { bindings, body } => {
3494 stack.push(body);
3495 for (_, def) in bindings.iter().rev() {
3496 stack.push(def);
3497 }
3498 }
3499 TypedExprKind::Ite {
3500 cond,
3501 then_expr,
3502 else_expr,
3503 } => {
3504 stack.push(else_expr);
3505 stack.push(then_expr);
3506 stack.push(cond);
3507 }
3508 TypedExprKind::Match { scrutinee, arms } => {
3509 for (_, expr) in arms.iter().rev() {
3510 stack.push(expr);
3511 }
3512 stack.push(scrutinee);
3513 }
3514 TypedExprKind::Var { .. }
3515 | TypedExprKind::Bool(..)
3516 | TypedExprKind::Uint(..)
3517 | TypedExprKind::Int(..)
3518 | TypedExprKind::Float(..)
3519 | TypedExprKind::String(..)
3520 | TypedExprKind::Uuid(..)
3521 | TypedExprKind::DateTime(..)
3522 | TypedExprKind::Hole => {}
3523 }
3524 }
3525}
3526
3527fn push_unique_type(out: &mut Vec<Type>, typ: Type) {
3528 if !out.iter().any(|t| t == &typ) {
3529 out.push(typ);
3530 }
3531}
3532
3533fn choose_default_type<State: Clone + Send + Sync + 'static>(
3534 engine: &Engine<State>,
3535 preds: &[Predicate],
3536 candidates: &[Type],
3537) -> Result<Option<Type>, EngineError> {
3538 for candidate in candidates {
3539 let mut ok = true;
3540 for pred in preds {
3541 let test = Predicate::new(pred.class.clone(), candidate.clone());
3542 if !entails(&engine.type_system.classes, &[], &test)? {
3543 ok = false;
3544 break;
3545 }
3546 }
3547 if ok {
3548 return Ok(Some(candidate.clone()));
3549 }
3550 }
3551 Ok(None)
3552}
3553
3554fn scheme_accepts(ts: &TypeSystem, scheme: &Scheme, typ: &Type) -> Result<bool, EngineError> {
3555 let mut supply = TypeVarSupply::new();
3556 let (preds, scheme_ty) = instantiate(scheme, &mut supply);
3557 let subst = match unify(&scheme_ty, typ) {
3558 Ok(s) => s,
3559 Err(_) => return Ok(false),
3560 };
3561 let preds = preds.apply(&subst);
3562 for pred in preds {
3563 if pred.typ.ftv().is_empty() {
3564 let ok = entails(&ts.classes, &[], &pred)?;
3565 if !ok {
3566 return Ok(false);
3567 }
3568 }
3569 }
3570 Ok(true)
3571}
3572
3573fn is_function_type(typ: &Type) -> bool {
3574 matches!(typ.as_ref(), TypeKind::Fun(..))
3575}
3576
3577fn collect_pattern_bindings(pat: &Pattern, out: &mut Vec<Symbol>) {
3578 match pat {
3579 Pattern::Wildcard(..) => {}
3580 Pattern::Var(var) => out.push(var.name.clone()),
3581 Pattern::Named(_, _, ps) => {
3582 for p in ps {
3583 collect_pattern_bindings(p, out);
3584 }
3585 }
3586 Pattern::Tuple(_, ps) => {
3587 for p in ps {
3588 collect_pattern_bindings(p, out);
3589 }
3590 }
3591 Pattern::List(_, ps) => {
3592 for p in ps {
3593 collect_pattern_bindings(p, out);
3594 }
3595 }
3596 Pattern::Cons(_, head, tail) => {
3597 collect_pattern_bindings(head, out);
3598 collect_pattern_bindings(tail, out);
3599 }
3600 Pattern::Dict(_, fields) => {
3601 for (_key, pat) in fields {
3602 collect_pattern_bindings(pat, out);
3603 }
3604 }
3605 }
3606}
3607
3608fn type_head_and_args(typ: &Type) -> Result<(Symbol, usize, Vec<Type>), EngineError> {
3609 let mut args = Vec::new();
3610 let mut head = typ;
3611 while let TypeKind::App(f, arg) = head.as_ref() {
3612 args.push(arg.clone());
3613 head = f;
3614 }
3615 args.reverse();
3616
3617 let TypeKind::Con(con) = head.as_ref() else {
3618 return Err(EngineError::Custom(format!(
3619 "cannot build ADT declaration from non-constructor type `{typ}`"
3620 )));
3621 };
3622 if !args.is_empty() && args.len() != con.arity {
3623 return Err(EngineError::Custom(format!(
3624 "constructor `{}` expected {} type arguments but got {} in `{typ}`",
3625 con.name,
3626 con.arity,
3627 args.len()
3628 )));
3629 }
3630 Ok((con.name.clone(), con.arity, args))
3631}
3632
3633fn type_arity(typ: &Type) -> usize {
3634 let mut count = 0;
3635 let mut cur = typ;
3636 while let TypeKind::Fun(_, next) = cur.as_ref() {
3637 count += 1;
3638 cur = next;
3639 }
3640 count
3641}
3642
3643fn split_fun(typ: &Type) -> Option<(Type, Type)> {
3644 match typ.as_ref() {
3645 TypeKind::Fun(a, b) => Some((a.clone(), b.clone())),
3646 _ => None,
3647 }
3648}
3649
3650fn impl_matches_type<State: Clone + Send + Sync + 'static>(
3651 imp: &NativeImpl<State>,
3652 typ: &Type,
3653) -> bool {
3654 let mut supply = TypeVarSupply::new();
3655 let (_preds, scheme_ty) = instantiate(&imp.scheme, &mut supply);
3656 unify(&scheme_ty, typ).is_ok()
3657}
3658
3659fn value_type(heap: &Heap, value: &Value) -> Result<Type, EngineError> {
3660 let pointer_type = |pointer: &Pointer| -> Result<Type, EngineError> {
3661 let value = heap.get(pointer)?;
3662 value_type(heap, value.as_ref())
3663 };
3664
3665 match value {
3666 Value::Bool(..) => Ok(Type::builtin(BuiltinTypeId::Bool)),
3667 Value::U8(..) => Ok(Type::builtin(BuiltinTypeId::U8)),
3668 Value::U16(..) => Ok(Type::builtin(BuiltinTypeId::U16)),
3669 Value::U32(..) => Ok(Type::builtin(BuiltinTypeId::U32)),
3670 Value::U64(..) => Ok(Type::builtin(BuiltinTypeId::U64)),
3671 Value::I8(..) => Ok(Type::builtin(BuiltinTypeId::I8)),
3672 Value::I16(..) => Ok(Type::builtin(BuiltinTypeId::I16)),
3673 Value::I32(..) => Ok(Type::builtin(BuiltinTypeId::I32)),
3674 Value::I64(..) => Ok(Type::builtin(BuiltinTypeId::I64)),
3675 Value::F32(..) => Ok(Type::builtin(BuiltinTypeId::F32)),
3676 Value::F64(..) => Ok(Type::builtin(BuiltinTypeId::F64)),
3677 Value::String(..) => Ok(Type::builtin(BuiltinTypeId::String)),
3678 Value::Uuid(..) => Ok(Type::builtin(BuiltinTypeId::Uuid)),
3679 Value::DateTime(..) => Ok(Type::builtin(BuiltinTypeId::DateTime)),
3680 Value::Tuple(elems) => {
3681 let mut tys = Vec::with_capacity(elems.len());
3682 for elem in elems {
3683 tys.push(pointer_type(elem)?);
3684 }
3685 Ok(Type::tuple(tys))
3686 }
3687 Value::Array(elems) => {
3688 let first = elems
3689 .first()
3690 .ok_or_else(|| EngineError::UnknownType(sym("array")))?;
3691 let elem_ty = pointer_type(first)?;
3692 for elem in elems.iter().skip(1) {
3693 let ty = pointer_type(elem)?;
3694 if ty != elem_ty {
3695 return Err(EngineError::NativeType {
3696 expected: elem_ty.to_string(),
3697 got: ty.to_string(),
3698 });
3699 }
3700 }
3701 Ok(Type::app(Type::builtin(BuiltinTypeId::Array), elem_ty))
3702 }
3703 Value::Dict(map) => {
3704 let first = map
3705 .values()
3706 .next()
3707 .ok_or_else(|| EngineError::UnknownType(sym("dict")))?;
3708 let elem_ty = pointer_type(first)?;
3709 for val in map.values().skip(1) {
3710 let ty = pointer_type(val)?;
3711 if ty != elem_ty {
3712 return Err(EngineError::NativeType {
3713 expected: elem_ty.to_string(),
3714 got: ty.to_string(),
3715 });
3716 }
3717 }
3718 Ok(Type::app(Type::builtin(BuiltinTypeId::Dict), elem_ty))
3719 }
3720 Value::Adt(tag, args) if sym_eq(tag, "Some") && args.len() == 1 => {
3721 let inner = pointer_type(&args[0])?;
3722 Ok(Type::app(Type::builtin(BuiltinTypeId::Option), inner))
3723 }
3724 Value::Adt(tag, args) if sym_eq(tag, "None") && args.is_empty() => {
3725 Err(EngineError::UnknownType(sym("option")))
3726 }
3727 Value::Adt(tag, args) if (sym_eq(tag, "Ok") || sym_eq(tag, "Err")) && args.len() == 1 => {
3728 Err(EngineError::UnknownType(sym("result")))
3729 }
3730 Value::Adt(tag, args)
3731 if (sym_eq(tag, "Empty") || sym_eq(tag, "Cons")) && args.len() <= 2 =>
3732 {
3733 let elems = list_to_vec(heap, value)?;
3734 let first = elems
3735 .first()
3736 .ok_or_else(|| EngineError::UnknownType(sym("list")))?;
3737 let elem_ty = pointer_type(first)?;
3738 for elem in elems.iter().skip(1) {
3739 let ty = pointer_type(elem)?;
3740 if ty != elem_ty {
3741 return Err(EngineError::NativeType {
3742 expected: elem_ty.to_string(),
3743 got: ty.to_string(),
3744 });
3745 }
3746 }
3747 Ok(Type::app(Type::builtin(BuiltinTypeId::List), elem_ty))
3748 }
3749 Value::Adt(tag, _args) => Err(EngineError::UnknownType(tag.clone())),
3750 Value::Uninitialized(..) => Err(EngineError::UnknownType(sym("uninitialized"))),
3751 Value::Closure(..) => Err(EngineError::UnknownType(sym("closure"))),
3752 Value::Native(..) => Err(EngineError::UnknownType(sym("native"))),
3753 Value::Overloaded(..) => Err(EngineError::UnknownType(sym("overloaded"))),
3754 }
3755}
3756
3757fn resolve_arg_type(
3758 heap: &Heap,
3759 arg_type: Option<&Type>,
3760 arg: &Pointer,
3761) -> Result<Type, EngineError> {
3762 let infer_from_value = |ty_hint: Option<&Type>| -> Result<Type, EngineError> {
3763 let value = heap.get(arg)?;
3764 match ty_hint {
3765 Some(ty) => match value_type(heap, value.as_ref()) {
3766 Ok(val_ty) if val_ty.ftv().is_empty() => Ok(val_ty),
3767 _ => Ok(ty.clone()),
3768 },
3769 None => value_type(heap, value.as_ref()),
3770 }
3771 };
3772 match arg_type {
3773 Some(ty) if ty.ftv().is_empty() => Ok(ty.clone()),
3774 Some(ty) => infer_from_value(Some(ty)),
3775 None => infer_from_value(None),
3776 }
3777}
3778
3779pub(crate) fn binary_arg_types(typ: &Type) -> Result<(Type, Type), EngineError> {
3780 let (lhs, rest) = split_fun(typ).ok_or_else(|| EngineError::NativeType {
3781 expected: "binary function".into(),
3782 got: typ.to_string(),
3783 })?;
3784 let (rhs, _res) = split_fun(&rest).ok_or_else(|| EngineError::NativeType {
3785 expected: "binary function".into(),
3786 got: typ.to_string(),
3787 })?;
3788 Ok((lhs, rhs))
3789}
3790
3791fn project_pointer(heap: &Heap, field: &Symbol, pointer: &Pointer) -> Result<Pointer, EngineError> {
3792 let value = heap.get(pointer)?;
3793 if let Ok(index) = field.as_ref().parse::<usize>() {
3794 return match value.as_ref() {
3795 Value::Tuple(items) => {
3796 items
3797 .get(index)
3798 .cloned()
3799 .ok_or_else(|| EngineError::UnknownField {
3800 field: field.clone(),
3801 value: "tuple".into(),
3802 })
3803 }
3804 _ => Err(EngineError::UnknownField {
3805 field: field.clone(),
3806 value: heap.type_name(pointer)?.into(),
3807 }),
3808 };
3809 }
3810 match value.as_ref() {
3811 Value::Adt(_, args) if args.len() == 1 => {
3812 let inner = heap.get(&args[0])?;
3813 match inner.as_ref() {
3814 Value::Dict(map) => {
3815 map.get(field)
3816 .cloned()
3817 .ok_or_else(|| EngineError::UnknownField {
3818 field: field.clone(),
3819 value: "record".into(),
3820 })
3821 }
3822 _ => Err(EngineError::UnknownField {
3823 field: field.clone(),
3824 value: heap.type_name(&args[0])?.into(),
3825 }),
3826 }
3827 }
3828 _ => Err(EngineError::UnknownField {
3829 field: field.clone(),
3830 value: heap.type_name(pointer)?.into(),
3831 }),
3832 }
3833}
3834
3835#[async_recursion]
3836async fn eval_typed_expr<State>(
3837 engine: &Engine<State>,
3838 env: &Env,
3839 expr: &TypedExpr,
3840 gas: &mut GasMeter,
3841) -> Result<Pointer, EngineError>
3842where
3843 State: Clone + Send + Sync + 'static,
3844{
3845 check_cancelled(engine)?;
3846 let mut env = env.clone();
3847 let mut cur = expr;
3848 loop {
3849 check_cancelled(engine)?;
3850 match &cur.kind {
3851 TypedExprKind::Let { name, def, body } => {
3852 gas.charge(gas.costs.eval_node)?;
3853 let ptr = eval_typed_expr(engine, &env, def, gas).await?;
3854 env = env.extend(name.clone(), ptr);
3855 cur = body;
3856 }
3857 _ => break,
3858 }
3859 }
3860
3861 gas.charge(gas.costs.eval_node)?;
3862 match &cur.kind {
3863 TypedExprKind::Bool(v) => engine.heap.alloc_bool(*v),
3864 TypedExprKind::Uint(v) => alloc_uint_literal_as(engine, *v, &cur.typ),
3865 TypedExprKind::Int(v) => alloc_int_literal_as(engine, *v, &cur.typ),
3866 TypedExprKind::Float(v) => engine.heap.alloc_f32(*v as f32),
3867 TypedExprKind::String(v) => engine.heap.alloc_string(v.clone()),
3868 TypedExprKind::Uuid(v) => engine.heap.alloc_uuid(*v),
3869 TypedExprKind::DateTime(v) => engine.heap.alloc_datetime(*v),
3870 TypedExprKind::Hole => Err(EngineError::UnsupportedExpr),
3871 TypedExprKind::Tuple(elems) => {
3872 let mut values = Vec::with_capacity(elems.len());
3873 for elem in elems {
3874 check_cancelled(engine)?;
3875 values.push(eval_typed_expr(engine, &env, elem, gas).await?);
3876 }
3877 engine.heap.alloc_tuple(values)
3878 }
3879 TypedExprKind::List(elems) => {
3880 let mut values = Vec::with_capacity(elems.len());
3881 for elem in elems {
3882 check_cancelled(engine)?;
3883 values.push(eval_typed_expr(engine, &env, elem, gas).await?);
3884 }
3885 let mut list = engine.heap.alloc_adt(sym("Empty"), vec![])?;
3886 for value in values.into_iter().rev() {
3887 list = engine.heap.alloc_adt(sym("Cons"), vec![value, list])?;
3888 }
3889 Ok(list)
3890 }
3891 TypedExprKind::Dict(kvs) => {
3892 let mut out = BTreeMap::new();
3893 for (k, v) in kvs {
3894 check_cancelled(engine)?;
3895 out.insert(k.clone(), eval_typed_expr(engine, &env, v, gas).await?);
3896 }
3897 engine.heap.alloc_dict(out)
3898 }
3899 TypedExprKind::RecordUpdate { base, updates } => {
3900 let base_ptr = eval_typed_expr(engine, &env, base, gas).await?;
3901 let mut update_vals = BTreeMap::new();
3902 for (k, v) in updates {
3903 check_cancelled(engine)?;
3904 update_vals.insert(k.clone(), eval_typed_expr(engine, &env, v, gas).await?);
3905 }
3906
3907 let base_val = engine.heap.get(&base_ptr)?;
3908 match base_val.as_ref() {
3909 Value::Dict(map) => {
3910 let mut map = map.clone();
3911 for (k, v) in update_vals {
3912 gas.charge(gas.costs.eval_record_update_field)?;
3913 map.insert(k, v);
3914 }
3915 engine.heap.alloc_dict(map)
3916 }
3917 Value::Adt(tag, args) if args.len() == 1 => {
3918 let inner = engine.heap.get(&args[0])?;
3919 match inner.as_ref() {
3920 Value::Dict(map) => {
3921 let mut out = map.clone();
3922 for (k, v) in update_vals {
3923 gas.charge(gas.costs.eval_record_update_field)?;
3924 out.insert(k, v);
3925 }
3926 let dict = engine.heap.alloc_dict(out)?;
3927 engine.heap.alloc_adt(tag.clone(), vec![dict])
3928 }
3929 _ => Err(EngineError::UnsupportedExpr),
3930 }
3931 }
3932 _ => Err(EngineError::UnsupportedExpr),
3933 }
3934 }
3935 TypedExprKind::Var { name, .. } => {
3936 if let Some(ptr) = env.get(name) {
3937 let value = engine.heap.get(&ptr)?;
3938 match value.as_ref() {
3939 Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
3940 native.call_zero(engine, gas).await
3941 }
3942 _ => Ok(ptr),
3943 }
3944 } else if engine.type_system.class_methods.contains_key(name) {
3945 engine.resolve_class_method(name, &cur.typ, gas).await
3946 } else {
3947 let value = engine.resolve_native(name.as_ref(), &cur.typ, gas)?;
3948 match engine.heap.get(&value)?.as_ref() {
3949 Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
3950 native.call_zero(engine, gas).await
3951 }
3952 _ => Ok(value),
3953 }
3954 }
3955 }
3956 TypedExprKind::App(..) => {
3957 let mut spine: Vec<(Type, &TypedExpr)> = Vec::new();
3958 let mut head = cur;
3959 while let TypedExprKind::App(f, x) = &head.kind {
3960 check_cancelled(engine)?;
3961 spine.push((f.typ.clone(), x.as_ref()));
3962 head = f.as_ref();
3963 }
3964 spine.reverse();
3965
3966 let mut func = eval_typed_expr(engine, &env, head, gas).await?;
3967 for (func_type, arg_expr) in spine {
3968 check_cancelled(engine)?;
3969 gas.charge(gas.costs.eval_app_step)?;
3970 let arg = eval_typed_expr(engine, &env, arg_expr, gas).await?;
3971 func = apply(
3972 engine,
3973 func,
3974 arg,
3975 Some(&func_type),
3976 Some(&arg_expr.typ),
3977 gas,
3978 )
3979 .await?;
3980 }
3981 Ok(func)
3982 }
3983 TypedExprKind::Project { expr, field } => {
3984 let value = eval_typed_expr(engine, &env, expr, gas).await?;
3985 project_pointer(&engine.heap, field, &value)
3986 }
3987 TypedExprKind::Lam { param, body } => {
3988 let param_ty = split_fun(&expr.typ)
3989 .map(|(arg, _)| arg)
3990 .ok_or_else(|| EngineError::NotCallable(expr.typ.to_string()))?;
3991 engine.heap.alloc_closure(
3992 env.clone(),
3993 param.clone(),
3994 param_ty,
3995 expr.typ.clone(),
3996 Arc::new(body.as_ref().clone()),
3997 )
3998 }
3999 TypedExprKind::LetRec { bindings, body } => {
4000 let mut env_rec = env.clone();
4001 let mut slots = Vec::with_capacity(bindings.len());
4002 for (name, _) in bindings {
4003 let placeholder = engine.heap.alloc_uninitialized(name.clone())?;
4004 env_rec = env_rec.extend(name.clone(), placeholder);
4005 slots.push(placeholder);
4006 }
4007
4008 for ((_, def), slot) in bindings.iter().zip(slots.iter()) {
4009 check_cancelled(engine)?;
4010 gas.charge(gas.costs.eval_node)?;
4011 let def_ptr = eval_typed_expr(engine, &env_rec, def, gas).await?;
4012 let def_value = engine.heap.get(&def_ptr)?;
4013 engine.heap.overwrite(slot, def_value.as_ref().clone())?;
4014 }
4015
4016 eval_typed_expr(engine, &env_rec, body, gas).await
4017 }
4018 TypedExprKind::Ite {
4019 cond,
4020 then_expr,
4021 else_expr,
4022 } => {
4023 let cond_ptr = eval_typed_expr(engine, &env, cond, gas).await?;
4024 match engine.heap.pointer_as_bool(&cond_ptr) {
4025 Ok(true) => eval_typed_expr(engine, &env, then_expr, gas).await,
4026 Ok(false) => eval_typed_expr(engine, &env, else_expr, gas).await,
4027 Err(EngineError::NativeType { got, .. }) => Err(EngineError::ExpectedBool(got)),
4028 Err(err) => Err(err),
4029 }
4030 }
4031 TypedExprKind::Match { scrutinee, arms } => {
4032 let value = eval_typed_expr(engine, &env, scrutinee, gas).await?;
4033 for (pat, expr) in arms {
4034 check_cancelled(engine)?;
4035 gas.charge(gas.costs.eval_match_arm)?;
4036 if let Some(bindings) = match_pattern_ptr(&engine.heap, pat, &value) {
4037 let env = env.extend_many(bindings);
4038 return eval_typed_expr(engine, &env, expr, gas).await;
4039 }
4040 }
4041 Err(EngineError::MatchFailure)
4042 }
4043 TypedExprKind::Let { .. } => {
4044 unreachable!("let chain handled in eval_typed_expr loop")
4045 }
4046 }
4047}
4048
4049#[async_recursion]
4050pub(crate) async fn apply<State>(
4051 engine: &Engine<State>,
4052 func: Pointer,
4053 arg: Pointer,
4054 func_type: Option<&Type>,
4055 arg_type: Option<&Type>,
4056 gas: &mut GasMeter,
4057) -> Result<Pointer, EngineError>
4058where
4059 State: Clone + Send + Sync + 'static,
4060{
4061 let func_value = engine.heap.get(&func)?.as_ref().clone();
4062 match func_value {
4063 Value::Closure(Closure {
4064 env,
4065 param,
4066 param_ty,
4067 typ,
4068 body,
4069 }) => {
4070 let mut subst = Subst::new_sync();
4071 if let Some(expected) = func_type {
4072 let s_fun = unify(&typ, expected).map_err(|_| EngineError::NativeType {
4073 expected: typ.to_string(),
4074 got: expected.to_string(),
4075 })?;
4076 subst = compose_subst(s_fun, subst);
4077 }
4078 let actual_ty = resolve_arg_type(&engine.heap, arg_type, &arg)?;
4079 let param_ty = param_ty.apply(&subst);
4080 let s_arg = unify(¶m_ty, &actual_ty).map_err(|_| EngineError::NativeType {
4081 expected: param_ty.to_string(),
4082 got: actual_ty.to_string(),
4083 })?;
4084 subst = compose_subst(s_arg, subst);
4085 let env = env.extend(param, arg);
4086 let body = body.apply(&subst);
4087 eval_typed_expr(engine, &env, &body, gas).await
4088 }
4089 Value::Native(native) => native.apply(engine, arg, arg_type, gas).await,
4090 Value::Overloaded(over) => over.apply(engine, arg, func_type, arg_type, gas).await,
4091 _ => Err(EngineError::NotCallable(
4092 engine.heap.type_name(&func)?.into(),
4093 )),
4094 }
4095}
4096
4097fn match_pattern_ptr(
4098 heap: &Heap,
4099 pat: &Pattern,
4100 value: &Pointer,
4101) -> Option<HashMap<Symbol, Pointer>> {
4102 match pat {
4103 Pattern::Wildcard(..) => Some(HashMap::new()),
4104 Pattern::Var(var) => {
4105 let mut bindings = HashMap::new();
4106 bindings.insert(var.name.clone(), *value);
4107 Some(bindings)
4108 }
4109 Pattern::Named(_, name, ps) => {
4110 let v = heap.get(value).ok()?;
4111 match v.as_ref() {
4112 Value::Adt(vname, args)
4113 if vname == &name.to_dotted_symbol() && args.len() == ps.len() =>
4114 {
4115 match_patterns(heap, ps, args)
4116 }
4117 _ => None,
4118 }
4119 }
4120 Pattern::Tuple(_, ps) => {
4121 let v = heap.get(value).ok()?;
4122 match v.as_ref() {
4123 Value::Tuple(xs) if xs.len() == ps.len() => match_patterns(heap, ps, xs),
4124 _ => None,
4125 }
4126 }
4127 Pattern::List(_, ps) => {
4128 let v = heap.get(value).ok()?;
4129 let values = list_to_vec(heap, v.as_ref()).ok()?;
4130 if values.len() == ps.len() {
4131 match_patterns(heap, ps, &values)
4132 } else {
4133 None
4134 }
4135 }
4136 Pattern::Cons(_, head, tail) => {
4137 let v = heap.get(value).ok()?;
4138 match v.as_ref() {
4139 Value::Adt(tag, args) if sym_eq(tag, "Cons") && args.len() == 2 => {
4140 let mut left = match_pattern_ptr(heap, head, &args[0])?;
4141 let right = match_pattern_ptr(heap, tail, &args[1])?;
4142 left.extend(right);
4143 Some(left)
4144 }
4145 _ => None,
4146 }
4147 }
4148 Pattern::Dict(_, fields) => {
4149 let v = heap.get(value).ok()?;
4150 match v.as_ref() {
4151 Value::Dict(map) => {
4152 let mut bindings = HashMap::new();
4153 for (key, pat) in fields {
4154 let v = map.get(key)?;
4155 let sub = match_pattern_ptr(heap, pat, v)?;
4156 bindings.extend(sub);
4157 }
4158 Some(bindings)
4159 }
4160 _ => None,
4161 }
4162 }
4163 }
4164}
4165
4166fn match_patterns(
4167 heap: &Heap,
4168 patterns: &[Pattern],
4169 values: &[Pointer],
4170) -> Option<HashMap<Symbol, Pointer>> {
4171 let mut bindings = HashMap::new();
4172 for (p, v) in patterns.iter().zip(values.iter()) {
4173 let sub = match_pattern_ptr(heap, p, v)?;
4174 bindings.extend(sub);
4175 }
4176 Some(bindings)
4177}
4178
4179#[cfg(test)]
4180mod tests {
4181 use super::*;
4182 use rexlang_lexer::Token;
4183 use rexlang_parser::Parser;
4184 use rexlang_util::{GasCosts, GasMeter};
4185 use std::path::Path;
4186
4187 use crate::ReplState;
4188
4189 fn parse(code: &str) -> Arc<Expr> {
4190 let mut parser = Parser::new(Token::tokenize(code).unwrap());
4191 parser.parse_program(&mut GasMeter::default()).unwrap().expr
4192 }
4193
4194 fn parse_program(code: &str) -> rexlang_ast::expr::Program {
4195 let mut parser = Parser::new(Token::tokenize(code).unwrap());
4196 parser.parse_program(&mut GasMeter::default()).unwrap()
4197 }
4198
4199 fn strip_span(mut err: TypeError) -> TypeError {
4200 while let TypeError::Spanned { error, .. } = err {
4201 err = *error;
4202 }
4203 err
4204 }
4205
4206 fn engine_with_arith() -> Engine {
4207 Engine::with_prelude(()).unwrap()
4208 }
4209
4210 fn unlimited_gas() -> GasMeter {
4211 GasMeter::default()
4212 }
4213
4214 #[test]
4215 fn registry_markdown_lists_core_sections() {
4216 let engine = Engine::with_prelude(()).unwrap();
4217 let doc = engine.registry_markdown();
4218
4219 assert!(doc.contains("# Engine Registry"));
4220 assert!(doc.contains("## Module Index"));
4221 assert!(doc.contains("## Modules"));
4222 assert!(doc.contains("## ADTs"));
4223 assert!(doc.contains("## Functions and Values"));
4224 assert!(doc.contains("## Type Classes"));
4225 assert!(doc.contains("## Native Implementations"));
4226 assert!(doc.contains("[`virtual:Prelude`](#module-virtual-prelude)"));
4227 assert!(doc.contains("<a id=\"module-virtual-prelude\"></a>"));
4228 assert!(doc.contains("### `virtual:Prelude`"));
4229 assert!(doc.contains("`List`"));
4230 assert!(doc.contains("`Option`"));
4231 }
4232
4233 #[test]
4234 fn module_add_adt_decls_from_types_collects_nested_unique_adts() {
4235 let mut engine = Engine::with_prelude(()).unwrap();
4236 let mut module = Module::new("acme.types");
4237 let a = Type::var(rexlang_typesystem::TypeVar::new(0, Some(sym("a"))));
4238 let types = vec![
4239 Type::fun(
4240 Type::app(Type::user_con("Foo", 1), a.clone()),
4241 Type::user_con("Bar", 0),
4242 ),
4243 Type::app(Type::user_con("Foo", 1), Type::builtin(BuiltinTypeId::I32)),
4244 ];
4245
4246 module.add_adt_decls_from_types(&mut engine, types).unwrap();
4247
4248 assert_eq!(module.declarations.len(), 2);
4249 assert!(
4250 module
4251 .declarations
4252 .iter()
4253 .any(|d| d.starts_with("pub type Foo t0 ="))
4254 );
4255 assert!(
4256 module
4257 .declarations
4258 .iter()
4259 .any(|d| d.starts_with("pub type Bar ="))
4260 );
4261 }
4262
4263 #[test]
4264 fn module_add_adt_decls_from_types_rejects_conflicting_adts() {
4265 let mut engine = Engine::with_prelude(()).unwrap();
4266 let mut module = Module::new("acme.types");
4267 let types = vec![Type::user_con("Thing", 1), Type::user_con("Thing", 2)];
4268
4269 let err = module
4270 .add_adt_decls_from_types(&mut engine, types)
4271 .unwrap_err();
4272
4273 assert!(matches!(err, EngineError::Custom(_)));
4274 assert!(
4275 err.to_string()
4276 .contains("conflicting ADT definitions discovered in input types")
4277 );
4278 }
4279
4280 #[tokio::test]
4281 async fn repl_persists_function_definitions() {
4282 let mut gas = unlimited_gas();
4283 let mut engine = Engine::with_prelude(()).unwrap();
4284 engine.add_default_resolvers();
4285 let mut state = ReplState::new();
4286
4287 let program1 = parse_program("fn inc (x: i32) -> i32 = x + 1\ninc 1");
4288 let (v1, t1) = engine
4289 .eval_repl_program(&program1, &mut state, &mut gas)
4290 .await
4291 .unwrap();
4292 assert_eq!(t1, Type::builtin(BuiltinTypeId::I32));
4293 let expected = engine.heap.alloc_i32(2).unwrap();
4294 assert!(crate::pointer_eq(&engine.heap, &v1, &expected).unwrap());
4295
4296 let program2 = parse_program("inc 2");
4297 let (v2, t2) = engine
4298 .eval_repl_program(&program2, &mut state, &mut gas)
4299 .await
4300 .unwrap();
4301 assert_eq!(t2, Type::builtin(BuiltinTypeId::I32));
4302 let expected = engine.heap.alloc_i32(3).unwrap();
4303 assert!(crate::pointer_eq(&engine.heap, &v2, &expected).unwrap());
4304 }
4305
4306 #[tokio::test]
4307 async fn repl_persists_import_aliases() {
4308 let mut gas = unlimited_gas();
4309 let mut engine = Engine::with_prelude(()).unwrap();
4310 engine.add_default_resolvers();
4311
4312 let examples =
4314 Path::new(env!("CARGO_MANIFEST_DIR")).join("../rexlang-cli/examples/modules_basic");
4315 engine.add_include_resolver(&examples).unwrap();
4316
4317 let mut state = ReplState::new();
4318 let program1 = parse_program("import foo.bar as Bar\n()");
4319 let (v1, t1) = engine
4320 .eval_repl_program(&program1, &mut state, &mut gas)
4321 .await
4322 .unwrap();
4323 assert_eq!(t1, Type::tuple(vec![]));
4324 let expected = engine.heap.alloc_tuple(vec![]).unwrap();
4325 assert!(crate::pointer_eq(&engine.heap, &v1, &expected).unwrap());
4326
4327 let program2 = parse_program("Bar.triple 10");
4328 let (v2, t2) = engine
4329 .eval_repl_program(&program2, &mut state, &mut gas)
4330 .await
4331 .unwrap();
4332 assert_eq!(t2, Type::builtin(BuiltinTypeId::I32));
4333 let expected = engine.heap.alloc_i32(30).unwrap();
4334 assert!(crate::pointer_eq(&engine.heap, &v2, &expected).unwrap());
4335 }
4336
4337 #[tokio::test]
4338 async fn repl_persists_imported_values() {
4339 let mut gas = unlimited_gas();
4340 let mut engine = Engine::with_prelude(()).unwrap();
4341 engine.add_default_resolvers();
4342
4343 let examples =
4345 Path::new(env!("CARGO_MANIFEST_DIR")).join("../rexlang-cli/examples/modules_basic");
4346 engine.add_include_resolver(&examples).unwrap();
4347
4348 let mut state = ReplState::new();
4349 let program1 = parse_program("import foo.bar (triple as t)\n()");
4350 let (v1, t1) = engine
4351 .eval_repl_program(&program1, &mut state, &mut gas)
4352 .await
4353 .unwrap();
4354 assert_eq!(t1, Type::tuple(vec![]));
4355 let expected = engine.heap.alloc_tuple(vec![]).unwrap();
4356 assert!(crate::pointer_eq(&engine.heap, &v1, &expected).unwrap());
4357
4358 let program2 = parse_program("t 10");
4359 let (v2, t2) = engine
4360 .eval_repl_program(&program2, &mut state, &mut gas)
4361 .await
4362 .unwrap();
4363 assert_eq!(t2, Type::builtin(BuiltinTypeId::I32));
4364 let expected = engine.heap.alloc_i32(30).unwrap();
4365 assert!(crate::pointer_eq(&engine.heap, &v2, &expected).unwrap());
4366 }
4367
4368 #[tokio::test]
4369 async fn injected_module_can_define_pub_adt_declarations() {
4370 let mut gas = unlimited_gas();
4371 let mut engine = Engine::with_prelude(()).unwrap();
4372 engine.add_default_resolvers();
4373
4374 let mut module = Module::new("acme.status");
4375 module
4376 .add_declaration("pub type Status = Ready | Failed string")
4377 .unwrap();
4378 engine.inject_module(module).unwrap();
4379
4380 let (value, _ty) = engine
4381 .eval_snippet(
4382 r#"
4383 import acme.status (Failed)
4384 Failed "boom"
4385 "#,
4386 &mut gas,
4387 )
4388 .await
4389 .unwrap();
4390
4391 let v = engine.heap.get(&value).unwrap();
4392 match v.as_ref() {
4393 Value::Adt(tag, args) => {
4394 assert!(tag.as_ref().ends_with(".Failed"));
4395 assert_eq!(args.len(), 1);
4396 }
4397 _ => panic!("expected ADT value"),
4398 }
4399 }
4400
4401 #[tokio::test]
4402 async fn eval_can_be_cancelled_while_waiting_on_async_native() {
4403 let expr = parse("stall");
4404 let mut engine = Engine::with_prelude(()).unwrap();
4405
4406 let (started_tx, started_rx) = std::sync::mpsc::channel::<()>();
4407 let scheme = Scheme::new(vec![], vec![], Type::builtin(BuiltinTypeId::I32));
4408 engine
4409 .export_native_async_cancellable(
4410 "stall",
4411 scheme,
4412 0,
4413 move |_engine, token: CancellationToken, _, _args| {
4414 let started_tx = started_tx.clone();
4415 async move {
4416 let _ = started_tx.send(());
4417 token.cancelled().await;
4418 _engine.heap.alloc_i32(0)
4419 }
4420 .boxed()
4421 },
4422 )
4423 .unwrap();
4424
4425 let token = engine.cancellation_token();
4426 let canceller = std::thread::spawn(move || {
4427 let recv = started_rx.recv_timeout(std::time::Duration::from_secs(2));
4428 assert!(recv.is_ok(), "stall native never started");
4429 token.cancel();
4430 });
4431
4432 let mut gas = unlimited_gas();
4433 let res = engine.eval(expr.as_ref(), &mut gas).await;
4434 let joined = canceller.join();
4435 assert!(joined.is_ok(), "cancel thread panicked");
4436 assert!(matches!(res, Err(EngineError::Cancelled)));
4437 }
4438
4439 #[tokio::test]
4440 async fn eval_can_be_cancelled_while_waiting_on_non_cancellable_async_native() {
4441 let expr = parse("stall");
4442 let mut engine = Engine::with_prelude(()).unwrap();
4443
4444 let (started_tx, started_rx) = std::sync::mpsc::channel::<()>();
4445 engine
4446 .export_async("stall", move |_state: &()| {
4447 let started_tx = started_tx.clone();
4448 async move {
4449 let _ = started_tx.send(());
4450 futures::future::pending::<Result<i32, EngineError>>().await
4451 }
4452 })
4453 .unwrap();
4454
4455 let token = engine.cancellation_token();
4456 let canceller = std::thread::spawn(move || {
4457 let recv = started_rx.recv_timeout(std::time::Duration::from_secs(2));
4458 assert!(recv.is_ok(), "stall native never started");
4459 token.cancel();
4460 });
4461
4462 let mut gas = unlimited_gas();
4463 let res = engine.eval(expr.as_ref(), &mut gas).await;
4464 let joined = canceller.join();
4465 assert!(joined.is_ok(), "cancel thread panicked");
4466 assert!(matches!(res, Err(EngineError::Cancelled)));
4467 }
4468
4469 #[tokio::test]
4470 async fn native_per_impl_gas_cost_is_charged() {
4471 let expr = parse("foo");
4472 let mut engine = Engine::with_prelude(()).unwrap();
4473 let scheme = Scheme::new(vec![], vec![], Type::builtin(BuiltinTypeId::I32));
4474 engine
4475 .export_native_with_gas_cost("foo", scheme, 0, 50, |engine, _t, _args| {
4476 engine.heap.alloc_i32(1)
4477 })
4478 .unwrap();
4479
4480 let mut gas = GasMeter::new(
4481 Some(10),
4482 GasCosts {
4483 eval_node: 1,
4484 native_call_base: 1,
4485 native_call_per_arg: 0,
4486 ..GasCosts::sensible_defaults()
4487 },
4488 );
4489 let err = match engine.eval(expr.as_ref(), &mut gas).await {
4490 Ok(_) => panic!("expected out of gas"),
4491 Err(e) => e,
4492 };
4493 assert!(matches!(err, EngineError::OutOfGas(..)));
4494 }
4495
4496 #[tokio::test]
4497 async fn export_value_typed_registers_global_value() {
4498 let expr = parse("answer");
4499 let mut engine = Engine::with_prelude(()).unwrap();
4500 engine
4501 .export_value_typed("answer", Type::builtin(BuiltinTypeId::I32), Value::I32(42))
4502 .unwrap();
4503
4504 let mut gas = unlimited_gas();
4505 let (value, ty) = engine.eval(expr.as_ref(), &mut gas).await.unwrap();
4506 assert_eq!(ty, Type::builtin(BuiltinTypeId::I32));
4507 let expected = engine.heap.alloc_i32(42).unwrap();
4508 assert!(crate::pointer_eq(&engine.heap, &value, &expected).unwrap());
4509 }
4510
4511 #[tokio::test]
4512 async fn async_native_per_impl_gas_cost_is_charged() {
4513 let expr = parse("foo");
4514 let mut engine = Engine::with_prelude(()).unwrap();
4515 let scheme = Scheme::new(vec![], vec![], Type::builtin(BuiltinTypeId::I32));
4516 engine
4517 .export_native_async_with_gas_cost("foo", scheme, 0, 50, |engine, _t, _args| {
4518 async move { engine.heap.alloc_i32(1) }.boxed()
4519 })
4520 .unwrap();
4521
4522 let mut gas = GasMeter::new(
4523 Some(10),
4524 GasCosts {
4525 eval_node: 1,
4526 native_call_base: 1,
4527 native_call_per_arg: 0,
4528 ..GasCosts::sensible_defaults()
4529 },
4530 );
4531 let err = match engine.eval(expr.as_ref(), &mut gas).await {
4532 Ok(_) => panic!("expected out of gas"),
4533 Err(e) => e,
4534 };
4535 assert!(matches!(err, EngineError::OutOfGas(..)));
4536 }
4537
4538 #[tokio::test]
4539 async fn cancellable_async_native_per_impl_gas_cost_is_charged() {
4540 let expr = parse("foo");
4541 let mut engine = Engine::with_prelude(()).unwrap();
4542 let scheme = Scheme::new(vec![], vec![], Type::builtin(BuiltinTypeId::I32));
4543 engine
4544 .export_native_async_cancellable_with_gas_cost(
4545 "foo",
4546 scheme,
4547 0,
4548 50,
4549 |engine, _token: CancellationToken, _t, _args| {
4550 async move { engine.heap.alloc_i32(1) }.boxed()
4551 },
4552 )
4553 .unwrap();
4554
4555 let mut gas = GasMeter::new(
4556 Some(10),
4557 GasCosts {
4558 eval_node: 1,
4559 native_call_base: 1,
4560 native_call_per_arg: 0,
4561 ..GasCosts::sensible_defaults()
4562 },
4563 );
4564 let err = match engine.eval(expr.as_ref(), &mut gas).await {
4565 Ok(_) => panic!("expected out of gas"),
4566 Err(e) => e,
4567 };
4568 assert!(matches!(err, EngineError::OutOfGas(..)));
4569 }
4570
4571 #[tokio::test]
4572 async fn record_update_requires_known_variant_for_sum_types() {
4573 let program = parse_program(
4574 r#"
4575 type Foo = Bar { x: i32 } | Baz { x: i32 }
4576 let
4577 f = \ (foo : Foo) -> { foo with { x = 2 } }
4578 in
4579 f (Bar { x = 1 })
4580 "#,
4581 );
4582 let mut engine = engine_with_arith();
4583 engine.inject_decls(&program.decls).unwrap();
4584 let mut gas = unlimited_gas();
4585 match engine.eval(program.expr.as_ref(), &mut gas).await {
4586 Err(EngineError::Type(err)) => {
4587 let err = strip_span(err);
4588 assert!(matches!(err, TypeError::FieldNotKnown { .. }));
4589 }
4590 _ => panic!("expected type error"),
4591 }
4592 }
4593}