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}