scheme_rs/
continuation.rs

1use async_trait::async_trait;
2use scheme_rs_macros::builtin;
3
4use crate::{
5    ast,
6    env::{Env, LexicalContour},
7    error::{RuntimeError, RuntimeErrorKind},
8    eval::{Eval, ValuesOrPreparedCall},
9    expand::Transformer,
10    gc::{Gc, Trace},
11    lists::list_to_vec,
12    proc::{Callable, PreparedCall},
13    syntax::{Identifier, Span},
14    util::{ArcSlice, RequireOne},
15    value::Value,
16};
17use std::sync::Arc;
18
19#[async_trait]
20pub trait Resumable: Trace + Send + Sync {
21    fn min_args(&self) -> usize {
22        1
23    }
24
25    fn max_args(&self) -> Option<usize> {
26        Some(1)
27    }
28
29    async fn resume(
30        &self,
31        args: Vec<Gc<Value>>,
32        cont: &Option<Arc<Continuation>>,
33    ) -> Result<Vec<Gc<Value>>, RuntimeError>;
34}
35
36#[derive(Clone, Trace)]
37pub struct Continuation {
38    resume_point: Arc<dyn Resumable>,
39    remaining: Option<Arc<Continuation>>,
40}
41
42impl Continuation {
43    pub fn new(resume_point: Arc<dyn Resumable>, remaining: &Option<Arc<Continuation>>) -> Self {
44        Self {
45            resume_point,
46            remaining: remaining.clone(),
47        }
48    }
49}
50
51#[async_trait]
52impl Resumable for Continuation {
53    async fn resume(
54        &self,
55        args: Vec<Gc<Value>>,
56        cont: &Option<Arc<Continuation>>,
57    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
58        if let Some(ref remaining) = self.remaining {
59            let new_cont = Some(Arc::new(Continuation::new(remaining.clone(), cont)));
60            let resume_result = self.resume_point.resume(args, &new_cont).await?;
61            remaining.resume(resume_result, cont).await
62        } else {
63            self.resume_point.resume(args, cont).await
64        }
65    }
66}
67
68#[async_trait]
69impl Callable for Option<Arc<Continuation>> {
70    fn min_args(&self) -> usize {
71        self.as_ref()
72            .map(|x| x.resume_point.min_args())
73            .unwrap_or(1)
74    }
75
76    fn max_args(&self) -> Option<usize> {
77        self.as_ref()
78            .map(|x| x.resume_point.max_args())
79            .unwrap_or(None)
80    }
81
82    async fn call(
83        &self,
84        args: Vec<Gc<Value>>,
85        _calling_cont: &Self,
86    ) -> Result<ValuesOrPreparedCall, RuntimeError> {
87        Err(RuntimeError::abandon_current_continuation(
88            args,
89            self.clone(),
90        ))
91    }
92}
93
94#[derive(Trace)]
95pub struct CatchContinuationCall {
96    inner: Arc<dyn Eval>,
97}
98
99impl CatchContinuationCall {
100    pub fn new(inner: Arc<dyn Eval>) -> Self {
101        Self { inner }
102    }
103}
104
105#[async_trait]
106impl Eval for CatchContinuationCall {
107    async fn eval(
108        &self,
109        env: &Env,
110        cont: &Option<Arc<Continuation>>,
111    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
112        let mut inner = self.inner.eval(env, cont).await;
113        while let Err(RuntimeError {
114            kind: RuntimeErrorKind::AbandonCurrentContinuation { args, new_cont },
115            ..
116        }) = inner
117        {
118            // Abandon the current continuation and evaluate the newly returned one
119            // TODO: Retain the backtrace for errors
120            // let arg = args.pop().unwrap();
121            if let Some(new_cont) = new_cont {
122                inner = new_cont.resume(args, cont).await;
123            } else {
124                return Ok(args);
125            }
126        }
127        inner
128    }
129}
130
131#[derive(Trace)]
132pub struct ResumableBody {
133    env: Env,
134    remaining: ArcSlice<Arc<dyn Eval>>,
135}
136
137impl ResumableBody {
138    pub fn new(env: &Env, remaining: &ArcSlice<Arc<dyn Eval>>) -> Self {
139        Self {
140            env: env.clone(),
141            remaining: remaining.clone(),
142        }
143    }
144}
145
146#[async_trait]
147impl Resumable for ResumableBody {
148    async fn resume(
149        &self,
150        args: Vec<Gc<Value>>,
151        cont: &Option<Arc<Continuation>>,
152    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
153        let Some(last) = self.remaining.last() else {
154            return Ok(args);
155        };
156        for (expr, tail) in self.remaining.skip_last() {
157            let cont = Some(Arc::new(Continuation::new(
158                Arc::new(ResumableBody::new(&self.env, &tail)),
159                cont,
160            )));
161            expr.eval(&self.env, &cont).await?;
162        }
163        last.eval(&self.env, cont).await
164    }
165}
166
167#[derive(Trace)]
168pub struct ResumableSyntaxCase {
169    env: Env,
170    transformer: Transformer,
171}
172
173impl ResumableSyntaxCase {
174    pub fn new(env: &Env, transformer: &Transformer) -> Self {
175        Self {
176            env: env.clone(),
177            transformer: transformer.clone(),
178        }
179    }
180}
181
182#[async_trait]
183impl Resumable for ResumableSyntaxCase {
184    async fn resume(
185        &self,
186        args: Vec<Gc<Value>>,
187        cont: &Option<Arc<Continuation>>,
188    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
189        let arg = args.require_one()?;
190        let arg = arg.read().await;
191        match &*arg {
192            Value::Syntax(syntax) => {
193                let result = self.transformer.expand(syntax).unwrap();
194                result
195                    .compile(&self.env, cont)
196                    .await?
197                    .eval(&self.env, cont)
198                    .await
199            }
200            _ => todo!(),
201        }
202    }
203}
204
205#[derive(Trace)]
206pub struct ResumableSet {
207    env: Env,
208    var: Identifier,
209}
210
211impl ResumableSet {
212    pub fn new(env: &Env, var: &Identifier) -> Self {
213        Self {
214            env: env.clone(),
215            var: var.clone(),
216        }
217    }
218}
219
220#[async_trait]
221impl Resumable for ResumableSet {
222    async fn resume(
223        &self,
224        args: Vec<Gc<Value>>,
225        _cont: &Option<Arc<Continuation>>,
226    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
227        // TODO: Add try_unwrap to GC to avoid the clone of the inner value
228        let arg = args.require_one()?;
229        let val = arg.read().await.clone();
230        *self
231            .env
232            .fetch_var(&self.var)
233            .await
234            .ok_or_else(|| RuntimeError::undefined_variable(self.var.clone()))?
235            .write()
236            .await = val;
237        Ok(vec![Gc::new(Value::Null)])
238    }
239}
240
241#[derive(Trace)]
242pub struct ResumableAnd {
243    env: Env,
244    args: ArcSlice<Arc<dyn Eval>>,
245}
246
247impl ResumableAnd {
248    pub fn new(env: &Env, args: &ArcSlice<Arc<dyn Eval>>) -> Self {
249        Self {
250            env: env.clone(),
251            args: args.clone(),
252        }
253    }
254}
255
256#[async_trait]
257impl Resumable for ResumableAnd {
258    async fn resume(
259        &self,
260        args: Vec<Gc<Value>>,
261        cont: &Option<Arc<Continuation>>,
262    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
263        // This situation should never occur, because we don't create a new continuation
264        // for the last argument
265        let Some(last) = self.args.last() else {
266            return Ok(args);
267        };
268        let arg = args.require_one()?;
269        if !arg.read().await.is_true() {
270            return Ok(vec![Gc::new(Value::Boolean(false))]);
271        }
272        for (arg, tail) in self.args.skip_last() {
273            let cont = Arc::new(Continuation::new(
274                Arc::new(ResumableAnd::new(&self.env, &tail)),
275                cont,
276            ));
277            if !arg
278                .eval(&self.env, &Some(cont))
279                .await?
280                .require_one()?
281                .read()
282                .await
283                .is_true()
284            {
285                return Ok(vec![Gc::new(Value::Boolean(false))]);
286            }
287        }
288        last.eval(&self.env, cont).await
289    }
290}
291
292#[derive(Trace)]
293pub struct ResumableOr {
294    env: Env,
295    args: ArcSlice<Arc<dyn Eval>>,
296}
297
298impl ResumableOr {
299    pub fn new(env: &Env, args: &ArcSlice<Arc<dyn Eval>>) -> Self {
300        Self {
301            env: env.clone(),
302            args: args.clone(),
303        }
304    }
305}
306
307#[async_trait]
308impl Resumable for ResumableOr {
309    async fn resume(
310        &self,
311        args: Vec<Gc<Value>>,
312        cont: &Option<Arc<Continuation>>,
313    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
314        // This situation should never occur, because we don't create a new continuation
315        // for the last argument
316        let Some(last) = self.args.last() else {
317            return Ok(args);
318        };
319        let arg = args.require_one()?;
320        if arg.read().await.is_true() {
321            return Ok(vec![Gc::new(Value::Boolean(true))]);
322        }
323        for (arg, tail) in self.args.skip_last() {
324            let cont = Arc::new(Continuation::new(
325                Arc::new(ResumableAnd::new(&self.env, &tail)),
326                cont,
327            ));
328            if arg
329                .eval(&self.env, &Some(cont))
330                .await?
331                .require_one()?
332                .read()
333                .await
334                .is_true()
335            {
336                return Ok(vec![Gc::new(Value::Boolean(true))]);
337            }
338        }
339        last.eval(&self.env, cont).await
340    }
341}
342
343#[derive(Trace)]
344pub struct ResumableLet {
345    scope: Gc<LexicalContour>,
346    curr: Identifier,
347    remaining_bindings: ArcSlice<(Identifier, Arc<dyn Eval>)>,
348    body: ast::Body,
349}
350
351impl ResumableLet {
352    pub fn new(
353        scope: &Gc<LexicalContour>,
354        curr: &Identifier,
355        remaining_bindings: ArcSlice<(Identifier, Arc<dyn Eval>)>,
356        body: &ast::Body,
357    ) -> Self {
358        Self {
359            scope: scope.clone(),
360            curr: curr.clone(),
361            remaining_bindings,
362            body: body.clone(),
363        }
364    }
365}
366
367#[async_trait]
368impl Resumable for ResumableLet {
369    async fn resume(
370        &self,
371        args: Vec<Gc<Value>>,
372        cont: &Option<Arc<Continuation>>,
373    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
374        let arg = args.require_one()?;
375        let up = {
376            let mut scope = self.scope.write().await;
377            scope.def_var(&self.curr, arg);
378            scope.up.clone()
379        };
380        for ((ident, expr), remaining) in self.remaining_bindings.iter() {
381            let cont = Arc::new(Continuation::new(
382                Arc::new(ResumableLet::new(&self.scope, ident, remaining, &self.body)),
383                cont,
384            ));
385            let val = expr.eval(&up, &Some(cont)).await?.require_one()?;
386            self.scope.write().await.def_var(ident, val);
387        }
388        self.body.eval(&Env::from(self.scope.clone()), cont).await
389    }
390}
391
392#[derive(Trace)]
393pub struct ResumableIf {
394    env: Env,
395    success: Arc<dyn Eval>,
396    failure: Option<Arc<dyn Eval>>,
397}
398
399impl ResumableIf {
400    pub fn new(env: &Env, success: &Arc<dyn Eval>, failure: &Option<Arc<dyn Eval>>) -> Self {
401        Self {
402            env: env.clone(),
403            success: success.clone(),
404            failure: failure.clone(),
405        }
406    }
407}
408
409#[async_trait]
410impl Resumable for ResumableIf {
411    async fn resume(
412        &self,
413        args: Vec<Gc<Value>>,
414        cont: &Option<Arc<Continuation>>,
415    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
416        let arg = args.require_one()?;
417        if arg.read().await.is_true() {
418            self.success.eval(&self.env, cont).await
419        } else if let Some(ref failure) = self.failure {
420            failure.eval(&self.env, cont).await
421        } else {
422            Ok(vec![Gc::new(Value::Null)])
423        }
424    }
425}
426
427#[derive(Trace)]
428pub struct ResumableDefineVar {
429    env: Env,
430    name: Identifier,
431}
432
433impl ResumableDefineVar {
434    pub fn new(env: &Env, name: &Identifier) -> Self {
435        Self {
436            env: env.clone(),
437            name: name.clone(),
438        }
439    }
440}
441
442#[async_trait]
443impl Resumable for ResumableDefineVar {
444    async fn resume(
445        &self,
446        args: Vec<Gc<Value>>,
447        _cont: &Option<Arc<Continuation>>,
448    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
449        let arg = args.require_one()?;
450        self.env.def_var(&self.name, arg).await;
451        Ok(vec![Gc::new(Value::Null)])
452    }
453}
454
455#[derive(Trace)]
456pub struct ResumableCall {
457    env: Env,
458    // TODO: Making this a SmallVec of around 10 would probably be a
459    // performance improvement.
460    collected: Vec<Gc<Value>>,
461    remaining: ArcSlice<Arc<dyn Eval>>,
462    proc_name: String,
463    location: Span,
464}
465
466impl ResumableCall {
467    pub fn new(
468        proc_name: &str,
469        location: &Span,
470        env: &Env,
471        collected: &[Gc<Value>],
472        remaining: ArcSlice<Arc<dyn Eval>>,
473    ) -> Self {
474        Self {
475            env: env.clone(),
476            collected: collected.to_owned(),
477            remaining,
478            proc_name: proc_name.to_string(),
479            location: location.clone(),
480        }
481    }
482}
483
484#[async_trait]
485impl Resumable for ResumableCall {
486    async fn resume(
487        &self,
488        args: Vec<Gc<Value>>,
489        cont: &Option<Arc<Continuation>>,
490    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
491        let arg = args.require_one()?;
492        let mut collected = self.collected.clone();
493        collected.push(arg);
494        for (arg, remaining) in self.remaining.iter() {
495            let cont = Arc::new(Continuation::new(
496                Arc::new(ResumableCall::new(
497                    &self.proc_name,
498                    &self.location,
499                    &self.env,
500                    &collected,
501                    remaining,
502                )),
503                cont,
504            ));
505            let arg = arg
506                .eval(&self.env, &Some(cont))
507                .await
508                .map_err(|mut err| {
509                    err.push_frame(self.proc_name.clone(), self.location.clone());
510                    err
511                })?
512                .require_one()?;
513            collected.push(arg);
514        }
515        PreparedCall::prepare(&self.proc_name, &self.location, collected)
516            .eval(cont)
517            .await
518    }
519}
520
521#[derive(Trace)]
522pub struct ResumableApply {
523    env: Env,
524    collected: Vec<Gc<Value>>,
525    remaining: ArcSlice<Arc<dyn Eval>>,
526    rest_args: Option<Arc<dyn Eval>>,
527    proc_name: String,
528    location: Span,
529}
530
531impl ResumableApply {
532    pub fn new(
533        proc_name: &str,
534        location: &Span,
535        env: &Env,
536        collected: &[Gc<Value>],
537        remaining: ArcSlice<Arc<dyn Eval>>,
538        rest_args: Option<Arc<dyn Eval>>,
539    ) -> Self {
540        Self {
541            proc_name: proc_name.to_string(),
542            location: location.clone(),
543            env: env.clone(),
544            collected: collected.to_owned(),
545            remaining,
546            rest_args,
547        }
548    }
549}
550
551#[async_trait]
552impl Resumable for ResumableApply {
553    async fn resume(
554        &self,
555        args: Vec<Gc<Value>>,
556        cont: &Option<Arc<Continuation>>,
557    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
558        let arg = args.require_one()?;
559        let mut collected = self.collected.clone();
560        if let Some(ref rest_args) = self.rest_args {
561            collected.push(arg);
562
563            for (arg, remaining) in self.remaining.iter() {
564                let cont = Arc::new(Continuation::new(
565                    Arc::new(ResumableApply::new(
566                        &self.proc_name,
567                        &self.location,
568                        &self.env,
569                        &collected,
570                        remaining,
571                        Some(rest_args.clone()),
572                    )),
573                    cont,
574                ));
575                let arg = arg.eval(&self.env, &Some(cont)).await?.require_one()?;
576                collected.push(arg);
577            }
578
579            let cont = Arc::new(Continuation::new(
580                Arc::new(ResumableApply::new(
581                    &self.proc_name,
582                    &self.location,
583                    &self.env,
584                    &collected,
585                    ArcSlice::empty(),
586                    None,
587                )),
588                cont,
589            ));
590            let rest_args = rest_args
591                .eval(&self.env, &Some(cont))
592                .await?
593                .require_one()?;
594            // TODO: Throw an error if rest_args is not a list
595            list_to_vec(&rest_args, &mut collected).await;
596        } else {
597            // TODO: Throw an error if arg is not a list
598            list_to_vec(&arg, &mut collected).await;
599        }
600
601        PreparedCall::prepare(&self.proc_name, &self.location, collected)
602            .eval(cont)
603            .await
604    }
605}
606
607#[builtin("call/cc")]
608pub async fn call_cc(
609    cont: &Option<Arc<Continuation>>,
610    proc: &Gc<Value>,
611) -> Result<Vec<Gc<Value>>, RuntimeError> {
612    let callable = {
613        let proc = proc.read().await;
614        proc.as_callable()
615            .ok_or_else(|| RuntimeError::invalid_type("procedure", proc.type_name()))?
616    };
617    callable
618        .call(vec![Gc::new(Value::Continuation(cont.clone()))], cont)
619        .await?
620        .eval(cont)
621        .await
622}
623
624#[derive(Trace)]
625pub struct CallWithValues {
626    min_args: usize,
627    max_args: Option<usize>,
628    consumer: Gc<Value>,
629}
630
631#[async_trait]
632impl Resumable for CallWithValues {
633    fn min_args(&self) -> usize {
634        self.min_args
635    }
636
637    fn max_args(&self) -> Option<usize> {
638        self.max_args
639    }
640
641    async fn resume(
642        &self,
643        args: Vec<Gc<Value>>,
644        cont: &Option<Arc<Continuation>>,
645    ) -> Result<Vec<Gc<Value>>, RuntimeError> {
646        let callable = {
647            let proc = self.consumer.read().await;
648            proc.as_callable().unwrap()
649        };
650        callable.call(args, cont).await?.eval(cont).await
651    }
652}
653
654#[builtin("call-with-values")]
655pub async fn call_with_values(
656    cont: &Option<Arc<Continuation>>,
657    producer: &Gc<Value>,
658    consumer: &Gc<Value>,
659) -> Result<Vec<Gc<Value>>, RuntimeError> {
660    let producer_callable = {
661        let proc = producer.read().await;
662        proc.as_callable()
663            .ok_or_else(|| RuntimeError::invalid_type("procedure", proc.type_name()))?
664    };
665    let consumer_callable = {
666        let proc = consumer.read().await;
667        proc.as_callable()
668            .ok_or_else(|| RuntimeError::invalid_type("procedure", proc.type_name()))?
669    };
670    let producer_cont = Arc::new(Continuation::new(
671        Arc::new(CallWithValues {
672            min_args: consumer_callable.min_args(),
673            max_args: consumer_callable.max_args(),
674            consumer: consumer.clone(),
675        }),
676        cont,
677    ));
678
679    let producer_result = producer_callable
680        .call(Vec::new(), &Some(producer_cont.clone()))
681        .await?
682        .eval(&Some(producer_cont))
683        .await?;
684
685    // Is it correct to use the calling continuation? Probably, whatever.
686    consumer_callable
687        .call(producer_result, cont)
688        .await?
689        .eval(cont)
690        .await
691}