lust/vm/
tasks.rs

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                // Prime the task so the host can immediately supply the first tick's argument via resume().
308                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 N>1, expect resume() to pass an Array of arguments.
328                        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                // Yield the on_tick() result back to the host; resume() will write the next tick arg into resume_reg.
345                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}