1use crate::ast::{EnumDef, FieldOwnership, Item, ItemKind, Span, StructDef, Type, TypeKind};
2use crate::bytecode::{Compiler, NativeCallResult, TaskHandle, Value};
3use crate::modules::{ModuleImports, ModuleLoader};
4use crate::number::{LustFloat, LustInt};
5use crate::typechecker::{FunctionSignature, TypeChecker};
6use crate::vm::VM;
7use crate::{LustConfig, LustError, Result};
8use hashbrown::HashMap;
9use std::cell::RefCell;
10use std::future::Future;
11use std::path::{Path, PathBuf};
12use std::pin::Pin;
13use std::rc::Rc;
14use std::sync::atomic::{AtomicBool, Ordering};
15use std::sync::Arc;
16use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
17
18type AsyncValueFuture = Pin<Box<dyn Future<Output = std::result::Result<Value, String>>>>;
19
20struct AsyncRegistry {
21 pending: HashMap<u64, AsyncTaskEntry>,
22}
23
24impl AsyncRegistry {
25 fn new() -> Self {
26 Self {
27 pending: HashMap::new(),
28 }
29 }
30
31 fn register(
32 &mut self,
33 handle: TaskHandle,
34 future: AsyncValueFuture,
35 ) -> std::result::Result<(), String> {
36 let key = handle.id();
37 if self.pending.contains_key(&key) {
38 return Err(format!(
39 "Task {} already has a pending async native call",
40 key
41 ));
42 }
43
44 self.pending
45 .insert(key, AsyncTaskEntry::new(handle, future));
46 Ok(())
47 }
48
49 fn is_empty(&self) -> bool {
50 self.pending.is_empty()
51 }
52}
53
54struct AsyncTaskEntry {
55 handle: TaskHandle,
56 future: AsyncValueFuture,
57 wake_flag: Arc<WakeFlag>,
58 immediate_poll: bool,
59}
60
61impl AsyncTaskEntry {
62 fn new(handle: TaskHandle, future: AsyncValueFuture) -> Self {
63 Self {
64 handle,
65 future,
66 wake_flag: Arc::new(WakeFlag::new()),
67 immediate_poll: true,
68 }
69 }
70
71 fn take_should_poll(&mut self) -> bool {
72 if self.immediate_poll {
73 self.immediate_poll = false;
74 true
75 } else {
76 self.wake_flag.take()
77 }
78 }
79
80 fn make_waker(&self) -> Waker {
81 make_async_waker(&self.wake_flag)
82 }
83}
84
85struct WakeFlag {
86 pending: AtomicBool,
87}
88
89impl WakeFlag {
90 fn new() -> Self {
91 Self {
92 pending: AtomicBool::new(true),
93 }
94 }
95
96 fn take(&self) -> bool {
97 self.pending.swap(false, Ordering::SeqCst)
98 }
99
100 fn wake(&self) {
101 self.pending.store(true, Ordering::SeqCst);
102 }
103}
104
105fn make_async_waker(flag: &Arc<WakeFlag>) -> Waker {
106 unsafe {
107 Waker::from_raw(RawWaker::new(
108 Arc::into_raw(flag.clone()) as *const (),
109 &ASYNC_WAKER_VTABLE,
110 ))
111 }
112}
113
114unsafe fn async_waker_clone(ptr: *const ()) -> RawWaker {
115 let arc = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
116 let cloned = arc.clone();
117 std::mem::forget(arc);
118 RawWaker::new(Arc::into_raw(cloned) as *const (), &ASYNC_WAKER_VTABLE)
119}
120
121unsafe fn async_waker_wake(ptr: *const ()) {
122 let arc = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
123 arc.wake();
124}
125
126unsafe fn async_waker_wake_by_ref(ptr: *const ()) {
127 let arc = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
128 arc.wake();
129 std::mem::forget(arc);
130}
131
132unsafe fn async_waker_drop(ptr: *const ()) {
133 let _ = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
134}
135
136static ASYNC_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
137 async_waker_clone,
138 async_waker_wake,
139 async_waker_wake_by_ref,
140 async_waker_drop,
141);
142pub struct EmbeddedBuilder {
143 base_dir: PathBuf,
144 modules: HashMap<String, String>,
145 entry_module: Option<String>,
146 config: LustConfig,
147}
148
149impl Default for EmbeddedBuilder {
150 fn default() -> Self {
151 Self {
152 base_dir: PathBuf::from("__embedded__"),
153 modules: HashMap::new(),
154 entry_module: None,
155 config: LustConfig::default(),
156 }
157 }
158}
159
160impl EmbeddedBuilder {
161 pub fn new() -> Self {
162 Self::default()
163 }
164
165 pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
166 self.set_base_dir(base_dir)
167 }
168
169 pub fn set_base_dir(mut self, base_dir: impl Into<PathBuf>) -> Self {
170 self.base_dir = base_dir.into();
171 self
172 }
173
174 pub fn module(mut self, module_path: impl Into<String>, source: impl Into<String>) -> Self {
175 self.modules.insert(module_path.into(), source.into());
176 self
177 }
178
179 pub fn enable_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
180 self.config.enable_module(module);
181 self
182 }
183
184 pub fn add_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
185 self.config.enable_module(module);
186 self
187 }
188
189 pub fn with_config(mut self, config: LustConfig) -> Self {
190 self.config = config;
191 self
192 }
193
194 pub fn set_config(mut self, config: LustConfig) -> Self {
195 self.config = config;
196 self
197 }
198
199 pub fn add_module(
200 &mut self,
201 module_path: impl Into<String>,
202 source: impl Into<String>,
203 ) -> &mut Self {
204 self.modules.insert(module_path.into(), source.into());
205 self
206 }
207
208 pub fn entry_module(mut self, module_path: impl Into<String>) -> Self {
209 self.set_entry_module(module_path);
210 self
211 }
212
213 pub fn set_entry_module(&mut self, module_path: impl Into<String>) -> &mut Self {
214 self.entry_module = Some(module_path.into());
215 self
216 }
217
218 pub fn compile(self) -> Result<EmbeddedProgram> {
219 let entry_module = self
220 .entry_module
221 .ok_or_else(|| LustError::Unknown("No entry module configured for embedding".into()))?;
222 let has_entry = self.modules.contains_key(&entry_module);
223 if !has_entry {
224 return Err(LustError::Unknown(format!(
225 "Entry module '{}' was not provided via EmbeddedBuilder::module",
226 entry_module
227 )));
228 }
229
230 let overrides: HashMap<PathBuf, String> = self
231 .modules
232 .into_iter()
233 .map(|(module, source)| (module_path_to_file(&self.base_dir, &module), source))
234 .collect();
235 compile_in_memory(self.base_dir, entry_module, overrides, self.config)
236 }
237}
238
239pub struct EmbeddedProgram {
240 vm: VM,
241 signatures: HashMap<String, FunctionSignature>,
242 struct_defs: HashMap<String, StructDef>,
243 enum_defs: HashMap<String, EnumDef>,
244 entry_script: Option<String>,
245 entry_module: String,
246 async_registry: Rc<RefCell<AsyncRegistry>>,
247}
248
249impl EmbeddedProgram {
250 pub fn builder() -> EmbeddedBuilder {
251 EmbeddedBuilder::default()
252 }
253
254 pub fn vm_mut(&mut self) -> &mut VM {
255 &mut self.vm
256 }
257
258 pub fn global_names(&self) -> Vec<String> {
259 self.vm.global_names()
260 }
261
262 pub fn globals(&self) -> Vec<(String, Value)> {
263 self.vm.globals_snapshot()
264 }
265
266 pub fn signature(&self, function_name: &str) -> Option<&FunctionSignature> {
267 self.find_signature(function_name).map(|(_, sig)| sig)
268 }
269
270 pub fn typed_functions(&self) -> impl Iterator<Item = (&String, &FunctionSignature)> {
271 self.signatures.iter()
272 }
273
274 pub fn struct_definition(&self, type_name: &str) -> Option<&StructDef> {
275 self.struct_defs.get(type_name)
276 }
277
278 pub fn enum_definition(&self, type_name: &str) -> Option<&EnumDef> {
279 self.enum_defs.get(type_name)
280 }
281
282 fn find_signature(&self, name: &str) -> Option<(String, &FunctionSignature)> {
283 if let Some(sig) = self.signatures.get(name) {
284 return Some((name.to_string(), sig));
285 }
286
287 for candidate in self.signature_lookup_candidates(name) {
288 if let Some(sig) = self.signatures.get(&candidate) {
289 return Some((candidate, sig));
290 }
291 }
292
293 let matches = self
294 .signatures
295 .iter()
296 .filter_map(|(key, sig)| {
297 if Self::simple_name(key) == name {
298 Some((key, sig))
299 } else {
300 None
301 }
302 })
303 .collect::<Vec<_>>();
304 if matches.len() == 1 {
305 let (key, sig) = matches[0];
306 return Some((key.clone(), sig));
307 }
308
309 None
310 }
311
312 fn resolve_signature(&self, name: &str) -> Result<(String, &FunctionSignature)> {
313 if let Some(found) = self.find_signature(name) {
314 return Ok(found);
315 }
316
317 let matches = self
318 .signatures
319 .keys()
320 .filter(|key| Self::simple_name(key) == name)
321 .count();
322 if matches > 1 {
323 return Err(LustError::TypeError {
324 message: format!(
325 "Cannot register native '{}': multiple matching functions found; specify a fully qualified name",
326 name
327 ),
328 });
329 }
330
331 Err(LustError::TypeError {
332 message: format!(
333 "Cannot register native '{}': function not declared in Lust source",
334 name
335 ),
336 })
337 }
338
339 fn signature_lookup_candidates(&self, name: &str) -> Vec<String> {
340 let mut candidates: Vec<String> = Vec::new();
341 if name.contains("::") {
342 candidates.push(name.replace("::", "."));
343 }
344
345 if name.contains('.') {
346 candidates.push(name.replace('.', "::"));
347 }
348
349 if !name.contains('.') && !name.contains("::") {
350 let module = &self.entry_module;
351 candidates.push(format!("{}.{}", module, name));
352 candidates.push(format!("{}::{}", module, name));
353 }
354
355 candidates
356 }
357
358 fn simple_name(name: &str) -> &str {
359 name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
360 }
361
362 fn register_native_with_aliases<F>(&mut self, requested_name: &str, canonical: String, func: F)
363 where
364 F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
365 {
366 let native_fn: Rc<dyn Fn(&[Value]) -> std::result::Result<NativeCallResult, String>> =
367 Rc::new(func);
368 let value = Value::NativeFunction(native_fn);
369 let mut aliases: Vec<String> = Vec::new();
370 aliases.push(canonical.clone());
371 let canonical_normalized = normalize_global_name(&canonical);
372 if canonical_normalized != canonical {
373 aliases.push(canonical_normalized);
374 }
375
376 if requested_name != canonical {
377 aliases.push(requested_name.to_string());
378 let normalized = normalize_global_name(requested_name);
379 if normalized != requested_name {
380 aliases.push(normalized);
381 }
382 }
383
384 aliases.sort();
385 aliases.dedup();
386 for key in aliases {
387 self.vm.register_native(key, value.clone());
388 }
389 }
390
391 pub fn get_global_value(&self, name: &str) -> Option<Value> {
392 let normalized = normalize_global_name(name);
393 self.vm.get_global(&normalized)
394 }
395
396 pub fn get_typed_global<T: FromLustValue>(&self, name: &str) -> Result<Option<T>> {
397 let normalized = normalize_global_name(name);
398 match self.vm.get_global(&normalized) {
399 Some(value) => T::from_value(value).map(Some),
400 None => Ok(None),
401 }
402 }
403
404 pub fn set_global_value<V: IntoTypedValue>(&mut self, name: impl Into<String>, value: V) {
405 let name_string = name.into();
406 let normalized = normalize_global_name(&name_string);
407 let value = value.into_typed_value().into_value();
408 self.vm.set_global(normalized, value);
409 }
410
411 pub fn struct_instance<I>(
412 &self,
413 type_name: impl Into<String>,
414 fields: I,
415 ) -> Result<StructInstance>
416 where
417 I: IntoIterator,
418 I::Item: Into<StructField>,
419 {
420 let type_name = type_name.into();
421 let def = self
422 .struct_defs
423 .get(&type_name)
424 .ok_or_else(|| LustError::TypeError {
425 message: format!("Unknown struct '{}'", type_name),
426 })?;
427 let mut provided: HashMap<String, TypedValue> = fields
428 .into_iter()
429 .map(|field| {
430 let field: StructField = field.into();
431 field.into_parts()
432 })
433 .collect();
434 let mut ordered_fields: Vec<(Rc<String>, Value)> = Vec::with_capacity(def.fields.len());
435 for field in &def.fields {
436 let typed_value = provided
437 .remove(&field.name)
438 .ok_or_else(|| LustError::TypeError {
439 message: format!(
440 "Struct '{}' is missing required field '{}'",
441 type_name, field.name
442 ),
443 })?;
444 let matches_declared = typed_value.matches(&field.ty);
445 let matches_ref_inner = matches!(field.ownership, FieldOwnership::Weak)
446 && field
447 .weak_target
448 .as_ref()
449 .map(|inner| typed_value.matches(inner))
450 .unwrap_or(false);
451 if !(matches_declared || matches_ref_inner) {
452 return Err(LustError::TypeError {
453 message: format!(
454 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
455 type_name,
456 field.name,
457 field.ty,
458 typed_value.description()
459 ),
460 });
461 }
462
463 ordered_fields.push((Rc::new(field.name.clone()), typed_value.into_value()));
464 }
465
466 if !provided.is_empty() {
467 let extra = provided.keys().cloned().collect::<Vec<_>>().join(", ");
468 return Err(LustError::TypeError {
469 message: format!(
470 "Struct '{}' received unknown field(s): {}",
471 type_name, extra
472 ),
473 });
474 }
475
476 let value = self.vm.instantiate_struct(&type_name, ordered_fields)?;
477 Ok(StructInstance::new(type_name.clone(), value))
478 }
479
480 pub fn enum_variant(
481 &self,
482 type_name: impl Into<String>,
483 variant: impl Into<String>,
484 ) -> Result<EnumInstance> {
485 self.enum_variant_with(type_name, variant, std::iter::empty::<Value>())
486 }
487
488 pub fn enum_variant_with<I, V>(
489 &self,
490 type_name: impl Into<String>,
491 variant: impl Into<String>,
492 payload: I,
493 ) -> Result<EnumInstance>
494 where
495 I: IntoIterator<Item = V>,
496 V: IntoTypedValue,
497 {
498 let type_name = type_name.into();
499 let variant_name = variant.into();
500 let def = self
501 .enum_defs
502 .get(&type_name)
503 .ok_or_else(|| LustError::TypeError {
504 message: format!("Unknown enum '{}'", type_name),
505 })?;
506 let enum_variant = def
507 .variants
508 .iter()
509 .find(|v| v.name == variant_name)
510 .ok_or_else(|| LustError::TypeError {
511 message: format!(
512 "Enum '{}' has no variant named '{}'",
513 type_name, variant_name
514 ),
515 })?;
516 let mut values: Vec<TypedValue> =
517 payload.into_iter().map(|v| v.into_typed_value()).collect();
518 let coerced_values: Option<Rc<Vec<Value>>> = match &enum_variant.fields {
519 None => {
520 if !values.is_empty() {
521 return Err(LustError::TypeError {
522 message: format!(
523 "Enum variant '{}.{}' does not accept payload values",
524 type_name, variant_name
525 ),
526 });
527 }
528
529 None
530 }
531
532 Some(field_types) => {
533 if values.len() != field_types.len() {
534 return Err(LustError::TypeError {
535 message: format!(
536 "Enum variant '{}.{}' expects {} value(s) but {} were supplied",
537 type_name,
538 variant_name,
539 field_types.len(),
540 values.len()
541 ),
542 });
543 }
544
545 let mut collected = Vec::with_capacity(field_types.len());
546 for (idx, (typed_value, field_ty)) in
547 values.drain(..).zip(field_types.iter()).enumerate()
548 {
549 if !typed_value.matches(field_ty) {
550 return Err(LustError::TypeError {
551 message: format!(
552 "Enum variant '{}.{}' field {} expects Lust type '{}' but Rust provided '{}'",
553 type_name,
554 variant_name,
555 idx + 1,
556 field_ty,
557 typed_value.description()
558 ),
559 });
560 }
561
562 collected.push(typed_value.into_value());
563 }
564
565 Some(Rc::new(collected))
566 }
567 };
568 Ok(EnumInstance::new(
569 type_name.clone(),
570 variant_name.clone(),
571 Value::Enum {
572 enum_name: type_name,
573 variant: variant_name,
574 values: coerced_values,
575 },
576 ))
577 }
578
579 pub fn register_native_fn<F>(&mut self, name: impl Into<String>, func: F)
580 where
581 F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
582 {
583 let native = Value::NativeFunction(Rc::new(func));
584 self.vm.register_native(name, native);
585 }
586
587 pub fn register_async_native<F, Fut>(&mut self, name: impl Into<String>, func: F) -> Result<()>
588 where
589 F: Fn(Vec<Value>) -> Fut + 'static,
590 Fut: Future<Output = std::result::Result<Value, String>> + 'static,
591 {
592 let registry = self.async_registry.clone();
593 let name_string = name.into();
594 let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
595 let args: Vec<Value> = values.iter().cloned().collect();
596 let future: AsyncValueFuture = Box::pin(func(args));
597 VM::with_current(|vm| {
598 let handle = vm
599 .current_task_handle()
600 .ok_or_else(|| "Async native functions require a running task".to_string())?;
601 registry.borrow_mut().register(handle, future)?;
602 Ok(NativeCallResult::Yield(Value::Nil))
603 })
604 };
605 self.register_native_fn(name_string, handler);
606 Ok(())
607 }
608
609 pub fn register_typed_native<Args, R, F>(&mut self, name: &str, func: F) -> Result<()>
610 where
611 Args: FromLustArgs,
612 R: IntoLustValue + FromLustValue,
613 F: Fn(Args) -> std::result::Result<R, String> + 'static,
614 {
615 let (canonical, signature) = self.resolve_signature(name)?;
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 ensure_return_type::<R>(name, &signature.return_type)?;
626 let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
627 let args = Args::from_values(values)?;
628 let result = func(args)?;
629 Ok(NativeCallResult::Return(result.into_value()))
630 };
631 self.register_native_with_aliases(name, canonical, handler);
632 Ok(())
633 }
634
635 pub fn register_async_typed_native<Args, R, F, Fut>(
636 &mut self,
637 name: &str,
638 func: F,
639 ) -> Result<()>
640 where
641 Args: FromLustArgs,
642 R: IntoLustValue + FromLustValue,
643 F: Fn(Args) -> Fut + 'static,
644 Fut: Future<Output = std::result::Result<R, String>> + 'static,
645 {
646 let (canonical, signature) = self.resolve_signature(name)?;
647 let signature = signature.clone();
648 if !Args::matches_signature(&signature.params) {
649 return Err(LustError::TypeError {
650 message: format!(
651 "Native '{}' argument types do not match Lust signature",
652 name
653 ),
654 });
655 }
656
657 ensure_return_type::<R>(name, &signature.return_type)?;
658 let registry = self.async_registry.clone();
659 let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
660 let args = Args::from_values(values)?;
661 let future = func(args);
662 let mapped = async move {
663 match future.await {
664 Ok(result) => Ok(result.into_value()),
665 Err(err) => Err(err),
666 }
667 };
668 let future: AsyncValueFuture = Box::pin(mapped);
669 VM::with_current(|vm| {
670 let handle = vm
671 .current_task_handle()
672 .ok_or_else(|| "Async native functions require a running task".to_string())?;
673 registry.borrow_mut().register(handle, future)?;
674 Ok(NativeCallResult::Yield(Value::Nil))
675 })
676 };
677 self.register_native_with_aliases(name, canonical, handler);
678 Ok(())
679 }
680
681 pub fn call_typed<Args, R>(&mut self, function_name: &str, args: Args) -> Result<R>
682 where
683 Args: FunctionArgs,
684 R: FromLustValue,
685 {
686 let signature = self
687 .signatures
688 .get(function_name)
689 .ok_or_else(|| LustError::TypeError {
690 message: format!(
691 "No type information available for function '{}'; \
692 use call_raw if the function is dynamically typed",
693 function_name
694 ),
695 })?;
696 Args::validate_signature(function_name, &signature.params)?;
697 ensure_return_type::<R>(function_name, &signature.return_type)?;
698 let values = args.into_values();
699 let value = self.vm.call(function_name, values)?;
700 R::from_value(value)
701 }
702
703 pub fn call_raw(&mut self, function_name: &str, args: Vec<Value>) -> Result<Value> {
704 self.vm.call(function_name, args)
705 }
706
707 pub fn run_entry_script(&mut self) -> Result<()> {
708 let Some(entry) = &self.entry_script else {
709 return Err(LustError::RuntimeError {
710 message: "Embedded program has no entry script".into(),
711 });
712 };
713 let result = self.vm.call(entry, Vec::new())?;
714 match result {
715 Value::Nil => Ok(()),
716 other => Err(LustError::RuntimeError {
717 message: format!(
718 "Entry script '{}' returned non-unit value: {:?}",
719 entry, other
720 ),
721 }),
722 }
723 }
724
725 pub fn poll_async_tasks(&mut self) -> Result<()> {
726 let pending_ids: Vec<u64> = {
727 let registry = self.async_registry.borrow();
728 registry.pending.keys().copied().collect()
729 };
730
731 let mut completions: Vec<(TaskHandle, std::result::Result<Value, String>)> = Vec::new();
732 for id in pending_ids {
733 let handle = TaskHandle(id);
734 if self.vm.get_task_instance(handle).is_err() {
735 self.async_registry.borrow_mut().pending.remove(&id);
736 continue;
737 }
738
739 let maybe_outcome = {
740 let mut registry = self.async_registry.borrow_mut();
741 let entry = match registry.pending.get_mut(&id) {
742 Some(entry) => entry,
743 None => continue,
744 };
745
746 if !entry.take_should_poll() {
747 continue;
748 }
749
750 let waker = entry.make_waker();
751 let mut cx = Context::from_waker(&waker);
752 match entry.future.as_mut().poll(&mut cx) {
753 Poll::Ready(result) => {
754 let handle = entry.handle;
755 registry.pending.remove(&id);
756 Some((handle, result))
757 }
758
759 Poll::Pending => None,
760 }
761 };
762
763 if let Some(outcome) = maybe_outcome {
764 completions.push(outcome);
765 }
766 }
767
768 for (handle, outcome) in completions {
769 match outcome {
770 Ok(value) => {
771 self.vm.resume_task_handle(handle, Some(value))?;
772 }
773
774 Err(message) => {
775 self.vm
776 .fail_task_handle(handle, LustError::RuntimeError { message })?;
777 }
778 }
779 }
780
781 Ok(())
782 }
783
784 pub fn has_pending_async_tasks(&self) -> bool {
785 !self.async_registry.borrow().is_empty()
786 }
787}
788
789fn compile_in_memory(
790 base_dir: PathBuf,
791 entry_module: String,
792 overrides: HashMap<PathBuf, String>,
793 config: LustConfig,
794) -> Result<EmbeddedProgram> {
795 let mut loader = ModuleLoader::new(base_dir.clone());
796 loader.set_source_overrides(overrides);
797 let entry_path = module_path_to_file(&base_dir, &entry_module);
798 let entry_path_str = entry_path
799 .to_str()
800 .ok_or_else(|| LustError::Unknown("Entry path contained invalid UTF-8".into()))?
801 .to_string();
802 let program = loader.load_program_from_entry(&entry_path_str)?;
803 let mut imports_map: HashMap<String, ModuleImports> = HashMap::new();
804 for module in &program.modules {
805 imports_map.insert(module.path.clone(), module.imports.clone());
806 }
807
808 let mut wrapped_items: Vec<Item> = Vec::new();
809 for module in &program.modules {
810 wrapped_items.push(Item::new(
811 ItemKind::Module {
812 name: module.path.clone(),
813 items: module.items.clone(),
814 },
815 Span::new(0, 0, 0, 0),
816 ));
817 }
818
819 let mut typechecker = TypeChecker::with_config(&config);
820 typechecker.set_imports_by_module(imports_map.clone());
821 typechecker.check_program(&program.modules)?;
822 let struct_defs = typechecker.struct_definitions();
823 let enum_defs = typechecker.enum_definitions();
824 let mut signatures = typechecker.function_signatures();
825 let mut compiler = Compiler::new();
826 compiler.configure_stdlib(&config);
827 compiler.set_imports_by_module(imports_map);
828 compiler.set_entry_module(program.entry_module.clone());
829 let functions = compiler.compile_module(&wrapped_items)?;
830 let trait_impls = compiler.get_trait_impls().to_vec();
831 let mut init_funcs = Vec::new();
832 for module in &program.modules {
833 if module.path != program.entry_module {
834 if let Some(init) = &module.init_function {
835 init_funcs.push(init.clone());
836 }
837 }
838 }
839
840 let function_names: Vec<String> = functions.iter().map(|f| f.name.clone()).collect();
841 let entry_script = function_names
842 .iter()
843 .find(|name| name.as_str() == "__script")
844 .cloned();
845 if let Some(script_name) = &entry_script {
846 signatures
847 .entry(script_name.clone())
848 .or_insert_with(|| FunctionSignature {
849 params: Vec::new(),
850 return_type: Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0)),
851 is_method: false,
852 });
853 }
854
855 let mut vm = VM::with_config(&config);
856 vm.load_functions(functions);
857 vm.register_structs(&struct_defs);
858 for (type_name, trait_name) in trait_impls {
859 vm.register_trait_impl(type_name, trait_name);
860 }
861
862 for init in init_funcs {
863 vm.call(&init, Vec::new())?;
864 }
865
866 Ok(EmbeddedProgram {
867 vm,
868 signatures,
869 struct_defs,
870 enum_defs,
871 entry_script,
872 entry_module: program.entry_module,
873 async_registry: Rc::new(RefCell::new(AsyncRegistry::new())),
874 })
875}
876
877fn module_path_to_file(base_dir: &Path, module_path: &str) -> PathBuf {
878 let mut path = base_dir.to_path_buf();
879 for segment in module_path.split('.') {
880 path.push(segment);
881 }
882
883 path.set_extension("lust");
884 path
885}
886
887fn normalize_global_name(name: &str) -> String {
888 if name.contains("::") {
889 name.to_string()
890 } else if let Some((module, identifier)) = name.rsplit_once('.') {
891 format!("{}::{}", module, identifier)
892 } else {
893 name.to_string()
894 }
895}
896
897fn ensure_return_type<R: FromLustValue>(function_name: &str, ty: &Type) -> Result<()> {
898 if matches!(ty.kind, TypeKind::Unknown) || R::matches_lust_type(ty) {
899 return Ok(());
900 }
901
902 Err(LustError::TypeError {
903 message: format!(
904 "Function '{}' reports return type '{}' which is incompatible with Rust receiver '{}'",
905 function_name,
906 ty,
907 R::type_description()
908 ),
909 })
910}
911
912pub struct TypedValue {
913 value: Value,
914 matcher: Box<dyn Fn(&Value, &Type) -> bool>,
915 description: &'static str,
916}
917
918impl TypedValue {
919 fn new<F>(value: Value, matcher: F, description: &'static str) -> Self
920 where
921 F: Fn(&Value, &Type) -> bool + 'static,
922 {
923 Self {
924 value,
925 matcher: Box::new(matcher),
926 description,
927 }
928 }
929
930 fn matches(&self, ty: &Type) -> bool {
931 match &ty.kind {
932 TypeKind::Union(types) => types.iter().any(|alt| (self.matcher)(&self.value, alt)),
933 _ => (self.matcher)(&self.value, ty),
934 }
935 }
936
937 fn description(&self) -> &'static str {
938 self.description
939 }
940
941 fn into_value(self) -> Value {
942 self.value
943 }
944}
945
946pub struct StructField {
947 name: String,
948 value: TypedValue,
949}
950
951impl StructField {
952 pub fn new(name: impl Into<String>, value: impl IntoTypedValue) -> Self {
953 Self {
954 name: name.into(),
955 value: value.into_typed_value(),
956 }
957 }
958
959 pub fn name(&self) -> &str {
960 &self.name
961 }
962
963 fn into_parts(self) -> (String, TypedValue) {
964 (self.name, self.value)
965 }
966}
967
968pub fn struct_field(name: impl Into<String>, value: impl IntoTypedValue) -> StructField {
969 StructField::new(name, value)
970}
971
972impl<K, V> From<(K, V)> for StructField
973where
974 K: Into<String>,
975 V: IntoTypedValue,
976{
977 fn from((name, value): (K, V)) -> Self {
978 StructField::new(name, value)
979 }
980}
981
982#[derive(Clone)]
983pub struct StructInstance {
984 type_name: String,
985 value: Value,
986}
987
988impl StructInstance {
989 fn new(type_name: String, value: Value) -> Self {
990 debug_assert!(matches!(value, Value::Struct { .. }));
991 Self { type_name, value }
992 }
993
994 pub fn type_name(&self) -> &str {
995 &self.type_name
996 }
997
998 pub fn field<T: FromLustValue>(&self, field: &str) -> Result<T> {
999 match &self.value {
1000 Value::Struct { layout, fields, .. } => {
1001 let index = layout
1002 .index_of_str(field)
1003 .ok_or_else(|| LustError::RuntimeError {
1004 message: format!(
1005 "Struct '{}' has no field named '{}'",
1006 self.type_name, field
1007 ),
1008 })?;
1009 let stored =
1010 fields
1011 .borrow()
1012 .get(index)
1013 .cloned()
1014 .ok_or_else(|| LustError::RuntimeError {
1015 message: format!(
1016 "Struct '{}' field '{}' is unavailable",
1017 self.type_name, field
1018 ),
1019 })?;
1020 let materialized = layout.materialize_field_value(index, stored);
1021 T::from_value(materialized)
1022 }
1023
1024 _ => Err(LustError::RuntimeError {
1025 message: "StructInstance does not contain a struct value".to_string(),
1026 }),
1027 }
1028 }
1029
1030 pub fn set_field<V: IntoTypedValue>(&self, field: &str, value: V) -> Result<()> {
1031 match &self.value {
1032 Value::Struct { layout, fields, .. } => {
1033 let index = layout
1034 .index_of_str(field)
1035 .ok_or_else(|| LustError::RuntimeError {
1036 message: format!(
1037 "Struct '{}' has no field named '{}'",
1038 self.type_name, field
1039 ),
1040 })?;
1041 let typed_value = value.into_typed_value();
1042 let matches_declared = typed_value.matches(layout.field_type(index));
1043 let matches_ref_inner = layout.is_weak(index)
1044 && layout
1045 .weak_target(index)
1046 .map(|inner| typed_value.matches(inner))
1047 .unwrap_or(false);
1048 if !(matches_declared || matches_ref_inner) {
1049 return Err(LustError::TypeError {
1050 message: format!(
1051 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
1052 self.type_name,
1053 field,
1054 layout.field_type(index),
1055 typed_value.description()
1056 ),
1057 });
1058 }
1059
1060 let canonical_value = layout
1061 .canonicalize_field_value(index, typed_value.into_value())
1062 .map_err(|message| LustError::TypeError { message })?;
1063 fields.borrow_mut()[index] = canonical_value;
1064 Ok(())
1065 }
1066
1067 _ => Err(LustError::RuntimeError {
1068 message: "StructInstance does not contain a struct value".to_string(),
1069 }),
1070 }
1071 }
1072
1073 pub fn update_field<F, V>(&self, field: &str, update: F) -> Result<()>
1074 where
1075 F: FnOnce(Value) -> Result<V>,
1076 V: IntoTypedValue,
1077 {
1078 match &self.value {
1079 Value::Struct { layout, fields, .. } => {
1080 let index = layout
1081 .index_of_str(field)
1082 .ok_or_else(|| LustError::RuntimeError {
1083 message: format!(
1084 "Struct '{}' has no field named '{}'",
1085 self.type_name, field
1086 ),
1087 })?;
1088 let mut slots = fields.borrow_mut();
1089 let slot = slots
1090 .get_mut(index)
1091 .ok_or_else(|| LustError::RuntimeError {
1092 message: format!(
1093 "Struct '{}' field '{}' is unavailable",
1094 self.type_name, field
1095 ),
1096 })?;
1097 let fallback = slot.clone();
1098 let current_canonical = std::mem::replace(slot, Value::Nil);
1099 let current_materialized = layout.materialize_field_value(index, current_canonical);
1100 let updated = match update(current_materialized) {
1101 Ok(value) => value,
1102 Err(err) => {
1103 *slot = fallback;
1104 return Err(err);
1105 }
1106 };
1107 let typed_value = updated.into_typed_value();
1108 let matches_declared = typed_value.matches(layout.field_type(index));
1109 let matches_ref_inner = layout.is_weak(index)
1110 && layout
1111 .weak_target(index)
1112 .map(|inner| typed_value.matches(inner))
1113 .unwrap_or(false);
1114 if !(matches_declared || matches_ref_inner) {
1115 *slot = fallback;
1116 return Err(LustError::TypeError {
1117 message: format!(
1118 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
1119 self.type_name,
1120 field,
1121 layout.field_type(index),
1122 typed_value.description()
1123 ),
1124 });
1125 }
1126
1127 let canonical_value = layout
1128 .canonicalize_field_value(index, typed_value.into_value())
1129 .map_err(|message| LustError::TypeError { message })?;
1130 *slot = canonical_value;
1131 Ok(())
1132 }
1133
1134 _ => Err(LustError::RuntimeError {
1135 message: "StructInstance does not contain a struct value".to_string(),
1136 }),
1137 }
1138 }
1139
1140 pub fn as_value(&self) -> &Value {
1141 &self.value
1142 }
1143}
1144
1145#[derive(Clone)]
1146pub struct EnumInstance {
1147 type_name: String,
1148 variant: String,
1149 value: Value,
1150}
1151
1152impl EnumInstance {
1153 fn new(type_name: String, variant: String, value: Value) -> Self {
1154 debug_assert!(matches!(value, Value::Enum { .. }));
1155 Self {
1156 type_name,
1157 variant,
1158 value,
1159 }
1160 }
1161
1162 pub fn type_name(&self) -> &str {
1163 &self.type_name
1164 }
1165
1166 pub fn variant(&self) -> &str {
1167 &self.variant
1168 }
1169
1170 pub fn payload_len(&self) -> usize {
1171 match &self.value {
1172 Value::Enum { values, .. } => values.as_ref().map(|v| v.len()).unwrap_or(0),
1173 _ => 0,
1174 }
1175 }
1176
1177 pub fn payload<T: FromLustValue>(&self, index: usize) -> Result<T> {
1178 match &self.value {
1179 Value::Enum { values, .. } => {
1180 let values = values.as_ref().ok_or_else(|| LustError::RuntimeError {
1181 message: format!(
1182 "Enum variant '{}.{}' carries no payload",
1183 self.type_name, self.variant
1184 ),
1185 })?;
1186 let stored = values
1187 .get(index)
1188 .cloned()
1189 .ok_or_else(|| LustError::RuntimeError {
1190 message: format!(
1191 "Enum variant '{}.{}' payload index {} is out of bounds",
1192 self.type_name, self.variant, index
1193 ),
1194 })?;
1195 T::from_value(stored)
1196 }
1197
1198 _ => Err(LustError::RuntimeError {
1199 message: "EnumInstance does not contain an enum value".to_string(),
1200 }),
1201 }
1202 }
1203
1204 pub fn as_value(&self) -> &Value {
1205 &self.value
1206 }
1207}
1208
1209pub trait IntoTypedValue {
1210 fn into_typed_value(self) -> TypedValue;
1211}
1212
1213impl IntoTypedValue for Value {
1214 fn into_typed_value(self) -> TypedValue {
1215 TypedValue::new(self, |_value, _ty| true, "Value")
1216 }
1217}
1218
1219impl IntoTypedValue for StructInstance {
1220 fn into_typed_value(self) -> TypedValue {
1221 let StructInstance {
1222 type_name: _,
1223 value,
1224 } = self;
1225 TypedValue::new(value, |v, ty| matches_lust_struct(v, ty), "struct")
1226 }
1227}
1228
1229impl IntoTypedValue for EnumInstance {
1230 fn into_typed_value(self) -> TypedValue {
1231 let EnumInstance {
1232 type_name: _,
1233 variant: _,
1234 value,
1235 } = self;
1236 TypedValue::new(value, |v, ty| matches_lust_enum(v, ty), "enum")
1237 }
1238}
1239
1240macro_rules! impl_into_typed_for_primitive {
1241 ($ty:ty, $desc:expr, $matcher:expr) => {
1242 impl IntoTypedValue for $ty {
1243 fn into_typed_value(self) -> TypedValue {
1244 let value = self.into_value();
1245 TypedValue::new(value, $matcher, $desc)
1246 }
1247 }
1248 };
1249}
1250
1251impl_into_typed_for_primitive!(LustInt, "int", |_, ty: &Type| match &ty.kind {
1252 TypeKind::Int | TypeKind::Unknown => true,
1253 TypeKind::Union(types) => types
1254 .iter()
1255 .any(|alt| matches!(&alt.kind, TypeKind::Int | TypeKind::Unknown)),
1256 _ => false,
1257});
1258impl_into_typed_for_primitive!(LustFloat, "float", |_, ty: &Type| match &ty.kind {
1259 TypeKind::Float | TypeKind::Unknown => true,
1260 TypeKind::Union(types) => types
1261 .iter()
1262 .any(|alt| matches!(&alt.kind, TypeKind::Float | TypeKind::Unknown)),
1263 _ => false,
1264});
1265impl_into_typed_for_primitive!(bool, "bool", |_, ty: &Type| match &ty.kind {
1266 TypeKind::Bool | TypeKind::Unknown => true,
1267 TypeKind::Union(types) => types
1268 .iter()
1269 .any(|alt| matches!(&alt.kind, TypeKind::Bool | TypeKind::Unknown)),
1270 _ => false,
1271});
1272impl IntoTypedValue for String {
1273 fn into_typed_value(self) -> TypedValue {
1274 let value = self.into_value();
1275 TypedValue::new(value, string_matcher, "string")
1276 }
1277}
1278
1279impl<'a> IntoTypedValue for &'a str {
1280 fn into_typed_value(self) -> TypedValue {
1281 let value = self.into_value();
1282 TypedValue::new(value, string_matcher, "string")
1283 }
1284}
1285
1286impl<'a> IntoTypedValue for &'a String {
1287 fn into_typed_value(self) -> TypedValue {
1288 let value = self.into_value();
1289 TypedValue::new(value, string_matcher, "string")
1290 }
1291}
1292
1293impl IntoTypedValue for () {
1294 fn into_typed_value(self) -> TypedValue {
1295 TypedValue::new(
1296 Value::Nil,
1297 |_, ty| matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown),
1298 "unit",
1299 )
1300 }
1301}
1302
1303impl<T> IntoTypedValue for Vec<T>
1304where
1305 T: IntoLustValue,
1306{
1307 fn into_typed_value(self) -> TypedValue {
1308 let values = self.into_iter().map(|item| item.into_value()).collect();
1309 TypedValue::new(
1310 Value::array(values),
1311 |_, ty| matches_array_type(ty, &T::matches_lust_type),
1312 "array",
1313 )
1314 }
1315}
1316
1317fn string_matcher(_: &Value, ty: &Type) -> bool {
1318 match &ty.kind {
1319 TypeKind::String | TypeKind::Unknown => true,
1320 TypeKind::Union(types) => types
1321 .iter()
1322 .any(|alt| matches!(&alt.kind, TypeKind::String | TypeKind::Unknown)),
1323 _ => false,
1324 }
1325}
1326
1327#[cfg(test)]
1328mod tests {
1329 use super::*;
1330 use std::future::Future;
1331 use std::pin::Pin;
1332 use std::sync::{Arc, Mutex};
1333 use std::task::{Context, Poll, Waker};
1334
1335 #[derive(Default)]
1336 struct ManualAsyncState {
1337 result: Mutex<Option<std::result::Result<LustInt, String>>>,
1338 waker: Mutex<Option<Waker>>,
1339 }
1340
1341 impl ManualAsyncState {
1342 fn new() -> Arc<Self> {
1343 Arc::new(Self::default())
1344 }
1345
1346 fn future(self: &Arc<Self>) -> ManualFuture {
1347 ManualFuture {
1348 state: Arc::clone(self),
1349 }
1350 }
1351
1352 fn complete_ok(&self, value: LustInt) {
1353 self.complete(Ok(value));
1354 }
1355
1356 fn complete_err(&self, message: impl Into<String>) {
1357 self.complete(Err(message.into()));
1358 }
1359
1360 fn complete(&self, value: std::result::Result<LustInt, String>) {
1361 {
1362 let mut slot = self.result.lock().unwrap();
1363 *slot = Some(value);
1364 }
1365
1366 if let Some(waker) = self.waker.lock().unwrap().take() {
1367 waker.wake();
1368 }
1369 }
1370 }
1371
1372 struct ManualFuture {
1373 state: Arc<ManualAsyncState>,
1374 }
1375
1376 impl Future for ManualFuture {
1377 type Output = std::result::Result<LustInt, String>;
1378
1379 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1380 {
1381 let mut slot = self.state.result.lock().unwrap();
1382 if let Some(result) = slot.take() {
1383 return Poll::Ready(result);
1384 }
1385 }
1386
1387 let mut waker_slot = self.state.waker.lock().unwrap();
1388 *waker_slot = Some(cx.waker().clone());
1389 Poll::Pending
1390 }
1391 }
1392
1393 fn build_program(source: &str) -> EmbeddedProgram {
1394 EmbeddedProgram::builder()
1395 .module("main", source)
1396 .entry_module("main")
1397 .compile()
1398 .expect("compile embedded program")
1399 }
1400
1401 #[test]
1402 fn struct_instance_supports_mixed_field_types() {
1403 let source = r#"
1404 struct Mixed
1405 count: int
1406 label: string
1407 enabled: bool
1408 end
1409 "#;
1410
1411 let program = build_program(source);
1412 let mixed = program
1413 .struct_instance(
1414 "main.Mixed",
1415 [
1416 struct_field("count", 7_i64),
1417 struct_field("label", "hi"),
1418 struct_field("enabled", true),
1419 ],
1420 )
1421 .expect("struct instance");
1422
1423 assert_eq!(mixed.field::<i64>("count").expect("count field"), 7);
1424 assert_eq!(mixed.field::<String>("label").expect("label field"), "hi");
1425 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1426 }
1427
1428 #[test]
1429 fn struct_instance_allows_setting_fields() {
1430 let source = r#"
1431 struct Mixed
1432 count: int
1433 label: string
1434 enabled: bool
1435 end
1436 "#;
1437
1438 let program = build_program(source);
1439 let mixed = program
1440 .struct_instance(
1441 "main.Mixed",
1442 [
1443 struct_field("count", 1_i64),
1444 struct_field("label", "start"),
1445 struct_field("enabled", false),
1446 ],
1447 )
1448 .expect("struct instance");
1449
1450 mixed
1451 .set_field("count", 11_i64)
1452 .expect("update count field");
1453 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1454
1455 let err = mixed
1456 .set_field("count", "oops")
1457 .expect_err("type mismatch should fail");
1458 match err {
1459 LustError::TypeError { message } => {
1460 assert!(message.contains("count"));
1461 assert!(message.contains("int"));
1462 }
1463 other => panic!("unexpected error: {other:?}"),
1464 }
1465 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1466
1467 mixed
1468 .set_field("label", String::from("updated"))
1469 .expect("update label");
1470 assert_eq!(
1471 mixed.field::<String>("label").expect("label field"),
1472 "updated"
1473 );
1474
1475 mixed.set_field("enabled", true).expect("update enabled");
1476 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1477 }
1478
1479 #[test]
1480 fn struct_instance_accepts_nested_structs() {
1481 let source = r#"
1482 struct Child
1483 value: int
1484 end
1485
1486 struct Parent
1487 child: main.Child
1488 end
1489 "#;
1490
1491 let program = build_program(source);
1492 let child = program
1493 .struct_instance("main.Child", [struct_field("value", 42_i64)])
1494 .expect("child struct");
1495 let parent = program
1496 .struct_instance("main.Parent", [struct_field("child", child.clone())])
1497 .expect("parent struct");
1498
1499 let nested: StructInstance = parent.field("child").expect("child field");
1500 assert_eq!(nested.field::<i64>("value").expect("value field"), 42);
1501 }
1502
1503 #[test]
1504 fn globals_snapshot_exposes_lust_values() {
1505 let source = r#"
1506 struct Child
1507 value: int
1508 end
1509
1510 struct Parent
1511 child: unknown
1512 end
1513
1514 function make_parent(): Parent
1515 return Parent { child = Child { value = 3 } }
1516 end
1517 "#;
1518
1519 let mut program = build_program(source);
1520 program.run_entry_script().expect("run entry script");
1521 let parent: StructInstance = program
1522 .call_typed("main.make_parent", ())
1523 .expect("call make_parent");
1524 program.set_global_value("main.some_nested_structure", parent.clone());
1525
1526 let globals = program.globals();
1527 let (_, value) = globals
1528 .into_iter()
1529 .find(|(name, _)| name.ends_with("some_nested_structure"))
1530 .expect("global binding present");
1531 let stored = StructInstance::from_value(value).expect("convert to struct");
1532 let child_value = stored
1533 .field::<StructInstance>("child")
1534 .expect("nested child");
1535 assert_eq!(child_value.field::<i64>("value").expect("child value"), 3);
1536 }
1537
1538 #[test]
1539 fn update_field_modifies_value_in_place() {
1540 let source = r#"
1541 struct Counter
1542 value: int
1543 end
1544 "#;
1545
1546 let program = build_program(source);
1547 let counter = program
1548 .struct_instance("main.Counter", [struct_field("value", 10_i64)])
1549 .expect("counter struct");
1550
1551 counter
1552 .update_field("value", |current| match current {
1553 Value::Int(v) => Ok(v + 5),
1554 other => Err(LustError::RuntimeError {
1555 message: format!("unexpected value {other:?}"),
1556 }),
1557 })
1558 .expect("update in place");
1559 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1560
1561 let err = counter
1562 .update_field("value", |_| Ok(String::from("oops")))
1563 .expect_err("string should fail type check");
1564 match err {
1565 LustError::TypeError { message } => {
1566 assert!(message.contains("value"));
1567 assert!(message.contains("int"));
1568 }
1569 other => panic!("unexpected error: {other:?}"),
1570 }
1571 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1572
1573 let err = counter
1574 .update_field("value", |_| -> Result<i64> {
1575 Err(LustError::RuntimeError {
1576 message: "closure failure".to_string(),
1577 })
1578 })
1579 .expect_err("closure error should propagate");
1580 match err {
1581 LustError::RuntimeError { message } => assert_eq!(message, "closure failure"),
1582 other => panic!("unexpected error: {other:?}"),
1583 }
1584 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1585 }
1586
1587 #[test]
1588 fn async_native_resumes_task_on_completion() {
1589 let source = r#"
1590 extern {
1591 function fetch_value(): int
1592 }
1593
1594 function compute(): int
1595 return fetch_value()
1596 end
1597 "#;
1598
1599 let mut program = build_program(source);
1600
1601 let state = ManualAsyncState::new();
1602 let register_state = Arc::clone(&state);
1603 program
1604 .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
1605 register_state.future()
1606 })
1607 .expect("register async native");
1608
1609 let handle = {
1610 let vm = program.vm_mut();
1611 let compute_fn = vm.function_value("main.compute").expect("compute function");
1612 vm.spawn_task_value(compute_fn, Vec::new())
1613 .expect("spawn task")
1614 };
1615
1616 assert!(program.has_pending_async_tasks());
1617 program.poll_async_tasks().expect("initial poll");
1618 assert!(program.has_pending_async_tasks());
1619
1620 state.complete_ok(123);
1621 program.poll_async_tasks().expect("resume after completion");
1622
1623 {
1624 let vm = program.vm_mut();
1625 let task = vm.get_task_instance(handle).expect("task exists");
1626 let result = task
1627 .last_result
1628 .as_ref()
1629 .and_then(|value| value.as_int())
1630 .expect("task produced result");
1631 assert_eq!(result, 123);
1632 assert!(task.error.is_none());
1633 }
1634
1635 assert!(!program.has_pending_async_tasks());
1636 }
1637
1638 #[test]
1639 fn async_native_failure_marks_task_failed() {
1640 let source = r#"
1641 extern {
1642 function fetch_value(): int
1643 }
1644
1645 function compute(): int
1646 return fetch_value()
1647 end
1648 "#;
1649
1650 let mut program = build_program(source);
1651
1652 let state = ManualAsyncState::new();
1653 let register_state = Arc::clone(&state);
1654 program
1655 .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
1656 register_state.future()
1657 })
1658 .expect("register async native");
1659
1660 let handle = {
1661 let vm = program.vm_mut();
1662 let compute_fn = vm.function_value("main.compute").expect("compute function");
1663 vm.spawn_task_value(compute_fn, Vec::new())
1664 .expect("spawn task")
1665 };
1666
1667 program.poll_async_tasks().expect("initial poll");
1668 state.complete_err("boom");
1669 let err = program
1670 .poll_async_tasks()
1671 .expect_err("poll should propagate failure");
1672 match err {
1673 LustError::RuntimeError { message } => assert_eq!(message, "boom"),
1674 other => panic!("unexpected error: {other:?}"),
1675 }
1676
1677 {
1678 let vm = program.vm_mut();
1679 let task = vm.get_task_instance(handle).expect("task exists");
1680 assert!(task.last_result.is_none());
1681 let error_message = task
1682 .error
1683 .as_ref()
1684 .map(|e| e.to_string())
1685 .expect("task should record error");
1686 assert!(error_message.contains("boom"));
1687 }
1688
1689 assert!(!program.has_pending_async_tasks());
1690 }
1691}
1692
1693fn matches_lust_struct(value: &Value, ty: &Type) -> bool {
1694 match (value, &ty.kind) {
1695 (Value::Struct { name, .. }, TypeKind::Named(expected)) => {
1696 lust_type_names_match(name, expected)
1697 }
1698 (Value::Struct { name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
1699 lust_type_names_match(name, expected)
1700 }
1701
1702 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_struct(value, alt)),
1703 (_, TypeKind::Unknown) => true,
1704 _ => false,
1705 }
1706}
1707
1708fn matches_lust_enum(value: &Value, ty: &Type) -> bool {
1709 match (value, &ty.kind) {
1710 (Value::Enum { enum_name, .. }, TypeKind::Named(expected)) => {
1711 lust_type_names_match(enum_name, expected)
1712 }
1713 (Value::Enum { enum_name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
1714 lust_type_names_match(enum_name, expected)
1715 }
1716
1717 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_enum(value, alt)),
1718 (_, TypeKind::Unknown) => true,
1719 _ => false,
1720 }
1721}
1722
1723fn lust_type_names_match(value: &str, expected: &str) -> bool {
1724 if value == expected {
1725 return true;
1726 }
1727
1728 let normalized_value = normalize_global_name(value);
1729 let normalized_expected = normalize_global_name(expected);
1730 if normalized_value == normalized_expected {
1731 return true;
1732 }
1733
1734 simple_type_name(&normalized_value) == simple_type_name(&normalized_expected)
1735}
1736
1737fn simple_type_name(name: &str) -> &str {
1738 name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
1739}
1740
1741fn matches_array_type<F>(ty: &Type, matcher: &F) -> bool
1742where
1743 F: Fn(&Type) -> bool,
1744{
1745 match &ty.kind {
1746 TypeKind::Array(inner) => matcher(inner),
1747 TypeKind::Unknown => true,
1748 TypeKind::Union(types) => types.iter().any(|alt| matches_array_type(alt, matcher)),
1749 _ => false,
1750 }
1751}
1752
1753pub trait FromLustArgs: Sized {
1754 fn from_values(values: &[Value]) -> std::result::Result<Self, String>;
1755 fn matches_signature(params: &[Type]) -> bool;
1756}
1757
1758macro_rules! impl_from_lust_args_tuple {
1759 ($( $name:ident ),+) => {
1760 impl<$($name),+> FromLustArgs for ($($name,)+)
1761 where
1762 $($name: FromLustValue,)+
1763 {
1764 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
1765 let expected = count_idents!($($name),+);
1766 if values.len() != expected {
1767 return Err(format!(
1768 "Native function expected {} argument(s) but received {}",
1769 expected,
1770 values.len()
1771 ));
1772 }
1773
1774 let mut idx = 0;
1775 let result = (
1776 $(
1777 {
1778 let value = $name::from_value(values[idx].clone()).map_err(|e| e.to_string())?;
1779 idx += 1;
1780 value
1781 },
1782 )+
1783 );
1784 let _ = idx;
1785 Ok(result)
1786 }
1787
1788 fn matches_signature(params: &[Type]) -> bool {
1789 let expected = count_idents!($($name),+);
1790 params.len() == expected && {
1791 let mut idx = 0;
1792 let mut ok = true;
1793 $(
1794 if ok && !$name::matches_lust_type(¶ms[idx]) {
1795 ok = false;
1796 }
1797
1798 idx += 1;
1799 )+
1800 let _ = idx;
1801 ok
1802 }
1803
1804 }
1805
1806 }
1807
1808 };
1809}
1810
1811macro_rules! count_idents {
1812 ($($name:ident),*) => {
1813 <[()]>::len(&[$(count_idents!(@sub $name)),*])
1814 };
1815 (@sub $name:ident) => { () };
1816}
1817
1818impl_from_lust_args_tuple!(A);
1819impl_from_lust_args_tuple!(A, B);
1820impl_from_lust_args_tuple!(A, B, C);
1821impl_from_lust_args_tuple!(A, B, C, D);
1822impl_from_lust_args_tuple!(A, B, C, D, E);
1823impl<T> FromLustArgs for T
1824where
1825 T: FromLustValue,
1826{
1827 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
1828 match values.len() {
1829 0 => T::from_value(Value::Nil).map_err(|e| e.to_string()),
1830 1 => T::from_value(values[0].clone()).map_err(|e| e.to_string()),
1831 count => Err(format!(
1832 "Native function expected 1 argument but received {}",
1833 count
1834 )),
1835 }
1836 }
1837
1838 fn matches_signature(params: &[Type]) -> bool {
1839 if params.is_empty() {
1840 let unit = Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0));
1841 return T::matches_lust_type(&unit);
1842 }
1843
1844 params.len() == 1 && T::matches_lust_type(¶ms[0])
1845 }
1846}
1847
1848pub trait IntoLustValue: Sized {
1849 fn into_value(self) -> Value;
1850 fn matches_lust_type(ty: &Type) -> bool;
1851 fn type_description() -> &'static str;
1852}
1853
1854pub trait FromLustValue: Sized {
1855 fn from_value(value: Value) -> Result<Self>;
1856 fn matches_lust_type(ty: &Type) -> bool;
1857 fn type_description() -> &'static str;
1858}
1859
1860pub trait FunctionArgs {
1861 fn into_values(self) -> Vec<Value>;
1862 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()>;
1863}
1864
1865impl IntoLustValue for Value {
1866 fn into_value(self) -> Value {
1867 self
1868 }
1869
1870 fn matches_lust_type(_: &Type) -> bool {
1871 true
1872 }
1873
1874 fn type_description() -> &'static str {
1875 "Value"
1876 }
1877}
1878
1879impl FromLustValue for Value {
1880 fn from_value(value: Value) -> Result<Self> {
1881 Ok(value)
1882 }
1883
1884 fn matches_lust_type(_: &Type) -> bool {
1885 true
1886 }
1887
1888 fn type_description() -> &'static str {
1889 "Value"
1890 }
1891}
1892
1893impl IntoLustValue for LustInt {
1894 fn into_value(self) -> Value {
1895 Value::Int(self)
1896 }
1897
1898 fn matches_lust_type(ty: &Type) -> bool {
1899 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
1900 }
1901
1902 fn type_description() -> &'static str {
1903 "int"
1904 }
1905}
1906
1907impl FromLustValue for LustInt {
1908 fn from_value(value: Value) -> Result<Self> {
1909 match value {
1910 Value::Int(v) => Ok(v),
1911 other => Err(LustError::RuntimeError {
1912 message: format!("Expected Lust value 'int' but received '{:?}'", other),
1913 }),
1914 }
1915 }
1916
1917 fn matches_lust_type(ty: &Type) -> bool {
1918 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
1919 }
1920
1921 fn type_description() -> &'static str {
1922 "int"
1923 }
1924}
1925
1926impl IntoLustValue for LustFloat {
1927 fn into_value(self) -> Value {
1928 Value::Float(self)
1929 }
1930
1931 fn matches_lust_type(ty: &Type) -> bool {
1932 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1933 }
1934
1935 fn type_description() -> &'static str {
1936 "float"
1937 }
1938}
1939
1940impl FromLustValue for LustFloat {
1941 fn from_value(value: Value) -> Result<Self> {
1942 match value {
1943 Value::Float(v) => Ok(v),
1944 other => Err(LustError::RuntimeError {
1945 message: format!("Expected Lust value 'float' but received '{:?}'", other),
1946 }),
1947 }
1948 }
1949
1950 fn matches_lust_type(ty: &Type) -> bool {
1951 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1952 }
1953
1954 fn type_description() -> &'static str {
1955 "float"
1956 }
1957}
1958
1959impl IntoLustValue for bool {
1960 fn into_value(self) -> Value {
1961 Value::Bool(self)
1962 }
1963
1964 fn matches_lust_type(ty: &Type) -> bool {
1965 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1966 }
1967
1968 fn type_description() -> &'static str {
1969 "bool"
1970 }
1971}
1972
1973impl FromLustValue for bool {
1974 fn from_value(value: Value) -> Result<Self> {
1975 match value {
1976 Value::Bool(b) => Ok(b),
1977 other => Err(LustError::RuntimeError {
1978 message: format!("Expected Lust value 'bool' but received '{:?}'", other),
1979 }),
1980 }
1981 }
1982
1983 fn matches_lust_type(ty: &Type) -> bool {
1984 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1985 }
1986
1987 fn type_description() -> &'static str {
1988 "bool"
1989 }
1990}
1991
1992impl IntoLustValue for String {
1993 fn into_value(self) -> Value {
1994 Value::String(Rc::new(self))
1995 }
1996
1997 fn matches_lust_type(ty: &Type) -> bool {
1998 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1999 }
2000
2001 fn type_description() -> &'static str {
2002 "string"
2003 }
2004}
2005
2006impl IntoLustValue for StructInstance {
2007 fn into_value(self) -> Value {
2008 self.value
2009 }
2010
2011 fn matches_lust_type(ty: &Type) -> bool {
2012 match &ty.kind {
2013 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2014 TypeKind::Union(types) => types
2015 .iter()
2016 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
2017 _ => false,
2018 }
2019 }
2020
2021 fn type_description() -> &'static str {
2022 "struct"
2023 }
2024}
2025
2026impl FromLustValue for StructInstance {
2027 fn from_value(value: Value) -> Result<Self> {
2028 match &value {
2029 Value::Struct { name, .. } => Ok(StructInstance {
2030 type_name: name.clone(),
2031 value,
2032 }),
2033 other => Err(LustError::RuntimeError {
2034 message: format!("Expected Lust value 'struct' but received '{:?}'", other),
2035 }),
2036 }
2037 }
2038
2039 fn matches_lust_type(ty: &Type) -> bool {
2040 match &ty.kind {
2041 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2042 TypeKind::Union(types) => types
2043 .iter()
2044 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
2045 _ => false,
2046 }
2047 }
2048
2049 fn type_description() -> &'static str {
2050 "struct"
2051 }
2052}
2053
2054impl IntoLustValue for EnumInstance {
2055 fn into_value(self) -> Value {
2056 self.value
2057 }
2058
2059 fn matches_lust_type(ty: &Type) -> bool {
2060 match &ty.kind {
2061 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2062 TypeKind::Union(types) => types
2063 .iter()
2064 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
2065 _ => false,
2066 }
2067 }
2068
2069 fn type_description() -> &'static str {
2070 "enum"
2071 }
2072}
2073
2074impl FromLustValue for EnumInstance {
2075 fn from_value(value: Value) -> Result<Self> {
2076 match &value {
2077 Value::Enum {
2078 enum_name, variant, ..
2079 } => Ok(EnumInstance {
2080 type_name: enum_name.clone(),
2081 variant: variant.clone(),
2082 value,
2083 }),
2084 other => Err(LustError::RuntimeError {
2085 message: format!("Expected Lust value 'enum' but received '{:?}'", other),
2086 }),
2087 }
2088 }
2089
2090 fn matches_lust_type(ty: &Type) -> bool {
2091 match &ty.kind {
2092 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2093 TypeKind::Union(types) => types
2094 .iter()
2095 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
2096 _ => false,
2097 }
2098 }
2099
2100 fn type_description() -> &'static str {
2101 "enum"
2102 }
2103}
2104
2105impl<T> IntoLustValue for Vec<T>
2106where
2107 T: IntoLustValue,
2108{
2109 fn into_value(self) -> Value {
2110 let values = self.into_iter().map(|item| item.into_value()).collect();
2111 Value::array(values)
2112 }
2113
2114 fn matches_lust_type(ty: &Type) -> bool {
2115 matches_array_type(ty, &T::matches_lust_type)
2116 }
2117
2118 fn type_description() -> &'static str {
2119 "array"
2120 }
2121}
2122
2123impl<T> FromLustValue for Vec<T>
2124where
2125 T: FromLustValue,
2126{
2127 fn from_value(value: Value) -> Result<Self> {
2128 match value {
2129 Value::Array(items) => {
2130 let borrowed = items.borrow();
2131 let mut result = Vec::with_capacity(borrowed.len());
2132 for item in borrowed.iter() {
2133 result.push(T::from_value(item.clone())?);
2134 }
2135
2136 Ok(result)
2137 }
2138
2139 other => Err(LustError::RuntimeError {
2140 message: format!("Expected Lust value 'array' but received '{:?}'", other),
2141 }),
2142 }
2143 }
2144
2145 fn matches_lust_type(ty: &Type) -> bool {
2146 matches_array_type(ty, &T::matches_lust_type)
2147 }
2148
2149 fn type_description() -> &'static str {
2150 "array"
2151 }
2152}
2153
2154impl<'a> IntoLustValue for &'a str {
2155 fn into_value(self) -> Value {
2156 Value::String(Rc::new(self.to_owned()))
2157 }
2158
2159 fn matches_lust_type(ty: &Type) -> bool {
2160 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2161 }
2162
2163 fn type_description() -> &'static str {
2164 "string"
2165 }
2166}
2167
2168impl<'a> IntoLustValue for &'a String {
2169 fn into_value(self) -> Value {
2170 Value::String(Rc::new(self.clone()))
2171 }
2172
2173 fn matches_lust_type(ty: &Type) -> bool {
2174 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2175 }
2176
2177 fn type_description() -> &'static str {
2178 "string"
2179 }
2180}
2181
2182impl FromLustValue for String {
2183 fn from_value(value: Value) -> Result<Self> {
2184 match value {
2185 Value::String(s) => Ok((*s).clone()),
2186 other => Err(LustError::RuntimeError {
2187 message: format!("Expected Lust value 'string' but received '{:?}'", other),
2188 }),
2189 }
2190 }
2191
2192 fn matches_lust_type(ty: &Type) -> bool {
2193 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2194 }
2195
2196 fn type_description() -> &'static str {
2197 "string"
2198 }
2199}
2200
2201impl FromLustValue for () {
2202 fn from_value(value: Value) -> Result<Self> {
2203 match value {
2204 Value::Nil => Ok(()),
2205 other => Err(LustError::RuntimeError {
2206 message: format!("Expected Lust value 'unit' but received '{:?}'", other),
2207 }),
2208 }
2209 }
2210
2211 fn matches_lust_type(ty: &Type) -> bool {
2212 matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown)
2213 }
2214
2215 fn type_description() -> &'static str {
2216 "unit"
2217 }
2218}
2219
2220impl FunctionArgs for () {
2221 fn into_values(self) -> Vec<Value> {
2222 Vec::new()
2223 }
2224
2225 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2226 ensure_arity(function_name, params, 0)
2227 }
2228}
2229
2230impl<T> FunctionArgs for T
2231where
2232 T: IntoLustValue,
2233{
2234 fn into_values(self) -> Vec<Value> {
2235 vec![self.into_value()]
2236 }
2237
2238 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2239 ensure_arity(function_name, params, 1)?;
2240 ensure_arg_type::<T>(function_name, params, 0)
2241 }
2242}
2243
2244impl<A, B> FunctionArgs for (A, B)
2245where
2246 A: IntoLustValue,
2247 B: IntoLustValue,
2248{
2249 fn into_values(self) -> Vec<Value> {
2250 vec![self.0.into_value(), self.1.into_value()]
2251 }
2252
2253 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2254 ensure_arity(function_name, params, 2)?;
2255 ensure_arg_type::<A>(function_name, params, 0)?;
2256 ensure_arg_type::<B>(function_name, params, 1)?;
2257 Ok(())
2258 }
2259}
2260
2261impl<A, B, C> FunctionArgs for (A, B, C)
2262where
2263 A: IntoLustValue,
2264 B: IntoLustValue,
2265 C: IntoLustValue,
2266{
2267 fn into_values(self) -> Vec<Value> {
2268 vec![
2269 self.0.into_value(),
2270 self.1.into_value(),
2271 self.2.into_value(),
2272 ]
2273 }
2274
2275 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2276 ensure_arity(function_name, params, 3)?;
2277 ensure_arg_type::<A>(function_name, params, 0)?;
2278 ensure_arg_type::<B>(function_name, params, 1)?;
2279 ensure_arg_type::<C>(function_name, params, 2)?;
2280 Ok(())
2281 }
2282}
2283
2284impl<A, B, C, D> FunctionArgs for (A, B, C, D)
2285where
2286 A: IntoLustValue,
2287 B: IntoLustValue,
2288 C: IntoLustValue,
2289 D: IntoLustValue,
2290{
2291 fn into_values(self) -> Vec<Value> {
2292 vec![
2293 self.0.into_value(),
2294 self.1.into_value(),
2295 self.2.into_value(),
2296 self.3.into_value(),
2297 ]
2298 }
2299
2300 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2301 ensure_arity(function_name, params, 4)?;
2302 ensure_arg_type::<A>(function_name, params, 0)?;
2303 ensure_arg_type::<B>(function_name, params, 1)?;
2304 ensure_arg_type::<C>(function_name, params, 2)?;
2305 ensure_arg_type::<D>(function_name, params, 3)?;
2306 Ok(())
2307 }
2308}
2309
2310impl<A, B, C, D, E> FunctionArgs for (A, B, C, D, E)
2311where
2312 A: IntoLustValue,
2313 B: IntoLustValue,
2314 C: IntoLustValue,
2315 D: IntoLustValue,
2316 E: IntoLustValue,
2317{
2318 fn into_values(self) -> Vec<Value> {
2319 vec![
2320 self.0.into_value(),
2321 self.1.into_value(),
2322 self.2.into_value(),
2323 self.3.into_value(),
2324 self.4.into_value(),
2325 ]
2326 }
2327
2328 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2329 ensure_arity(function_name, params, 5)?;
2330 ensure_arg_type::<A>(function_name, params, 0)?;
2331 ensure_arg_type::<B>(function_name, params, 1)?;
2332 ensure_arg_type::<C>(function_name, params, 2)?;
2333 ensure_arg_type::<D>(function_name, params, 3)?;
2334 ensure_arg_type::<E>(function_name, params, 4)?;
2335 Ok(())
2336 }
2337}
2338
2339fn ensure_arity(function_name: &str, params: &[Type], provided: usize) -> Result<()> {
2340 if params.len() == provided {
2341 Ok(())
2342 } else {
2343 Err(LustError::TypeError {
2344 message: format!(
2345 "Function '{}' expects {} argument(s) but {} were supplied",
2346 function_name,
2347 params.len(),
2348 provided
2349 ),
2350 })
2351 }
2352}
2353
2354fn ensure_arg_type<T: IntoLustValue>(
2355 function_name: &str,
2356 params: &[Type],
2357 index: usize,
2358) -> Result<()> {
2359 if <T as IntoLustValue>::matches_lust_type(¶ms[index]) {
2360 Ok(())
2361 } else {
2362 Err(argument_type_mismatch(
2363 function_name,
2364 index,
2365 <T as IntoLustValue>::type_description(),
2366 ¶ms[index],
2367 ))
2368 }
2369}
2370
2371fn argument_type_mismatch(
2372 function_name: &str,
2373 index: usize,
2374 rust_type: &str,
2375 lust_type: &Type,
2376) -> LustError {
2377 LustError::TypeError {
2378 message: format!(
2379 "Function '{}' parameter {} expects Lust type '{}' but Rust provided '{}'",
2380 function_name,
2381 index + 1,
2382 lust_type,
2383 rust_type
2384 ),
2385 }
2386}