lust/vm/
tasks.rs

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