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