scheme_rs/
proc.rs

1use crate::{
2    ast::Body,
3    continuation::Continuation,
4    env::Env,
5    error::{Frame, RuntimeError},
6    eval::{Eval, ValuesOrPreparedCall},
7    gc::{Gc, Trace},
8    syntax::{Identifier, Span},
9    value::Value,
10};
11use async_trait::async_trait;
12use futures::future::BoxFuture;
13use std::sync::Arc;
14
15#[async_trait]
16pub trait Callable: Send + Sync + 'static {
17    fn min_args(&self) -> usize;
18
19    fn max_args(&self) -> Option<usize>;
20
21    async fn call(
22        &self,
23        mut args: Vec<Gc<Value>>,
24        cont: &Option<Arc<Continuation>>,
25    ) -> Result<ValuesOrPreparedCall, RuntimeError>;
26}
27
28#[derive(Clone, derive_more::Debug, Trace)]
29pub struct Procedure {
30    #[debug(skip)]
31    pub up: Env,
32    pub args: Vec<Identifier>,
33    pub remaining: Option<Identifier>,
34    #[debug(skip)]
35    pub body: Body,
36    pub is_variable_transformer: bool,
37}
38
39#[async_trait]
40impl Callable for Procedure {
41    fn min_args(&self) -> usize {
42        self.args.len()
43    }
44
45    fn max_args(&self) -> Option<usize> {
46        self.remaining.is_none().then_some(self.args.len())
47    }
48
49    async fn call(
50        &self,
51        args: Vec<Gc<Value>>,
52        cont: &Option<Arc<Continuation>>,
53    ) -> Result<ValuesOrPreparedCall, RuntimeError> {
54        let env = Gc::new(self.up.new_lexical_contour());
55        let provided = args.len();
56        let mut args_iter = args.iter().peekable();
57
58        for required in &self.args {
59            // We shouldn't ever need to check this, but probably safer to put
60            // this call here as well.
61            let Some(value) = args_iter.next().cloned() else {
62                return Err(RuntimeError::wrong_num_of_args(self.args.len(), provided));
63            };
64            env.write().await.def_var(required, value);
65        }
66
67        if let Some(ref remaining) = self.remaining {
68            env.write().await.def_var(
69                remaining,
70                Gc::new(Value::from(args_iter.cloned().collect::<Vec<_>>())),
71            );
72        } else if args_iter.peek().is_some() {
73            return Err(RuntimeError::wrong_num_of_args(self.args.len(), provided));
74        }
75
76        self.body.tail_eval(&Env::from(env.clone()), cont).await
77    }
78}
79
80pub type ExprFuture = BoxFuture<'static, Result<Vec<Gc<Value>>, RuntimeError>>;
81
82#[derive(Debug, Clone, Trace)]
83pub struct ExternalFn {
84    pub name: &'static str,
85    pub num_args: usize,
86    pub variadic: bool,
87    pub func: fn(Option<Arc<Continuation>>, Vec<Gc<Value>>) -> ExprFuture,
88}
89
90#[async_trait]
91impl Callable for ExternalFn {
92    fn min_args(&self) -> usize {
93        self.num_args
94    }
95
96    fn max_args(&self) -> Option<usize> {
97        (!self.variadic).then_some(self.num_args)
98    }
99
100    async fn call(
101        &self,
102        args: Vec<Gc<Value>>,
103        cont: &Option<Arc<Continuation>>,
104    ) -> Result<ValuesOrPreparedCall, RuntimeError> {
105        // TODO: check the arguments
106        Ok(ValuesOrPreparedCall::Values(
107            (self.func)(cont.clone(), args).await?,
108        ))
109    }
110}
111
112pub struct PreparedCall {
113    proc_name: String,
114    location: Span,
115    operator: Gc<Value>,
116    args: Vec<Gc<Value>>,
117}
118
119impl PreparedCall {
120    pub async fn eval(
121        self,
122        cont: &Option<Arc<Continuation>>,
123    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
124        let mut curr_proc = Some(self);
125        let mut bt = Vec::new();
126        loop {
127            let proc = curr_proc.take().unwrap();
128            bt.push(Frame::new(proc.proc_name.clone(), proc.location.clone()));
129            let callable = {
130                let proc = proc.operator.read().await;
131                let Some(callable) = proc.as_callable() else {
132                    return Err(RuntimeError::invalid_operator_type(proc.type_name()));
133                };
134                drop(proc);
135                callable
136            };
137            if proc.args.len() < callable.min_args() {
138                return Err(RuntimeError::wrong_num_of_args(
139                    callable.min_args(),
140                    proc.args.len(),
141                ));
142            }
143            if let Some(max_args) = callable.max_args() {
144                if proc.args.len() > max_args {
145                    return Err(RuntimeError::wrong_num_of_args(max_args, proc.args.len()));
146                }
147            }
148            let ret = callable.call(proc.args, cont).await.map_err(|mut err| {
149                err.backtrace.extend(std::mem::take(&mut bt));
150                err
151            })?;
152            match ret {
153                ValuesOrPreparedCall::Values(value) => return Ok(value),
154                ValuesOrPreparedCall::PreparedCall(prepared) => {
155                    curr_proc = Some(prepared);
156                    // Continue
157                }
158            }
159        }
160    }
161
162    pub fn prepare(proc_name: &str, location: &Span, args: Vec<Gc<Value>>) -> Self {
163        let operator = args[0].clone();
164        let args = args[1..].to_owned();
165        Self {
166            proc_name: proc_name.to_string(),
167            location: location.clone(),
168            operator,
169            args,
170        }
171    }
172}