aplang_lib/interpreter/
procedure.rs

1use crate::interpreter::errors::RuntimeError;
2use crate::interpreter::{Interpreter, Value};
3use crate::parser::ast::{ProcDeclaration, Stmt, Variable};
4use miette::SourceSpan;
5use std::collections::HashMap;
6use std::rc::Rc;
7use std::sync::Arc;
8
9pub type FunctionMap = HashMap<String, (Rc<dyn Callable>, Option<Arc<ProcDeclaration>>)>;
10/*                            |^^^^^^  |^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^|> Maybe pointer to function def
11                              |        |                                                  If None: it is native function
12                              |        |> Pointer to the function
13                              |> Function name (symbol)
14*/
15
16pub trait Callable {
17    fn call(
18        &self,
19        interpreter: &mut Interpreter,
20        args: &[Value],
21        args_tokens: &[SourceSpan],
22        source: Arc<str>,
23    ) -> Result<Value, RuntimeError>;
24    fn arity(&self) -> u8;
25}
26
27pub struct Procedure {
28    pub name: String,
29    pub params: Vec<Variable>,
30    pub body: Stmt,
31}
32
33impl Callable for Procedure {
34    fn call(
35        &self,
36        interpreter: &mut Interpreter,
37        args: &[Value],
38        args_tokens: &[SourceSpan],
39        source: Arc<str>,
40    ) -> Result<Value, RuntimeError> {
41        // save the return value
42        let cached_return_value = interpreter.return_value.clone();
43
44        // todo: consider allowing variables to be taken into context
45        // ignore the global env
46        interpreter.venv.initialize_empty_scope();
47
48        // copy in the arguments
49        // assigns them to their appropriate name parameter
50        self.params
51            .iter()
52            .zip(args.iter().cloned())
53            .for_each(|(param, arg)| interpreter.venv.define(Arc::new(param.clone()), arg));
54
55        // execute the function
56        interpreter.stmt(&self.body)?;
57
58        let return_value = interpreter.return_value.clone();
59        // todo implement backtrace
60        interpreter.return_value = cached_return_value;
61
62        // restore the previous env
63        interpreter.venv.scrape();
64
65        match return_value {
66            None => Ok(Value::Null),
67            Some(value) => Ok(value),
68        }
69    }
70
71    fn arity(&self) -> u8 {
72        self.params.len().try_into().unwrap()
73    }
74}
75
76pub struct NativeProcedure {
77    pub name: String,
78    pub arity: u8,
79    pub callable: fn(
80        &mut Interpreter,
81        &[Value],
82        args_tokens: &[SourceSpan],
83        source: Arc<str>,
84    ) -> Result<Value, RuntimeError>,
85}
86
87impl Callable for NativeProcedure {
88    fn call(
89        &self,
90        interpreter: &mut Interpreter,
91        args: &[Value],
92        args_tokens: &[SourceSpan],
93        source: Arc<str>,
94    ) -> Result<Value, RuntimeError> {
95        (self.callable)(interpreter, args, args_tokens, source)
96    }
97
98    fn arity(&self) -> u8 {
99        self.arity
100    }
101}