lust/vm/
api.rs

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