1use std::collections::HashMap;
13use std::rc::Rc;
14
15use aver_rt::AverVector;
16
17use crate::nan_value::{Arena, NanValue};
18use crate::value::{RuntimeError, Value, list_from_vec, list_view};
19
20pub fn register(global: &mut HashMap<String, Value>) {
21 let mut members = HashMap::new();
22 for method in &["new", "get", "set", "len", "fromList", "toList"] {
23 members.insert(
24 method.to_string(),
25 Value::Builtin(format!("Vector.{}", method)),
26 );
27 }
28 global.insert(
29 "Vector".to_string(),
30 Value::Namespace {
31 name: "Vector".to_string(),
32 members,
33 },
34 );
35}
36
37pub fn effects(_name: &str) -> &'static [&'static str] {
38 &[]
39}
40
41pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
42 match name {
43 "Vector.new" => Some(vec_new(args)),
44 "Vector.get" => Some(vec_get(args)),
45 "Vector.set" => Some(vec_set(args)),
46 "Vector.len" => Some(vec_len(args)),
47 "Vector.fromList" => Some(vec_from_list(args)),
48 "Vector.toList" => Some(vec_to_list(args)),
49 _ => None,
50 }
51}
52
53fn vec_new(args: &[Value]) -> Result<Value, RuntimeError> {
54 if args.len() != 2 {
55 return Err(RuntimeError::Error(format!(
56 "Vector.new() takes 2 arguments (size, default), got {}",
57 args.len()
58 )));
59 }
60 let Value::Int(size) = &args[0] else {
61 return Err(RuntimeError::Error(
62 "Vector.new: size must be an Int".to_string(),
63 ));
64 };
65 if *size < 0 {
66 return Err(RuntimeError::Error(
67 "Vector.new: size must not be negative".to_string(),
68 ));
69 }
70 Ok(Value::Vector(AverVector::new(
71 *size as usize,
72 args[1].clone(),
73 )))
74}
75
76fn vec_get(args: &[Value]) -> Result<Value, RuntimeError> {
77 if args.len() != 2 {
78 return Err(RuntimeError::Error(format!(
79 "Vector.get() takes 2 arguments, got {}",
80 args.len()
81 )));
82 }
83 let Value::Vector(vec) = &args[0] else {
84 return Err(RuntimeError::Error(
85 "Vector.get: first argument must be a Vector".to_string(),
86 ));
87 };
88 let Value::Int(idx) = &args[1] else {
89 return Err(RuntimeError::Error(
90 "Vector.get: index must be an Int".to_string(),
91 ));
92 };
93 if *idx < 0 {
94 return Ok(Value::None);
95 }
96 Ok(match vec.get(*idx as usize) {
97 Some(v) => Value::Some(Box::new(v.clone())),
98 None => Value::None,
99 })
100}
101
102fn vec_set(args: &[Value]) -> Result<Value, RuntimeError> {
103 if args.len() != 3 {
104 return Err(RuntimeError::Error(format!(
105 "Vector.set() takes 3 arguments, got {}",
106 args.len()
107 )));
108 }
109 let Value::Vector(vec) = &args[0] else {
110 return Err(RuntimeError::Error(
111 "Vector.set: first argument must be a Vector".to_string(),
112 ));
113 };
114 let Value::Int(idx) = &args[1] else {
115 return Err(RuntimeError::Error(
116 "Vector.set: index must be an Int".to_string(),
117 ));
118 };
119 if *idx < 0 {
120 return Ok(Value::None);
121 }
122 Ok(match vec.set(*idx as usize, args[2].clone()) {
123 Some(new_vec) => Value::Some(Box::new(Value::Vector(new_vec))),
124 None => Value::None,
125 })
126}
127
128fn vec_len(args: &[Value]) -> Result<Value, RuntimeError> {
129 if args.len() != 1 {
130 return Err(RuntimeError::Error(format!(
131 "Vector.len() takes 1 argument, got {}",
132 args.len()
133 )));
134 }
135 let Value::Vector(vec) = &args[0] else {
136 return Err(RuntimeError::Error(
137 "Vector.len: argument must be a Vector".to_string(),
138 ));
139 };
140 Ok(Value::Int(vec.len() as i64))
141}
142
143fn vec_from_list(args: &[Value]) -> Result<Value, RuntimeError> {
144 if args.len() != 1 {
145 return Err(RuntimeError::Error(format!(
146 "Vector.fromList() takes 1 argument, got {}",
147 args.len()
148 )));
149 }
150 let items = list_view(&args[0]).ok_or_else(|| {
151 RuntimeError::Error("Vector.fromList: argument must be a List".to_string())
152 })?;
153 Ok(Value::Vector(AverVector::from_list(items)))
154}
155
156fn vec_to_list(args: &[Value]) -> Result<Value, RuntimeError> {
157 if args.len() != 1 {
158 return Err(RuntimeError::Error(format!(
159 "Vector.toList() takes 1 argument, got {}",
160 args.len()
161 )));
162 }
163 let Value::Vector(vec) = &args[0] else {
164 return Err(RuntimeError::Error(
165 "Vector.toList: argument must be a Vector".to_string(),
166 ));
167 };
168 Ok(list_from_vec(vec.to_vec()))
169}
170
171pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
174 let methods = &["new", "get", "set", "len", "fromList", "toList"];
175 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
176 for method in methods {
177 let idx = arena.push_builtin(&format!("Vector.{}", method));
178 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
179 }
180 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
181 name: Rc::from("Vector"),
182 members,
183 });
184 global.insert("Vector".to_string(), NanValue::new_namespace(ns_idx));
185}
186
187pub fn call_nv(
188 name: &str,
189 args: &[NanValue],
190 arena: &mut Arena,
191) -> Option<Result<NanValue, RuntimeError>> {
192 match name {
193 "Vector.new" => Some(vec_new_nv(args, arena)),
194 "Vector.get" => Some(vec_get_nv(args, arena)),
195 "Vector.set" => Some(vec_set_nv(args, arena)),
196 "Vector.len" => Some(vec_len_nv(args, arena)),
197 "Vector.fromList" => Some(vec_from_list_nv(args, arena)),
198 "Vector.toList" => Some(vec_to_list_nv(args, arena)),
199 _ => None,
200 }
201}
202
203fn vec_new_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
204 if args.len() != 2 {
205 return Err(RuntimeError::Error(format!(
206 "Vector.new() takes 2 arguments (size, default), got {}",
207 args.len()
208 )));
209 }
210 if !args[0].is_int() {
211 return Err(RuntimeError::Error(
212 "Vector.new: size must be an Int".to_string(),
213 ));
214 }
215 let size = args[0].as_int(arena);
216 if size < 0 {
217 return Err(RuntimeError::Error(
218 "Vector.new: size must not be negative".to_string(),
219 ));
220 }
221 let items = vec![args[1]; size as usize];
222 if items.is_empty() {
223 Ok(NanValue::EMPTY_VECTOR)
224 } else {
225 Ok(NanValue::new_vector(arena.push_vector(items)))
226 }
227}
228
229fn vec_get_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
230 if args.len() != 2 {
231 return Err(RuntimeError::Error(format!(
232 "Vector.get() takes 2 arguments, got {}",
233 args.len()
234 )));
235 }
236 if !args[0].is_vector() {
237 return Err(RuntimeError::Error(
238 "Vector.get: first argument must be a Vector".to_string(),
239 ));
240 }
241 if !args[1].is_int() {
242 return Err(RuntimeError::Error(
243 "Vector.get: index must be an Int".to_string(),
244 ));
245 }
246 let idx = args[1].as_int(arena);
247 if idx < 0 {
248 return Ok(NanValue::NONE);
249 }
250 let items = arena.vector_ref_value(args[0]);
251 match items.get(idx as usize) {
252 Some(&v) => Ok(NanValue::new_some_value(v, arena)),
253 None => Ok(NanValue::NONE),
254 }
255}
256
257fn vec_set_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
258 if args.len() != 3 {
259 return Err(RuntimeError::Error(format!(
260 "Vector.set() takes 3 arguments, got {}",
261 args.len()
262 )));
263 }
264 if !args[0].is_vector() {
265 return Err(RuntimeError::Error(
266 "Vector.set: first argument must be a Vector".to_string(),
267 ));
268 }
269 if !args[1].is_int() {
270 return Err(RuntimeError::Error(
271 "Vector.set: index must be an Int".to_string(),
272 ));
273 }
274 let idx = args[1].as_int(arena);
275 if idx < 0 {
276 return Ok(NanValue::NONE);
277 }
278 let mut items = arena.clone_vector_value(args[0]);
279 let uidx = idx as usize;
280 if uidx >= items.len() {
281 return Ok(NanValue::NONE);
282 }
283 items[uidx] = args[2];
284 let new_vec_idx = arena.push_vector(items);
285 Ok(NanValue::new_some_value(
286 NanValue::new_vector(new_vec_idx),
287 arena,
288 ))
289}
290
291fn vec_len_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
292 if args.len() != 1 {
293 return Err(RuntimeError::Error(format!(
294 "Vector.len() takes 1 argument, got {}",
295 args.len()
296 )));
297 }
298 if !args[0].is_vector() {
299 return Err(RuntimeError::Error(
300 "Vector.len: argument must be a Vector".to_string(),
301 ));
302 }
303 let items = arena.vector_ref_value(args[0]);
304 Ok(NanValue::new_int(items.len() as i64, arena))
305}
306
307fn vec_from_list_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
308 if args.len() != 1 {
309 return Err(RuntimeError::Error(format!(
310 "Vector.fromList() takes 1 argument, got {}",
311 args.len()
312 )));
313 }
314 if !args[0].is_list() {
315 return Err(RuntimeError::Error(
316 "Vector.fromList: argument must be a List".to_string(),
317 ));
318 }
319 let items = arena.list_to_vec_value(args[0]);
320 if items.is_empty() {
321 Ok(NanValue::EMPTY_VECTOR)
322 } else {
323 Ok(NanValue::new_vector(arena.push_vector(items)))
324 }
325}
326
327fn vec_to_list_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
328 if args.len() != 1 {
329 return Err(RuntimeError::Error(format!(
330 "Vector.toList() takes 1 argument, got {}",
331 args.len()
332 )));
333 }
334 if !args[0].is_vector() {
335 return Err(RuntimeError::Error(
336 "Vector.toList: argument must be a Vector".to_string(),
337 ));
338 }
339 let items = arena.clone_vector_value(args[0]);
340 if items.is_empty() {
341 Ok(NanValue::EMPTY_LIST)
342 } else {
343 let list_idx = arena.push_list(items);
344 Ok(NanValue::new_list(list_idx))
345 }
346}