lust/vm/
api.rs

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