1use std::collections::HashMap;
9use std::rc::Rc;
10
11use crate::nan_value::{Arena, NanValue};
12use crate::value::{RuntimeError, Value};
13
14pub fn register(global: &mut HashMap<String, Value>) {
15 let mut members = HashMap::new();
16 for method in &["int", "float"] {
17 members.insert(
18 method.to_string(),
19 Value::Builtin(format!("Random.{}", method)),
20 );
21 }
22 global.insert(
23 "Random".to_string(),
24 Value::Namespace {
25 name: "Random".to_string(),
26 members,
27 },
28 );
29}
30
31pub fn effects(name: &str) -> &'static [&'static str] {
32 match name {
33 "Random.int" => &["Random.int"],
34 "Random.float" => &["Random.float"],
35 _ => &[],
36 }
37}
38
39pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
40 match name {
41 "Random.int" => Some(random_int(args)),
42 "Random.float" => Some(random_float(args)),
43 _ => None,
44 }
45}
46
47fn random_int(args: &[Value]) -> Result<Value, RuntimeError> {
48 if args.len() != 2 {
49 return Err(RuntimeError::Error(format!(
50 "Random.int takes 2 arguments (min, max), got {}",
51 args.len()
52 )));
53 }
54 let Value::Int(min) = &args[0] else {
55 return Err(RuntimeError::Error(
56 "Random.int: first argument must be an Int".to_string(),
57 ));
58 };
59 let Value::Int(max) = &args[1] else {
60 return Err(RuntimeError::Error(
61 "Random.int: second argument must be an Int".to_string(),
62 ));
63 };
64
65 match aver_rt::random::random_int(*min, *max) {
66 Ok(value) => Ok(Value::Int(value)),
67 Err(msg) => Err(RuntimeError::Error(msg)),
68 }
69}
70
71fn random_float(args: &[Value]) -> Result<Value, RuntimeError> {
72 if !args.is_empty() {
73 return Err(RuntimeError::Error(format!(
74 "Random.float takes 0 arguments, got {}",
75 args.len()
76 )));
77 }
78 Ok(Value::Float(aver_rt::random::random_float()))
79}
80
81pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
84 let methods = &["int", "float"];
85 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
86 for method in methods {
87 let idx = arena.push_builtin(&format!("Random.{}", method));
88 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
89 }
90 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
91 name: Rc::from("Random"),
92 members,
93 });
94 global.insert("Random".to_string(), NanValue::new_namespace(ns_idx));
95}
96
97pub fn call_nv(
98 name: &str,
99 args: &[NanValue],
100 arena: &mut Arena,
101) -> Option<Result<NanValue, RuntimeError>> {
102 match name {
103 "Random.int" => Some(random_int_nv(args, arena)),
104 "Random.float" => Some(random_float_nv(args, arena)),
105 _ => None,
106 }
107}
108
109fn random_int_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
110 if args.len() != 2 {
111 return Err(RuntimeError::Error(format!(
112 "Random.int takes 2 arguments (min, max), got {}",
113 args.len()
114 )));
115 }
116 if !args[0].is_int() {
117 return Err(RuntimeError::Error(
118 "Random.int: first argument must be an Int".to_string(),
119 ));
120 }
121 if !args[1].is_int() {
122 return Err(RuntimeError::Error(
123 "Random.int: second argument must be an Int".to_string(),
124 ));
125 }
126 let min = args[0].as_int(arena);
127 let max = args[1].as_int(arena);
128 match aver_rt::random::random_int(min, max) {
129 Ok(value) => Ok(NanValue::new_int(value, arena)),
130 Err(msg) => Err(RuntimeError::Error(msg)),
131 }
132}
133
134fn random_float_nv(args: &[NanValue], _arena: &mut Arena) -> Result<NanValue, RuntimeError> {
135 if !args.is_empty() {
136 return Err(RuntimeError::Error(format!(
137 "Random.float takes 0 arguments, got {}",
138 args.len()
139 )));
140 }
141 Ok(NanValue::new_float(aver_rt::random::random_float()))
142}