scheme_rs/
lists.rs

1use crate::{continuation::Continuation, error::RuntimeError, gc::Gc, num::Number, value::Value};
2use futures::future::BoxFuture;
3use scheme_rs_macros::builtin;
4use std::sync::Arc;
5
6pub fn fmt_list<'a>(car: &'a Gc<Value>, cdr: &'a Gc<Value>) -> BoxFuture<'a, String> {
7    // TODO(map): If the list is circular, DO NOT print infinitely!
8    Box::pin(async move {
9        match &*cdr.read().await {
10            Value::Pair(_, _) | Value::Null => (),
11            cdr => {
12                // This is not a proper list
13                let car = car.read().await.fmt().await;
14                let cdr = cdr.fmt().await;
15                return format!("({car} . {cdr})");
16            }
17        }
18
19        let mut output = String::from("(");
20        output.push_str(&car.read().await.fmt().await);
21
22        let mut stack = vec![cdr.clone()];
23
24        while let Some(head) = stack.pop() {
25            match &*head.read().await {
26                Value::Null => {
27                    if !stack.is_empty() {
28                        output.push_str(" ()");
29                    }
30                }
31                Value::Pair(car, cdr) => {
32                    output.push(' ');
33                    output.push_str(&car.read().await.fmt().await);
34                    stack.push(cdr.clone());
35                }
36                x => {
37                    output.push(' ');
38                    output.push_str(&x.fmt().await)
39                }
40            }
41        }
42
43        output.push(')');
44        output
45    })
46}
47
48pub fn list_to_vec<'a>(curr: &'a Gc<Value>, out: &'a mut Vec<Gc<Value>>) -> BoxFuture<'a, ()> {
49    Box::pin(async move {
50        let val = curr.read().await;
51        match &*val {
52            Value::Pair(a, b) => {
53                out.push(a.clone());
54                list_to_vec(b, out).await;
55            }
56            Value::Null => (),
57            _ => out.push(curr.clone()),
58        }
59    })
60}
61
62#[builtin("list")]
63pub async fn list(
64    _cont: &Option<Arc<Continuation>>,
65    args: Vec<Gc<Value>>,
66) -> Result<Vec<Gc<Value>>, RuntimeError> {
67    // Construct the list in reverse
68    let mut cdr = Gc::new(Value::Null);
69    for arg in args.into_iter().rev() {
70        cdr = Gc::new(Value::Pair(arg, cdr.clone()));
71    }
72    Ok(vec![cdr])
73}
74
75#[builtin("cons")]
76pub async fn cons(
77    _cont: &Option<Arc<Continuation>>,
78    car: &Gc<Value>,
79    cdr: &Gc<Value>,
80) -> Result<Vec<Gc<Value>>, RuntimeError> {
81    Ok(vec![Gc::new(Value::Pair(car.clone(), cdr.clone()))])
82}
83
84#[builtin("car")]
85pub async fn car(
86    _cont: &Option<Arc<Continuation>>,
87    val: &Gc<Value>,
88) -> Result<Vec<Gc<Value>>, RuntimeError> {
89    let val = val.read().await;
90    match &*val {
91        Value::Pair(car, _cdr) => Ok(vec![car.clone()]),
92        _ => Err(RuntimeError::invalid_type("pair", val.type_name())),
93    }
94}
95
96#[builtin("cdr")]
97pub async fn cdr(
98    _cont: &Option<Arc<Continuation>>,
99    val: &Gc<Value>,
100) -> Result<Vec<Gc<Value>>, RuntimeError> {
101    let val = val.read().await;
102    match &*val {
103        Value::Pair(_car, cdr) => Ok(vec![cdr.clone()]),
104        _ => Err(RuntimeError::invalid_type("pair", val.type_name())),
105    }
106}
107
108#[builtin("set-car!")]
109pub async fn set_car(
110    _cont: &Option<Arc<Continuation>>,
111    var: &Gc<Value>,
112    val: &Gc<Value>,
113) -> Result<Vec<Gc<Value>>, RuntimeError> {
114    let mut var = var.write().await;
115    match &mut *var {
116        Value::Pair(ref mut car, _cdr) => *car = val.clone(),
117        _ => todo!(),
118    }
119    Ok(vec![Gc::new(Value::Null)])
120}
121
122#[builtin("length")]
123pub async fn length(
124    _cont: &Option<Arc<Continuation>>,
125    arg: &Gc<Value>,
126) -> Result<Vec<Gc<Value>>, RuntimeError> {
127    let mut length = 0;
128    let mut arg = arg.clone();
129    loop {
130        arg = {
131            let val = arg.read().await;
132            match &*val {
133                Value::Pair(_, cdr) => cdr.clone(),
134                _ => break,
135            }
136        };
137        length += 1;
138    }
139    Ok(vec![Gc::new(Value::Number(Number::from(length)))])
140}