lust/embed/
program.rs

1use super::async_runtime::{
2    signal_pair, AsyncRegistry, AsyncTaskEntry, AsyncTaskQueue, AsyncTaskTarget, AsyncValueFuture,
3    PendingAsyncTask,
4};
5use super::conversions::{
6    FromLustArgs, FromLustValue, FunctionArgs, IntoLustValue, IntoTypedValue,
7};
8use super::native_types::ExternRegistry;
9use super::values::{EnumInstance, FunctionHandle, StructField, StructInstance, TypedValue};
10use crate::ast::{
11    EnumDef, FieldOwnership, FunctionDef, ImplBlock, Item, ItemKind, Span, StructDef, TraitDef,
12    Type, TypeKind,
13};
14use crate::bytecode::{Compiler, NativeCallResult, Value};
15use crate::modules::{ModuleImports, ModuleLoader};
16use crate::typechecker::{FunctionSignature, TypeChecker};
17use crate::vm::VM;
18use crate::{LustConfig, LustError, Result};
19use hashbrown::HashMap;
20use std::cell::RefCell;
21use std::future::Future;
22use std::path::{Path, PathBuf};
23use std::rc::Rc;
24use std::task::{Context, Poll};
25
26pub struct EmbeddedBuilder {
27    base_dir: PathBuf,
28    modules: HashMap<String, String>,
29    entry_module: Option<String>,
30    config: LustConfig,
31    extern_registry: ExternRegistry,
32}
33
34impl Default for EmbeddedBuilder {
35    fn default() -> Self {
36        Self {
37            base_dir: PathBuf::from("__embedded__"),
38            modules: HashMap::new(),
39            entry_module: None,
40            config: LustConfig::default(),
41            extern_registry: ExternRegistry::new(),
42        }
43    }
44}
45
46impl EmbeddedBuilder {
47    pub fn new() -> Self {
48        Self::default()
49    }
50
51    pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
52        self.set_base_dir(base_dir)
53    }
54
55    pub fn set_base_dir(mut self, base_dir: impl Into<PathBuf>) -> Self {
56        self.base_dir = base_dir.into();
57        self
58    }
59
60    pub fn module(mut self, module_path: impl Into<String>, source: impl Into<String>) -> Self {
61        self.modules.insert(module_path.into(), source.into());
62        self
63    }
64
65    pub fn enable_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
66        self.config.enable_module(module);
67        self
68    }
69
70    pub fn add_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
71        self.config.enable_module(module);
72        self
73    }
74
75    pub fn declare_struct(mut self, def: StructDef) -> Self {
76        self.extern_registry.add_struct(def);
77        self
78    }
79
80    pub fn declare_enum(mut self, def: EnumDef) -> Self {
81        self.extern_registry.add_enum(def);
82        self
83    }
84
85    pub fn declare_trait(mut self, def: TraitDef) -> Self {
86        self.extern_registry.add_trait(def);
87        self
88    }
89
90    pub fn declare_impl(mut self, impl_block: ImplBlock) -> Self {
91        self.extern_registry.add_impl(impl_block);
92        self
93    }
94
95    pub fn declare_function(mut self, func: FunctionDef) -> Self {
96        self.extern_registry.add_function(func);
97        self
98    }
99
100    pub fn with_extern_registry(mut self, registry: ExternRegistry) -> Self {
101        self.extern_registry = registry;
102        self
103    }
104
105    pub fn extern_registry_mut(&mut self) -> &mut ExternRegistry {
106        &mut self.extern_registry
107    }
108
109    pub fn with_config(mut self, config: LustConfig) -> Self {
110        self.config = config;
111        self
112    }
113
114    pub fn set_config(mut self, config: LustConfig) -> Self {
115        self.config = config;
116        self
117    }
118
119    pub fn add_module(
120        &mut self,
121        module_path: impl Into<String>,
122        source: impl Into<String>,
123    ) -> &mut Self {
124        self.modules.insert(module_path.into(), source.into());
125        self
126    }
127
128    pub fn entry_module(mut self, module_path: impl Into<String>) -> Self {
129        self.set_entry_module(module_path);
130        self
131    }
132
133    pub fn set_entry_module(&mut self, module_path: impl Into<String>) -> &mut Self {
134        self.entry_module = Some(module_path.into());
135        self
136    }
137
138    pub fn compile(self) -> Result<EmbeddedProgram> {
139        let entry_module = self
140            .entry_module
141            .ok_or_else(|| LustError::Unknown("No entry module configured for embedding".into()))?;
142        let has_entry = self.modules.contains_key(&entry_module);
143        if !has_entry {
144            return Err(LustError::Unknown(format!(
145                "Entry module '{}' was not provided via EmbeddedBuilder::module",
146                entry_module
147            )));
148        }
149
150        let overrides: HashMap<PathBuf, String> = self
151            .modules
152            .into_iter()
153            .map(|(module, source)| (module_path_to_file(&self.base_dir, &module), source))
154            .collect();
155        compile_in_memory(
156            self.base_dir,
157            entry_module,
158            overrides,
159            self.config,
160            self.extern_registry,
161        )
162    }
163}
164
165pub struct EmbeddedProgram {
166    vm: VM,
167    signatures: HashMap<String, FunctionSignature>,
168    struct_defs: HashMap<String, StructDef>,
169    enum_defs: HashMap<String, EnumDef>,
170    entry_script: Option<String>,
171    entry_module: String,
172    async_registry: Rc<RefCell<AsyncRegistry>>,
173}
174
175pub struct AsyncDriver<'a> {
176    program: &'a mut EmbeddedProgram,
177}
178
179impl<'a> AsyncDriver<'a> {
180    pub fn new(program: &'a mut EmbeddedProgram) -> Self {
181        Self { program }
182    }
183
184    pub fn poll(&mut self) -> Result<()> {
185        self.program.poll_async_tasks()
186    }
187
188    pub fn pump_until_idle(&mut self) -> Result<()> {
189        while self.program.has_pending_async_tasks() {
190            self.program.poll_async_tasks()?;
191        }
192        Ok(())
193    }
194
195    pub fn has_pending(&self) -> bool {
196        self.program.has_pending_async_tasks()
197    }
198}
199
200impl EmbeddedProgram {
201    pub fn builder() -> EmbeddedBuilder {
202        EmbeddedBuilder::default()
203    }
204
205    pub fn vm_mut(&mut self) -> &mut VM {
206        &mut self.vm
207    }
208
209    pub(crate) fn vm(&self) -> &VM {
210        &self.vm
211    }
212
213    pub fn global_names(&self) -> Vec<String> {
214        self.vm.global_names()
215    }
216
217    pub fn globals(&self) -> Vec<(String, Value)> {
218        self.vm.globals_snapshot()
219    }
220
221    pub fn signature(&self, function_name: &str) -> Option<&FunctionSignature> {
222        self.find_signature(function_name).map(|(_, sig)| sig)
223    }
224
225    pub fn typed_functions(&self) -> impl Iterator<Item = (&String, &FunctionSignature)> {
226        self.signatures.iter()
227    }
228
229    pub fn struct_definition(&self, type_name: &str) -> Option<&StructDef> {
230        self.struct_defs.get(type_name)
231    }
232
233    pub fn enum_definition(&self, type_name: &str) -> Option<&EnumDef> {
234        self.enum_defs.get(type_name)
235    }
236
237    fn find_signature(&self, name: &str) -> Option<(String, &FunctionSignature)> {
238        if let Some(sig) = self.signatures.get(name) {
239            return Some((name.to_string(), sig));
240        }
241
242        for candidate in self.signature_lookup_candidates(name) {
243            if let Some(sig) = self.signatures.get(&candidate) {
244                return Some((candidate, sig));
245            }
246        }
247
248        let matches = self
249            .signatures
250            .iter()
251            .filter_map(|(key, sig)| {
252                if Self::simple_name(key) == name {
253                    Some((key, sig))
254                } else {
255                    None
256                }
257            })
258            .collect::<Vec<_>>();
259        if matches.len() == 1 {
260            let (key, sig) = matches[0];
261            return Some((key.clone(), sig));
262        }
263
264        None
265    }
266
267    fn resolve_signature(&self, name: &str) -> Result<(String, &FunctionSignature)> {
268        if let Some(found) = self.find_signature(name) {
269            return Ok(found);
270        }
271
272        let matches = self
273            .signatures
274            .keys()
275            .filter(|key| Self::simple_name(key) == name)
276            .count();
277        if matches > 1 {
278            return Err(LustError::TypeError {
279                message: format!(
280                    "Cannot register native '{}': multiple matching functions found; specify a fully qualified name",
281                    name
282                ),
283            });
284        }
285
286        Err(LustError::TypeError {
287            message: format!(
288                "Cannot register native '{}': function not declared in Lust source",
289                name
290            ),
291        })
292    }
293
294    fn signature_lookup_candidates(&self, name: &str) -> Vec<String> {
295        let mut candidates: Vec<String> = Vec::new();
296        if name.contains("::") {
297            candidates.push(name.replace("::", "."));
298        }
299
300        if name.contains('.') {
301            candidates.push(name.replace('.', "::"));
302        }
303
304        if !name.contains('.') && !name.contains("::") {
305            let module = &self.entry_module;
306            candidates.push(format!("{}.{}", module, name));
307            candidates.push(format!("{}::{}", module, name));
308        }
309
310        candidates
311    }
312
313    fn simple_name(name: &str) -> &str {
314        name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
315    }
316
317    fn register_native_with_aliases<F>(&mut self, requested_name: &str, canonical: String, func: F)
318    where
319        F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
320    {
321        let native_fn: Rc<dyn Fn(&[Value]) -> std::result::Result<NativeCallResult, String>> =
322            Rc::new(func);
323        let value = Value::NativeFunction(native_fn);
324        let mut aliases: Vec<String> = Vec::new();
325        aliases.push(canonical.clone());
326        let canonical_normalized = normalize_global_name(&canonical);
327        if canonical_normalized != canonical {
328            aliases.push(canonical_normalized);
329        }
330
331        if requested_name != canonical {
332            aliases.push(requested_name.to_string());
333            let normalized = normalize_global_name(requested_name);
334            if normalized != requested_name {
335                aliases.push(normalized);
336            }
337        }
338
339        aliases.sort();
340        aliases.dedup();
341        #[cfg(debug_assertions)]
342        eprintln!(
343            "register_native_with_aliases requested='{}' canonical='{}' aliases={:?}",
344            requested_name, canonical, aliases
345        );
346        for key in aliases {
347            self.vm.register_native(key, value.clone());
348        }
349    }
350
351    pub fn get_global_value(&self, name: &str) -> Option<Value> {
352        let normalized = normalize_global_name(name);
353        self.vm.get_global(&normalized)
354    }
355
356    pub fn get_typed_global<T: FromLustValue>(&self, name: &str) -> Result<Option<T>> {
357        let normalized = normalize_global_name(name);
358        match self.vm.get_global(&normalized) {
359            Some(value) => T::from_value(value).map(Some),
360            None => Ok(None),
361        }
362    }
363
364    pub fn set_global_value<V: IntoTypedValue>(&mut self, name: impl Into<String>, value: V) {
365        let name_string = name.into();
366        let normalized = normalize_global_name(&name_string);
367        let value = value.into_typed_value().into_value();
368        self.vm.set_global(normalized, value);
369    }
370
371    pub fn struct_instance<I>(
372        &self,
373        type_name: impl Into<String>,
374        fields: I,
375    ) -> Result<StructInstance>
376    where
377        I: IntoIterator,
378        I::Item: Into<StructField>,
379    {
380        let type_name = type_name.into();
381        let def = self
382            .struct_defs
383            .get(&type_name)
384            .ok_or_else(|| LustError::TypeError {
385                message: format!("Unknown struct '{}'", type_name),
386            })?;
387        let mut provided: HashMap<String, TypedValue> = fields
388            .into_iter()
389            .map(|field| {
390                let field: StructField = field.into();
391                field.into_parts()
392            })
393            .collect();
394        let mut ordered_fields: Vec<(Rc<String>, Value)> = Vec::with_capacity(def.fields.len());
395        for field in &def.fields {
396            let typed_value = provided
397                .remove(&field.name)
398                .ok_or_else(|| LustError::TypeError {
399                    message: format!(
400                        "Struct '{}' is missing required field '{}'",
401                        type_name, field.name
402                    ),
403                })?;
404
405            let matches_ref_inner = matches!(field.ownership, FieldOwnership::Weak)
406                && matches!(typed_value.as_value(), Value::Struct { .. });
407            if !typed_value.matches(&field.ty) && !matches_ref_inner {
408                return Err(LustError::TypeError {
409                    message: format!(
410                        "Struct field '{}' expects Rust value of type '{}' but received '{}'",
411                        field.name,
412                        field.ty,
413                        typed_value.description()
414                    ),
415                });
416            }
417
418            ordered_fields.push((Rc::new(field.name.clone()), typed_value.into_value()));
419        }
420
421        if !provided.is_empty() {
422            let mut unexpected: Vec<String> = provided.into_keys().collect();
423            unexpected.sort();
424            return Err(LustError::TypeError {
425                message: format!(
426                    "Struct '{}' received unexpected field(s): {}",
427                    type_name,
428                    unexpected.join(", ")
429                ),
430            });
431        }
432
433        let value = self.vm.instantiate_struct(&type_name, ordered_fields)?;
434        Ok(StructInstance::new(type_name.clone(), value))
435    }
436
437    pub fn enum_variant(
438        &self,
439        type_name: impl Into<String>,
440        variant: impl Into<String>,
441    ) -> Result<EnumInstance> {
442        self.enum_variant_with(type_name, variant, std::iter::empty::<Value>())
443    }
444
445    pub fn enum_variant_with<I, V>(
446        &self,
447        type_name: impl Into<String>,
448        variant: impl Into<String>,
449        payload: I,
450    ) -> Result<EnumInstance>
451    where
452        I: IntoIterator<Item = V>,
453        V: IntoTypedValue,
454    {
455        let type_name = type_name.into();
456        let variant_name = variant.into();
457        let def = self
458            .enum_defs
459            .get(&type_name)
460            .ok_or_else(|| LustError::TypeError {
461                message: format!("Unknown enum '{}'", type_name),
462            })?;
463        let enum_variant = def
464            .variants
465            .iter()
466            .find(|v| v.name == variant_name)
467            .ok_or_else(|| LustError::TypeError {
468                message: format!(
469                    "Enum '{}' has no variant named '{}'",
470                    type_name, variant_name
471                ),
472            })?;
473        let mut values: Vec<TypedValue> =
474            payload.into_iter().map(|v| v.into_typed_value()).collect();
475        let coerced_values: Option<Rc<Vec<Value>>> = match &enum_variant.fields {
476            None => {
477                if !values.is_empty() {
478                    return Err(LustError::TypeError {
479                        message: format!(
480                            "Enum variant '{}.{}' does not accept payload values",
481                            type_name, variant_name
482                        ),
483                    });
484                }
485
486                None
487            }
488
489            Some(field_types) => {
490                if values.len() != field_types.len() {
491                    return Err(LustError::TypeError {
492                        message: format!(
493                            "Enum variant '{}.{}' expects {} value(s) but {} were supplied",
494                            type_name,
495                            variant_name,
496                            field_types.len(),
497                            values.len()
498                        ),
499                    });
500                }
501
502                let mut collected = Vec::with_capacity(field_types.len());
503                for (idx, (typed_value, field_ty)) in
504                    values.drain(..).zip(field_types.iter()).enumerate()
505                {
506                    if !typed_value.matches(field_ty) {
507                        return Err(LustError::TypeError {
508                            message: format!(
509                                "Enum variant '{}.{}' field {} expects Lust type '{}' but Rust provided '{}'",
510                                type_name,
511                                variant_name,
512                                idx + 1,
513                                field_ty,
514                                typed_value.description()
515                            ),
516                        });
517                    }
518
519                    collected.push(typed_value.into_value());
520                }
521
522                Some(Rc::new(collected))
523            }
524        };
525        Ok(EnumInstance::new(
526            type_name.clone(),
527            variant_name.clone(),
528            Value::Enum {
529                enum_name: type_name,
530                variant: variant_name,
531                values: coerced_values,
532            },
533        ))
534    }
535
536    pub fn register_native_fn<F>(&mut self, name: impl Into<String>, func: F)
537    where
538        F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
539    {
540        let native = Value::NativeFunction(Rc::new(func));
541        self.vm.register_native(name, native);
542    }
543
544    pub fn register_async_native<F, Fut>(&mut self, name: impl Into<String>, func: F) -> Result<()>
545    where
546        F: Fn(Vec<Value>) -> Fut + 'static,
547        Fut: Future<Output = std::result::Result<Value, String>> + 'static,
548    {
549        let registry = self.async_registry.clone();
550        let name_string = name.into();
551        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
552            let args: Vec<Value> = values.iter().cloned().collect();
553            let future: AsyncValueFuture = Box::pin(func(args));
554            VM::with_current(|vm| {
555                let handle = vm
556                    .current_task_handle()
557                    .ok_or_else(|| "Async native functions require a running task".to_string())?;
558                let mut registry = registry.borrow_mut();
559                if registry.has_pending_for(handle) {
560                    return Err(format!(
561                        "Task {} already has a pending async native call",
562                        handle.id()
563                    ));
564                }
565
566                registry.register(AsyncTaskEntry::new(
567                    AsyncTaskTarget::ScriptTask(handle),
568                    future,
569                ));
570                Ok(NativeCallResult::Yield(Value::Nil))
571            })
572        };
573        self.register_native_fn(name_string, handler);
574        Ok(())
575    }
576
577    pub fn register_typed_native<Args, R, F>(&mut self, name: &str, func: F) -> Result<()>
578    where
579        Args: FromLustArgs,
580        R: IntoLustValue + FromLustValue,
581        F: Fn(Args) -> std::result::Result<R, String> + 'static,
582    {
583        let (canonical, signature) = self.resolve_signature(name)?;
584        if !Args::matches_signature(&signature.params) {
585            return Err(LustError::TypeError {
586                message: format!(
587                    "Native '{}' argument types do not match Lust signature",
588                    name
589                ),
590            });
591        }
592
593        ensure_return_type::<R>(name, &signature.return_type)?;
594        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
595            let args = Args::from_values(values)?;
596            let result = func(args)?;
597            Ok(NativeCallResult::Return(result.into_value()))
598        };
599        self.register_native_with_aliases(name, canonical, handler);
600        Ok(())
601    }
602
603    pub fn register_async_typed_native<Args, R, F, Fut>(
604        &mut self,
605        name: &str,
606        func: F,
607    ) -> Result<()>
608    where
609        Args: FromLustArgs,
610        R: IntoLustValue + FromLustValue,
611        F: Fn(Args) -> Fut + 'static,
612        Fut: Future<Output = std::result::Result<R, String>> + 'static,
613    {
614        let (canonical, signature) = self.resolve_signature(name)?;
615        let signature = signature.clone();
616        if !Args::matches_signature(&signature.params) {
617            return Err(LustError::TypeError {
618                message: format!(
619                    "Native '{}' argument types do not match Lust signature",
620                    name
621                ),
622            });
623        }
624
625        let registry = self.async_registry.clone();
626        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
627            let args = Args::from_values(values)?;
628            let future = func(args);
629            let mapped = async move {
630                match future.await {
631                    Ok(result) => Ok(result.into_value()),
632                    Err(err) => Err(err),
633                }
634            };
635            let future: AsyncValueFuture = Box::pin(mapped);
636            VM::with_current(|vm| {
637                let handle = vm
638                    .current_task_handle()
639                    .ok_or_else(|| "Async native functions require a running task".to_string())?;
640                let mut registry = registry.borrow_mut();
641                if registry.has_pending_for(handle) {
642                    return Err(format!(
643                        "Task {} already has a pending async native call",
644                        handle.id()
645                    ));
646                }
647
648                registry.register(AsyncTaskEntry::new(
649                    AsyncTaskTarget::ScriptTask(handle),
650                    future,
651                ));
652                Ok(NativeCallResult::Yield(Value::Nil))
653            })
654        };
655        self.register_native_with_aliases(name, canonical, handler);
656        Ok(())
657    }
658
659    pub fn register_async_task_native<Args, R, F, Fut>(&mut self, name: &str, func: F) -> Result<()>
660    where
661        Args: FromLustArgs,
662        R: IntoLustValue + FromLustValue,
663        F: Fn(Args) -> Fut + 'static,
664        Fut: Future<Output = std::result::Result<R, String>> + 'static,
665    {
666        let (canonical, signature) = self.resolve_signature(name)?;
667        let signature = signature.clone();
668        if !Args::matches_signature(&signature.params) {
669            return Err(LustError::TypeError {
670                message: format!(
671                    "Native '{}' argument types do not match Lust signature",
672                    name
673                ),
674            });
675        }
676
677        let registry = self.async_registry.clone();
678        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
679            let args = Args::from_values(values)?;
680            let future = func(args);
681            let mapped = async move {
682                match future.await {
683                    Ok(result) => Ok(result.into_value()),
684                    Err(err) => Err(err),
685                }
686            };
687            let future: AsyncValueFuture = Box::pin(mapped);
688            VM::with_current(|vm| {
689                let mut registry = registry.borrow_mut();
690                let handle = vm.create_native_future_task();
691                let entry = AsyncTaskEntry::new(AsyncTaskTarget::NativeTask(handle), future);
692                registry.register(entry);
693                Ok(NativeCallResult::Return(Value::task(handle)))
694            })
695        };
696        self.register_native_with_aliases(name, canonical, handler);
697        Ok(())
698    }
699
700    pub fn register_async_task_queue<Args, R>(
701        &mut self,
702        name: &str,
703        queue: AsyncTaskQueue<Args, R>,
704    ) -> Result<()>
705    where
706        Args: FromLustArgs + 'static,
707        R: IntoLustValue + FromLustValue + 'static,
708    {
709        let (canonical, signature) = self.resolve_signature(name)?;
710        let signature = signature.clone();
711        if !Args::matches_signature(&signature.params) {
712            return Err(LustError::TypeError {
713                message: format!(
714                    "Native '{}' argument types do not match Lust signature",
715                    name
716                ),
717            });
718        }
719
720        let registry = self.async_registry.clone();
721        let queue_clone = queue.clone();
722        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
723            let args = Args::from_values(values)?;
724            let (completer, signal_future) = signal_pair::<R>();
725            let future: AsyncValueFuture = Box::pin(async move {
726                match signal_future.await {
727                    Ok(result) => Ok(result.into_value()),
728                    Err(err) => Err(err),
729                }
730            });
731
732            VM::with_current(|vm| {
733                let mut registry = registry.borrow_mut();
734                let handle = vm.create_native_future_task();
735                let entry = AsyncTaskEntry::new(AsyncTaskTarget::NativeTask(handle), future);
736                registry.register(entry);
737                queue_clone.push(PendingAsyncTask::new(handle, args, completer));
738                Ok(NativeCallResult::Return(Value::task(handle)))
739            })
740        };
741        self.register_native_with_aliases(name, canonical, handler);
742        Ok(())
743    }
744
745    pub fn call_typed<Args, R>(&mut self, function_name: &str, args: Args) -> Result<R>
746    where
747        Args: FunctionArgs,
748        R: FromLustValue,
749    {
750        let signature = self
751            .signatures
752            .get(function_name)
753            .ok_or_else(|| LustError::TypeError {
754                message: format!(
755                    "No type information available for function '{}'; \
756                     use call_raw if the function is dynamically typed",
757                    function_name
758                ),
759            })?;
760        Args::validate_signature(function_name, &signature.params)?;
761        ensure_return_type::<R>(function_name, &signature.return_type)?;
762        let values = args.into_values();
763        let value = self.vm.call(function_name, values)?;
764        R::from_value(value)
765    }
766
767    pub fn call_raw(&mut self, function_name: &str, args: Vec<Value>) -> Result<Value> {
768        self.vm.call(function_name, args)
769    }
770
771    pub fn function_handle(&self, function_name: &str) -> Result<FunctionHandle> {
772        let mut candidates = Vec::new();
773        candidates.push(function_name.to_string());
774        candidates.extend(self.signature_lookup_candidates(function_name));
775        for name in candidates {
776            if let Some(value) = self.vm.function_value(&name) {
777                return FunctionHandle::from_value(value);
778            }
779        }
780        Err(LustError::RuntimeError {
781            message: format!("Function '{}' not found in embedded program", function_name),
782        })
783    }
784
785    pub fn run_entry_script(&mut self) -> Result<()> {
786        let Some(entry) = &self.entry_script else {
787            return Err(LustError::RuntimeError {
788                message: "Embedded program has no entry script".into(),
789            });
790        };
791        let result = self.vm.call(entry, Vec::new())?;
792        match result {
793            Value::Nil => Ok(()),
794            other => Err(LustError::RuntimeError {
795                message: format!(
796                    "Entry script '{}' returned non-unit value: {:?}",
797                    entry, other
798                ),
799            }),
800        }
801    }
802
803    pub fn poll_async_tasks(&mut self) -> Result<()> {
804        let pending_ids: Vec<u64> = {
805            let registry = self.async_registry.borrow();
806            registry.pending.keys().copied().collect()
807        };
808
809        for id in pending_ids {
810            let mut completion: Option<(AsyncTaskTarget, std::result::Result<Value, String>)> =
811                None;
812            {
813                let mut registry = self.async_registry.borrow_mut();
814                let entry = match registry.pending.get_mut(&id) {
815                    Some(entry) => entry,
816                    None => continue,
817                };
818
819                if !entry.take_should_poll() {
820                    continue;
821                }
822
823                let waker = entry.make_waker();
824                let mut cx = Context::from_waker(&waker);
825                if let Poll::Ready(result) = entry.future.as_mut().poll(&mut cx) {
826                    completion = Some((entry.target, result));
827                }
828            }
829
830            if let Some((target, outcome)) = completion {
831                self.async_registry.borrow_mut().pending.remove(&id);
832                match target {
833                    AsyncTaskTarget::ScriptTask(handle) => match outcome {
834                        Ok(value) => {
835                            self.vm.resume_task_handle(handle, Some(value))?;
836                        }
837
838                        Err(message) => {
839                            self.vm
840                                .fail_task_handle(handle, LustError::RuntimeError { message })?;
841                        }
842                    },
843
844                    AsyncTaskTarget::NativeTask(handle) => {
845                        self.vm.complete_native_future_task(handle, outcome)?;
846                    }
847                }
848            }
849        }
850
851        Ok(())
852    }
853
854    pub fn has_pending_async_tasks(&self) -> bool {
855        !self.async_registry.borrow().is_empty()
856    }
857}
858
859fn compile_in_memory(
860    base_dir: PathBuf,
861    entry_module: String,
862    overrides: HashMap<PathBuf, String>,
863    config: LustConfig,
864    extern_registry: ExternRegistry,
865) -> Result<EmbeddedProgram> {
866    let mut loader = ModuleLoader::new(base_dir.clone());
867    loader.set_source_overrides(overrides);
868    let entry_path = module_path_to_file(&base_dir, &entry_module);
869    let entry_path_str = entry_path
870        .to_str()
871        .ok_or_else(|| LustError::Unknown("Entry path contained invalid UTF-8".into()))?
872        .to_string();
873    let program = loader.load_program_from_entry(&entry_path_str)?;
874    let mut imports_map: HashMap<String, ModuleImports> = HashMap::new();
875    for module in &program.modules {
876        imports_map.insert(module.path.clone(), module.imports.clone());
877    }
878
879    let mut wrapped_items: Vec<Item> = Vec::new();
880    for module in &program.modules {
881        wrapped_items.push(Item::new(
882            ItemKind::Module {
883                name: module.path.clone(),
884                items: module.items.clone(),
885            },
886            Span::new(0, 0, 0, 0),
887        ));
888    }
889
890    let mut typechecker = TypeChecker::with_config(&config);
891    typechecker.set_imports_by_module(imports_map.clone());
892    extern_registry.register_with_typechecker(&mut typechecker)?;
893    typechecker.check_program(&program.modules)?;
894    let option_coercions = typechecker.take_option_coercions();
895    let mut struct_defs = typechecker.struct_definitions();
896    for def in extern_registry.structs() {
897        struct_defs.insert(def.name.clone(), def.clone());
898    }
899    let mut enum_defs = typechecker.enum_definitions();
900    for def in extern_registry.enums() {
901        enum_defs.insert(def.name.clone(), def.clone());
902    }
903    let mut signatures = typechecker.function_signatures();
904    let mut compiler = Compiler::new();
905    compiler.set_option_coercions(option_coercions);
906    compiler.configure_stdlib(&config);
907    compiler.set_imports_by_module(imports_map);
908    compiler.set_entry_module(program.entry_module.clone());
909    compiler.set_function_signatures(signatures.clone());
910    let functions = compiler.compile_module(&wrapped_items)?;
911    let trait_impls = compiler.get_trait_impls().to_vec();
912    let mut init_funcs: Vec<(String, String)> = Vec::new();
913    for module in &program.modules {
914        if module.path != program.entry_module {
915            if let Some(init) = &module.init_function {
916                let init_name = module
917                    .imports
918                    .function_aliases
919                    .get(init)
920                    .cloned()
921                    .unwrap_or_else(|| init.clone());
922                init_funcs.push((module.path.clone(), init_name));
923            }
924        }
925    }
926
927    let function_names: Vec<String> = functions.iter().map(|f| f.name.clone()).collect();
928    let entry_script = function_names
929        .iter()
930        .find(|name| name.as_str() == "__script")
931        .cloned();
932    if let Some(script_name) = &entry_script {
933        signatures
934            .entry(script_name.clone())
935            .or_insert_with(|| FunctionSignature {
936                params: Vec::new(),
937                return_type: Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0)),
938                is_method: false,
939            });
940    }
941
942    let mut vm = VM::with_config(&config);
943    vm.load_functions(functions);
944    vm.register_structs(&struct_defs);
945    extern_registry.register_type_stubs(&mut vm);
946    for (type_name, trait_name) in trait_impls {
947        vm.register_trait_impl(type_name, trait_name);
948    }
949
950    for (module_path, init) in init_funcs {
951        let value = vm.call(&init, Vec::new())?;
952        vm.set_global(module_path, value);
953    }
954
955    Ok(EmbeddedProgram {
956        vm,
957        signatures,
958        struct_defs,
959        enum_defs,
960        entry_script,
961        entry_module: program.entry_module,
962        async_registry: Rc::new(RefCell::new(AsyncRegistry::new())),
963    })
964}
965
966fn module_path_to_file(base_dir: &Path, module_path: &str) -> PathBuf {
967    let mut path = base_dir.to_path_buf();
968    for segment in module_path.split('.') {
969        path.push(segment);
970    }
971
972    path.set_extension("lust");
973    path
974}
975
976pub(crate) fn normalize_global_name(name: &str) -> String {
977    if name.contains("::") {
978        name.to_string()
979    } else if let Some((module, identifier)) = name.rsplit_once('.') {
980        format!("{}::{}", module, identifier)
981    } else {
982        name.to_string()
983    }
984}
985
986pub(crate) fn ensure_return_type<R: FromLustValue>(function_name: &str, ty: &Type) -> Result<()> {
987    if matches!(ty.kind, TypeKind::Unknown) || R::matches_lust_type(ty) {
988        return Ok(());
989    }
990
991    Err(LustError::TypeError {
992        message: format!(
993            "Function '{}' reports return type '{}' which is incompatible with Rust receiver '{}'",
994            function_name,
995            ty,
996            R::type_description()
997        ),
998    })
999}