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