uni_core/primitives/
vector.rs1use crate::compat::{format, Rc, ToString, Vec};
4use crate::interpreter::Interpreter;
5use crate::value::{RuntimeError, Value};
6
7#[cfg(not(target_os = "none"))]
8use std::cell::RefCell;
9#[cfg(target_os = "none")]
10use core::cell::RefCell;
11
12#[cfg(target_os = "none")]
13use num_traits::Float;
14
15fn expect_array(value: Value, op_name: &str) -> Result<Rc<RefCell<Vec<Value>>>, RuntimeError> {
16 match value {
17 Value::Array(array) => Ok(array),
18 _ => Err(RuntimeError::TypeError(format!(
19 "{} expects an array",
20 op_name
21 ))),
22 }
23}
24
25fn expect_index(index: f64, op_name: &str) -> Result<usize, RuntimeError> {
26 if index < 0.0 || index.fract() != 0.0 {
27 return Err(RuntimeError::TypeError(format!(
28 "{} index must be a non-negative integer",
29 op_name
30 )));
31 }
32 Ok(index as usize)
33}
34
35fn collect_list_elements(list: Value) -> Result<Vec<Value>, RuntimeError> {
36 let mut elements = Vec::new();
37 let mut current = list;
38
39 loop {
40 match current {
41 Value::Pair(car, cdr) => {
42 elements.push((*car).clone());
43 current = (*cdr).clone();
44 }
45 Value::Nil => break,
46 _ => {
47 return Err(RuntimeError::TypeError(
48 "list->vector expects a proper list".to_string(),
49 ));
50 }
51 }
52 }
53
54 Ok(elements)
55}
56
57pub fn vector_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
60 let count_value = interp.pop_number()?;
61 if count_value < 0.0 || count_value.fract() != 0.0 {
62 return Err(RuntimeError::TypeError(
63 "vector count must be a non-negative integer".to_string(),
64 ));
65 }
66
67 let count = count_value as usize;
68 let mut elements = Vec::with_capacity(count);
69 for _ in 0..count {
70 elements.push(interp.pop()?);
71 }
72 elements.reverse();
73
74 interp.push(interp.make_array(elements));
75 Ok(())
76}
77
78pub fn make_vector_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
81 let fill_value = interp.pop()?;
82 let count_value = interp.pop_number()?;
83 if count_value < 0.0 || count_value.fract() != 0.0 {
84 return Err(RuntimeError::TypeError(
85 "make-vector count must be a non-negative integer".to_string(),
86 ));
87 }
88 let count = count_value as usize;
89
90 let mut elements = Vec::with_capacity(count);
91 for _ in 0..count {
92 elements.push(fill_value.clone());
93 }
94
95 interp.push(interp.make_array(elements));
96 Ok(())
97}
98
99pub fn vector_length_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
101 let vector_value = interp.pop()?;
102 let array = expect_array(vector_value, "vector-length")?;
103 let len = array.borrow().len();
104 interp.push(Value::Number(len as f64));
105 Ok(())
106}
107
108pub fn vector_ref_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
110 let index_value = interp.pop_number()?;
111 let index = expect_index(index_value, "vector-ref")?;
112 let vector_value = interp.pop()?;
113 let array = expect_array(vector_value, "vector-ref")?;
114
115 let elements = array.borrow();
116 let element = elements.get(index).cloned().ok_or_else(|| {
117 RuntimeError::TypeError(format!(
118 "vector-ref index {} out of bounds for length {}",
119 index,
120 elements.len()
121 ))
122 })?;
123
124 interp.push(element);
125 Ok(())
126}
127
128pub fn vector_set_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
131 let index_value = interp.pop_number()?;
132 let index = expect_index(index_value, "vector-set!")?;
133 let vector_value = interp.pop()?;
134 let array = expect_array(vector_value, "vector-set!")?;
135 let new_value = interp.pop()?;
136
137 let mut elements = array.borrow_mut();
138 if index >= elements.len() {
139 return Err(RuntimeError::TypeError(format!(
140 "vector-set! index {} out of bounds for length {}",
141 index,
142 elements.len()
143 )));
144 }
145 elements[index] = new_value;
146 Ok(())
147}
148
149pub fn vector_to_list_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
151 let vector_value = interp.pop()?;
152 let array = expect_array(vector_value, "vector->list")?;
153 let elements = array.borrow();
154 let list_elements: Vec<Value> = elements.iter().cloned().collect();
155 interp.push(interp.make_list(list_elements));
156 Ok(())
157}
158
159pub fn list_to_vector_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
161 let list_value = interp.pop()?;
162 let elements = collect_list_elements(list_value)?;
163 interp.push(interp.make_array(elements));
164 Ok(())
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 fn setup_interpreter() -> Interpreter {
172 Interpreter::new()
173 }
174
175 fn unwrap_array(value: Value) -> Rc<RefCell<Vec<Value>>> {
176 match value {
177 Value::Array(array) => array,
178 _ => panic!("Expected array"),
179 }
180 }
181
182 #[test]
183 fn test_vector_builtin_basic() {
184 let mut interp = setup_interpreter();
185
186 interp.push(Value::Number(1.0));
187 interp.push(Value::Number(2.0));
188 interp.push(Value::Number(3.0));
189 interp.push(Value::Number(3.0));
190 vector_builtin(&mut interp).unwrap();
191
192 let array_rc = unwrap_array(interp.pop().unwrap());
193 let array = array_rc.borrow();
194 assert_eq!(array.len(), 3);
195 assert!(matches!(array[0], Value::Number(n) if n == 1.0));
196 assert!(matches!(array[1], Value::Number(n) if n == 2.0));
197 assert!(matches!(array[2], Value::Number(n) if n == 3.0));
198 }
199
200 #[test]
201 fn test_make_vector_builtin() {
202 let mut interp = setup_interpreter();
203
204 interp.push(Value::Number(4.0));
205 interp.push(Value::String("fill".into()));
206 make_vector_builtin(&mut interp).unwrap();
207
208 let array_rc = unwrap_array(interp.pop().unwrap());
209 let array = array_rc.borrow();
210 assert_eq!(array.len(), 4);
211 for element in array.iter() {
212 assert!(matches!(element, Value::String(s) if s.as_ref() == "fill"));
213 }
214 }
215
216 #[test]
217 fn test_vector_length_builtin() {
218 let mut interp = setup_interpreter();
219
220 interp.push(Value::Number(5.0));
221 interp.push(Value::Number(6.0));
222 interp.push(Value::Number(2.0));
223 vector_builtin(&mut interp).unwrap();
224 vector_length_builtin(&mut interp).unwrap();
225
226 let len_value = interp.pop().unwrap();
227 assert!(matches!(len_value, Value::Number(n) if n == 2.0));
228 }
229
230 #[test]
231 fn test_vector_ref_builtin() {
232 let mut interp = setup_interpreter();
233
234 interp.push(Value::Number(7.0));
235 interp.push(Value::Number(8.0));
236 interp.push(Value::Number(2.0));
237 vector_builtin(&mut interp).unwrap();
238
239 let vector_value = interp.pop().unwrap();
240 interp.push(vector_value.clone());
241 interp.push(Value::Number(1.0));
242 vector_ref_builtin(&mut interp).unwrap();
243
244 let result = interp.pop().unwrap();
245 assert!(matches!(result, Value::Number(n) if n == 8.0));
246 }
247
248 #[test]
249 fn test_vector_set_builtin() {
250 let mut interp = setup_interpreter();
251
252 interp.push(Value::Number(1.0));
253 interp.push(Value::Number(1.0));
254 vector_builtin(&mut interp).unwrap();
255
256 let vector_value = interp.pop().unwrap();
257 interp.push(Value::Number(42.0));
258 interp.push(vector_value.clone());
259 interp.push(Value::Number(0.0));
260 vector_set_builtin(&mut interp).unwrap();
261
262 let array_rc = unwrap_array(vector_value);
263 let array = array_rc.borrow();
264 assert!(matches!(array[0], Value::Number(n) if n == 42.0));
265 }
266
267 #[test]
268 fn test_vector_to_list_builtin() {
269 let mut interp = setup_interpreter();
270
271 interp.push(Value::Number(1.0));
272 interp.push(Value::Number(2.0));
273 interp.push(Value::Number(2.0));
274 vector_builtin(&mut interp).unwrap();
275
276 let vector_value = interp.pop().unwrap();
277 interp.push(vector_value);
278 vector_to_list_builtin(&mut interp).unwrap();
279
280 let list_value = interp.pop().unwrap();
281 match list_value {
282 Value::Pair(car, cdr) => {
283 assert!(matches!(car.as_ref(), Value::Number(n) if *n == 1.0));
284 match cdr.as_ref() {
285 Value::Pair(car2, cdr2) => {
286 assert!(matches!(car2.as_ref(), Value::Number(n) if *n == 2.0));
287 assert!(matches!(cdr2.as_ref(), Value::Nil));
288 }
289 _ => panic!("Expected second element in list"),
290 }
291 }
292 _ => panic!("Expected list"),
293 }
294 }
295
296 #[test]
297 fn test_list_to_vector_builtin() {
298 let mut interp = setup_interpreter();
299
300 let list = interp.make_list(vec![Value::Number(5.0), Value::Boolean(true)]);
301 interp.push(list);
302 list_to_vector_builtin(&mut interp).unwrap();
303
304 let array_rc = unwrap_array(interp.pop().unwrap());
305 let array = array_rc.borrow();
306 assert_eq!(array.len(), 2);
307 assert!(matches!(array[0], Value::Number(n) if n == 5.0));
308 assert!(matches!(array[1], Value::Boolean(true)));
309 }
310
311 #[test]
312 fn test_list_to_vector_requires_proper_list() {
313 let mut interp = setup_interpreter();
314
315 interp.push(Value::Number(10.0));
316 let result = list_to_vector_builtin(&mut interp);
317 assert!(matches!(
318 result,
319 Err(RuntimeError::TypeError(msg)) if msg.contains("proper list")
320 ));
321 }
322}