lust/vm/
api.rs

1use super::*;
2use crate::ast::Type;
3use crate::config::LustConfig;
4use alloc::rc::Rc;
5use alloc::string::String;
6use alloc::vec::Vec;
7use core::result::Result as CoreResult;
8use core::{array, mem};
9
10#[derive(Debug, Clone)]
11pub struct NativeExportParam {
12    name: String,
13    ty: String,
14}
15
16impl NativeExportParam {
17    pub fn new(name: impl Into<String>, ty: impl Into<String>) -> Self {
18        Self {
19            name: name.into(),
20            ty: ty.into(),
21        }
22    }
23
24    pub fn name(&self) -> &str {
25        &self.name
26    }
27
28    pub fn ty(&self) -> &str {
29        &self.ty
30    }
31}
32
33#[derive(Debug, Clone)]
34pub struct NativeExport {
35    name: String,
36    params: Vec<NativeExportParam>,
37    return_type: String,
38    doc: Option<String>,
39}
40
41impl NativeExport {
42    pub fn new(
43        name: impl Into<String>,
44        params: Vec<NativeExportParam>,
45        return_type: impl Into<String>,
46    ) -> Self {
47        Self {
48            name: name.into(),
49            params,
50            return_type: return_type.into(),
51            doc: None,
52        }
53    }
54
55    pub fn with_doc(mut self, doc: impl Into<String>) -> Self {
56        self.doc = Some(doc.into());
57        self
58    }
59
60    pub fn name(&self) -> &str {
61        &self.name
62    }
63
64    pub fn params(&self) -> &[NativeExportParam] {
65        &self.params
66    }
67
68    pub fn return_type(&self) -> &str {
69        &self.return_type
70    }
71
72    pub fn doc(&self) -> Option<&str> {
73        self.doc.as_deref()
74    }
75}
76impl VM {
77    pub fn new() -> Self {
78        Self::with_config(&LustConfig::default())
79    }
80
81    pub fn with_config(config: &LustConfig) -> Self {
82        let mut vm = Self {
83            jit: JitState::new(),
84            functions: Vec::new(),
85            natives: HashMap::new(),
86            globals: HashMap::new(),
87            call_stack: Vec::new(),
88            max_stack_depth: 1000,
89            pending_return_value: None,
90            pending_return_dest: None,
91            trace_recorder: None,
92            side_trace_context: None,
93            skip_next_trace_record: false,
94            trait_impls: HashMap::new(),
95            struct_tostring_cache: HashMap::new(),
96            struct_metadata: HashMap::new(),
97            call_until_depth: None,
98            task_manager: TaskManager::new(),
99            current_task: None,
100            pending_task_signal: None,
101            last_task_signal: None,
102            cycle_collector: cycle::CycleCollector::new(),
103            exported_natives: Vec::new(),
104            export_prefix_stack: Vec::new(),
105            exported_type_stubs: Vec::new(),
106        };
107        vm.jit.enabled = vm.jit.enabled && config.jit_enabled();
108        vm.trait_impls
109            .insert(("int".to_string(), "ToString".to_string()), true);
110        vm.trait_impls
111            .insert(("float".to_string(), "ToString".to_string()), true);
112        vm.trait_impls
113            .insert(("string".to_string(), "ToString".to_string()), true);
114        vm.trait_impls
115            .insert(("bool".to_string(), "ToString".to_string()), true);
116        vm.trait_impls
117            .insert(("int".to_string(), "Hashable".to_string()), true);
118        vm.trait_impls
119            .insert(("float".to_string(), "Hashable".to_string()), true);
120        vm.trait_impls
121            .insert(("string".to_string(), "Hashable".to_string()), true);
122        vm.trait_impls
123            .insert(("bool".to_string(), "Hashable".to_string()), true);
124        super::corelib::install_core_builtins(&mut vm);
125        #[cfg(feature = "std")]
126        for (name, func) in super::stdlib::create_stdlib(config) {
127            vm.register_native(name, func);
128        }
129
130        vm
131    }
132
133    pub(super) fn observe_value(&mut self, value: &Value) {
134        self.cycle_collector.register_value(value);
135    }
136
137    pub(super) fn maybe_collect_cycles(&mut self) {
138        let mut collector = mem::take(&mut self.cycle_collector);
139        collector.maybe_collect(self);
140        self.cycle_collector = collector;
141    }
142
143    pub fn with_current<F, R>(f: F) -> CoreResult<R, String>
144    where
145        F: FnOnce(&mut VM) -> CoreResult<R, String>,
146    {
147        let ptr_opt = super::with_vm_stack(|stack| stack.last().copied());
148        if let Some(ptr) = ptr_opt {
149            let vm = unsafe { &mut *ptr };
150            f(vm)
151        } else {
152            Err("task API requires a running VM".to_string())
153        }
154    }
155
156    pub fn load_functions(&mut self, functions: Vec<Function>) {
157        self.functions = functions;
158    }
159
160    pub fn register_structs(&mut self, defs: &HashMap<String, StructDef>) {
161        for (name, def) in defs {
162            let field_names: Vec<Rc<String>> = def
163                .fields
164                .iter()
165                .map(|field| Rc::new(field.name.clone()))
166                .collect();
167            let field_storage: Vec<FieldStorage> = def
168                .fields
169                .iter()
170                .map(|field| match field.ownership {
171                    FieldOwnership::Weak => FieldStorage::Weak,
172                    FieldOwnership::Strong => FieldStorage::Strong,
173                })
174                .collect();
175            let field_types: Vec<Type> = def.fields.iter().map(|field| field.ty.clone()).collect();
176            let weak_targets: Vec<Option<Type>> = def
177                .fields
178                .iter()
179                .map(|field| field.weak_target.clone())
180                .collect();
181            let layout = Rc::new(StructLayout::new(
182                def.name.clone(),
183                field_names,
184                field_storage,
185                field_types,
186                weak_targets,
187            ));
188            self.struct_metadata.insert(
189                name.clone(),
190                RuntimeStructInfo {
191                    layout: layout.clone(),
192                },
193            );
194            if let Some(simple) = name.rsplit('.').next() {
195                self.struct_metadata.insert(
196                    simple.to_string(),
197                    RuntimeStructInfo {
198                        layout: layout.clone(),
199                    },
200                );
201            }
202        }
203    }
204
205    pub fn instantiate_struct(
206        &self,
207        struct_name: &str,
208        fields: Vec<(Rc<String>, Value)>,
209    ) -> Result<Value> {
210        let info =
211            self.struct_metadata
212                .get(struct_name)
213                .ok_or_else(|| LustError::RuntimeError {
214                    message: format!("Unknown struct '{}'", struct_name),
215                })?;
216        Self::build_struct_value(struct_name, info, fields)
217    }
218
219    fn build_struct_value(
220        struct_name: &str,
221        info: &RuntimeStructInfo,
222        mut fields: Vec<(Rc<String>, Value)>,
223    ) -> Result<Value> {
224        let layout = info.layout.clone();
225        let field_count = layout.field_names().len();
226        let mut ordered = vec![Value::Nil; field_count];
227        let mut filled = vec![false; field_count];
228        for (field_name, field_value) in fields.drain(..) {
229            let index_opt = layout
230                .index_of_rc(&field_name)
231                .or_else(|| layout.index_of_str(field_name.as_str()));
232            let index = match index_opt {
233                Some(i) => i,
234                None => {
235                    return Err(LustError::RuntimeError {
236                        message: format!("Struct '{}' has no field '{}'", struct_name, field_name),
237                    })
238                }
239            };
240            let canonical = layout
241                .canonicalize_field_value(index, field_value)
242                .map_err(|msg| LustError::RuntimeError { message: msg })?;
243            ordered[index] = canonical;
244            filled[index] = true;
245        }
246
247        if filled.iter().any(|slot| !*slot) {
248            let missing: Vec<String> = layout
249                .field_names()
250                .iter()
251                .enumerate()
252                .filter_map(|(idx, name)| (!filled[idx]).then(|| (**name).clone()))
253                .collect();
254            return Err(LustError::RuntimeError {
255                message: format!(
256                    "Struct '{}' is missing required field(s): {}",
257                    struct_name,
258                    missing.join(", ")
259                ),
260            });
261        }
262
263        Ok(Value::Struct {
264            name: struct_name.to_string(),
265            layout,
266            fields: Rc::new(RefCell::new(ordered)),
267        })
268    }
269
270    pub fn register_trait_impl(&mut self, type_name: String, trait_name: String) {
271        self.trait_impls.insert((type_name, trait_name), true);
272    }
273
274    pub fn register_native(&mut self, name: impl Into<String>, value: Value) {
275        let name = name.into();
276        match value {
277            Value::NativeFunction(_) => {
278                let cloned = value.clone();
279                self.natives.insert(name.clone(), value);
280                self.globals.insert(name, cloned);
281            }
282
283            other => {
284                self.globals.insert(name, other);
285            }
286        }
287    }
288
289    pub(crate) fn push_export_prefix(&mut self, crate_name: &str) {
290        let sanitized = crate_name.replace('-', "_");
291        self.export_prefix_stack.push(sanitized);
292    }
293
294    pub(crate) fn pop_export_prefix(&mut self) {
295        self.export_prefix_stack.pop();
296    }
297
298    fn current_export_prefix(&self) -> Option<&str> {
299        self.export_prefix_stack.last().map(|s| s.as_str())
300    }
301
302    pub fn export_prefix(&self) -> Option<String> {
303        self.current_export_prefix().map(|s| s.to_string())
304    }
305
306    pub fn register_exported_native<F>(&mut self, export: NativeExport, func: F)
307    where
308        F: Fn(&[Value]) -> CoreResult<NativeCallResult, String> + 'static,
309    {
310        let mut export = export;
311        if let Some(prefix) = self.current_export_prefix() {
312            let needs_prefix = match export.name.strip_prefix(prefix) {
313                Some(rest) => {
314                    if rest.is_empty() {
315                        false
316                    } else {
317                        !matches!(rest.chars().next(), Some('.') | Some(':'))
318                    }
319                }
320                None => true,
321            };
322            if needs_prefix {
323                export.name = if export.name.is_empty() {
324                    prefix.to_string()
325                } else {
326                    format!("{prefix}.{}", export.name)
327                };
328            }
329        }
330        let name = export.name.clone();
331        self.exported_natives.push(export);
332        let native = Value::NativeFunction(Rc::new(func));
333        self.register_native(name, native);
334    }
335
336    pub fn register_type_stubs(&mut self, stubs: Vec<ModuleStub>) {
337        if stubs.is_empty() {
338            return;
339        }
340        self.exported_type_stubs.extend(stubs);
341    }
342
343    pub fn take_type_stubs(&mut self) -> Vec<ModuleStub> {
344        mem::take(&mut self.exported_type_stubs)
345    }
346
347    pub fn exported_natives(&self) -> &[NativeExport] {
348        &self.exported_natives
349    }
350
351    pub fn take_exported_natives(&mut self) -> Vec<NativeExport> {
352        mem::take(&mut self.exported_natives)
353    }
354
355    pub fn clear_native_functions(&mut self) {
356        self.natives.clear();
357        self.exported_type_stubs.clear();
358    }
359
360    pub fn get_global(&self, name: &str) -> Option<Value> {
361        if let Some(value) = self.globals.get(name) {
362            Some(value.clone())
363        } else {
364            self.natives.get(name).cloned()
365        }
366    }
367
368    pub fn global_names(&self) -> Vec<String> {
369        self.globals.keys().cloned().collect()
370    }
371
372    pub fn globals_snapshot(&self) -> Vec<(String, Value)> {
373        self.globals
374            .iter()
375            .map(|(name, value)| (name.clone(), value.clone()))
376            .collect()
377    }
378
379    pub fn set_global(&mut self, name: impl Into<String>, value: Value) {
380        let name = name.into();
381        self.observe_value(&value);
382        self.globals.insert(name.clone(), value);
383        self.natives.remove(&name);
384        self.maybe_collect_cycles();
385    }
386
387    pub fn call(&mut self, function_name: &str, args: Vec<Value>) -> Result<Value> {
388        let func_idx = self
389            .functions
390            .iter()
391            .position(|f| f.name == function_name)
392            .ok_or_else(|| LustError::RuntimeError {
393                message: format!("Function not found: {}", function_name),
394            })?;
395        let mut frame = CallFrame {
396            function_idx: func_idx,
397            ip: 0,
398            registers: array::from_fn(|_| Value::Nil),
399            base_register: 0,
400            return_dest: None,
401            upvalues: Vec::new(),
402        };
403        let func = &self.functions[func_idx];
404        if args.len() != func.param_count as usize {
405            return Err(LustError::RuntimeError {
406                message: format!(
407                    "Function {} expects {} arguments, got {}",
408                    function_name,
409                    func.param_count,
410                    args.len()
411                ),
412            });
413        }
414
415        for (i, arg) in args.into_iter().enumerate() {
416            frame.registers[i] = arg;
417        }
418
419        self.call_stack.push(frame);
420        match self.run() {
421            Ok(v) => Ok(v),
422            Err(e) => Err(self.annotate_runtime_error(e)),
423        }
424    }
425
426    pub fn function_value(&self, function_name: &str) -> Option<Value> {
427        let canonical = if function_name.contains("::") {
428            function_name.replace("::", ".")
429        } else {
430            function_name.to_string()
431        };
432        self.functions
433            .iter()
434            .position(|f| f.name == canonical)
435            .map(Value::Function)
436    }
437
438    pub fn function_name(&self, index: usize) -> Option<&str> {
439        self.functions.get(index).map(|f| f.name.as_str())
440    }
441
442    pub fn fail_task_handle(&mut self, handle: TaskHandle, error: LustError) -> Result<()> {
443        let task_id = self.task_id_from_handle(handle)?;
444        let mut task =
445            self.task_manager
446                .detach(task_id)
447                .ok_or_else(|| LustError::RuntimeError {
448                    message: format!("Invalid task handle {}", handle.id()),
449                })?;
450        task.state = TaskState::Failed;
451        task.error = Some(error.clone());
452        task.last_yield = None;
453        task.last_result = None;
454        task.yield_dest = None;
455        task.call_stack.clear();
456        task.pending_return_value = None;
457        task.pending_return_dest = None;
458        self.task_manager.attach(task);
459        Err(error)
460    }
461}