1use collect_upvars::collect_upvars;
4
5use crate::error::ErrorKind;
6
7use super::{Callable, ConValue, Environment, Error, IResult, Interpret, pattern};
8use cl_ast::{Function as FnDecl, Sym};
9use std::{
10 cell::{Ref, RefCell},
11 collections::HashMap,
12 rc::Rc,
13};
14
15pub mod collect_upvars;
16
17type Upvars = HashMap<Sym, Option<ConValue>>;
18
19#[derive(Clone, Debug)]
21pub struct Function {
22 decl: Rc<FnDecl>,
24 upvars: RefCell<Upvars>,
26 is_constructor: bool,
27}
28
29impl Function {
30 pub fn new(decl: &FnDecl) -> Self {
31 Self { decl: decl.clone().into(), upvars: Default::default(), is_constructor: false }
33 }
34 pub fn new_constructor(decl: FnDecl) -> Self {
35 Self { decl: decl.into(), upvars: Default::default(), is_constructor: true }
36 }
37 pub fn decl(&self) -> &FnDecl {
38 &self.decl
39 }
40 pub fn upvars(&self) -> Ref<Upvars> {
41 self.upvars.borrow()
42 }
43 pub fn lift_upvars(&self, env: &Environment) {
44 let upvars = collect_upvars(&self.decl, env);
45 if let Ok(mut self_upvars) = self.upvars.try_borrow_mut() {
46 *self_upvars = upvars;
47 }
48 }
49}
50
51impl Callable for Function {
52 fn name(&self) -> Sym {
53 let FnDecl { name, .. } = *self.decl;
54 name
55 }
56 fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
57 let FnDecl { name, gens: _, bind, body, sign: _ } = &*self.decl;
58
59 if self.is_constructor {
61 return Ok(ConValue::TupleStruct(Box::new((
62 name.to_ref(),
63 args.into(),
64 ))));
65 }
66 let Some(body) = body else {
67 return Err(Error::NotDefined(*name));
68 };
69
70 let upvars = self.upvars.take();
71 env.push_frame("upvars", upvars);
72
73 let mut frame = env.frame("fn args");
75 for (name, value) in pattern::substitution(bind, ConValue::Tuple(args.into()))? {
76 frame.insert(*name, Some(value));
77 }
78 let res = body.interpret(&mut frame);
79 drop(frame);
80 if let Some((upvars, _)) = env.pop_frame() {
81 self.upvars.replace(upvars);
82 }
83 match res {
84 Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
85 Err(Error { kind: ErrorKind::Break(value), .. }) => Err(Error::BadBreak(value)),
86 other => other,
87 }
88 }
89}