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