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}