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 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 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 }
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}