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