1use std::collections::HashMap;
9use std::sync::Arc as Rc;
10
11use crate::nan_value::{Arena, NanIntExt, 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 const DECLARED_EFFECTS: &[&str] = &["Random.int", "Random.float"];
32
33pub fn effects(name: &str) -> &'static [&'static str] {
34 match name {
35 "Random.int" => &["Random.int"],
36 "Random.float" => &["Random.float"],
37 _ => &[],
38 }
39}
40
41pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
42 match name {
43 "Random.int" => Some(random_int(args)),
44 "Random.float" => Some(random_float(args)),
45 _ => None,
46 }
47}
48
49fn random_int(args: &[Value]) -> Result<Value, RuntimeError> {
50 if args.len() != 2 {
51 return Err(RuntimeError::Error(format!(
52 "Random.int takes 2 arguments (min, max), got {}",
53 args.len()
54 )));
55 }
56 let Value::Int(min) = &args[0] else {
57 return Err(RuntimeError::Error(
58 "Random.int: first argument must be an Int".to_string(),
59 ));
60 };
61 let Value::Int(max) = &args[1] else {
62 return Err(RuntimeError::Error(
63 "Random.int: second argument must be an Int".to_string(),
64 ));
65 };
66
67 let (Some(min), Some(max)) = (min.to_i64(), max.to_i64()) else {
68 return Err(RuntimeError::Error(
69 "Random.int: bounds must fit a 64-bit integer".to_string(),
70 ));
71 };
72 match aver_rt::random::random_int(min, max) {
73 Ok(value) => Ok(Value::int(value)),
74 Err(msg) => Err(RuntimeError::Error(msg)),
75 }
76}
77
78fn random_float(args: &[Value]) -> Result<Value, RuntimeError> {
79 if !args.is_empty() {
80 return Err(RuntimeError::Error(format!(
81 "Random.float takes 0 arguments, got {}",
82 args.len()
83 )));
84 }
85 Ok(Value::Float(aver_rt::random::random_float()))
86}
87
88pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
91 let methods = &["int", "float"];
92 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
93 for method in methods {
94 let idx = arena.push_builtin(&format!("Random.{}", method));
95 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
96 }
97 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
98 name: Rc::from("Random"),
99 members,
100 });
101 global.insert("Random".to_string(), NanValue::new_namespace(ns_idx));
102}
103
104pub fn call_nv(
105 name: &str,
106 args: &[NanValue],
107 arena: &mut Arena,
108) -> Option<Result<NanValue, RuntimeError>> {
109 match name {
110 "Random.int" => Some(random_int_nv(args, arena)),
111 "Random.float" => Some(random_float_nv(args, arena)),
112 _ => None,
113 }
114}
115
116fn random_int_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
117 if args.len() != 2 {
118 return Err(RuntimeError::Error(format!(
119 "Random.int takes 2 arguments (min, max), got {}",
120 args.len()
121 )));
122 }
123 if !args[0].is_int() {
124 return Err(RuntimeError::Error(
125 "Random.int: first argument must be an Int".to_string(),
126 ));
127 }
128 if !args[1].is_int() {
129 return Err(RuntimeError::Error(
130 "Random.int: second argument must be an Int".to_string(),
131 ));
132 }
133 let (Some(min), Some(max)) = (
134 args[0].as_aver_int(arena).to_i64(),
135 args[1].as_aver_int(arena).to_i64(),
136 ) else {
137 return Err(RuntimeError::Error(
138 "Random.int: bounds must fit a 64-bit integer".to_string(),
139 ));
140 };
141 match aver_rt::random::random_int(min, max) {
142 Ok(value) => Ok(NanValue::new_int(value, arena)),
143 Err(msg) => Err(RuntimeError::Error(msg)),
144 }
145}
146
147fn random_float_nv(args: &[NanValue], _arena: &mut Arena) -> Result<NanValue, RuntimeError> {
148 if !args.is_empty() {
149 return Err(RuntimeError::Error(format!(
150 "Random.float takes 0 arguments, got {}",
151 args.len()
152 )));
153 }
154 Ok(NanValue::new_float(aver_rt::random::random_float()))
155}