Skip to main content

cl_interpret/
function.rs

1//! Represents a block of code which lives inside the Interpreter
2
3use crate::{
4    error::ErrorKind,
5    interpret::{Match, MatchEnv},
6};
7
8use super::{Callable, ConValue, Environment, Error, IResult, Interpret};
9use cl_ast::{At, Bind, BindOp, Expr, Op, Pat, PatOp, types::Symbol as Sym};
10use cl_structures::{intern::interned::Interned, span::Span};
11use std::{
12    cell::{Ref, RefCell},
13    collections::HashMap,
14    rc::Rc,
15};
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<(At<Pat>, At<Expr>)>,
24    /// Stores data from the enclosing scopes
25    upvars: RefCell<Upvars>,
26}
27
28impl Function {
29    pub fn new(decl: &Bind) -> Self {
30        // let upvars = collect_upvars(decl, env);
31        if let Bind(BindOp::Fn, _, pat, exprs) = decl
32            && let [body] = exprs.as_slice()
33        {
34            Self { decl: (pat.clone(), body.clone()).into(), upvars: Default::default() }
35        } else {
36            unimplemented!()
37        }
38    }
39    pub fn decl(&self) -> &(At<Pat>, At<Expr>) {
40        &self.decl
41    }
42    pub fn span(&self) -> Span {
43        self.decl.1.1
44    }
45    pub fn upvars(&self) -> Ref<'_, Upvars> {
46        self.upvars.borrow()
47    }
48    pub fn lift_upvars(&self, env: &Environment) {
49        // TODO: collect upvars externally. We should know them here.
50        let upvars = Default::default();
51        if let Ok(mut self_upvars) = self.upvars.try_borrow_mut() {
52            *self_upvars = upvars;
53        }
54    }
55}
56
57impl Callable for Function {
58    fn name(&self) -> Option<Sym> {
59        fn get_name(pat: &Pat) -> Option<Sym> {
60            match pat {
61                Pat::Name(name) => Some(*name),
62                Pat::Op(PatOp::Tuple | PatOp::Slice | PatOp::Fn, _) => None,
63                Pat::Op(_op, pats) => pats.iter().find_map(|At(pat, ..)| get_name(pat)),
64                _ => None,
65            }
66        }
67        get_name(self.decl.0.value())
68    }
69    fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
70        let args = ConValue::Tuple(args.into());
71        let (pat, body) = self.decl();
72
73        let mut bindings = HashMap::new();
74        pat.matches(args, &mut MatchEnv::new(env, &mut bindings))?;
75
76        let mut scope = env.with_frame("args", bindings);
77        let mut scope = scope.frame(
78            self.name().map(|name| name.to_ref()).unwrap_or("closure"),
79            Some(self.span()),
80        );
81        match body.interpret(&mut scope) {
82            Err(Error { kind: ErrorKind::Panic(e, depth), span }) => {
83                println!("{depth:>4}: {pat} at {}", span.unwrap_or(self.span()));
84                Err(Error { kind: ErrorKind::Panic(e, depth + 1), span: None })
85            }
86            Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
87            other => other,
88        }
89    }
90}
91
92impl std::fmt::Display for Function {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        let (pat, At(expr, ..)) = self.decl();
95        write!(f, "fn {pat}")?;
96        match expr {
97            Expr::Op(Op::Block, ..) => write!(f, " {expr}"),
98            _ => write!(f, " = {expr}"),
99        }
100    }
101}