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