cl_interpret/
function.rs

1//! Represents a block of code which lives inside the Interpreter
2
3use 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/// Represents a block of code which persists inside the Interpreter
20#[derive(Clone, Debug)]
21pub struct Function {
22    /// Stores the contents of the function declaration
23    decl: Rc<FnDecl>,
24    /// Stores data from the enclosing scopes
25    upvars: RefCell<Upvars>,
26    is_constructor: bool,
27}
28
29impl Function {
30    pub fn new(decl: &FnDecl) -> Self {
31        // let upvars = collect_upvars(decl, env);
32        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        // Check arg mapping
60        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        // TODO: completely refactor data storage
74        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}