Skip to main content

scheme_rs/
lists.rs

1//! Scheme pairs and lists.
2
3use hashbrown::HashSet;
4use indexmap::IndexMap;
5use parking_lot::RwLock;
6
7use crate::{
8    exceptions::Exception,
9    gc::{Gc, GcInner, Trace},
10    proc::{Application, ContBarrier, Procedure},
11    registry::{bridge, cps_bridge},
12    runtime::{Runtime, RuntimeInner},
13    strings::WideString,
14    value::{UnpackedValue, Value, ValueType, write_value},
15    vectors::Vector,
16};
17use std::fmt;
18
19#[derive(Trace)]
20#[repr(align(16))]
21pub(crate) struct PairInner {
22    /// The head of the pair
23    car: RwLock<Value>,
24    /// The tail of the pair
25    cdr: RwLock<Value>,
26    /// Whether or not the pair can be modified post creation
27    mutable: bool,
28}
29
30/// A pair of Scheme [Values](Value). Has a head (the [car](Pair::car())) and a
31/// tail (the [cdr](Pair::cdr())).
32#[derive(Clone, Trace)]
33pub struct Pair(pub(crate) Gc<PairInner>);
34
35impl Pair {
36    /// Construct a new mutable Pair from a car and cdr
37    pub fn mutable(car: Value, cdr: Value) -> Self {
38        Self(Gc::new(PairInner {
39            car: RwLock::new(car),
40            cdr: RwLock::new(cdr),
41            mutable: true,
42        }))
43    }
44
45    /// Construct a new immutable Pair from a car and cdr
46    pub fn immutable(car: Value, cdr: Value) -> Self {
47        Self(Gc::new(PairInner {
48            car: RwLock::new(car),
49            cdr: RwLock::new(cdr),
50            mutable: false,
51        }))
52    }
53
54    /// Extract the car (aka the head) from the Pair.
55    pub fn car(&self) -> Value {
56        self.0.car.read().clone()
57    }
58
59    /// Alias for [`car`](Pair::car())
60    pub fn head(&self) -> Value {
61        self.car()
62    }
63
64    /// Extract the cdr (aka the tail) from the Pair.
65    pub fn cdr(&self) -> Value {
66        self.0.cdr.read().clone()
67    }
68
69    /// Alias for [`cdr`](Pair::cdr())
70    pub fn tail(&self) -> Value {
71        self.cdr()
72    }
73
74    /// Set the car of the Pair. Returns an error if pair is immutable.
75    pub fn set_car(&self, new_car: Value) -> Result<(), Exception> {
76        if self.0.mutable {
77            *self.0.car.write() = new_car;
78            Ok(())
79        } else {
80            Err(Exception::error("pair is not mutable"))
81        }
82    }
83
84    /// Set the cdr of the Pair. Returns an error if pair is immutable.
85    pub fn set_cdr(&self, new_cdr: Value) -> Result<(), Exception> {
86        if self.0.mutable {
87            *self.0.cdr.write() = new_cdr;
88            Ok(())
89        } else {
90            Err(Exception::error("pair is not mutable"))
91        }
92    }
93}
94
95impl From<Pair> for (Value, Value) {
96    fn from(value: Pair) -> Self {
97        (value.car(), value.cdr())
98    }
99}
100
101pub(crate) fn write_list(
102    car: &Value,
103    cdr: &Value,
104    fmt: fn(&Value, &mut IndexMap<Value, bool>, &mut fmt::Formatter<'_>) -> fmt::Result,
105    circular_values: &mut IndexMap<Value, bool>,
106    f: &mut fmt::Formatter<'_>,
107) -> fmt::Result {
108    match cdr.type_of() {
109        ValueType::Pair | ValueType::Null => (),
110        _ => {
111            // This is not a proper list
112            write!(f, "(")?;
113            write_value(car, fmt, circular_values, f)?;
114            write!(f, " . ")?;
115            write_value(cdr, fmt, circular_values, f)?;
116            write!(f, ")")?;
117            return Ok(());
118        }
119    }
120
121    write!(f, "(")?;
122    write_value(car, fmt, circular_values, f)?;
123    let mut stack = vec![cdr.clone()];
124
125    while let Some(head) = stack.pop() {
126        if let Some((idx, _, seen)) = circular_values.get_full_mut(&head) {
127            if *seen {
128                write!(f, " . #{idx}#")?;
129                continue;
130            } else {
131                write!(f, " #{idx}=")?;
132                *seen = true;
133            }
134        }
135        match &*head.unpacked_ref() {
136            UnpackedValue::Null => {
137                if !stack.is_empty() {
138                    write!(f, " ()")?;
139                }
140            }
141            UnpackedValue::Pair(pair) => {
142                let (car, cdr) = pair.clone().into();
143                write!(f, " ")?;
144                write_value(&car, fmt, circular_values, f)?;
145                stack.push(cdr);
146            }
147            x => {
148                let val = x.clone().into_value();
149                write!(f, " ")?;
150                if stack.is_empty() {
151                    write!(f, ". ")?;
152                }
153                write_value(&val, fmt, circular_values, f)?;
154            }
155        }
156    }
157
158    write!(f, ")")
159}
160
161/// A proper list.
162///
163/// Conversion to this type guarantees that a type is a proper list and allows
164/// for fast retrieval of the length or any individual element of the list.
165///
166/// # Performance
167///
168/// This is done by copying the list into a `Vec`, which can be a quite
169/// expensive operation, so only use this if you need all elements of the list.
170pub struct List {
171    head: Value,
172    items: Vec<Value>,
173}
174
175impl List {
176    pub fn as_slice(&self) -> &[Value] {
177        self.items.as_slice()
178    }
179
180    pub fn into_vec(self) -> Vec<Value> {
181        self.items
182    }
183}
184
185impl IntoIterator for List {
186    type Item = Value;
187    type IntoIter = std::vec::IntoIter<Value>;
188
189    fn into_iter(self) -> Self::IntoIter {
190        self.items.into_iter()
191    }
192}
193
194impl From<List> for Value {
195    fn from(value: List) -> Self {
196        value.head
197    }
198}
199
200impl From<&Value> for Option<List> {
201    fn from(value: &Value) -> Self {
202        let mut seen = HashSet::new();
203        let mut cdr = value.clone();
204        let mut items = Vec::new();
205        while !cdr.is_null() {
206            if !seen.insert(cdr.clone()) {
207                return None;
208            }
209            let (car, new_cdr) = cdr.cast_to_scheme_type()?;
210            items.push(car);
211            cdr = new_cdr;
212        }
213        Some(List {
214            head: value.clone(),
215            items,
216        })
217    }
218}
219
220impl<V> FromIterator<V> for List
221where
222    V: Into<Value>,
223{
224    fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
225        let items = iter.into_iter().map(Into::into).collect::<Vec<_>>();
226        let mut head = Value::null();
227        for item in items.iter().rev() {
228            head = Value::from((item.clone(), head));
229        }
230        Self { head, items }
231    }
232}
233
234impl From<Vec<Value>> for List {
235    fn from(items: Vec<Value>) -> Self {
236        let mut head = Value::null();
237        for item in items.iter().rev() {
238            head = Value::from((item.clone(), head));
239        }
240        Self { head, items }
241    }
242}
243
244impl TryFrom<&Value> for List {
245    type Error = Exception;
246
247    fn try_from(value: &Value) -> Result<Self, Self::Error> {
248        value
249            .cast_to_scheme_type::<List>()
250            .ok_or_else(|| Exception::error("value is not a proper list"))
251    }
252}
253
254/// Convert a slice of values to a proper list
255pub fn slice_to_list(items: &[Value]) -> Value {
256    match items {
257        [] => Value::null(),
258        [head, tail @ ..] => Value::from(Pair::immutable(head.clone(), slice_to_list(tail))),
259    }
260}
261
262pub fn list_to_vec(curr: &Value, out: &mut Vec<Value>) {
263    match &*curr.unpacked_ref() {
264        UnpackedValue::Pair(pair) => {
265            let (car, cdr) = pair.clone().into();
266            out.push(car);
267            list_to_vec(&cdr, out);
268        }
269        UnpackedValue::Null => (),
270        _ => out.push(curr.clone()),
271    }
272}
273
274pub fn list_to_vec_with_null(curr: &Value, out: &mut Vec<Value>) {
275    match &*curr.unpacked_ref() {
276        UnpackedValue::Pair(pair) => {
277            let (car, cdr) = pair.clone().into();
278            out.push(car);
279            list_to_vec_with_null(&cdr, out);
280        }
281        _ => out.push(curr.clone()),
282    }
283}
284
285pub fn is_list(curr: &Value, seen: &mut HashSet<Value>) -> bool {
286    if curr.is_null() {
287        return true;
288    }
289
290    if !seen.insert(curr.clone()) {
291        return false;
292    }
293
294    let Some(curr) = curr.cast_to_scheme_type::<Pair>() else {
295        return false;
296    };
297
298    is_list(&curr.cdr(), seen)
299}
300
301#[bridge(name = "list?", lib = "(rnrs base builtins (6))")]
302pub fn list_pred(arg: &Value) -> Result<Vec<Value>, Exception> {
303    Ok(vec![Value::from(is_list(arg, &mut HashSet::default()))])
304}
305
306#[bridge(name = "list", lib = "(rnrs base builtins (6))")]
307pub fn list(args: &[Value]) -> Result<Vec<Value>, Exception> {
308    // Construct the list in reverse
309    let mut cdr = Value::null();
310    for arg in args.iter().rev() {
311        cdr = Value::from(Pair::mutable(arg.clone(), cdr));
312    }
313    Ok(vec![cdr])
314}
315
316#[bridge(name = "cons", lib = "(rnrs base builtins (6))")]
317pub fn cons(car: &Value, cdr: &Value) -> Result<Vec<Value>, Exception> {
318    Ok(vec![Value::from(Pair::mutable(car.clone(), cdr.clone()))])
319}
320
321#[bridge(name = "car", lib = "(rnrs base builtins (6))")]
322pub fn car(val: &Value) -> Result<Vec<Value>, Exception> {
323    Ok(vec![val.try_to_scheme_type::<Pair>()?.car()])
324}
325
326#[bridge(name = "cdr", lib = "(rnrs base builtins (6))")]
327pub fn cdr(val: &Value) -> Result<Vec<Value>, Exception> {
328    Ok(vec![val.try_to_scheme_type::<Pair>()?.cdr()])
329}
330
331#[bridge(name = "set-car!", lib = "(rnrs mutable-pairs (6))")]
332pub fn set_car(var: &Value, val: &Value) -> Result<Vec<Value>, Exception> {
333    let pair: Pair = var.clone().try_into()?;
334    pair.set_car(val.clone())?;
335    Ok(Vec::new())
336}
337
338#[bridge(name = "set-cdr!", lib = "(rnrs mutable-pairs (6))")]
339pub fn set_cdr(var: &Value, val: &Value) -> Result<Vec<Value>, Exception> {
340    let pair: Pair = var.clone().try_into()?;
341    pair.set_cdr(val.clone())?;
342    Ok(Vec::new())
343}
344
345#[bridge(name = "length", lib = "(rnrs base builtins (6))")]
346pub fn length_builtin(arg: &Value) -> Result<Vec<Value>, Exception> {
347    Ok(vec![Value::from(length(arg)?)])
348}
349
350pub fn length(arg: &Value) -> Result<usize, Exception> {
351    let mut length = 0usize;
352    let mut arg = arg.clone();
353    loop {
354        arg = {
355            match &*arg.unpacked_ref() {
356                UnpackedValue::Pair(pair) => pair.cdr(),
357                UnpackedValue::Null => break,
358                _ => return Err(Exception::error("list must be proper")),
359            }
360        };
361        length += 1;
362    }
363    Ok(length)
364}
365
366#[bridge(name = "list->vector", lib = "(rnrs base builtins (6))")]
367pub fn list_to_vector(list: &Value) -> Result<Vec<Value>, Exception> {
368    let List { items, .. } = list.try_to_scheme_type()?;
369    Ok(vec![Value::from(items)])
370}
371
372#[bridge(name = "list->string", lib = "(rnrs base builtins (6))")]
373pub fn list_to_string(List { items, .. }: List) -> Result<Vec<Value>, Exception> {
374    let chars = items
375        .into_iter()
376        .map(char::try_from)
377        .collect::<Result<Vec<_>, _>>()?;
378    Ok(vec![Value::from(WideString::mutable(chars))])
379}
380
381#[bridge(name = "append", lib = "(rnrs base builtins (6))")]
382pub fn append(list: &Value, to_append: &Value) -> Result<Vec<Value>, Exception> {
383    let mut vec = Vec::new();
384    list_to_vec(list, &mut vec);
385    let mut list = to_append.clone();
386    for item in vec.into_iter().rev() {
387        list = Value::from(Pair::mutable(item, list));
388    }
389    Ok(vec![list])
390}
391
392#[cps_bridge(def = "map proc list1 . listn", lib = "(rnrs base builtins (6))")]
393pub fn map(
394    runtime: &Runtime,
395    _env: &[Value],
396    args: &[Value],
397    list_n: &[Value],
398    barrier: &mut ContBarrier,
399    k: Value,
400) -> Result<Application, Exception> {
401    let [mapper, list_1] = args else {
402        unreachable!()
403    };
404    let mapper_proc: Procedure = mapper.clone().try_into()?;
405    let mut inputs = Some(list_1.clone())
406        .into_iter()
407        .chain(list_n.iter().cloned())
408        .collect::<Vec<_>>();
409    let mut args = Vec::new();
410
411    for input in inputs.iter_mut() {
412        if input.type_of() == ValueType::Null {
413            // TODO: Check if the rest are also empty and args is empty
414            return Ok(Application::new(k.try_into()?, vec![Value::null()]));
415        }
416
417        let (car, cdr) = input.try_to_scheme_type::<Pair>()?.into();
418
419        args.push(car);
420        *input = cdr;
421    }
422
423    let map_k = barrier.new_k(
424        runtime.clone(),
425        vec![
426            Value::from(Vec::<Value>::new()),
427            Value::from(inputs),
428            mapper.clone(),
429            k,
430        ],
431        map_k,
432        1,
433        false,
434    );
435
436    args.push(Value::from(map_k));
437
438    Ok(Application::new(mapper_proc, args))
439}
440
441unsafe extern "C" fn map_k(
442    runtime: *mut GcInner<RwLock<RuntimeInner>>,
443    env: *const Value,
444    args: *const Value,
445    barrier: *mut ContBarrier,
446) -> *mut Application {
447    unsafe {
448        // TODO: Probably need to do this in a way that avoids mutable variables
449
450        // env[0] is the output list
451        let output: Vector = env.as_ref().unwrap().clone().try_into().unwrap();
452
453        output.0.vec.write().push(args.as_ref().unwrap().clone());
454
455        // env[1] is the input lists
456        let inputs: Vector = env.add(1).as_ref().unwrap().clone().try_into().unwrap();
457
458        // env[2] is the mapper function
459        let mapper: Procedure = env.add(2).as_ref().unwrap().clone().try_into().unwrap();
460
461        // env[3] is the continuation
462        let k: Procedure = env.add(3).as_ref().unwrap().clone().try_into().unwrap();
463
464        let mut args = Vec::new();
465
466        // TODO: We need to collect a new list
467        for input in inputs.0.vec.write().iter_mut() {
468            if input.type_of() == ValueType::Null {
469                // TODO: Check if the rest are also empty and args is empty
470                let output = slice_to_list(&output.0.vec.read());
471                let app = Application::new(k, vec![output]);
472                return Box::into_raw(Box::new(app));
473            }
474
475            let (car, cdr) = input.cast_to_scheme_type::<Pair>().unwrap().into();
476            args.push(car);
477            *input = cdr;
478        }
479
480        let map_k = barrier.as_mut().unwrap().new_k(
481            Runtime::from_raw_inc_rc(runtime),
482            vec![
483                Value::from(output),
484                Value::from(inputs),
485                Value::from(mapper.clone()),
486                Value::from(k),
487            ],
488            map_k,
489            1,
490            false,
491        );
492
493        args.push(Value::from(map_k));
494
495        Box::into_raw(Box::new(Application::new(mapper, args)))
496    }
497}
498
499#[bridge(name = "zip", lib = "(rnrs base builtins (6))")]
500pub fn zip(list1: &Value, listn: &[Value]) -> Result<Vec<Value>, Exception> {
501    let mut output: Option<Vec<Value>> = None;
502    for list in Some(list1).into_iter().chain(listn.iter()).rev() {
503        let List { items, .. } = list.try_to_scheme_type()?;
504        if let Some(output) = &output {
505            if output.len() != items.len() {
506                return Err(Exception::error("lists do not have the same length"));
507            }
508        } else {
509            output = Some(vec![Value::null(); items.len()]);
510        }
511
512        let output = output.as_mut().unwrap();
513        for (i, item) in items.into_iter().enumerate() {
514            output[i] = Value::from((item, output[i].clone()));
515        }
516    }
517
518    if let Some(output) = output {
519        Ok(vec![slice_to_list(&output)])
520    } else {
521        Ok(vec![Value::null()])
522    }
523}