1use super::*;
2use crate::bytecode::{LustMap, ValueKey};
3use crate::vm::task::TaskKind;
4use crate::LustInt;
5use alloc::{format, string::ToString};
6use core::{array, cell::RefCell, mem};
7impl VM {
8 pub(super) fn run_task_internal(
9 &mut self,
10 task_id: TaskId,
11 resume_value: Option<Value>,
12 ) -> Result<()> {
13 let mut task = match self.task_manager.detach(task_id) {
14 Some(task) => task,
15 None => {
16 return Err(LustError::RuntimeError {
17 message: format!("Invalid task handle {}", task_id.as_u64()),
18 })
19 }
20 };
21 if matches!(task.kind(), TaskKind::NativeFuture { .. }) {
22 let message = format!(
23 "Task {} is managed by the host runtime and cannot be resumed manually",
24 task_id.as_u64()
25 );
26 self.task_manager.attach(task);
27 return Err(LustError::RuntimeError { message });
28 }
29
30 match task.state {
31 TaskState::Completed | TaskState::Failed | TaskState::Stopped => {
32 let message = format!(
33 "Task {} cannot be resumed (state: {})",
34 task_id.as_u64(),
35 task.state.as_str()
36 );
37 self.task_manager.attach(task);
38 return Err(LustError::RuntimeError { message });
39 }
40
41 TaskState::Running => {
42 self.task_manager.attach(task);
43 return Err(LustError::RuntimeError {
44 message: format!("Task {} is already running", task_id.as_u64()),
45 });
46 }
47
48 _ => {}
49 }
50
51 task.state = TaskState::Running;
52 task.last_yield = None;
53 let mut resume_value_opt = resume_value;
54 if let Some(dest) = task.yield_dest.take() {
55 let value = resume_value_opt.take().unwrap_or(Value::Nil);
56 if let Some(frame) = task.call_stack.last_mut() {
57 frame.registers[dest as usize] = value;
58 }
59 } else if resume_value_opt.is_some() {
60 let message = format!(
61 "Task {} is not waiting for a resume value",
62 task_id.as_u64()
63 );
64 self.task_manager.attach(task);
65 return Err(LustError::RuntimeError { message });
66 }
67
68 mem::swap(&mut self.call_stack, &mut task.call_stack);
69 mem::swap(
70 &mut self.pending_return_value,
71 &mut task.pending_return_value,
72 );
73 mem::swap(&mut self.pending_return_dest, &mut task.pending_return_dest);
74 self.current_task = Some(task_id);
75 self.last_task_signal = None;
76 let run_result = self.run();
77 let signal = self.last_task_signal.take();
78 self.current_task = None;
79 let mut error_result: Option<LustError> = None;
80 match run_result {
81 Ok(value) => {
82 if let Some(signal) = signal {
83 match signal {
84 TaskSignal::Yield {
85 dest,
86 value: yielded,
87 } => {
88 task.state = TaskState::Yielded;
89 task.last_yield = Some(yielded);
90 task.last_result = None;
91 task.yield_dest = Some(dest);
92 }
93
94 TaskSignal::Stop { value: stop_value } => {
95 task.state = TaskState::Stopped;
96 task.last_result = Some(stop_value);
97 task.last_yield = None;
98 task.call_stack.clear();
99 task.pending_return_value = None;
100 task.pending_return_dest = None;
101 }
102 }
103 } else {
104 task.state = TaskState::Completed;
105 task.last_result = Some(value);
106 task.last_yield = None;
107 }
108 }
109
110 Err(err) => {
111 let annotated = self.annotate_runtime_error(err);
112 task.state = TaskState::Failed;
113 task.error = Some(annotated.clone());
114 task.last_yield = None;
115 error_result = Some(annotated);
116 }
117 }
118
119 mem::swap(&mut self.call_stack, &mut task.call_stack);
120 mem::swap(
121 &mut self.pending_return_value,
122 &mut task.pending_return_value,
123 );
124 mem::swap(&mut self.pending_return_dest, &mut task.pending_return_dest);
125 self.task_manager.attach(task);
126 if let Some(err) = error_result {
127 Err(err)
128 } else {
129 Ok(())
130 }
131 }
132
133 pub(super) fn task_id_from_handle(&self, handle: TaskHandle) -> Result<TaskId> {
134 let id = TaskId(handle.id());
135 if self.task_manager.contains(id) {
136 Ok(id)
137 } else {
138 Err(LustError::RuntimeError {
139 message: format!("Invalid task handle {}", handle.id()),
140 })
141 }
142 }
143
144 pub(super) fn prepare_task_frame(
145 &mut self,
146 func: Value,
147 args: Vec<Value>,
148 ) -> Result<CallFrame> {
149 match func {
150 Value::Function(func_idx) => {
151 let function = &self.functions[func_idx];
152 if args.len() != function.param_count as usize {
153 return Err(LustError::RuntimeError {
154 message: format!(
155 "Task entry expects {} arguments, got {}",
156 function.param_count,
157 args.len()
158 ),
159 });
160 }
161
162 let mut frame = CallFrame {
163 function_idx: func_idx,
164 ip: 0,
165 registers: array::from_fn(|_| Value::Nil),
166 base_register: 0,
167 return_dest: None,
168 upvalues: Vec::new(),
169 };
170 for (i, arg) in args.into_iter().enumerate() {
171 frame.registers[i] = arg;
172 }
173
174 Ok(frame)
175 }
176
177 Value::Closure {
178 function_idx,
179 upvalues,
180 } => {
181 let function = &self.functions[function_idx];
182 if args.len() != function.param_count as usize {
183 return Err(LustError::RuntimeError {
184 message: format!(
185 "Task entry expects {} arguments, got {}",
186 function.param_count,
187 args.len()
188 ),
189 });
190 }
191
192 let captured: Vec<Value> = upvalues.iter().map(|uv| uv.get()).collect();
193 let mut frame = CallFrame {
194 function_idx,
195 ip: 0,
196 registers: array::from_fn(|_| Value::Nil),
197 base_register: 0,
198 return_dest: None,
199 upvalues: captured,
200 };
201 for (i, arg) in args.into_iter().enumerate() {
202 frame.registers[i] = arg;
203 }
204
205 Ok(frame)
206 }
207
208 other => Err(LustError::RuntimeError {
209 message: format!("task.run() expects a function or closure, got {:?}", other),
210 }),
211 }
212 }
213
214 pub(super) fn create_task_value(
215 &mut self,
216 func: Value,
217 args: Vec<Value>,
218 ) -> Result<TaskHandle> {
219 let frame = self.prepare_task_frame(func, args)?;
220 let task_id = self.task_manager.next_id();
221 let task = TaskInstance::new(task_id, frame);
222 self.task_manager.insert(task);
223 Ok(task_id.to_handle())
224 }
225
226 pub fn spawn_task_value(&mut self, func: Value, args: Vec<Value>) -> Result<TaskHandle> {
227 let handle = self.create_task_value(func, args)?;
228 let task_id = TaskId(handle.id());
229 if let Err(err) = self.run_task_internal(task_id, None) {
230 let _ = self.task_manager.detach(task_id);
231 return Err(err);
232 }
233
234 Ok(handle)
235 }
236
237 pub fn spawn_tick_task(&mut self, function_name: &str) -> Result<TaskHandle> {
238 let canonical = if function_name.contains("::") {
239 function_name.replace("::", ".")
240 } else {
241 function_name.to_string()
242 };
243 let func_idx = self
244 .functions
245 .iter()
246 .position(|f| f.name == canonical)
247 .ok_or_else(|| LustError::RuntimeError {
248 message: format!("Function not found: {}", function_name),
249 })?;
250
251 let yield_fn = self
252 .globals
253 .get("task")
254 .cloned()
255 .and_then(|task| match task {
256 Value::Map(map) => map
257 .borrow()
258 .get(&ValueKey::string("yield".to_string()))
259 .cloned(),
260 _ => None,
261 })
262 .ok_or_else(|| LustError::RuntimeError {
263 message: "Missing corelib 'task.yield' (task module not installed?)".to_string(),
264 })?;
265
266 if !matches!(yield_fn, Value::NativeFunction(_)) {
267 return Err(LustError::RuntimeError {
268 message: "corelib 'task.yield' is not a native function".to_string(),
269 });
270 }
271
272 let wrapper_name = format!("__jit_tick_driver_{}", func_idx);
273 let wrapper_idx = match self.functions.iter().position(|f| f.name == wrapper_name) {
274 Some(existing) => existing,
275 None => {
276 let target = &self.functions[func_idx];
277 let arg_count = target.param_count;
278
279 let mut wrapper = Function::new(wrapper_name, 0, false);
280
281 let resume_reg: Register = 0;
282 let tick_fn_reg: Register = 1;
283 let yield_fn_reg: Register = 2;
284 let idx_reg: Register = 3;
285 let arg_base: Register = 4;
286 let result_reg: Register = arg_base.saturating_add(arg_count);
287
288 let required_registers = (result_reg as u16 + 1).min(256) as u8;
289 wrapper.set_register_count(required_registers);
290
291 let tick_const = wrapper.chunk.add_constant(Value::Function(func_idx));
292 let yield_const = wrapper.chunk.add_constant(yield_fn);
293 let mut index_consts = Vec::new();
294 if arg_count > 1 {
295 for i in 0..(arg_count as LustInt) {
296 index_consts.push(wrapper.chunk.add_constant(Value::Int(i)));
297 }
298 }
299
300 wrapper
301 .chunk
302 .emit(Instruction::LoadConst(tick_fn_reg, tick_const), 0);
303 wrapper
304 .chunk
305 .emit(Instruction::LoadConst(yield_fn_reg, yield_const), 0);
306
307 wrapper
309 .chunk
310 .emit(Instruction::Call(yield_fn_reg, 0, 0, resume_reg), 0);
311
312 let loop_start = wrapper.chunk.instructions.len();
313
314 match arg_count {
315 0 => {
316 wrapper
317 .chunk
318 .emit(Instruction::Call(tick_fn_reg, 0, 0, result_reg), 0);
319 }
320 1 => {
321 wrapper.chunk.emit(
322 Instruction::Call(tick_fn_reg, resume_reg, 1, result_reg),
323 0,
324 );
325 }
326 _ => {
327 for (i, const_idx) in index_consts.iter().enumerate() {
329 wrapper
330 .chunk
331 .emit(Instruction::LoadConst(idx_reg, *const_idx), 0);
332 wrapper.chunk.emit(
333 Instruction::GetIndex(arg_base + i as u8, resume_reg, idx_reg),
334 0,
335 );
336 }
337 wrapper.chunk.emit(
338 Instruction::Call(tick_fn_reg, arg_base, arg_count, result_reg),
339 0,
340 );
341 }
342 }
343
344 wrapper.chunk.emit(
346 Instruction::Call(yield_fn_reg, result_reg, 1, resume_reg),
347 0,
348 );
349
350 let jump_idx = wrapper.chunk.emit(Instruction::Jump(0), 0);
351 wrapper.chunk.patch_jump(jump_idx, loop_start);
352
353 let new_idx = self.functions.len();
354 self.functions.push(wrapper);
355 new_idx
356 }
357 };
358
359 self.spawn_task_value(Value::Function(wrapper_idx), Vec::new())
360 }
361
362 pub fn tick_task(&mut self, handle: TaskHandle, resume_value: Value) -> Result<Value> {
363 self.resume_task_handle(handle, Some(resume_value))?;
364 let task = self.get_task_instance(handle)?;
365 match task.state {
366 TaskState::Yielded => Ok(task.last_yield.clone().unwrap_or(Value::Nil)),
367 TaskState::Completed | TaskState::Stopped => Ok(task.last_result.clone().unwrap_or(Value::Nil)),
368 TaskState::Ready | TaskState::Running => Ok(Value::Nil),
369 TaskState::Failed => Err(task.error.clone().unwrap_or_else(|| LustError::RuntimeError {
370 message: "Task failed".to_string(),
371 })),
372 }
373 }
374
375 pub fn resume_task_handle(
376 &mut self,
377 handle: TaskHandle,
378 resume_value: Option<Value>,
379 ) -> Result<()> {
380 let task_id = self.task_id_from_handle(handle)?;
381 self.run_task_internal(task_id, resume_value)
382 }
383
384 pub(super) fn stop_task_handle(&mut self, handle: TaskHandle) -> Result<()> {
385 let task_id = self.task_id_from_handle(handle)?;
386 let mut task = match self.task_manager.detach(task_id) {
387 Some(task) => task,
388 None => {
389 return Err(LustError::RuntimeError {
390 message: format!("Invalid task handle {}", handle.id()),
391 })
392 }
393 };
394 match task.state {
395 TaskState::Stopped | TaskState::Completed | TaskState::Failed => {
396 self.task_manager.attach(task);
397 return Ok(());
398 }
399
400 TaskState::Running => {
401 self.task_manager.attach(task);
402 return Err(LustError::RuntimeError {
403 message: format!("Task {} is currently running", handle.id()),
404 });
405 }
406
407 _ => {}
408 }
409
410 task.state = TaskState::Stopped;
411 task.call_stack.clear();
412 task.pending_return_value = None;
413 task.pending_return_dest = None;
414 task.yield_dest = None;
415 task.last_yield = None;
416 self.task_manager.attach(task);
417 Ok(())
418 }
419
420 pub(super) fn restart_task_handle(&mut self, handle: TaskHandle) -> Result<()> {
421 let task_id = self.task_id_from_handle(handle)?;
422 let mut task = match self.task_manager.detach(task_id) {
423 Some(task) => task,
424 None => {
425 return Err(LustError::RuntimeError {
426 message: format!("Invalid task handle {}", handle.id()),
427 })
428 }
429 };
430 task.reset();
431 self.task_manager.insert(task);
432 if let Err(err) = self.run_task_internal(task_id, None) {
433 return Err(err);
434 }
435
436 Ok(())
437 }
438
439 pub fn get_task_instance(&self, handle: TaskHandle) -> Result<&TaskInstance> {
440 let task_id = self.task_id_from_handle(handle)?;
441 self.task_manager
442 .get(task_id)
443 .ok_or_else(|| LustError::RuntimeError {
444 message: format!("Invalid task handle {}", handle.id()),
445 })
446 }
447
448 pub fn current_task_handle(&self) -> Option<TaskHandle> {
449 self.current_task.map(|id| id.to_handle())
450 }
451
452 pub fn create_native_future_task(&mut self) -> TaskHandle {
453 let id = self.task_manager.next_id();
454 let task = TaskInstance::new_native_future(id);
455 let handle = task.handle();
456 self.task_manager.insert(task);
457 handle
458 }
459
460 pub fn complete_native_future_task(
461 &mut self,
462 handle: TaskHandle,
463 outcome: core::result::Result<Value, String>,
464 ) -> Result<()> {
465 let task_id = self.task_id_from_handle(handle)?;
466 let mut task = match self.task_manager.detach(task_id) {
467 Some(task) => task,
468 None => {
469 return Err(LustError::RuntimeError {
470 message: format!("Invalid task handle {}", handle.id()),
471 })
472 }
473 };
474
475 match task.kind_mut() {
476 TaskKind::NativeFuture { .. } => {
477 match outcome {
478 Ok(value) => {
479 task.state = TaskState::Completed;
480 task.last_result = Some(value);
481 task.error = None;
482 }
483 Err(err_msg) => {
484 task.state = TaskState::Failed;
485 task.last_result = None;
486 task.error = Some(LustError::RuntimeError { message: err_msg });
487 }
488 }
489 task.last_yield = None;
490 task.pending_return_value = None;
491 task.pending_return_dest = None;
492 task.yield_dest = None;
493 self.task_manager.attach(task);
494 Ok(())
495 }
496
497 TaskKind::Script => {
498 self.task_manager.attach(task);
499 Err(LustError::RuntimeError {
500 message: "Attempted to complete a script task using native future completion"
501 .to_string(),
502 })
503 }
504 }
505 }
506
507 pub(super) fn call_builtin_method(
508 &mut self,
509 object: &Value,
510 method_name: &str,
511 args: Vec<Value>,
512 ) -> Result<Value> {
513 #[cfg(feature = "std")]
514 if std::env::var_os("LUST_LUA_SOCKET_TRACE").is_some() && method_name == "settimeout" {
515 match object {
516 Value::Enum {
517 enum_name,
518 variant,
519 ..
520 } => {
521 eprintln!(
522 "[lua-socket] CallMethod enum={} variant={} method={}",
523 enum_name, variant, method_name
524 );
525 }
526 other => {
527 eprintln!(
528 "[lua-socket] CallMethod type={:?} method={}",
529 other.type_of(),
530 method_name
531 );
532 }
533 }
534 }
535
536 if let Value::Enum {
537 enum_name,
538 variant,
539 ..
540 } = object
541 {
542 if enum_name == "LuaValue" && variant == "Userdata" {
543 if let Some(result) = self.try_call_lua_dynamic_method(object, method_name, &args)?
544 {
545 return Ok(result);
546 }
547 #[cfg(feature = "std")]
548 if std::env::var_os("LUST_LUA_SOCKET_TRACE").is_some() {
549 let indexer = self.lua_index_metamethod(object);
550 eprintln!(
551 "[lua-socket] userdata missing method '{}' indexer={:?} userdata={:?}",
552 method_name,
553 indexer.as_ref().map(|v| v.type_of()),
554 object
555 );
556 }
557 }
558 }
559
560 if let Value::Struct { name, .. } = object {
561 if name == "LuaTable" {
562 if let Some(result) = self.try_call_lua_dynamic_method(object, method_name, &args)?
563 {
564 return Ok(result);
565 }
566 }
567 }
568
569 if let Value::Enum {
570 enum_name,
571 variant,
572 values,
573 } = object
574 {
575 if enum_name == "LuaValue" && variant == "Table" {
576 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
577 return self.call_builtin_method(inner, method_name, args);
578 }
579 }
580 }
581
582 if let Value::Struct {
583 name: struct_name, ..
584 } = object
585 {
586 let mangled_name = format!("{}:{}", struct_name, method_name);
587 if let Some(func_idx) = self.functions.iter().position(|f| f.name == mangled_name) {
588 let mut method_args = vec![object.clone()];
589 method_args.extend(args.clone());
590 return self.call_value(&Value::Function(func_idx), method_args);
591 }
592
593 let mut candidate_names = vec![mangled_name.clone()];
594 if let Some(simple) = struct_name.rsplit(|c| c == '.' || c == ':').next() {
595 candidate_names.push(format!("{}:{}", simple, method_name));
596 }
597
598 for candidate in candidate_names {
599 let mut resolved = None;
600 for variant in [candidate.clone(), candidate.replace('.', "::")] {
601 if let Some(value) = self.get_global(&variant) {
602 resolved = Some(value);
603 break;
604 }
605 }
606
607 if let Some(global_func) = resolved {
608 let mut method_args = vec![object.clone()];
609 method_args.extend(args.clone());
610 return self.call_value(&global_func, method_args);
611 }
612 }
613 }
614
615 match object {
616 Value::Struct { name, .. } if name == "LuaTable" => {
617 let Some(map_rc) = lua_table_map_rc(object) else {
618 return Err(LustError::RuntimeError {
619 message: "LuaTable is missing 'table' map field".to_string(),
620 });
621 };
622 match method_name {
623 "len" => {
624 if !args.is_empty() {
625 return Err(LustError::RuntimeError {
626 message: "len() takes no arguments".to_string(),
627 });
628 }
629 let seq = lua_table_read_sequence(&map_rc.borrow());
630 Ok(Value::Int(seq.len() as LustInt))
631 }
632 "push" => {
633 if args.len() != 1 {
634 return Err(LustError::RuntimeError {
635 message: "push() requires 1 argument (value)".to_string(),
636 });
637 }
638 let value = super::corelib::unwrap_lua_value(args[0].clone());
639 let mut map = map_rc.borrow_mut();
640 let len = lua_table_sequence_len(&map);
641 let key = ValueKey::from_value(&Value::Int((len as LustInt) + 1));
642 if self.budgets.mem_budget_enabled() && !map.contains_key(&key) {
643 self.budgets.charge_map_entry_estimate()?;
644 }
645 map.insert(key, value);
646 Ok(Value::Nil)
647 }
648 "insert" => {
649 if args.len() != 2 {
650 return Err(LustError::RuntimeError {
651 message: "insert() requires 2 arguments (pos, value)".to_string(),
652 });
653 }
654 let pos_raw = super::corelib::unwrap_lua_value(args[0].clone());
655 let pos = pos_raw.as_int().unwrap_or(0).max(1) as usize;
656 let value = super::corelib::unwrap_lua_value(args[1].clone());
657 let mut seq = lua_table_read_sequence(&map_rc.borrow());
658 let idx = pos.saturating_sub(1);
659 if idx > seq.len() {
660 seq.push(value);
661 } else {
662 seq.insert(idx, value);
663 }
664 lua_table_write_sequence(&map_rc, &seq);
665 Ok(Value::Nil)
666 }
667 "remove" => {
668 if args.len() != 1 {
669 return Err(LustError::RuntimeError {
670 message: "remove() requires 1 argument (pos)".to_string(),
671 });
672 }
673 let pos_raw = super::corelib::unwrap_lua_value(args[0].clone());
674 let mut seq = lua_table_read_sequence(&map_rc.borrow());
675 if seq.is_empty() {
676 return Ok(Value::Nil);
677 }
678 let pos = pos_raw.as_int().unwrap_or(seq.len() as LustInt);
679 let idx =
680 ((pos - 1).max(0) as usize).min(seq.len().saturating_sub(1));
681 let removed = seq.remove(idx);
682 lua_table_write_sequence(&map_rc, &seq);
683 Ok(removed)
684 }
685 "concat" => {
686 if args.len() != 3 {
687 return Err(LustError::RuntimeError {
688 message: "concat() requires 3 arguments (sep, i, j)".to_string(),
689 });
690 }
691 let sep_raw = super::corelib::unwrap_lua_value(args[0].clone());
692 let sep = sep_raw.as_string().unwrap_or_default();
693 let seq = lua_table_read_sequence(&map_rc.borrow());
694 let start = super::corelib::unwrap_lua_value(args[1].clone())
695 .as_int()
696 .unwrap_or(1);
697 let end = super::corelib::unwrap_lua_value(args[2].clone())
698 .as_int()
699 .unwrap_or(seq.len() as LustInt);
700 let start_idx = (start - 1).max(0) as usize;
701 let end_idx = end.max(0) as usize;
702 let mut pieces: Vec<String> = Vec::new();
703 for (i, val) in seq.iter().enumerate() {
704 if i < start_idx || i >= end_idx {
705 continue;
706 }
707 let raw = super::corelib::unwrap_lua_value(val.clone());
708 pieces.push(format!("{}", raw));
709 }
710 Ok(Value::string(pieces.join(&sep)))
711 }
712 #[cfg(feature = "std")]
713 "unpack" => {
714 if args.len() != 2 {
715 return Err(LustError::RuntimeError {
716 message: "unpack() requires 2 arguments (i, j)".to_string(),
717 });
718 }
719 let unpack = super::stdlib::create_table_unpack_fn();
720 let Value::NativeFunction(func) = unpack else {
721 return Err(LustError::RuntimeError {
722 message: "unpack() builtin is not a native function".to_string(),
723 });
724 };
725 let call_args = vec![object.clone(), args[0].clone(), args[1].clone()];
726 match func(&call_args).map_err(|e| LustError::RuntimeError { message: e })? {
727 NativeCallResult::Return(value) => Ok(value),
728 NativeCallResult::Yield(_) => Err(LustError::RuntimeError {
729 message: "unpack() unexpectedly yielded".to_string(),
730 }),
731 NativeCallResult::Stop(_) => Err(LustError::RuntimeError {
732 message: "unpack() unexpectedly stopped execution".to_string(),
733 }),
734 }
735 }
736 "sort" => {
737 if args.len() != 1 {
738 return Err(LustError::RuntimeError {
739 message: "sort() requires 1 argument (comp)".to_string(),
740 });
741 }
742 let mut seq = lua_table_read_sequence(&map_rc.borrow());
743 seq.sort_by(|a, b| {
744 let la = format!("{}", super::corelib::unwrap_lua_value(a.clone()));
745 let lb = format!("{}", super::corelib::unwrap_lua_value(b.clone()));
746 la.cmp(&lb)
747 });
748 lua_table_write_sequence(&map_rc, &seq);
749 Ok(Value::Nil)
750 }
751 "maxn" => {
752 if !args.is_empty() {
753 return Err(LustError::RuntimeError {
754 message: "maxn() takes no arguments".to_string(),
755 });
756 }
757 let map = map_rc.borrow();
758 let mut max_idx: LustInt = 0;
759 for key in map.keys() {
760 if let Value::Int(i) = key.to_value() {
761 if i > max_idx && i > 0 {
762 max_idx = i;
763 }
764 }
765 }
766 Ok(Value::Int(max_idx))
767 }
768 _ => Err(LustError::RuntimeError {
769 message: format!("LuaTable has no method '{}'", method_name),
770 }),
771 }
772 }
773 Value::Enum {
774 enum_name,
775 variant,
776 values,
777 } if enum_name == "Option" => match method_name {
778 "is_some" => Ok(Value::Bool(variant == "Some")),
779 "is_none" => Ok(Value::Bool(variant == "None")),
780 "unwrap" => {
781 if variant == "Some" {
782 if let Some(vals) = values {
783 if !vals.is_empty() {
784 Ok(vals[0].clone())
785 } else {
786 Err(LustError::RuntimeError {
787 message: "Option::Some has no value".to_string(),
788 })
789 }
790 } else {
791 Err(LustError::RuntimeError {
792 message: "Option::Some has no value".to_string(),
793 })
794 }
795 } else {
796 Err(LustError::RuntimeError {
797 message: "Called unwrap() on Option::None".to_string(),
798 })
799 }
800 }
801
802 "unwrap_or" => {
803 if args.is_empty() {
804 return Err(LustError::RuntimeError {
805 message: "unwrap_or requires a default value".to_string(),
806 });
807 }
808
809 if variant == "Some" {
810 if let Some(vals) = values {
811 if !vals.is_empty() {
812 Ok(vals[0].clone())
813 } else {
814 Ok(args[0].clone())
815 }
816 } else {
817 Ok(args[0].clone())
818 }
819 } else {
820 Ok(args[0].clone())
821 }
822 }
823
824 _ => Err(LustError::RuntimeError {
825 message: format!("Option has no method '{}'", method_name),
826 }),
827 },
828 Value::Enum {
829 enum_name,
830 variant,
831 values,
832 } if enum_name == "Result" => match method_name {
833 "is_ok" => Ok(Value::Bool(variant == "Ok")),
834 "is_err" => Ok(Value::Bool(variant == "Err")),
835 "unwrap" => {
836 if variant == "Ok" {
837 if let Some(vals) = values {
838 if !vals.is_empty() {
839 Ok(vals[0].clone())
840 } else {
841 Err(LustError::RuntimeError {
842 message: "Result::Ok has no value".to_string(),
843 })
844 }
845 } else {
846 Err(LustError::RuntimeError {
847 message: "Result::Ok has no value".to_string(),
848 })
849 }
850 } else {
851 Err(LustError::RuntimeError {
852 message: "Called unwrap() on Result::Err".to_string(),
853 })
854 }
855 }
856
857 "unwrap_or" => {
858 if args.is_empty() {
859 return Err(LustError::RuntimeError {
860 message: "unwrap_or requires a default value".to_string(),
861 });
862 }
863
864 if variant == "Ok" {
865 if let Some(vals) = values {
866 if !vals.is_empty() {
867 Ok(vals[0].clone())
868 } else {
869 Ok(args[0].clone())
870 }
871 } else {
872 Ok(args[0].clone())
873 }
874 } else {
875 Ok(args[0].clone())
876 }
877 }
878
879 _ => Err(LustError::RuntimeError {
880 message: format!("Result has no method '{}'", method_name),
881 }),
882 },
883 Value::Array(arr) => match method_name {
884 "iter" => {
885 let items = arr.borrow().clone();
886 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
887 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
888 }
889
890 "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
891 "get" => {
892 if args.is_empty() {
893 return Err(LustError::RuntimeError {
894 message: "get requires an index argument".to_string(),
895 });
896 }
897
898 let index = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
899 message: "Array index must be an integer".to_string(),
900 })?;
901 let borrowed = arr.borrow();
902 if index < 0 || index as usize >= borrowed.len() {
903 Ok(Value::none())
904 } else {
905 Ok(Value::some(borrowed[index as usize].clone()))
906 }
907 }
908
909 "first" => {
910 let borrowed = arr.borrow();
911 if borrowed.is_empty() {
912 Ok(Value::none())
913 } else {
914 Ok(Value::some(borrowed[0].clone()))
915 }
916 }
917
918 "last" => {
919 let borrowed = arr.borrow();
920 if borrowed.is_empty() {
921 Ok(Value::none())
922 } else {
923 Ok(Value::some(borrowed[borrowed.len() - 1].clone()))
924 }
925 }
926
927 "push" => {
928 if args.is_empty() {
929 return Err(LustError::RuntimeError {
930 message: "push requires a value argument".to_string(),
931 });
932 }
933
934 let mut borrowed = arr.borrow_mut();
935 if self.budgets.mem_budget_enabled() {
936 let len = borrowed.len();
937 let cap = borrowed.capacity();
938 if len == cap {
939 let new_cap = if cap == 0 { 4 } else { cap.saturating_mul(2) };
940 self.budgets.charge_vec_growth::<Value>(cap, new_cap)?;
941 }
942 }
943 borrowed.push(args[0].clone());
944 Ok(Value::Nil)
945 }
946
947 "pop" => {
948 let popped = arr.borrow_mut().pop();
949 match popped {
950 Some(val) => Ok(Value::some(val)),
951 None => Ok(Value::none()),
952 }
953 }
954
955 "map" => {
956 if args.is_empty() {
957 return Err(LustError::RuntimeError {
958 message: "map requires a function argument".to_string(),
959 });
960 }
961
962 let func = &args[0];
963 let borrowed = arr.borrow();
964 self.budgets.charge_value_vec(borrowed.len())?;
965 let mut result = Vec::with_capacity(borrowed.len());
966 for elem in borrowed.iter() {
967 let mapped_value = self.call_value(func, vec![elem.clone()])?;
968 result.push(mapped_value);
969 }
970
971 Ok(Value::array(result))
972 }
973
974 "filter" => {
975 if args.is_empty() {
976 return Err(LustError::RuntimeError {
977 message: "filter requires a function argument".to_string(),
978 });
979 }
980
981 let func = &args[0];
982 let borrowed = arr.borrow();
983 self.budgets.charge_value_vec(borrowed.len())?;
984 let mut result = Vec::with_capacity(borrowed.len());
985 for elem in borrowed.iter() {
986 let keep = self.call_value(func, vec![elem.clone()])?;
987 if keep.is_truthy() {
988 result.push(elem.clone());
989 }
990 }
991
992 Ok(Value::array(result))
993 }
994
995 "reduce" => {
996 if args.len() < 2 {
997 return Err(LustError::RuntimeError {
998 message: "reduce requires an initial value and function".to_string(),
999 });
1000 }
1001
1002 let init_value = &args[0];
1003 let func = &args[1];
1004 let borrowed = arr.borrow();
1005 let mut accumulator = init_value.clone();
1006 for elem in borrowed.iter() {
1007 accumulator = self.call_value(func, vec![accumulator, elem.clone()])?;
1008 }
1009
1010 Ok(accumulator)
1011 }
1012
1013 "slice" => {
1014 if args.len() < 2 {
1015 return Err(LustError::RuntimeError {
1016 message: "slice requires start and end indices".to_string(),
1017 });
1018 }
1019
1020 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1021 message: "Start index must be an integer".to_string(),
1022 })? as usize;
1023 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1024 message: "End index must be an integer".to_string(),
1025 })? as usize;
1026 let borrowed = arr.borrow();
1027 if start > borrowed.len() || end > borrowed.len() || start > end {
1028 return Err(LustError::RuntimeError {
1029 message: "Invalid slice indices".to_string(),
1030 });
1031 }
1032
1033 let sliced = borrowed[start..end].to_vec();
1034 Ok(Value::array(sliced))
1035 }
1036
1037 "clear" => {
1038 arr.borrow_mut().clear();
1039 Ok(Value::Nil)
1040 }
1041
1042 "is_empty" => Ok(Value::Bool(arr.borrow().is_empty())),
1043 _ => Err(LustError::RuntimeError {
1044 message: format!("Array has no method '{}'", method_name),
1045 }),
1046 },
1047 Value::String(s) => match method_name {
1048 "iter" => {
1049 let items: Vec<Value> =
1050 s.chars().map(|c| Value::string(c.to_string())).collect();
1051 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
1052 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
1053 }
1054
1055 "len" => Ok(Value::Int(int_from_usize(s.len()))),
1056 "substring" => {
1057 if args.len() < 2 {
1058 return Err(LustError::RuntimeError {
1059 message: "substring requires start and end indices".to_string(),
1060 });
1061 }
1062
1063 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1064 message: "Start index must be an integer".to_string(),
1065 })? as usize;
1066 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1067 message: "End index must be an integer".to_string(),
1068 })? as usize;
1069 if start > s.len() || end > s.len() || start > end {
1070 return Err(LustError::RuntimeError {
1071 message: "Invalid substring indices".to_string(),
1072 });
1073 }
1074
1075 Ok(Value::string(&s[start..end]))
1076 }
1077
1078 "find" => {
1079 if args.is_empty() {
1080 return Err(LustError::RuntimeError {
1081 message: "find requires a search string".to_string(),
1082 });
1083 }
1084
1085 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1086 message: "Search string must be a string".to_string(),
1087 })?;
1088 match s.find(search) {
1089 Some(pos) => Ok(Value::some(Value::Int(int_from_usize(pos)))),
1090 None => Ok(Value::none()),
1091 }
1092 }
1093
1094 "starts_with" => {
1095 if args.is_empty() {
1096 return Err(LustError::RuntimeError {
1097 message: "starts_with requires a prefix string".to_string(),
1098 });
1099 }
1100
1101 let prefix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1102 message: "Prefix must be a string".to_string(),
1103 })?;
1104 Ok(Value::Bool(s.starts_with(prefix)))
1105 }
1106
1107 "ends_with" => {
1108 if args.is_empty() {
1109 return Err(LustError::RuntimeError {
1110 message: "ends_with requires a suffix string".to_string(),
1111 });
1112 }
1113
1114 let suffix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1115 message: "Suffix must be a string".to_string(),
1116 })?;
1117 Ok(Value::Bool(s.ends_with(suffix)))
1118 }
1119
1120 "split" => {
1121 if args.is_empty() {
1122 return Err(LustError::RuntimeError {
1123 message: "split requires a separator string".to_string(),
1124 });
1125 }
1126
1127 let separator = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1128 message: "Separator must be a string".to_string(),
1129 })?;
1130 let parts: Vec<Value> =
1131 s.split(separator).map(|part| Value::string(part)).collect();
1132 Ok(Value::array(parts))
1133 }
1134
1135 "trim" => Ok(Value::string(s.trim())),
1136 "trim_start" => Ok(Value::string(s.trim_start())),
1137 "trim_end" => Ok(Value::string(s.trim_end())),
1138 "replace" => {
1139 if args.len() < 2 {
1140 return Err(LustError::RuntimeError {
1141 message: "replace requires 'from' and 'to' string arguments"
1142 .to_string(),
1143 });
1144 }
1145
1146 let from = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1147 message: "First argument must be a string".to_string(),
1148 })?;
1149 let to = args[1].as_string().ok_or_else(|| LustError::RuntimeError {
1150 message: "Second argument must be a string".to_string(),
1151 })?;
1152 Ok(Value::string(&s.replace(from, to)))
1153 }
1154
1155 "to_upper" => Ok(Value::string(&s.to_uppercase())),
1156 "to_lower" => Ok(Value::string(&s.to_lowercase())),
1157 "contains" => {
1158 if args.is_empty() {
1159 return Err(LustError::RuntimeError {
1160 message: "contains requires a search string".to_string(),
1161 });
1162 }
1163
1164 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1165 message: "Search string must be a string".to_string(),
1166 })?;
1167 Ok(Value::Bool(s.contains(search)))
1168 }
1169
1170 "is_empty" => Ok(Value::Bool(s.is_empty())),
1171 "chars" => {
1172 let chars: Vec<Value> =
1173 s.chars().map(|c| Value::string(&c.to_string())).collect();
1174 Ok(Value::array(chars))
1175 }
1176
1177 "lines" => {
1178 let lines: Vec<Value> = s.lines().map(|line| Value::string(line)).collect();
1179 Ok(Value::array(lines))
1180 }
1181
1182 _ => Err(LustError::RuntimeError {
1183 message: format!("String has no method '{}'", method_name),
1184 }),
1185 },
1186 Value::Map(map) => {
1187 use crate::bytecode::ValueKey;
1188 match method_name {
1189 "iter" => {
1190 let items: Vec<(ValueKey, Value)> = map
1191 .borrow()
1192 .iter()
1193 .map(|(k, v)| (k.clone(), v.clone()))
1194 .collect();
1195 let iter =
1196 crate::bytecode::value::IteratorState::MapPairs { items, index: 0 };
1197 return Ok(Value::Iterator(Rc::new(RefCell::new(iter))));
1198 }
1199
1200 "len" => Ok(Value::Int(int_from_usize(map.borrow().len()))),
1201 "get" => {
1202 if args.is_empty() {
1203 return Err(LustError::RuntimeError {
1204 message: "get requires a key argument".to_string(),
1205 });
1206 }
1207
1208 let key = self.make_hash_key(&args[0])?;
1209 match map.borrow().get(&key) {
1210 Some(value) => Ok(Value::some(value.clone())),
1211 None => Ok(Value::none()),
1212 }
1213 }
1214
1215 "set" => {
1216 if args.len() < 2 {
1217 return Err(LustError::RuntimeError {
1218 message: "set requires key and value arguments".to_string(),
1219 });
1220 }
1221
1222 let key = self.make_hash_key(&args[0])?;
1223 let value = args[1].clone();
1224 if self.budgets.mem_budget_enabled() && !map.borrow().contains_key(&key) {
1225 self.budgets.charge_map_entry_estimate()?;
1226 }
1227 map.borrow_mut().insert(key, value);
1228 Ok(Value::Nil)
1229 }
1230
1231 "has" => {
1232 if args.is_empty() {
1233 return Err(LustError::RuntimeError {
1234 message: "has requires a key argument".to_string(),
1235 });
1236 }
1237
1238 let key = self.make_hash_key(&args[0])?;
1239 Ok(Value::Bool(map.borrow().contains_key(&key)))
1240 }
1241
1242 "delete" => {
1243 if args.is_empty() {
1244 return Err(LustError::RuntimeError {
1245 message: "delete requires a key argument".to_string(),
1246 });
1247 }
1248
1249 let key = self.make_hash_key(&args[0])?;
1250 match map.borrow_mut().remove(&key) {
1251 Some(value) => Ok(Value::some(value)),
1252 None => Ok(Value::none()),
1253 }
1254 }
1255
1256 "keys" => {
1257 let keys: Vec<Value> = map.borrow().keys().map(|k| k.to_value()).collect();
1258 Ok(Value::array(keys))
1259 }
1260
1261 "values" => {
1262 let values: Vec<Value> = map.borrow().values().cloned().collect();
1263 Ok(Value::array(values))
1264 }
1265
1266 _ => Err(LustError::RuntimeError {
1267 message: format!("Map has no method '{}'", method_name),
1268 }),
1269 }
1270 }
1271
1272 Value::Iterator(state_rc) => match method_name {
1273 "iter" => Ok(Value::Iterator(state_rc.clone())),
1274 "next" => {
1275 use crate::bytecode::value::IteratorState;
1276 let mut state = state_rc.borrow_mut();
1277 match &mut *state {
1278 IteratorState::Array { items, index } => {
1279 if *index < items.len() {
1280 let v = items[*index].clone();
1281 *index += 1;
1282 Ok(Value::some(v))
1283 } else {
1284 Ok(Value::none())
1285 }
1286 }
1287
1288 IteratorState::MapPairs { items, index } => {
1289 if *index < items.len() {
1290 let (k, v) = items[*index].clone();
1291 *index += 1;
1292 Ok(Value::some(Value::array(vec![k.to_value(), v])))
1293 } else {
1294 Ok(Value::none())
1295 }
1296 }
1297 }
1298 }
1299
1300 _ => Err(LustError::RuntimeError {
1301 message: format!("Iterator has no method '{}'", method_name),
1302 }),
1303 },
1304 Value::Float(f) => match method_name {
1305 "to_int" => {
1306 if !args.is_empty() {
1307 return Err(LustError::RuntimeError {
1308 message: "to_int() takes no arguments".to_string(),
1309 });
1310 }
1311
1312 Ok(Value::Int(int_from_float(*f)))
1313 }
1314
1315 "floor" => {
1316 if !args.is_empty() {
1317 return Err(LustError::RuntimeError {
1318 message: "floor() takes no arguments".to_string(),
1319 });
1320 }
1321
1322 Ok(Value::Float(float_floor(*f)))
1323 }
1324
1325 "ceil" => {
1326 if !args.is_empty() {
1327 return Err(LustError::RuntimeError {
1328 message: "ceil() takes no arguments".to_string(),
1329 });
1330 }
1331
1332 Ok(Value::Float(float_ceil(*f)))
1333 }
1334
1335 "round" => {
1336 if !args.is_empty() {
1337 return Err(LustError::RuntimeError {
1338 message: "round() takes no arguments".to_string(),
1339 });
1340 }
1341
1342 Ok(Value::Float(float_round(*f)))
1343 }
1344
1345 "sqrt" => {
1346 if !args.is_empty() {
1347 return Err(LustError::RuntimeError {
1348 message: "sqrt() takes no arguments".to_string(),
1349 });
1350 }
1351
1352 if *f < 0.0 {
1353 return Err(LustError::RuntimeError {
1354 message: "sqrt() requires a non-negative number".to_string(),
1355 });
1356 }
1357
1358 Ok(Value::Float(float_sqrt(*f)))
1359 }
1360
1361 "abs" => {
1362 if !args.is_empty() {
1363 return Err(LustError::RuntimeError {
1364 message: "abs() takes no arguments".to_string(),
1365 });
1366 }
1367
1368 Ok(Value::Float(float_abs(*f)))
1369 }
1370
1371 "sin" => {
1372 if !args.is_empty() {
1373 return Err(LustError::RuntimeError {
1374 message: "sin() takes no arguments".to_string(),
1375 });
1376 }
1377
1378 Ok(Value::Float(float_sin(*f)))
1379 }
1380
1381 "cos" => {
1382 if !args.is_empty() {
1383 return Err(LustError::RuntimeError {
1384 message: "cos() takes no arguments".to_string(),
1385 });
1386 }
1387
1388 Ok(Value::Float(float_cos(*f)))
1389 }
1390
1391 "tan" => {
1392 if !args.is_empty() {
1393 return Err(LustError::RuntimeError {
1394 message: "tan() takes no arguments".to_string(),
1395 });
1396 }
1397
1398 Ok(Value::Float(float_tan(*f)))
1399 }
1400
1401 "asin" => {
1402 if !args.is_empty() {
1403 return Err(LustError::RuntimeError {
1404 message: "asin() takes no arguments".to_string(),
1405 });
1406 }
1407
1408 Ok(Value::Float(float_asin(*f)))
1409 }
1410
1411 "acos" => {
1412 if !args.is_empty() {
1413 return Err(LustError::RuntimeError {
1414 message: "acos() takes no arguments".to_string(),
1415 });
1416 }
1417
1418 Ok(Value::Float(float_acos(*f)))
1419 }
1420
1421 "atan" => {
1422 if !args.is_empty() {
1423 return Err(LustError::RuntimeError {
1424 message: "atan() takes no arguments".to_string(),
1425 });
1426 }
1427
1428 Ok(Value::Float(float_atan(*f)))
1429 }
1430
1431 "atan2" => {
1432 if args.len() != 1 {
1433 return Err(LustError::RuntimeError {
1434 message: "atan2() requires 1 argument (other)".to_string(),
1435 });
1436 }
1437 let other = args[0].as_float().ok_or_else(|| LustError::RuntimeError {
1438 message: "atan2() other must be a number".to_string(),
1439 })?;
1440 Ok(Value::Float(float_atan2(*f, other)))
1441 }
1442
1443 "min" => {
1444 if args.len() != 1 {
1445 return Err(LustError::RuntimeError {
1446 message: "min() requires 1 argument (other)".to_string(),
1447 });
1448 }
1449 let other = args[0]
1450 .as_float()
1451 .or_else(|| args[0].as_int().map(float_from_int))
1452 .ok_or_else(|| LustError::RuntimeError {
1453 message: "min() other must be a number".to_string(),
1454 })?;
1455 Ok(Value::Float(f.min(other)))
1456 }
1457
1458 "max" => {
1459 if args.len() != 1 {
1460 return Err(LustError::RuntimeError {
1461 message: "max() requires 1 argument (other)".to_string(),
1462 });
1463 }
1464 let other = args[0]
1465 .as_float()
1466 .or_else(|| args[0].as_int().map(float_from_int))
1467 .ok_or_else(|| LustError::RuntimeError {
1468 message: "max() other must be a number".to_string(),
1469 })?;
1470 Ok(Value::Float(f.max(other)))
1471 }
1472
1473 "clamp" => {
1474 if args.len() != 2 {
1475 return Err(LustError::RuntimeError {
1476 message: "clamp() requires 2 arguments (min, max)".to_string(),
1477 });
1478 }
1479
1480 let min = args[0].as_float().ok_or_else(|| LustError::RuntimeError {
1481 message: "clamp() min must be a number".to_string(),
1482 })?;
1483 let max = args[1].as_float().ok_or_else(|| LustError::RuntimeError {
1484 message: "clamp() max must be a number".to_string(),
1485 })?;
1486 if min > max {
1487 return Err(LustError::RuntimeError {
1488 message: "clamp() min must be less than or equal to max".to_string(),
1489 });
1490 }
1491
1492 Ok(Value::Float(float_clamp(*f, min, max)))
1493 }
1494
1495 _ => Err(LustError::RuntimeError {
1496 message: format!("Float has no method '{}'", method_name),
1497 }),
1498 },
1499 Value::Int(i) => match method_name {
1500 "to_float" => {
1501 if !args.is_empty() {
1502 return Err(LustError::RuntimeError {
1503 message: "to_float() takes no arguments".to_string(),
1504 });
1505 }
1506
1507 Ok(Value::Float(float_from_int(*i)))
1508 }
1509
1510 "abs" => {
1511 if !args.is_empty() {
1512 return Err(LustError::RuntimeError {
1513 message: "abs() takes no arguments".to_string(),
1514 });
1515 }
1516
1517 Ok(Value::Int(i.abs()))
1518 }
1519
1520 "min" => {
1521 if args.len() != 1 {
1522 return Err(LustError::RuntimeError {
1523 message: "min() requires 1 argument (other)".to_string(),
1524 });
1525 }
1526 if let Some(other) = args[0].as_int() {
1527 return Ok(Value::Int((*i).min(other)));
1528 }
1529 if let Some(other) = args[0].as_float() {
1530 return Ok(Value::Float(float_from_int(*i).min(other)));
1531 }
1532 Err(LustError::RuntimeError {
1533 message: "min() other must be a number".to_string(),
1534 })
1535 }
1536
1537 "max" => {
1538 if args.len() != 1 {
1539 return Err(LustError::RuntimeError {
1540 message: "max() requires 1 argument (other)".to_string(),
1541 });
1542 }
1543 if let Some(other) = args[0].as_int() {
1544 return Ok(Value::Int((*i).max(other)));
1545 }
1546 if let Some(other) = args[0].as_float() {
1547 return Ok(Value::Float(float_from_int(*i).max(other)));
1548 }
1549 Err(LustError::RuntimeError {
1550 message: "max() other must be a number".to_string(),
1551 })
1552 }
1553
1554 "clamp" => {
1555 if args.len() != 2 {
1556 return Err(LustError::RuntimeError {
1557 message: "clamp() requires 2 arguments (min, max)".to_string(),
1558 });
1559 }
1560
1561 let min = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1562 message: "clamp() min must be an integer".to_string(),
1563 })?;
1564 let max = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1565 message: "clamp() max must be an integer".to_string(),
1566 })?;
1567 if min > max {
1568 return Err(LustError::RuntimeError {
1569 message: "clamp() min must be less than or equal to max".to_string(),
1570 });
1571 }
1572
1573 Ok(Value::Int((*i).clamp(min, max)))
1574 }
1575
1576 _ => Err(LustError::RuntimeError {
1577 message: format!("Int has no method '{}'", method_name),
1578 }),
1579 },
1580 _ => Err(LustError::RuntimeError {
1581 message: format!(
1582 "Type {:?} has no method '{}'",
1583 object.type_of(),
1584 method_name
1585 ),
1586 }),
1587 }
1588 }
1589
1590 fn try_call_lua_dynamic_method(
1591 &mut self,
1592 receiver: &Value,
1593 method_name: &str,
1594 args: &[Value],
1595 ) -> Result<Option<Value>> {
1596 let key = Value::string(method_name.to_string());
1597 let method = self.lua_resolve_index(receiver, &key, 8)?;
1598 if matches!(method, Value::Nil) {
1599 return Ok(None);
1600 }
1601
1602 let mut call_args = Vec::with_capacity(1 + args.len());
1603 call_args.push(receiver.clone());
1604 call_args.extend_from_slice(args);
1605 let result = self.call_value(&method, call_args)?;
1606 Ok(Some(result))
1607 }
1608
1609 fn lua_resolve_index(&mut self, receiver: &Value, key: &Value, depth: usize) -> Result<Value> {
1610 if depth == 0 {
1611 return Ok(Value::Nil);
1612 }
1613
1614 if let Some(direct) = self.lua_direct_index(receiver, key) {
1615 if !matches!(direct, Value::Nil) {
1616 return Ok(direct);
1617 }
1618 }
1619
1620 let Some(indexer) = self.lua_index_metamethod(receiver) else {
1621 return Ok(Value::Nil);
1622 };
1623 if matches!(indexer, Value::Nil) {
1624 return Ok(Value::Nil);
1625 }
1626
1627 let is_callable = matches!(
1628 indexer,
1629 Value::Function(_) | Value::Closure { .. } | Value::NativeFunction(_)
1630 ) || matches!(
1631 &indexer,
1632 Value::Enum {
1633 enum_name,
1634 variant,
1635 ..
1636 } if enum_name == "LuaValue" && variant == "Function"
1637 );
1638
1639 if is_callable {
1640 self.call_value(&indexer, vec![receiver.clone(), key.clone()])
1641 } else {
1642 self.lua_resolve_index(&indexer, key, depth - 1)
1643 }
1644 }
1645
1646 fn lua_direct_index(&self, receiver: &Value, key: &Value) -> Option<Value> {
1647 if let Value::Enum {
1648 enum_name,
1649 variant,
1650 values,
1651 } = receiver
1652 {
1653 if enum_name == "LuaValue" && variant == "Table" {
1654 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1655 return self.lua_direct_index(inner, key);
1656 }
1657 }
1658 }
1659
1660 match receiver {
1661 Value::Struct { name, .. } if name == "LuaTable" => {
1662 let Some(Value::Map(map_rc)) = receiver.struct_get_field("table") else {
1663 return None;
1664 };
1665 let raw_key = super::corelib::unwrap_lua_value(key.clone());
1666 let lookup_key = ValueKey::from_value(&raw_key);
1667 let value = map_rc.borrow().get(&lookup_key).cloned();
1668 value
1669 }
1670 Value::Map(map_rc) => {
1671 let raw_key = super::corelib::unwrap_lua_value(key.clone());
1672 let lookup_key = ValueKey::from_value(&raw_key);
1673 let value = map_rc.borrow().get(&lookup_key).cloned();
1674 value
1675 }
1676 _ => None,
1677 }
1678 }
1679
1680 fn lua_index_metamethod(&self, receiver: &Value) -> Option<Value> {
1681 if let Value::Enum {
1682 enum_name,
1683 variant,
1684 values,
1685 } = receiver
1686 {
1687 if enum_name == "LuaValue" && variant == "Table" {
1688 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1689 return self.lua_index_metamethod(inner);
1690 }
1691 }
1692 if enum_name == "LuaValue" && variant == "Userdata" {
1693 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1694 return self.lua_index_metamethod(inner);
1695 }
1696 }
1697 }
1698
1699 let Value::Struct { name, .. } = receiver else {
1700 return None;
1701 };
1702 let Some(Value::Map(meta_rc)) = receiver.struct_get_field("metamethods") else {
1703 return None;
1704 };
1705 if name != "LuaTable" && name != "LuaUserdata" {
1706 return None;
1707 }
1708 let value = meta_rc
1709 .borrow()
1710 .get(&ValueKey::string("__index".to_string()))
1711 .cloned();
1712 value
1713 }
1714}
1715
1716fn lua_table_map_rc(table: &Value) -> Option<Rc<RefCell<LustMap>>> {
1717 match table.struct_get_field("table") {
1718 Some(Value::Map(map_rc)) => Some(map_rc),
1719 _ => None,
1720 }
1721}
1722
1723fn lua_table_sequence_len(map: &LustMap) -> usize {
1724 let mut idx: LustInt = 1;
1725 loop {
1726 let key = ValueKey::from_value(&Value::Int(idx));
1727 if map.contains_key(&key) {
1728 idx += 1;
1729 } else {
1730 break;
1731 }
1732 }
1733 (idx - 1) as usize
1734}
1735
1736fn lua_table_read_sequence(map: &LustMap) -> Vec<Value> {
1737 let mut seq: Vec<Value> = Vec::new();
1738 let mut idx: LustInt = 1;
1739 loop {
1740 let key = ValueKey::from_value(&Value::Int(idx));
1741 if let Some(val) = map.get(&key) {
1742 seq.push(val.clone());
1743 idx += 1;
1744 } else {
1745 break;
1746 }
1747 }
1748 seq
1749}
1750
1751fn lua_table_write_sequence(map_rc: &Rc<RefCell<LustMap>>, seq: &[Value]) {
1752 let mut map = map_rc.borrow_mut();
1753 let mut idx: LustInt = 1;
1754 loop {
1755 let key = ValueKey::from_value(&Value::Int(idx));
1756 if map.remove(&key).is_some() {
1757 idx += 1;
1758 } else {
1759 break;
1760 }
1761 }
1762 for (i, val) in seq.iter().enumerate() {
1763 let key = ValueKey::from_value(&Value::Int((i as LustInt) + 1));
1764 map.insert(key, val.clone());
1765 }
1766}