cl_interpret/
closure.rs

1use crate::{
2    Callable,
3    convalue::ConValue,
4    env::Environment,
5    error::{Error, ErrorKind, IResult},
6    function::collect_upvars::CollectUpvars,
7    interpret::Interpret,
8    pattern,
9};
10use cl_ast::{Sym, ast_visitor::Visit};
11use std::{collections::HashMap, fmt::Display};
12
13/// Represents an ad-hoc anonymous function
14/// which captures surrounding state by COPY
15#[derive(Clone, Debug)]
16pub struct Closure {
17    decl: cl_ast::Closure,
18    lift: HashMap<Sym, Option<ConValue>>,
19}
20
21impl Closure {
22    const NAME: &'static str = "{closure}";
23}
24
25impl Closure {
26    pub fn new(env: &mut Environment, decl: &cl_ast::Closure) -> Self {
27        let lift = CollectUpvars::new(env).visit(decl).finish_copied();
28        Self { decl: decl.clone(), lift }
29    }
30}
31
32impl Display for Closure {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        let Self { decl, lift: _ } = self;
35        write!(f, "{decl}")
36    }
37}
38
39impl Callable for Closure {
40    fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
41        let Self { decl, lift } = self;
42        let mut env = env.frame(Self::NAME);
43
44        // place lifts in scope
45        for (name, value) in lift.clone() {
46            env.insert(name, value);
47        }
48
49        let mut env = env.frame("args");
50
51        for (name, value) in pattern::substitution(&decl.arg, ConValue::Tuple(args.into()))? {
52            env.insert(*name, Some(value));
53        }
54
55        let res = decl.body.interpret(&mut env);
56        drop(env);
57
58        match res {
59            Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
60            Err(Error { kind: ErrorKind::Break(value), .. }) => Err(Error::BadBreak(value)),
61            other => other,
62        }
63    }
64
65    fn name(&self) -> cl_ast::Sym {
66        "{closure}".into()
67    }
68}