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);
381 return self.call_value(&Value::Function(func_idx), method_args);
382 }
383 }
384
385 match object {
386 Value::Enum {
387 enum_name,
388 variant,
389 values,
390 } if enum_name == "Option" => match method_name {
391 "is_some" => Ok(Value::Bool(variant == "Some")),
392 "is_none" => Ok(Value::Bool(variant == "None")),
393 "unwrap" => {
394 if variant == "Some" {
395 if let Some(vals) = values {
396 if !vals.is_empty() {
397 Ok(vals[0].clone())
398 } else {
399 Err(LustError::RuntimeError {
400 message: "Option::Some has no value".to_string(),
401 })
402 }
403 } else {
404 Err(LustError::RuntimeError {
405 message: "Option::Some has no value".to_string(),
406 })
407 }
408 } else {
409 Err(LustError::RuntimeError {
410 message: "Called unwrap() on Option::None".to_string(),
411 })
412 }
413 }
414
415 "unwrap_or" => {
416 if args.is_empty() {
417 return Err(LustError::RuntimeError {
418 message: "unwrap_or requires a default value".to_string(),
419 });
420 }
421
422 if variant == "Some" {
423 if let Some(vals) = values {
424 if !vals.is_empty() {
425 Ok(vals[0].clone())
426 } else {
427 Ok(args[0].clone())
428 }
429 } else {
430 Ok(args[0].clone())
431 }
432 } else {
433 Ok(args[0].clone())
434 }
435 }
436
437 _ => Err(LustError::RuntimeError {
438 message: format!("Option has no method '{}'", method_name),
439 }),
440 },
441 Value::Enum {
442 enum_name,
443 variant,
444 values,
445 } if enum_name == "Result" => match method_name {
446 "is_ok" => Ok(Value::Bool(variant == "Ok")),
447 "is_err" => Ok(Value::Bool(variant == "Err")),
448 "unwrap" => {
449 if variant == "Ok" {
450 if let Some(vals) = values {
451 if !vals.is_empty() {
452 Ok(vals[0].clone())
453 } else {
454 Err(LustError::RuntimeError {
455 message: "Result::Ok has no value".to_string(),
456 })
457 }
458 } else {
459 Err(LustError::RuntimeError {
460 message: "Result::Ok has no value".to_string(),
461 })
462 }
463 } else {
464 Err(LustError::RuntimeError {
465 message: "Called unwrap() on Result::Err".to_string(),
466 })
467 }
468 }
469
470 "unwrap_or" => {
471 if args.is_empty() {
472 return Err(LustError::RuntimeError {
473 message: "unwrap_or requires a default value".to_string(),
474 });
475 }
476
477 if variant == "Ok" {
478 if let Some(vals) = values {
479 if !vals.is_empty() {
480 Ok(vals[0].clone())
481 } else {
482 Ok(args[0].clone())
483 }
484 } else {
485 Ok(args[0].clone())
486 }
487 } else {
488 Ok(args[0].clone())
489 }
490 }
491
492 _ => Err(LustError::RuntimeError {
493 message: format!("Result has no method '{}'", method_name),
494 }),
495 },
496 Value::Array(arr) => match method_name {
497 "iter" => {
498 let items = arr.borrow().clone();
499 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
500 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
501 }
502
503 "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
504 "get" => {
505 if args.is_empty() {
506 return Err(LustError::RuntimeError {
507 message: "get requires an index argument".to_string(),
508 });
509 }
510
511 let index = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
512 message: "Array index must be an integer".to_string(),
513 })?;
514 let borrowed = arr.borrow();
515 if index < 0 || index as usize >= borrowed.len() {
516 Ok(Value::none())
517 } else {
518 Ok(Value::some(borrowed[index as usize].clone()))
519 }
520 }
521
522 "first" => {
523 let borrowed = arr.borrow();
524 if borrowed.is_empty() {
525 Ok(Value::none())
526 } else {
527 Ok(Value::some(borrowed[0].clone()))
528 }
529 }
530
531 "last" => {
532 let borrowed = arr.borrow();
533 if borrowed.is_empty() {
534 Ok(Value::none())
535 } else {
536 Ok(Value::some(borrowed[borrowed.len() - 1].clone()))
537 }
538 }
539
540 "push" => {
541 if args.is_empty() {
542 return Err(LustError::RuntimeError {
543 message: "push requires a value argument".to_string(),
544 });
545 }
546
547 arr.borrow_mut().push(args[0].clone());
548 Ok(Value::Nil)
549 }
550
551 "pop" => {
552 let popped = arr.borrow_mut().pop();
553 match popped {
554 Some(val) => Ok(Value::some(val)),
555 None => Ok(Value::none()),
556 }
557 }
558
559 "map" => {
560 if args.is_empty() {
561 return Err(LustError::RuntimeError {
562 message: "map requires a function argument".to_string(),
563 });
564 }
565
566 let func = &args[0];
567 let borrowed = arr.borrow();
568 let mut result = Vec::new();
569 for elem in borrowed.iter() {
570 let mapped_value = self.call_value(func, vec![elem.clone()])?;
571 result.push(mapped_value);
572 }
573
574 Ok(Value::array(result))
575 }
576
577 "filter" => {
578 if args.is_empty() {
579 return Err(LustError::RuntimeError {
580 message: "filter requires a function argument".to_string(),
581 });
582 }
583
584 let func = &args[0];
585 let borrowed = arr.borrow();
586 let mut result = Vec::new();
587 for elem in borrowed.iter() {
588 let keep = self.call_value(func, vec![elem.clone()])?;
589 if keep.is_truthy() {
590 result.push(elem.clone());
591 }
592 }
593
594 Ok(Value::array(result))
595 }
596
597 "reduce" => {
598 if args.len() < 2 {
599 return Err(LustError::RuntimeError {
600 message: "reduce requires an initial value and function".to_string(),
601 });
602 }
603
604 let init_value = &args[0];
605 let func = &args[1];
606 let borrowed = arr.borrow();
607 let mut accumulator = init_value.clone();
608 for elem in borrowed.iter() {
609 accumulator = self.call_value(func, vec![accumulator, elem.clone()])?;
610 }
611
612 Ok(accumulator)
613 }
614
615 "slice" => {
616 if args.len() < 2 {
617 return Err(LustError::RuntimeError {
618 message: "slice requires start and end indices".to_string(),
619 });
620 }
621
622 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
623 message: "Start index must be an integer".to_string(),
624 })? as usize;
625 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
626 message: "End index must be an integer".to_string(),
627 })? as usize;
628 let borrowed = arr.borrow();
629 if start > borrowed.len() || end > borrowed.len() || start > end {
630 return Err(LustError::RuntimeError {
631 message: "Invalid slice indices".to_string(),
632 });
633 }
634
635 let sliced = borrowed[start..end].to_vec();
636 Ok(Value::array(sliced))
637 }
638
639 "clear" => {
640 arr.borrow_mut().clear();
641 Ok(Value::Nil)
642 }
643
644 "is_empty" => Ok(Value::Bool(arr.borrow().is_empty())),
645 _ => Err(LustError::RuntimeError {
646 message: format!("Array has no method '{}'", method_name),
647 }),
648 },
649 Value::String(s) => match method_name {
650 "iter" => {
651 let items: Vec<Value> =
652 s.chars().map(|c| Value::string(c.to_string())).collect();
653 let iter = crate::bytecode::value::IteratorState::Array { items, index: 0 };
654 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
655 }
656
657 "len" => Ok(Value::Int(int_from_usize(s.len()))),
658 "substring" => {
659 if args.len() < 2 {
660 return Err(LustError::RuntimeError {
661 message: "substring requires start and end indices".to_string(),
662 });
663 }
664
665 let start = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
666 message: "Start index must be an integer".to_string(),
667 })? as usize;
668 let end = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
669 message: "End index must be an integer".to_string(),
670 })? as usize;
671 if start > s.len() || end > s.len() || start > end {
672 return Err(LustError::RuntimeError {
673 message: "Invalid substring indices".to_string(),
674 });
675 }
676
677 Ok(Value::string(&s[start..end]))
678 }
679
680 "find" => {
681 if args.is_empty() {
682 return Err(LustError::RuntimeError {
683 message: "find requires a search string".to_string(),
684 });
685 }
686
687 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
688 message: "Search string must be a string".to_string(),
689 })?;
690 match s.find(search) {
691 Some(pos) => Ok(Value::some(Value::Int(int_from_usize(pos)))),
692 None => Ok(Value::none()),
693 }
694 }
695
696 "starts_with" => {
697 if args.is_empty() {
698 return Err(LustError::RuntimeError {
699 message: "starts_with requires a prefix string".to_string(),
700 });
701 }
702
703 let prefix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
704 message: "Prefix must be a string".to_string(),
705 })?;
706 Ok(Value::Bool(s.starts_with(prefix)))
707 }
708
709 "ends_with" => {
710 if args.is_empty() {
711 return Err(LustError::RuntimeError {
712 message: "ends_with requires a suffix string".to_string(),
713 });
714 }
715
716 let suffix = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
717 message: "Suffix must be a string".to_string(),
718 })?;
719 Ok(Value::Bool(s.ends_with(suffix)))
720 }
721
722 "split" => {
723 if args.is_empty() {
724 return Err(LustError::RuntimeError {
725 message: "split requires a separator string".to_string(),
726 });
727 }
728
729 let separator = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
730 message: "Separator must be a string".to_string(),
731 })?;
732 let parts: Vec<Value> =
733 s.split(separator).map(|part| Value::string(part)).collect();
734 Ok(Value::array(parts))
735 }
736
737 "trim" => Ok(Value::string(s.trim())),
738 "trim_start" => Ok(Value::string(s.trim_start())),
739 "trim_end" => Ok(Value::string(s.trim_end())),
740 "replace" => {
741 if args.len() < 2 {
742 return Err(LustError::RuntimeError {
743 message: "replace requires 'from' and 'to' string arguments"
744 .to_string(),
745 });
746 }
747
748 let from = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
749 message: "First argument must be a string".to_string(),
750 })?;
751 let to = args[1].as_string().ok_or_else(|| LustError::RuntimeError {
752 message: "Second argument must be a string".to_string(),
753 })?;
754 Ok(Value::string(&s.replace(from, to)))
755 }
756
757 "to_upper" => Ok(Value::string(&s.to_uppercase())),
758 "to_lower" => Ok(Value::string(&s.to_lowercase())),
759 "contains" => {
760 if args.is_empty() {
761 return Err(LustError::RuntimeError {
762 message: "contains requires a search string".to_string(),
763 });
764 }
765
766 let search = args[0].as_string().ok_or_else(|| LustError::RuntimeError {
767 message: "Search string must be a string".to_string(),
768 })?;
769 Ok(Value::Bool(s.contains(search)))
770 }
771
772 "is_empty" => Ok(Value::Bool(s.is_empty())),
773 "chars" => {
774 let chars: Vec<Value> =
775 s.chars().map(|c| Value::string(&c.to_string())).collect();
776 Ok(Value::array(chars))
777 }
778
779 "lines" => {
780 let lines: Vec<Value> = s.lines().map(|line| Value::string(line)).collect();
781 Ok(Value::array(lines))
782 }
783
784 _ => Err(LustError::RuntimeError {
785 message: format!("String has no method '{}'", method_name),
786 }),
787 },
788 Value::Map(map) => {
789 use crate::bytecode::ValueKey;
790 match method_name {
791 "iter" => {
792 let items: Vec<(ValueKey, Value)> = map
793 .borrow()
794 .iter()
795 .map(|(k, v)| (k.clone(), v.clone()))
796 .collect();
797 let iter =
798 crate::bytecode::value::IteratorState::MapPairs { items, index: 0 };
799 return Ok(Value::Iterator(Rc::new(RefCell::new(iter))));
800 }
801
802 "len" => Ok(Value::Int(int_from_usize(map.borrow().len()))),
803 "get" => {
804 if args.is_empty() {
805 return Err(LustError::RuntimeError {
806 message: "get requires a key argument".to_string(),
807 });
808 }
809
810 let key = ValueKey::from_value(&args[0]).ok_or_else(|| {
811 LustError::RuntimeError {
812 message: format!(
813 "Cannot use {:?} as map key (not hashable)",
814 args[0]
815 ),
816 }
817 })?;
818 match map.borrow().get(&key) {
819 Some(value) => Ok(Value::some(value.clone())),
820 None => Ok(Value::none()),
821 }
822 }
823
824 "set" => {
825 if args.len() < 2 {
826 return Err(LustError::RuntimeError {
827 message: "set requires key and value arguments".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 let value = args[1].clone();
840 map.borrow_mut().insert(key, value);
841 Ok(Value::Nil)
842 }
843
844 "has" => {
845 if args.is_empty() {
846 return Err(LustError::RuntimeError {
847 message: "has requires a key argument".to_string(),
848 });
849 }
850
851 let key = ValueKey::from_value(&args[0]).ok_or_else(|| {
852 LustError::RuntimeError {
853 message: format!(
854 "Cannot use {:?} as map key (not hashable)",
855 args[0]
856 ),
857 }
858 })?;
859 Ok(Value::Bool(map.borrow().contains_key(&key)))
860 }
861
862 "delete" => {
863 if args.is_empty() {
864 return Err(LustError::RuntimeError {
865 message: "delete requires a key argument".to_string(),
866 });
867 }
868
869 let key = ValueKey::from_value(&args[0]).ok_or_else(|| {
870 LustError::RuntimeError {
871 message: format!(
872 "Cannot use {:?} as map key (not hashable)",
873 args[0]
874 ),
875 }
876 })?;
877 match map.borrow_mut().remove(&key) {
878 Some(value) => Ok(Value::some(value)),
879 None => Ok(Value::none()),
880 }
881 }
882
883 "keys" => {
884 let keys: Vec<Value> = map.borrow().keys().map(|k| k.to_value()).collect();
885 Ok(Value::array(keys))
886 }
887
888 "values" => {
889 let values: Vec<Value> = map.borrow().values().cloned().collect();
890 Ok(Value::array(values))
891 }
892
893 _ => Err(LustError::RuntimeError {
894 message: format!("Map has no method '{}'", method_name),
895 }),
896 }
897 }
898
899 Value::Iterator(state_rc) => match method_name {
900 "iter" => Ok(Value::Iterator(state_rc.clone())),
901 "next" => {
902 use crate::bytecode::value::IteratorState;
903 let mut state = state_rc.borrow_mut();
904 match &mut *state {
905 IteratorState::Array { items, index } => {
906 if *index < items.len() {
907 let v = items[*index].clone();
908 *index += 1;
909 Ok(Value::some(v))
910 } else {
911 Ok(Value::none())
912 }
913 }
914
915 IteratorState::MapPairs { items, index } => {
916 if *index < items.len() {
917 let (k, v) = items[*index].clone();
918 *index += 1;
919 Ok(Value::some(Value::array(vec![k.to_value(), v])))
920 } else {
921 Ok(Value::none())
922 }
923 }
924 }
925 }
926
927 _ => Err(LustError::RuntimeError {
928 message: format!("Iterator has no method '{}'", method_name),
929 }),
930 },
931 Value::Float(f) => match method_name {
932 "to_int" => {
933 if !args.is_empty() {
934 return Err(LustError::RuntimeError {
935 message: "to_int() takes no arguments".to_string(),
936 });
937 }
938
939 Ok(Value::Int(int_from_float(*f)))
940 }
941
942 "floor" => {
943 if !args.is_empty() {
944 return Err(LustError::RuntimeError {
945 message: "floor() takes no arguments".to_string(),
946 });
947 }
948
949 Ok(Value::Float(float_floor(*f)))
950 }
951
952 "ceil" => {
953 if !args.is_empty() {
954 return Err(LustError::RuntimeError {
955 message: "ceil() takes no arguments".to_string(),
956 });
957 }
958
959 Ok(Value::Float(float_ceil(*f)))
960 }
961
962 "round" => {
963 if !args.is_empty() {
964 return Err(LustError::RuntimeError {
965 message: "round() takes no arguments".to_string(),
966 });
967 }
968
969 Ok(Value::Float(float_round(*f)))
970 }
971
972 "sqrt" => {
973 if !args.is_empty() {
974 return Err(LustError::RuntimeError {
975 message: "sqrt() takes no arguments".to_string(),
976 });
977 }
978
979 if *f < 0.0 {
980 return Err(LustError::RuntimeError {
981 message: "sqrt() requires a non-negative number".to_string(),
982 });
983 }
984
985 Ok(Value::Float(float_sqrt(*f)))
986 }
987
988 "abs" => {
989 if !args.is_empty() {
990 return Err(LustError::RuntimeError {
991 message: "abs() takes no arguments".to_string(),
992 });
993 }
994
995 Ok(Value::Float(float_abs(*f)))
996 }
997
998 "clamp" => {
999 if args.len() != 2 {
1000 return Err(LustError::RuntimeError {
1001 message: "clamp() requires 2 arguments (min, max)".to_string(),
1002 });
1003 }
1004
1005 let min = args[0].as_float().ok_or_else(|| LustError::RuntimeError {
1006 message: "clamp() min must be a number".to_string(),
1007 })?;
1008 let max = args[1].as_float().ok_or_else(|| LustError::RuntimeError {
1009 message: "clamp() max must be a number".to_string(),
1010 })?;
1011 if min > max {
1012 return Err(LustError::RuntimeError {
1013 message: "clamp() min must be less than or equal to max".to_string(),
1014 });
1015 }
1016
1017 Ok(Value::Float(float_clamp(*f, min, max)))
1018 }
1019
1020 _ => Err(LustError::RuntimeError {
1021 message: format!("Float has no method '{}'", method_name),
1022 }),
1023 },
1024 Value::Int(i) => match method_name {
1025 "to_float" => {
1026 if !args.is_empty() {
1027 return Err(LustError::RuntimeError {
1028 message: "to_float() takes no arguments".to_string(),
1029 });
1030 }
1031
1032 Ok(Value::Float(float_from_int(*i)))
1033 }
1034
1035 "abs" => {
1036 if !args.is_empty() {
1037 return Err(LustError::RuntimeError {
1038 message: "abs() takes no arguments".to_string(),
1039 });
1040 }
1041
1042 Ok(Value::Int(i.abs()))
1043 }
1044
1045 "clamp" => {
1046 if args.len() != 2 {
1047 return Err(LustError::RuntimeError {
1048 message: "clamp() requires 2 arguments (min, max)".to_string(),
1049 });
1050 }
1051
1052 let min = args[0].as_int().ok_or_else(|| LustError::RuntimeError {
1053 message: "clamp() min must be an integer".to_string(),
1054 })?;
1055 let max = args[1].as_int().ok_or_else(|| LustError::RuntimeError {
1056 message: "clamp() max must be an integer".to_string(),
1057 })?;
1058 if min > max {
1059 return Err(LustError::RuntimeError {
1060 message: "clamp() min must be less than or equal to max".to_string(),
1061 });
1062 }
1063
1064 Ok(Value::Int((*i).clamp(min, max)))
1065 }
1066
1067 _ => Err(LustError::RuntimeError {
1068 message: format!("Int has no method '{}'", method_name),
1069 }),
1070 },
1071 _ => Err(LustError::RuntimeError {
1072 message: format!(
1073 "Type {:?} has no method '{}'",
1074 object.type_of(),
1075 method_name
1076 ),
1077 }),
1078 }
1079 }
1080}