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 i64) {
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: std::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 "unpack" => {
713 if args.len() != 2 {
714 return Err(LustError::RuntimeError {
715 message: "unpack() requires 2 arguments (i, j)".to_string(),
716 });
717 }
718 let unpack = super::stdlib::create_table_unpack_fn();
719 let Value::NativeFunction(func) = unpack else {
720 return Err(LustError::RuntimeError {
721 message: "unpack() builtin is not a native function".to_string(),
722 });
723 };
724 let call_args = vec![object.clone(), args[0].clone(), args[1].clone()];
725 match func(&call_args).map_err(|e| LustError::RuntimeError { message: e })? {
726 NativeCallResult::Return(value) => Ok(value),
727 NativeCallResult::Yield(_) => Err(LustError::RuntimeError {
728 message: "unpack() unexpectedly yielded".to_string(),
729 }),
730 NativeCallResult::Stop(_) => Err(LustError::RuntimeError {
731 message: "unpack() unexpectedly stopped execution".to_string(),
732 }),
733 }
734 }
735 "sort" => {
736 if args.len() != 1 {
737 return Err(LustError::RuntimeError {
738 message: "sort() requires 1 argument (comp)".to_string(),
739 });
740 }
741 let mut seq = lua_table_read_sequence(&map_rc.borrow());
742 seq.sort_by(|a, b| {
743 let la = format!("{}", super::corelib::unwrap_lua_value(a.clone()));
744 let lb = format!("{}", super::corelib::unwrap_lua_value(b.clone()));
745 la.cmp(&lb)
746 });
747 lua_table_write_sequence(&map_rc, &seq);
748 Ok(Value::Nil)
749 }
750 "maxn" => {
751 if !args.is_empty() {
752 return Err(LustError::RuntimeError {
753 message: "maxn() takes no arguments".to_string(),
754 });
755 }
756 let map = map_rc.borrow();
757 let mut max_idx: LustInt = 0;
758 for key in map.keys() {
759 if let Value::Int(i) = key.to_value() {
760 if i > max_idx && i > 0 {
761 max_idx = i;
762 }
763 }
764 }
765 Ok(Value::Int(max_idx))
766 }
767 _ => Err(LustError::RuntimeError {
768 message: format!("LuaTable has no method '{}'", method_name),
769 }),
770 }
771 }
772 Value::Enum {
773 enum_name,
774 variant,
775 values,
776 } if enum_name == "Option" => match method_name {
777 "is_some" => Ok(Value::Bool(variant == "Some")),
778 "is_none" => Ok(Value::Bool(variant == "None")),
779 "unwrap" => {
780 if variant == "Some" {
781 if let Some(vals) = values {
782 if !vals.is_empty() {
783 Ok(vals[0].clone())
784 } else {
785 Err(LustError::RuntimeError {
786 message: "Option::Some has no value".to_string(),
787 })
788 }
789 } else {
790 Err(LustError::RuntimeError {
791 message: "Option::Some has no value".to_string(),
792 })
793 }
794 } else {
795 Err(LustError::RuntimeError {
796 message: "Called unwrap() on Option::None".to_string(),
797 })
798 }
799 }
800
801 "unwrap_or" => {
802 if args.is_empty() {
803 return Err(LustError::RuntimeError {
804 message: "unwrap_or requires a default value".to_string(),
805 });
806 }
807
808 if variant == "Some" {
809 if let Some(vals) = values {
810 if !vals.is_empty() {
811 Ok(vals[0].clone())
812 } else {
813 Ok(args[0].clone())
814 }
815 } else {
816 Ok(args[0].clone())
817 }
818 } else {
819 Ok(args[0].clone())
820 }
821 }
822
823 _ => Err(LustError::RuntimeError {
824 message: format!("Option has no method '{}'", method_name),
825 }),
826 },
827 Value::Enum {
828 enum_name,
829 variant,
830 values,
831 } if enum_name == "Result" => match method_name {
832 "is_ok" => Ok(Value::Bool(variant == "Ok")),
833 "is_err" => Ok(Value::Bool(variant == "Err")),
834 "unwrap" => {
835 if variant == "Ok" {
836 if let Some(vals) = values {
837 if !vals.is_empty() {
838 Ok(vals[0].clone())
839 } else {
840 Err(LustError::RuntimeError {
841 message: "Result::Ok has no value".to_string(),
842 })
843 }
844 } else {
845 Err(LustError::RuntimeError {
846 message: "Result::Ok has no value".to_string(),
847 })
848 }
849 } else {
850 Err(LustError::RuntimeError {
851 message: "Called unwrap() on Result::Err".to_string(),
852 })
853 }
854 }
855
856 "unwrap_or" => {
857 if args.is_empty() {
858 return Err(LustError::RuntimeError {
859 message: "unwrap_or requires a default value".to_string(),
860 });
861 }
862
863 if variant == "Ok" {
864 if let Some(vals) = values {
865 if !vals.is_empty() {
866 Ok(vals[0].clone())
867 } else {
868 Ok(args[0].clone())
869 }
870 } else {
871 Ok(args[0].clone())
872 }
873 } else {
874 Ok(args[0].clone())
875 }
876 }
877
878 _ => Err(LustError::RuntimeError {
879 message: format!("Result has no method '{}'", method_name),
880 }),
881 },
882 Value::Array(arr) => match method_name {
883 "iter" => {
884 let items = arr.borrow().clone();
885 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
886 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
887 }
888
889 "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
890 "get" => {
891 if args.is_empty() {
892 return Err(LustError::RuntimeError {
893 message: "get requires an index argument".to_string(),
894 });
895 }
896
897 let index = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
898 message: "Array index must be an integer".to_string(),
899 })?;
900 let borrowed = arr.borrow();
901 if index < 0 || index as usize >= borrowed.len() {
902 Ok(Value::none())
903 } else {
904 Ok(Value::some(borrowed[index as usize].clone()))
905 }
906 }
907
908 "first" => {
909 let borrowed = arr.borrow();
910 if borrowed.is_empty() {
911 Ok(Value::none())
912 } else {
913 Ok(Value::some(borrowed[0].clone()))
914 }
915 }
916
917 "last" => {
918 let borrowed = arr.borrow();
919 if borrowed.is_empty() {
920 Ok(Value::none())
921 } else {
922 Ok(Value::some(borrowed[borrowed.len() - 1].clone()))
923 }
924 }
925
926 "push" => {
927 if args.is_empty() {
928 return Err(LustError::RuntimeError {
929 message: "push requires a value argument".to_string(),
930 });
931 }
932
933 let mut borrowed = arr.borrow_mut();
934 if self.budgets.mem_budget_enabled() {
935 let len = borrowed.len();
936 let cap = borrowed.capacity();
937 if len == cap {
938 let new_cap = if cap == 0 { 4 } else { cap.saturating_mul(2) };
939 self.budgets.charge_vec_growth::<Value>(cap, new_cap)?;
940 }
941 }
942 borrowed.push(args[0].clone());
943 Ok(Value::Nil)
944 }
945
946 "pop" => {
947 let popped = arr.borrow_mut().pop();
948 match popped {
949 Some(val) => Ok(Value::some(val)),
950 None => Ok(Value::none()),
951 }
952 }
953
954 "map" => {
955 if args.is_empty() {
956 return Err(LustError::RuntimeError {
957 message: "map requires a function argument".to_string(),
958 });
959 }
960
961 let func = &args[0];
962 let borrowed = arr.borrow();
963 self.budgets.charge_value_vec(borrowed.len())?;
964 let mut result = Vec::with_capacity(borrowed.len());
965 for elem in borrowed.iter() {
966 let mapped_value = self.call_value(func, vec![elem.clone()])?;
967 result.push(mapped_value);
968 }
969
970 Ok(Value::array(result))
971 }
972
973 "filter" => {
974 if args.is_empty() {
975 return Err(LustError::RuntimeError {
976 message: "filter requires a function argument".to_string(),
977 });
978 }
979
980 let func = &args[0];
981 let borrowed = arr.borrow();
982 self.budgets.charge_value_vec(borrowed.len())?;
983 let mut result = Vec::with_capacity(borrowed.len());
984 for elem in borrowed.iter() {
985 let keep = self.call_value(func, vec![elem.clone()])?;
986 if keep.is_truthy() {
987 result.push(elem.clone());
988 }
989 }
990
991 Ok(Value::array(result))
992 }
993
994 "reduce" => {
995 if args.len() < 2 {
996 return Err(LustError::RuntimeError {
997 message: "reduce requires an initial value and function".to_string(),
998 });
999 }
1000
1001 let init_value = &args[0];
1002 let func = &args[1];
1003 let borrowed = arr.borrow();
1004 let mut accumulator = init_value.clone();
1005 for elem in borrowed.iter() {
1006 accumulator = self.call_value(func, vec![accumulator, elem.clone()])?;
1007 }
1008
1009 Ok(accumulator)
1010 }
1011
1012 "slice" => {
1013 if args.len() < 2 {
1014 return Err(LustError::RuntimeError {
1015 message: "slice requires start and end indices".to_string(),
1016 });
1017 }
1018
1019 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1020 message: "Start index must be an integer".to_string(),
1021 })? as usize;
1022 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1023 message: "End index must be an integer".to_string(),
1024 })? as usize;
1025 let borrowed = arr.borrow();
1026 if start > borrowed.len() || end > borrowed.len() || start > end {
1027 return Err(LustError::RuntimeError {
1028 message: "Invalid slice indices".to_string(),
1029 });
1030 }
1031
1032 let sliced = borrowed[start..end].to_vec();
1033 Ok(Value::array(sliced))
1034 }
1035
1036 "clear" => {
1037 arr.borrow_mut().clear();
1038 Ok(Value::Nil)
1039 }
1040
1041 "is_empty" => Ok(Value::Bool(arr.borrow().is_empty())),
1042 _ => Err(LustError::RuntimeError {
1043 message: format!("Array has no method '{}'", method_name),
1044 }),
1045 },
1046 Value::String(s) => match method_name {
1047 "iter" => {
1048 let items: Vec<Value> =
1049 s.chars().map(|c| Value::string(c.to_string())).collect();
1050 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
1051 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
1052 }
1053
1054 "len" => Ok(Value::Int(int_from_usize(s.len()))),
1055 "substring" => {
1056 if args.len() < 2 {
1057 return Err(LustError::RuntimeError {
1058 message: "substring requires start and end indices".to_string(),
1059 });
1060 }
1061
1062 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1063 message: "Start index must be an integer".to_string(),
1064 })? as usize;
1065 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1066 message: "End index must be an integer".to_string(),
1067 })? as usize;
1068 if start > s.len() || end > s.len() || start > end {
1069 return Err(LustError::RuntimeError {
1070 message: "Invalid substring indices".to_string(),
1071 });
1072 }
1073
1074 Ok(Value::string(&s[start..end]))
1075 }
1076
1077 "find" => {
1078 if args.is_empty() {
1079 return Err(LustError::RuntimeError {
1080 message: "find requires a search string".to_string(),
1081 });
1082 }
1083
1084 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1085 message: "Search string must be a string".to_string(),
1086 })?;
1087 match s.find(search) {
1088 Some(pos) => Ok(Value::some(Value::Int(int_from_usize(pos)))),
1089 None => Ok(Value::none()),
1090 }
1091 }
1092
1093 "starts_with" => {
1094 if args.is_empty() {
1095 return Err(LustError::RuntimeError {
1096 message: "starts_with requires a prefix string".to_string(),
1097 });
1098 }
1099
1100 let prefix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1101 message: "Prefix must be a string".to_string(),
1102 })?;
1103 Ok(Value::Bool(s.starts_with(prefix)))
1104 }
1105
1106 "ends_with" => {
1107 if args.is_empty() {
1108 return Err(LustError::RuntimeError {
1109 message: "ends_with requires a suffix string".to_string(),
1110 });
1111 }
1112
1113 let suffix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1114 message: "Suffix must be a string".to_string(),
1115 })?;
1116 Ok(Value::Bool(s.ends_with(suffix)))
1117 }
1118
1119 "split" => {
1120 if args.is_empty() {
1121 return Err(LustError::RuntimeError {
1122 message: "split requires a separator string".to_string(),
1123 });
1124 }
1125
1126 let separator = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1127 message: "Separator must be a string".to_string(),
1128 })?;
1129 let parts: Vec<Value> =
1130 s.split(separator).map(|part| Value::string(part)).collect();
1131 Ok(Value::array(parts))
1132 }
1133
1134 "trim" => Ok(Value::string(s.trim())),
1135 "trim_start" => Ok(Value::string(s.trim_start())),
1136 "trim_end" => Ok(Value::string(s.trim_end())),
1137 "replace" => {
1138 if args.len() < 2 {
1139 return Err(LustError::RuntimeError {
1140 message: "replace requires 'from' and 'to' string arguments"
1141 .to_string(),
1142 });
1143 }
1144
1145 let from = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1146 message: "First argument must be a string".to_string(),
1147 })?;
1148 let to = args[1].as_string().ok_or_else(|| LustError::RuntimeError {
1149 message: "Second argument must be a string".to_string(),
1150 })?;
1151 Ok(Value::string(&s.replace(from, to)))
1152 }
1153
1154 "to_upper" => Ok(Value::string(&s.to_uppercase())),
1155 "to_lower" => Ok(Value::string(&s.to_lowercase())),
1156 "contains" => {
1157 if args.is_empty() {
1158 return Err(LustError::RuntimeError {
1159 message: "contains requires a search string".to_string(),
1160 });
1161 }
1162
1163 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
1164 message: "Search string must be a string".to_string(),
1165 })?;
1166 Ok(Value::Bool(s.contains(search)))
1167 }
1168
1169 "is_empty" => Ok(Value::Bool(s.is_empty())),
1170 "chars" => {
1171 let chars: Vec<Value> =
1172 s.chars().map(|c| Value::string(&c.to_string())).collect();
1173 Ok(Value::array(chars))
1174 }
1175
1176 "lines" => {
1177 let lines: Vec<Value> = s.lines().map(|line| Value::string(line)).collect();
1178 Ok(Value::array(lines))
1179 }
1180
1181 _ => Err(LustError::RuntimeError {
1182 message: format!("String has no method '{}'", method_name),
1183 }),
1184 },
1185 Value::Map(map) => {
1186 use crate::bytecode::ValueKey;
1187 match method_name {
1188 "iter" => {
1189 let items: Vec<(ValueKey, Value)> = map
1190 .borrow()
1191 .iter()
1192 .map(|(k, v)| (k.clone(), v.clone()))
1193 .collect();
1194 let iter =
1195 crate::bytecode::value::IteratorState::MapPairs { items, index: 0 };
1196 return Ok(Value::Iterator(Rc::new(RefCell::new(iter))));
1197 }
1198
1199 "len" => Ok(Value::Int(int_from_usize(map.borrow().len()))),
1200 "get" => {
1201 if args.is_empty() {
1202 return Err(LustError::RuntimeError {
1203 message: "get requires a key argument".to_string(),
1204 });
1205 }
1206
1207 let key = self.make_hash_key(&args[0])?;
1208 match map.borrow().get(&key) {
1209 Some(value) => Ok(Value::some(value.clone())),
1210 None => Ok(Value::none()),
1211 }
1212 }
1213
1214 "set" => {
1215 if args.len() < 2 {
1216 return Err(LustError::RuntimeError {
1217 message: "set requires key and value arguments".to_string(),
1218 });
1219 }
1220
1221 let key = self.make_hash_key(&args[0])?;
1222 let value = args[1].clone();
1223 if self.budgets.mem_budget_enabled() && !map.borrow().contains_key(&key) {
1224 self.budgets.charge_map_entry_estimate()?;
1225 }
1226 map.borrow_mut().insert(key, value);
1227 Ok(Value::Nil)
1228 }
1229
1230 "has" => {
1231 if args.is_empty() {
1232 return Err(LustError::RuntimeError {
1233 message: "has requires a key argument".to_string(),
1234 });
1235 }
1236
1237 let key = self.make_hash_key(&args[0])?;
1238 Ok(Value::Bool(map.borrow().contains_key(&key)))
1239 }
1240
1241 "delete" => {
1242 if args.is_empty() {
1243 return Err(LustError::RuntimeError {
1244 message: "delete requires a key argument".to_string(),
1245 });
1246 }
1247
1248 let key = self.make_hash_key(&args[0])?;
1249 match map.borrow_mut().remove(&key) {
1250 Some(value) => Ok(Value::some(value)),
1251 None => Ok(Value::none()),
1252 }
1253 }
1254
1255 "keys" => {
1256 let keys: Vec<Value> = map.borrow().keys().map(|k| k.to_value()).collect();
1257 Ok(Value::array(keys))
1258 }
1259
1260 "values" => {
1261 let values: Vec<Value> = map.borrow().values().cloned().collect();
1262 Ok(Value::array(values))
1263 }
1264
1265 _ => Err(LustError::RuntimeError {
1266 message: format!("Map has no method '{}'", method_name),
1267 }),
1268 }
1269 }
1270
1271 Value::Iterator(state_rc) => match method_name {
1272 "iter" => Ok(Value::Iterator(state_rc.clone())),
1273 "next" => {
1274 use crate::bytecode::value::IteratorState;
1275 let mut state = state_rc.borrow_mut();
1276 match &mut *state {
1277 IteratorState::Array { items, index } => {
1278 if *index < items.len() {
1279 let v = items[*index].clone();
1280 *index += 1;
1281 Ok(Value::some(v))
1282 } else {
1283 Ok(Value::none())
1284 }
1285 }
1286
1287 IteratorState::MapPairs { items, index } => {
1288 if *index < items.len() {
1289 let (k, v) = items[*index].clone();
1290 *index += 1;
1291 Ok(Value::some(Value::array(vec![k.to_value(), v])))
1292 } else {
1293 Ok(Value::none())
1294 }
1295 }
1296 }
1297 }
1298
1299 _ => Err(LustError::RuntimeError {
1300 message: format!("Iterator has no method '{}'", method_name),
1301 }),
1302 },
1303 Value::Float(f) => match method_name {
1304 "to_int" => {
1305 if !args.is_empty() {
1306 return Err(LustError::RuntimeError {
1307 message: "to_int() takes no arguments".to_string(),
1308 });
1309 }
1310
1311 Ok(Value::Int(int_from_float(*f)))
1312 }
1313
1314 "floor" => {
1315 if !args.is_empty() {
1316 return Err(LustError::RuntimeError {
1317 message: "floor() takes no arguments".to_string(),
1318 });
1319 }
1320
1321 Ok(Value::Float(float_floor(*f)))
1322 }
1323
1324 "ceil" => {
1325 if !args.is_empty() {
1326 return Err(LustError::RuntimeError {
1327 message: "ceil() takes no arguments".to_string(),
1328 });
1329 }
1330
1331 Ok(Value::Float(float_ceil(*f)))
1332 }
1333
1334 "round" => {
1335 if !args.is_empty() {
1336 return Err(LustError::RuntimeError {
1337 message: "round() takes no arguments".to_string(),
1338 });
1339 }
1340
1341 Ok(Value::Float(float_round(*f)))
1342 }
1343
1344 "sqrt" => {
1345 if !args.is_empty() {
1346 return Err(LustError::RuntimeError {
1347 message: "sqrt() takes no arguments".to_string(),
1348 });
1349 }
1350
1351 if *f < 0.0 {
1352 return Err(LustError::RuntimeError {
1353 message: "sqrt() requires a non-negative number".to_string(),
1354 });
1355 }
1356
1357 Ok(Value::Float(float_sqrt(*f)))
1358 }
1359
1360 "abs" => {
1361 if !args.is_empty() {
1362 return Err(LustError::RuntimeError {
1363 message: "abs() takes no arguments".to_string(),
1364 });
1365 }
1366
1367 Ok(Value::Float(float_abs(*f)))
1368 }
1369
1370 "min" => {
1371 if args.len() != 1 {
1372 return Err(LustError::RuntimeError {
1373 message: "min() requires 1 argument (other)".to_string(),
1374 });
1375 }
1376 let other = args[0]
1377 .as_float()
1378 .or_else(|| args[0].as_int().map(float_from_int))
1379 .ok_or_else(|| LustError::RuntimeError {
1380 message: "min() other must be a number".to_string(),
1381 })?;
1382 Ok(Value::Float(f.min(other)))
1383 }
1384
1385 "max" => {
1386 if args.len() != 1 {
1387 return Err(LustError::RuntimeError {
1388 message: "max() requires 1 argument (other)".to_string(),
1389 });
1390 }
1391 let other = args[0]
1392 .as_float()
1393 .or_else(|| args[0].as_int().map(float_from_int))
1394 .ok_or_else(|| LustError::RuntimeError {
1395 message: "max() other must be a number".to_string(),
1396 })?;
1397 Ok(Value::Float(f.max(other)))
1398 }
1399
1400 "clamp" => {
1401 if args.len() != 2 {
1402 return Err(LustError::RuntimeError {
1403 message: "clamp() requires 2 arguments (min, max)".to_string(),
1404 });
1405 }
1406
1407 let min = args[0].as_float().ok_or_else(|| LustError::RuntimeError {
1408 message: "clamp() min must be a number".to_string(),
1409 })?;
1410 let max = args[1].as_float().ok_or_else(|| LustError::RuntimeError {
1411 message: "clamp() max must be a number".to_string(),
1412 })?;
1413 if min > max {
1414 return Err(LustError::RuntimeError {
1415 message: "clamp() min must be less than or equal to max".to_string(),
1416 });
1417 }
1418
1419 Ok(Value::Float(float_clamp(*f, min, max)))
1420 }
1421
1422 _ => Err(LustError::RuntimeError {
1423 message: format!("Float has no method '{}'", method_name),
1424 }),
1425 },
1426 Value::Int(i) => match method_name {
1427 "to_float" => {
1428 if !args.is_empty() {
1429 return Err(LustError::RuntimeError {
1430 message: "to_float() takes no arguments".to_string(),
1431 });
1432 }
1433
1434 Ok(Value::Float(float_from_int(*i)))
1435 }
1436
1437 "abs" => {
1438 if !args.is_empty() {
1439 return Err(LustError::RuntimeError {
1440 message: "abs() takes no arguments".to_string(),
1441 });
1442 }
1443
1444 Ok(Value::Int(i.abs()))
1445 }
1446
1447 "min" => {
1448 if args.len() != 1 {
1449 return Err(LustError::RuntimeError {
1450 message: "min() requires 1 argument (other)".to_string(),
1451 });
1452 }
1453 if let Some(other) = args[0].as_int() {
1454 return Ok(Value::Int((*i).min(other)));
1455 }
1456 if let Some(other) = args[0].as_float() {
1457 return Ok(Value::Float(float_from_int(*i).min(other)));
1458 }
1459 Err(LustError::RuntimeError {
1460 message: "min() other must be a number".to_string(),
1461 })
1462 }
1463
1464 "max" => {
1465 if args.len() != 1 {
1466 return Err(LustError::RuntimeError {
1467 message: "max() requires 1 argument (other)".to_string(),
1468 });
1469 }
1470 if let Some(other) = args[0].as_int() {
1471 return Ok(Value::Int((*i).max(other)));
1472 }
1473 if let Some(other) = args[0].as_float() {
1474 return Ok(Value::Float(float_from_int(*i).max(other)));
1475 }
1476 Err(LustError::RuntimeError {
1477 message: "max() other must be a number".to_string(),
1478 })
1479 }
1480
1481 "clamp" => {
1482 if args.len() != 2 {
1483 return Err(LustError::RuntimeError {
1484 message: "clamp() requires 2 arguments (min, max)".to_string(),
1485 });
1486 }
1487
1488 let min = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1489 message: "clamp() min must be an integer".to_string(),
1490 })?;
1491 let max = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1492 message: "clamp() max must be an integer".to_string(),
1493 })?;
1494 if min > max {
1495 return Err(LustError::RuntimeError {
1496 message: "clamp() min must be less than or equal to max".to_string(),
1497 });
1498 }
1499
1500 Ok(Value::Int((*i).clamp(min, max)))
1501 }
1502
1503 _ => Err(LustError::RuntimeError {
1504 message: format!("Int has no method '{}'", method_name),
1505 }),
1506 },
1507 _ => Err(LustError::RuntimeError {
1508 message: format!(
1509 "Type {:?} has no method '{}'",
1510 object.type_of(),
1511 method_name
1512 ),
1513 }),
1514 }
1515 }
1516
1517 fn try_call_lua_dynamic_method(
1518 &mut self,
1519 receiver: &Value,
1520 method_name: &str,
1521 args: &[Value],
1522 ) -> Result<Option<Value>> {
1523 let key = Value::string(method_name.to_string());
1524 let method = self.lua_resolve_index(receiver, &key, 8)?;
1525 if matches!(method, Value::Nil) {
1526 return Ok(None);
1527 }
1528
1529 let mut call_args = Vec::with_capacity(1 + args.len());
1530 call_args.push(receiver.clone());
1531 call_args.extend_from_slice(args);
1532 let result = self.call_value(&method, call_args)?;
1533 Ok(Some(result))
1534 }
1535
1536 fn lua_resolve_index(&mut self, receiver: &Value, key: &Value, depth: usize) -> Result<Value> {
1537 if depth == 0 {
1538 return Ok(Value::Nil);
1539 }
1540
1541 if let Some(direct) = self.lua_direct_index(receiver, key) {
1542 if !matches!(direct, Value::Nil) {
1543 return Ok(direct);
1544 }
1545 }
1546
1547 let Some(indexer) = self.lua_index_metamethod(receiver) else {
1548 return Ok(Value::Nil);
1549 };
1550 if matches!(indexer, Value::Nil) {
1551 return Ok(Value::Nil);
1552 }
1553
1554 let is_callable = matches!(
1555 indexer,
1556 Value::Function(_) | Value::Closure { .. } | Value::NativeFunction(_)
1557 ) || matches!(
1558 &indexer,
1559 Value::Enum {
1560 enum_name,
1561 variant,
1562 ..
1563 } if enum_name == "LuaValue" && variant == "Function"
1564 );
1565
1566 if is_callable {
1567 self.call_value(&indexer, vec![receiver.clone(), key.clone()])
1568 } else {
1569 self.lua_resolve_index(&indexer, key, depth - 1)
1570 }
1571 }
1572
1573 fn lua_direct_index(&self, receiver: &Value, key: &Value) -> Option<Value> {
1574 if let Value::Enum {
1575 enum_name,
1576 variant,
1577 values,
1578 } = receiver
1579 {
1580 if enum_name == "LuaValue" && variant == "Table" {
1581 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1582 return self.lua_direct_index(inner, key);
1583 }
1584 }
1585 }
1586
1587 match receiver {
1588 Value::Struct { name, .. } if name == "LuaTable" => {
1589 let Some(Value::Map(map_rc)) = receiver.struct_get_field("table") else {
1590 return None;
1591 };
1592 let raw_key = super::corelib::unwrap_lua_value(key.clone());
1593 let lookup_key = ValueKey::from_value(&raw_key);
1594 let value = map_rc.borrow().get(&lookup_key).cloned();
1595 value
1596 }
1597 Value::Map(map_rc) => {
1598 let raw_key = super::corelib::unwrap_lua_value(key.clone());
1599 let lookup_key = ValueKey::from_value(&raw_key);
1600 let value = map_rc.borrow().get(&lookup_key).cloned();
1601 value
1602 }
1603 _ => None,
1604 }
1605 }
1606
1607 fn lua_index_metamethod(&self, receiver: &Value) -> Option<Value> {
1608 if let Value::Enum {
1609 enum_name,
1610 variant,
1611 values,
1612 } = receiver
1613 {
1614 if enum_name == "LuaValue" && variant == "Table" {
1615 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1616 return self.lua_index_metamethod(inner);
1617 }
1618 }
1619 if enum_name == "LuaValue" && variant == "Userdata" {
1620 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1621 return self.lua_index_metamethod(inner);
1622 }
1623 }
1624 }
1625
1626 let Value::Struct { name, .. } = receiver else {
1627 return None;
1628 };
1629 let Some(Value::Map(meta_rc)) = receiver.struct_get_field("metamethods") else {
1630 return None;
1631 };
1632 if name != "LuaTable" && name != "LuaUserdata" {
1633 return None;
1634 }
1635 let value = meta_rc
1636 .borrow()
1637 .get(&ValueKey::string("__index".to_string()))
1638 .cloned();
1639 value
1640 }
1641}
1642
1643fn lua_table_map_rc(table: &Value) -> Option<Rc<RefCell<LustMap>>> {
1644 match table.struct_get_field("table") {
1645 Some(Value::Map(map_rc)) => Some(map_rc),
1646 _ => None,
1647 }
1648}
1649
1650fn lua_table_sequence_len(map: &LustMap) -> usize {
1651 let mut idx: LustInt = 1;
1652 loop {
1653 let key = ValueKey::from_value(&Value::Int(idx));
1654 if map.contains_key(&key) {
1655 idx += 1;
1656 } else {
1657 break;
1658 }
1659 }
1660 (idx - 1) as usize
1661}
1662
1663fn lua_table_read_sequence(map: &LustMap) -> Vec<Value> {
1664 let mut seq: Vec<Value> = Vec::new();
1665 let mut idx: LustInt = 1;
1666 loop {
1667 let key = ValueKey::from_value(&Value::Int(idx));
1668 if let Some(val) = map.get(&key) {
1669 seq.push(val.clone());
1670 idx += 1;
1671 } else {
1672 break;
1673 }
1674 }
1675 seq
1676}
1677
1678fn lua_table_write_sequence(map_rc: &Rc<RefCell<LustMap>>, seq: &[Value]) {
1679 let mut map = map_rc.borrow_mut();
1680 let mut idx: LustInt = 1;
1681 loop {
1682 let key = ValueKey::from_value(&Value::Int(idx));
1683 if map.remove(&key).is_some() {
1684 idx += 1;
1685 } else {
1686 break;
1687 }
1688 }
1689 for (i, val) in seq.iter().enumerate() {
1690 let key = ValueKey::from_value(&Value::Int((i as LustInt) + 1));
1691 map.insert(key, val.clone());
1692 }
1693}