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, 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}
27
28impl Function {
29    pub fn new(decl: &FnDecl) -> Self {
30        // let upvars = collect_upvars(decl, env);
31        Self { decl: decl.clone().into(), upvars: Default::default() }
32    }
33    pub fn decl(&self) -> &FnDecl {
34        &self.decl
35    }
36    pub fn upvars(&self) -> Ref<'_, Upvars> {
37        self.upvars.borrow()
38    }
39    pub fn lift_upvars(&self, env: &Environment) {
40        let upvars = collect_upvars(&self.decl, env);
41        if let Ok(mut self_upvars) = self.upvars.try_borrow_mut() {
42            *self_upvars = upvars;
43        }
44    }
45}
46
47impl Callable for Function {
48    fn name(&self) -> Sym {
49        let FnDecl { name, .. } = *self.decl;
50        name
51    }
52    fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
53        let FnDecl { name, gens: _, bind, body, sign: _ } = &*self.decl;
54
55        // Check arg mapping
56        let Some(body) = body else {
57            return Err(Error::NotDefined(*name));
58        };
59
60        let upvars = self.upvars.take();
61        let mut env = env.with_frame("upvars", upvars);
62
63        // TODO: completely refactor data storage
64        let mut frame = env.frame("fn args");
65        for (name, value) in pattern::substitution(&frame, bind, ConValue::Tuple(args.into()))? {
66            frame.insert(name, value);
67        }
68        let res = body.interpret(&mut frame);
69        drop(frame);
70        if let Some(upvars) = env.pop_values() {
71            self.upvars.replace(upvars);
72        }
73        match res {
74            Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
75            Err(Error { kind: ErrorKind::Break(value), .. }) => Err(Error::BadBreak(value)),
76            Err(Error { kind: ErrorKind::Panic(msg, depth), span: Some(span) }) => {
77                println!("{depth:>4}: {name}{bind} at {}", span.head);
78                Err(Error { kind: ErrorKind::Panic(msg, depth + 1), span: None })
79            }
80            other => other,
81        }
82    }
83}