1use super::*;
2use crate::vm::task::TaskKind;
3use alloc::{format, string::ToString};
4use core::{array, cell::RefCell, mem};
5impl VM {
6 pub(super) fn run_task_internal(
7 &mut self,
8 task_id: TaskId,
9 resume_value: Option<Value>,
10 ) -> Result<()> {
11 let mut task = match self.task_manager.detach(task_id) {
12 Some(task) => task,
13 None => {
14 return Err(LustError::RuntimeError {
15 message: format!("Invalid task handle {}", task_id.as_u64()),
16 })
17 }
18 };
19 if matches!(task.kind(), TaskKind::NativeFuture { .. }) {
20 let message = format!(
21 "Task {} is managed by the host runtime and cannot be resumed manually",
22 task_id.as_u64()
23 );
24 self.task_manager.attach(task);
25 return Err(LustError::RuntimeError { message });
26 }
27
28 match task.state {
29 TaskState::Completed | TaskState::Failed | TaskState::Stopped => {
30 let message = format!(
31 "Task {} cannot be resumed (state: {})",
32 task_id.as_u64(),
33 task.state.as_str()
34 );
35 self.task_manager.attach(task);
36 return Err(LustError::RuntimeError { message });
37 }
38
39 TaskState::Running => {
40 self.task_manager.attach(task);
41 return Err(LustError::RuntimeError {
42 message: format!("Task {} is already running", task_id.as_u64()),
43 });
44 }
45
46 _ => {}
47 }
48
49 task.state = TaskState::Running;
50 task.last_yield = None;
51 let mut resume_value_opt = resume_value;
52 if let Some(dest) = task.yield_dest.take() {
53 let value = resume_value_opt.take().unwrap_or(Value::Nil);
54 if let Some(frame) = task.call_stack.last_mut() {
55 frame.registers[dest as usize] = value;
56 }
57 } else if resume_value_opt.is_some() {
58 let message = format!(
59 "Task {} is not waiting for a resume value",
60 task_id.as_u64()
61 );
62 self.task_manager.attach(task);
63 return Err(LustError::RuntimeError { message });
64 }
65
66 mem::swap(&mut self.call_stack, &mut task.call_stack);
67 mem::swap(
68 &mut self.pending_return_value,
69 &mut task.pending_return_value,
70 );
71 mem::swap(&mut self.pending_return_dest, &mut task.pending_return_dest);
72 self.current_task = Some(task_id);
73 self.last_task_signal = None;
74 let run_result = self.run();
75 let signal = self.last_task_signal.take();
76 self.current_task = None;
77 let mut error_result: Option<LustError> = None;
78 match run_result {
79 Ok(value) => {
80 if let Some(signal) = signal {
81 match signal {
82 TaskSignal::Yield {
83 dest,
84 value: yielded,
85 } => {
86 task.state = TaskState::Yielded;
87 task.last_yield = Some(yielded);
88 task.last_result = None;
89 task.yield_dest = Some(dest);
90 }
91
92 TaskSignal::Stop { value: stop_value } => {
93 task.state = TaskState::Stopped;
94 task.last_result = Some(stop_value);
95 task.last_yield = None;
96 task.call_stack.clear();
97 task.pending_return_value = None;
98 task.pending_return_dest = None;
99 }
100 }
101 } else {
102 task.state = TaskState::Completed;
103 task.last_result = Some(value);
104 task.last_yield = None;
105 }
106 }
107
108 Err(err) => {
109 let annotated = self.annotate_runtime_error(err);
110 task.state = TaskState::Failed;
111 task.error = Some(annotated.clone());
112 task.last_yield = None;
113 error_result = Some(annotated);
114 }
115 }
116
117 mem::swap(&mut self.call_stack, &mut task.call_stack);
118 mem::swap(
119 &mut self.pending_return_value,
120 &mut task.pending_return_value,
121 );
122 mem::swap(&mut self.pending_return_dest, &mut task.pending_return_dest);
123 self.task_manager.attach(task);
124 if let Some(err) = error_result {
125 Err(err)
126 } else {
127 Ok(())
128 }
129 }
130
131 pub(super) fn task_id_from_handle(&self, handle: TaskHandle) -> Result<TaskId> {
132 let id = TaskId(handle.id());
133 if self.task_manager.contains(id) {
134 Ok(id)
135 } else {
136 Err(LustError::RuntimeError {
137 message: format!("Invalid task handle {}", handle.id()),
138 })
139 }
140 }
141
142 pub(super) fn prepare_task_frame(
143 &mut self,
144 func: Value,
145 args: Vec<Value>,
146 ) -> Result<CallFrame> {
147 match func {
148 Value::Function(func_idx) => {
149 let function = &self.functions[func_idx];
150 if args.len() != function.param_count as usize {
151 return Err(LustError::RuntimeError {
152 message: format!(
153 "Task entry expects {} arguments, got {}",
154 function.param_count,
155 args.len()
156 ),
157 });
158 }
159
160 let mut frame = CallFrame {
161 function_idx: func_idx,
162 ip: 0,
163 registers: array::from_fn(|_| Value::Nil),
164 base_register: 0,
165 return_dest: None,
166 upvalues: Vec::new(),
167 };
168 for (i, arg) in args.into_iter().enumerate() {
169 frame.registers[i] = arg;
170 }
171
172 Ok(frame)
173 }
174
175 Value::Closure {
176 function_idx,
177 upvalues,
178 } => {
179 let function = &self.functions[function_idx];
180 if args.len() != function.param_count as usize {
181 return Err(LustError::RuntimeError {
182 message: format!(
183 "Task entry expects {} arguments, got {}",
184 function.param_count,
185 args.len()
186 ),
187 });
188 }
189
190 let captured: Vec<Value> = upvalues.iter().map(|uv| uv.get()).collect();
191 let mut frame = CallFrame {
192 function_idx,
193 ip: 0,
194 registers: array::from_fn(|_| Value::Nil),
195 base_register: 0,
196 return_dest: None,
197 upvalues: captured,
198 };
199 for (i, arg) in args.into_iter().enumerate() {
200 frame.registers[i] = arg;
201 }
202
203 Ok(frame)
204 }
205
206 other => Err(LustError::RuntimeError {
207 message: format!("task.run() expects a function or closure, got {:?}", other),
208 }),
209 }
210 }
211
212 pub(super) fn create_task_value(
213 &mut self,
214 func: Value,
215 args: Vec<Value>,
216 ) -> Result<TaskHandle> {
217 let frame = self.prepare_task_frame(func, args)?;
218 let task_id = self.task_manager.next_id();
219 let task = TaskInstance::new(task_id, frame);
220 self.task_manager.insert(task);
221 Ok(task_id.to_handle())
222 }
223
224 pub fn spawn_task_value(&mut self, func: Value, args: Vec<Value>) -> Result<TaskHandle> {
225 let handle = self.create_task_value(func, args)?;
226 let task_id = TaskId(handle.id());
227 if let Err(err) = self.run_task_internal(task_id, None) {
228 let _ = self.task_manager.detach(task_id);
229 return Err(err);
230 }
231
232 Ok(handle)
233 }
234
235 pub fn resume_task_handle(
236 &mut self,
237 handle: TaskHandle,
238 resume_value: Option<Value>,
239 ) -> Result<()> {
240 let task_id = self.task_id_from_handle(handle)?;
241 self.run_task_internal(task_id, resume_value)
242 }
243
244 pub(super) fn stop_task_handle(&mut self, handle: TaskHandle) -> Result<()> {
245 let task_id = self.task_id_from_handle(handle)?;
246 let mut task = match self.task_manager.detach(task_id) {
247 Some(task) => task,
248 None => {
249 return Err(LustError::RuntimeError {
250 message: format!("Invalid task handle {}", handle.id()),
251 })
252 }
253 };
254 match task.state {
255 TaskState::Stopped | TaskState::Completed | TaskState::Failed => {
256 self.task_manager.attach(task);
257 return Ok(());
258 }
259
260 TaskState::Running => {
261 self.task_manager.attach(task);
262 return Err(LustError::RuntimeError {
263 message: format!("Task {} is currently running", handle.id()),
264 });
265 }
266
267 _ => {}
268 }
269
270 task.state = TaskState::Stopped;
271 task.call_stack.clear();
272 task.pending_return_value = None;
273 task.pending_return_dest = None;
274 task.yield_dest = None;
275 task.last_yield = None;
276 self.task_manager.attach(task);
277 Ok(())
278 }
279
280 pub(super) fn restart_task_handle(&mut self, handle: TaskHandle) -> Result<()> {
281 let task_id = self.task_id_from_handle(handle)?;
282 let mut task = match self.task_manager.detach(task_id) {
283 Some(task) => task,
284 None => {
285 return Err(LustError::RuntimeError {
286 message: format!("Invalid task handle {}", handle.id()),
287 })
288 }
289 };
290 task.reset();
291 self.task_manager.insert(task);
292 if let Err(err) = self.run_task_internal(task_id, None) {
293 return Err(err);
294 }
295
296 Ok(())
297 }
298
299 pub fn get_task_instance(&self, handle: TaskHandle) -> Result<&TaskInstance> {
300 let task_id = self.task_id_from_handle(handle)?;
301 self.task_manager
302 .get(task_id)
303 .ok_or_else(|| LustError::RuntimeError {
304 message: format!("Invalid task handle {}", handle.id()),
305 })
306 }
307
308 pub fn current_task_handle(&self) -> Option<TaskHandle> {
309 self.current_task.map(|id| id.to_handle())
310 }
311
312 pub fn create_native_future_task(&mut self) -> TaskHandle {
313 let id = self.task_manager.next_id();
314 let task = TaskInstance::new_native_future(id);
315 let handle = task.handle();
316 self.task_manager.insert(task);
317 handle
318 }
319
320 pub fn complete_native_future_task(
321 &mut self,
322 handle: TaskHandle,
323 outcome: std::result::Result<Value, String>,
324 ) -> Result<()> {
325 let task_id = self.task_id_from_handle(handle)?;
326 let mut task = match self.task_manager.detach(task_id) {
327 Some(task) => task,
328 None => {
329 return Err(LustError::RuntimeError {
330 message: format!("Invalid task handle {}", handle.id()),
331 })
332 }
333 };
334
335 match task.kind_mut() {
336 TaskKind::NativeFuture { .. } => {
337 match outcome {
338 Ok(value) => {
339 task.state = TaskState::Completed;
340 task.last_result = Some(value);
341 task.error = None;
342 }
343 Err(err_msg) => {
344 task.state = TaskState::Failed;
345 task.last_result = None;
346 task.error = Some(LustError::RuntimeError { message: err_msg });
347 }
348 }
349 task.last_yield = None;
350 task.pending_return_value = None;
351 task.pending_return_dest = None;
352 task.yield_dest = None;
353 self.task_manager.attach(task);
354 Ok(())
355 }
356
357 TaskKind::Script => {
358 self.task_manager.attach(task);
359 Err(LustError::RuntimeError {
360 message: "Attempted to complete a script task using native future completion"
361 .to_string(),
362 })
363 }
364 }
365 }
366
367 pub(super) fn call_builtin_method(
368 &mut self,
369 object: &Value,
370 method_name: &str,
371 args: Vec<Value>,
372 ) -> Result<Value> {
373 if let Value::Struct {
374 name: struct_name, ..
375 } = object
376 {
377 let mangled_name = format!("{}:{}", struct_name, method_name);
378 if let Some(func_idx) = self.functions.iter().position(|f| f.name == mangled_name) {
379 let mut method_args = vec![object.clone()];
380 method_args.extend(args.clone());
381 return self.call_value(&Value::Function(func_idx), method_args);
382 }
383
384 let mut candidate_names = vec![mangled_name.clone()];
385 if let Some(simple) = struct_name.rsplit(|c| c == '.' || c == ':').next() {
386 candidate_names.push(format!("{}:{}", simple, method_name));
387 }
388
389 for candidate in candidate_names {
390 let mut resolved = None;
391 for variant in [candidate.clone(), candidate.replace('.', "::")] {
392 if let Some(value) = self.get_global(&variant) {
393 resolved = Some(value);
394 break;
395 }
396 }
397
398 if let Some(global_func) = resolved {
399 let mut method_args = vec![object.clone()];
400 method_args.extend(args.clone());
401 return self.call_value(&global_func, method_args);
402 }
403 }
404 }
405
406 match object {
407 Value::Enum {
408 enum_name,
409 variant,
410 values,
411 } if enum_name == "Option" => match method_name {
412 "is_some" => Ok(Value::Bool(variant == "Some")),
413 "is_none" => Ok(Value::Bool(variant == "None")),
414 "unwrap" => {
415 if variant == "Some" {
416 if let Some(vals) = values {
417 if !vals.is_empty() {
418 Ok(vals[0].clone())
419 } else {
420 Err(LustError::RuntimeError {
421 message: "Option::Some has no value".to_string(),
422 })
423 }
424 } else {
425 Err(LustError::RuntimeError {
426 message: "Option::Some has no value".to_string(),
427 })
428 }
429 } else {
430 Err(LustError::RuntimeError {
431 message: "Called unwrap() on Option::None".to_string(),
432 })
433 }
434 }
435
436 "unwrap_or" => {
437 if args.is_empty() {
438 return Err(LustError::RuntimeError {
439 message: "unwrap_or requires a default value".to_string(),
440 });
441 }
442
443 if variant == "Some" {
444 if let Some(vals) = values {
445 if !vals.is_empty() {
446 Ok(vals[0].clone())
447 } else {
448 Ok(args[0].clone())
449 }
450 } else {
451 Ok(args[0].clone())
452 }
453 } else {
454 Ok(args[0].clone())
455 }
456 }
457
458 _ => Err(LustError::RuntimeError {
459 message: format!("Option has no method '{}'", method_name),
460 }),
461 },
462 Value::Enum {
463 enum_name,
464 variant,
465 values,
466 } if enum_name == "Result" => match method_name {
467 "is_ok" => Ok(Value::Bool(variant == "Ok")),
468 "is_err" => Ok(Value::Bool(variant == "Err")),
469 "unwrap" => {
470 if variant == "Ok" {
471 if let Some(vals) = values {
472 if !vals.is_empty() {
473 Ok(vals[0].clone())
474 } else {
475 Err(LustError::RuntimeError {
476 message: "Result::Ok has no value".to_string(),
477 })
478 }
479 } else {
480 Err(LustError::RuntimeError {
481 message: "Result::Ok has no value".to_string(),
482 })
483 }
484 } else {
485 Err(LustError::RuntimeError {
486 message: "Called unwrap() on Result::Err".to_string(),
487 })
488 }
489 }
490
491 "unwrap_or" => {
492 if args.is_empty() {
493 return Err(LustError::RuntimeError {
494 message: "unwrap_or requires a default value".to_string(),
495 });
496 }
497
498 if variant == "Ok" {
499 if let Some(vals) = values {
500 if !vals.is_empty() {
501 Ok(vals[0].clone())
502 } else {
503 Ok(args[0].clone())
504 }
505 } else {
506 Ok(args[0].clone())
507 }
508 } else {
509 Ok(args[0].clone())
510 }
511 }
512
513 _ => Err(LustError::RuntimeError {
514 message: format!("Result has no method '{}'", method_name),
515 }),
516 },
517 Value::Array(arr) => match method_name {
518 "iter" => {
519 let items = arr.borrow().clone();
520 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
521 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
522 }
523
524 "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
525 "get" => {
526 if args.is_empty() {
527 return Err(LustError::RuntimeError {
528 message: "get requires an index argument".to_string(),
529 });
530 }
531
532 let index = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
533 message: "Array index must be an integer".to_string(),
534 })?;
535 let borrowed = arr.borrow();
536 if index < 0 || index as usize >= borrowed.len() {
537 Ok(Value::none())
538 } else {
539 Ok(Value::some(borrowed[index as usize].clone()))
540 }
541 }
542
543 "first" => {
544 let borrowed = arr.borrow();
545 if borrowed.is_empty() {
546 Ok(Value::none())
547 } else {
548 Ok(Value::some(borrowed[0].clone()))
549 }
550 }
551
552 "last" => {
553 let borrowed = arr.borrow();
554 if borrowed.is_empty() {
555 Ok(Value::none())
556 } else {
557 Ok(Value::some(borrowed[borrowed.len() - 1].clone()))
558 }
559 }
560
561 "push" => {
562 if args.is_empty() {
563 return Err(LustError::RuntimeError {
564 message: "push requires a value argument".to_string(),
565 });
566 }
567
568 arr.borrow_mut().push(args[0].clone());
569 Ok(Value::Nil)
570 }
571
572 "pop" => {
573 let popped = arr.borrow_mut().pop();
574 match popped {
575 Some(val) => Ok(Value::some(val)),
576 None => Ok(Value::none()),
577 }
578 }
579
580 "map" => {
581 if args.is_empty() {
582 return Err(LustError::RuntimeError {
583 message: "map requires a function argument".to_string(),
584 });
585 }
586
587 let func = &args[0];
588 let borrowed = arr.borrow();
589 let mut result = Vec::new();
590 for elem in borrowed.iter() {
591 let mapped_value = self.call_value(func, vec![elem.clone()])?;
592 result.push(mapped_value);
593 }
594
595 Ok(Value::array(result))
596 }
597
598 "filter" => {
599 if args.is_empty() {
600 return Err(LustError::RuntimeError {
601 message: "filter requires a function argument".to_string(),
602 });
603 }
604
605 let func = &args[0];
606 let borrowed = arr.borrow();
607 let mut result = Vec::new();
608 for elem in borrowed.iter() {
609 let keep = self.call_value(func, vec![elem.clone()])?;
610 if keep.is_truthy() {
611 result.push(elem.clone());
612 }
613 }
614
615 Ok(Value::array(result))
616 }
617
618 "reduce" => {
619 if args.len() < 2 {
620 return Err(LustError::RuntimeError {
621 message: "reduce requires an initial value and function".to_string(),
622 });
623 }
624
625 let init_value = &args[0];
626 let func = &args[1];
627 let borrowed = arr.borrow();
628 let mut accumulator = init_value.clone();
629 for elem in borrowed.iter() {
630 accumulator = self.call_value(func, vec![accumulator, elem.clone()])?;
631 }
632
633 Ok(accumulator)
634 }
635
636 "slice" => {
637 if args.len() < 2 {
638 return Err(LustError::RuntimeError {
639 message: "slice requires start and end indices".to_string(),
640 });
641 }
642
643 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
644 message: "Start index must be an integer".to_string(),
645 })? as usize;
646 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
647 message: "End index must be an integer".to_string(),
648 })? as usize;
649 let borrowed = arr.borrow();
650 if start > borrowed.len() || end > borrowed.len() || start > end {
651 return Err(LustError::RuntimeError {
652 message: "Invalid slice indices".to_string(),
653 });
654 }
655
656 let sliced = borrowed[start..end].to_vec();
657 Ok(Value::array(sliced))
658 }
659
660 "clear" => {
661 arr.borrow_mut().clear();
662 Ok(Value::Nil)
663 }
664
665 "is_empty" => Ok(Value::Bool(arr.borrow().is_empty())),
666 _ => Err(LustError::RuntimeError {
667 message: format!("Array has no method '{}'", method_name),
668 }),
669 },
670 Value::String(s) => match method_name {
671 "iter" => {
672 let items: Vec<Value> =
673 s.chars().map(|c| Value::string(c.to_string())).collect();
674 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
675 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
676 }
677
678 "len" => Ok(Value::Int(int_from_usize(s.len()))),
679 "substring" => {
680 if args.len() < 2 {
681 return Err(LustError::RuntimeError {
682 message: "substring requires start and end indices".to_string(),
683 });
684 }
685
686 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
687 message: "Start index must be an integer".to_string(),
688 })? as usize;
689 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
690 message: "End index must be an integer".to_string(),
691 })? as usize;
692 if start > s.len() || end > s.len() || start > end {
693 return Err(LustError::RuntimeError {
694 message: "Invalid substring indices".to_string(),
695 });
696 }
697
698 Ok(Value::string(&s[start..end]))
699 }
700
701 "find" => {
702 if args.is_empty() {
703 return Err(LustError::RuntimeError {
704 message: "find requires a search string".to_string(),
705 });
706 }
707
708 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
709 message: "Search string must be a string".to_string(),
710 })?;
711 match s.find(search) {
712 Some(pos) => Ok(Value::some(Value::Int(int_from_usize(pos)))),
713 None => Ok(Value::none()),
714 }
715 }
716
717 "starts_with" => {
718 if args.is_empty() {
719 return Err(LustError::RuntimeError {
720 message: "starts_with requires a prefix string".to_string(),
721 });
722 }
723
724 let prefix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
725 message: "Prefix must be a string".to_string(),
726 })?;
727 Ok(Value::Bool(s.starts_with(prefix)))
728 }
729
730 "ends_with" => {
731 if args.is_empty() {
732 return Err(LustError::RuntimeError {
733 message: "ends_with requires a suffix string".to_string(),
734 });
735 }
736
737 let suffix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
738 message: "Suffix must be a string".to_string(),
739 })?;
740 Ok(Value::Bool(s.ends_with(suffix)))
741 }
742
743 "split" => {
744 if args.is_empty() {
745 return Err(LustError::RuntimeError {
746 message: "split requires a separator string".to_string(),
747 });
748 }
749
750 let separator = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
751 message: "Separator must be a string".to_string(),
752 })?;
753 let parts: Vec<Value> =
754 s.split(separator).map(|part| Value::string(part)).collect();
755 Ok(Value::array(parts))
756 }
757
758 "trim" => Ok(Value::string(s.trim())),
759 "trim_start" => Ok(Value::string(s.trim_start())),
760 "trim_end" => Ok(Value::string(s.trim_end())),
761 "replace" => {
762 if args.len() < 2 {
763 return Err(LustError::RuntimeError {
764 message: "replace requires 'from' and 'to' string arguments"
765 .to_string(),
766 });
767 }
768
769 let from = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
770 message: "First argument must be a string".to_string(),
771 })?;
772 let to = args[1].as_string().ok_or_else(|| LustError::RuntimeError {
773 message: "Second argument must be a string".to_string(),
774 })?;
775 Ok(Value::string(&s.replace(from, to)))
776 }
777
778 "to_upper" => Ok(Value::string(&s.to_uppercase())),
779 "to_lower" => Ok(Value::string(&s.to_lowercase())),
780 "contains" => {
781 if args.is_empty() {
782 return Err(LustError::RuntimeError {
783 message: "contains requires a search string".to_string(),
784 });
785 }
786
787 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
788 message: "Search string must be a string".to_string(),
789 })?;
790 Ok(Value::Bool(s.contains(search)))
791 }
792
793 "is_empty" => Ok(Value::Bool(s.is_empty())),
794 "chars" => {
795 let chars: Vec<Value> =
796 s.chars().map(|c| Value::string(&c.to_string())).collect();
797 Ok(Value::array(chars))
798 }
799
800 "lines" => {
801 let lines: Vec<Value> = s.lines().map(|line| Value::string(line)).collect();
802 Ok(Value::array(lines))
803 }
804
805 _ => Err(LustError::RuntimeError {
806 message: format!("String has no method '{}'", method_name),
807 }),
808 },
809 Value::Map(map) => {
810 use crate::bytecode::ValueKey;
811 match method_name {
812 "iter" => {
813 let items: Vec<(ValueKey, Value)> = map
814 .borrow()
815 .iter()
816 .map(|(k, v)| (k.clone(), v.clone()))
817 .collect();
818 let iter =
819 crate::bytecode::value::IteratorState::MapPairs { items, index: 0 };
820 return Ok(Value::Iterator(Rc::new(RefCell::new(iter))));
821 }
822
823 "len" => Ok(Value::Int(int_from_usize(map.borrow().len()))),
824 "get" => {
825 if args.is_empty() {
826 return Err(LustError::RuntimeError {
827 message: "get requires a key argument".to_string(),
828 });
829 }
830
831 let key = ValueKey::from_value(&args[0]).ok_or_else(|| {
832 LustError::RuntimeError {
833 message: format!(
834 "Cannot use {:?} as map key (not hashable)",
835 args[0]
836 ),
837 }
838 })?;
839 match map.borrow().get(&key) {
840 Some(value) => Ok(Value::some(value.clone())),
841 None => Ok(Value::none()),
842 }
843 }
844
845 "set" => {
846 if args.len() < 2 {
847 return Err(LustError::RuntimeError {
848 message: "set requires key and value arguments".to_string(),
849 });
850 }
851
852 let key = ValueKey::from_value(&args[0]).ok_or_else(|| {
853 LustError::RuntimeError {
854 message: format!(
855 "Cannot use {:?} as map key (not hashable)",
856 args[0]
857 ),
858 }
859 })?;
860 let value = args[1].clone();
861 map.borrow_mut().insert(key, value);
862 Ok(Value::Nil)
863 }
864
865 "has" => {
866 if args.is_empty() {
867 return Err(LustError::RuntimeError {
868 message: "has requires a key argument".to_string(),
869 });
870 }
871
872 let key = ValueKey::from_value(&args[0]).ok_or_else(|| {
873 LustError::RuntimeError {
874 message: format!(
875 "Cannot use {:?} as map key (not hashable)",
876 args[0]
877 ),
878 }
879 })?;
880 Ok(Value::Bool(map.borrow().contains_key(&key)))
881 }
882
883 "delete" => {
884 if args.is_empty() {
885 return Err(LustError::RuntimeError {
886 message: "delete requires a key argument".to_string(),
887 });
888 }
889
890 let key = ValueKey::from_value(&args[0]).ok_or_else(|| {
891 LustError::RuntimeError {
892 message: format!(
893 "Cannot use {:?} as map key (not hashable)",
894 args[0]
895 ),
896 }
897 })?;
898 match map.borrow_mut().remove(&key) {
899 Some(value) => Ok(Value::some(value)),
900 None => Ok(Value::none()),
901 }
902 }
903
904 "keys" => {
905 let keys: Vec<Value> = map.borrow().keys().map(|k| k.to_value()).collect();
906 Ok(Value::array(keys))
907 }
908
909 "values" => {
910 let values: Vec<Value> = map.borrow().values().cloned().collect();
911 Ok(Value::array(values))
912 }
913
914 _ => Err(LustError::RuntimeError {
915 message: format!("Map has no method '{}'", method_name),
916 }),
917 }
918 }
919
920 Value::Iterator(state_rc) => match method_name {
921 "iter" => Ok(Value::Iterator(state_rc.clone())),
922 "next" => {
923 use crate::bytecode::value::IteratorState;
924 let mut state = state_rc.borrow_mut();
925 match &mut *state {
926 IteratorState::Array { items, index } => {
927 if *index < items.len() {
928 let v = items[*index].clone();
929 *index += 1;
930 Ok(Value::some(v))
931 } else {
932 Ok(Value::none())
933 }
934 }
935
936 IteratorState::MapPairs { items, index } => {
937 if *index < items.len() {
938 let (k, v) = items[*index].clone();
939 *index += 1;
940 Ok(Value::some(Value::array(vec![k.to_value(), v])))
941 } else {
942 Ok(Value::none())
943 }
944 }
945 }
946 }
947
948 _ => Err(LustError::RuntimeError {
949 message: format!("Iterator has no method '{}'", method_name),
950 }),
951 },
952 Value::Float(f) => match method_name {
953 "to_int" => {
954 if !args.is_empty() {
955 return Err(LustError::RuntimeError {
956 message: "to_int() takes no arguments".to_string(),
957 });
958 }
959
960 Ok(Value::Int(int_from_float(*f)))
961 }
962
963 "floor" => {
964 if !args.is_empty() {
965 return Err(LustError::RuntimeError {
966 message: "floor() takes no arguments".to_string(),
967 });
968 }
969
970 Ok(Value::Float(float_floor(*f)))
971 }
972
973 "ceil" => {
974 if !args.is_empty() {
975 return Err(LustError::RuntimeError {
976 message: "ceil() takes no arguments".to_string(),
977 });
978 }
979
980 Ok(Value::Float(float_ceil(*f)))
981 }
982
983 "round" => {
984 if !args.is_empty() {
985 return Err(LustError::RuntimeError {
986 message: "round() takes no arguments".to_string(),
987 });
988 }
989
990 Ok(Value::Float(float_round(*f)))
991 }
992
993 "sqrt" => {
994 if !args.is_empty() {
995 return Err(LustError::RuntimeError {
996 message: "sqrt() takes no arguments".to_string(),
997 });
998 }
999
1000 if *f < 0.0 {
1001 return Err(LustError::RuntimeError {
1002 message: "sqrt() requires a non-negative number".to_string(),
1003 });
1004 }
1005
1006 Ok(Value::Float(float_sqrt(*f)))
1007 }
1008
1009 "abs" => {
1010 if !args.is_empty() {
1011 return Err(LustError::RuntimeError {
1012 message: "abs() takes no arguments".to_string(),
1013 });
1014 }
1015
1016 Ok(Value::Float(float_abs(*f)))
1017 }
1018
1019 "clamp" => {
1020 if args.len() != 2 {
1021 return Err(LustError::RuntimeError {
1022 message: "clamp() requires 2 arguments (min, max)".to_string(),
1023 });
1024 }
1025
1026 let min = args[0].as_float().ok_or_else(|| LustError::RuntimeError {
1027 message: "clamp() min must be a number".to_string(),
1028 })?;
1029 let max = args[1].as_float().ok_or_else(|| LustError::RuntimeError {
1030 message: "clamp() max must be a number".to_string(),
1031 })?;
1032 if min > max {
1033 return Err(LustError::RuntimeError {
1034 message: "clamp() min must be less than or equal to max".to_string(),
1035 });
1036 }
1037
1038 Ok(Value::Float(float_clamp(*f, min, max)))
1039 }
1040
1041 _ => Err(LustError::RuntimeError {
1042 message: format!("Float has no method '{}'", method_name),
1043 }),
1044 },
1045 Value::Int(i) => match method_name {
1046 "to_float" => {
1047 if !args.is_empty() {
1048 return Err(LustError::RuntimeError {
1049 message: "to_float() takes no arguments".to_string(),
1050 });
1051 }
1052
1053 Ok(Value::Float(float_from_int(*i)))
1054 }
1055
1056 "abs" => {
1057 if !args.is_empty() {
1058 return Err(LustError::RuntimeError {
1059 message: "abs() takes no arguments".to_string(),
1060 });
1061 }
1062
1063 Ok(Value::Int(i.abs()))
1064 }
1065
1066 "clamp" => {
1067 if args.len() != 2 {
1068 return Err(LustError::RuntimeError {
1069 message: "clamp() requires 2 arguments (min, max)".to_string(),
1070 });
1071 }
1072
1073 let min = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1074 message: "clamp() min must be an integer".to_string(),
1075 })?;
1076 let max = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1077 message: "clamp() max must be an integer".to_string(),
1078 })?;
1079 if min > max {
1080 return Err(LustError::RuntimeError {
1081 message: "clamp() min must be less than or equal to max".to_string(),
1082 });
1083 }
1084
1085 Ok(Value::Int((*i).clamp(min, max)))
1086 }
1087
1088 _ => Err(LustError::RuntimeError {
1089 message: format!("Int has no method '{}'", method_name),
1090 }),
1091 },
1092 _ => Err(LustError::RuntimeError {
1093 message: format!(
1094 "Type {:?} has no method '{}'",
1095 object.type_of(),
1096 method_name
1097 ),
1098 }),
1099 }
1100 }
1101}