81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Represents a block of code which lives inside the Interpreter
 | |
| 
 | |
| use collect_upvars::collect_upvars;
 | |
| 
 | |
| use super::{Callable, ConValue, Environment, Error, IResult, Interpret};
 | |
| use cl_ast::{Function as FnDecl, Param, Sym};
 | |
| use std::{
 | |
|     cell::{Ref, RefCell},
 | |
|     collections::HashMap,
 | |
|     rc::Rc,
 | |
| };
 | |
| 
 | |
| pub mod collect_upvars;
 | |
| 
 | |
| type Upvars = HashMap<Sym, Option<ConValue>>;
 | |
| 
 | |
| /// Represents a block of code which persists inside the Interpreter
 | |
| #[derive(Clone, Debug)]
 | |
| pub struct Function {
 | |
|     /// Stores the contents of the function declaration
 | |
|     decl: Rc<FnDecl>,
 | |
|     /// Stores data from the enclosing scopes
 | |
|     upvars: RefCell<Upvars>,
 | |
| }
 | |
| 
 | |
| impl Function {
 | |
|     pub fn new(decl: &FnDecl) -> Self {
 | |
|         // let upvars = collect_upvars(decl, env);
 | |
|         Self { decl: decl.clone().into(), upvars: Default::default() }
 | |
|     }
 | |
|     pub fn decl(&self) -> &FnDecl {
 | |
|         &self.decl
 | |
|     }
 | |
|     pub fn upvars(&self) -> Ref<Upvars> {
 | |
|         self.upvars.borrow()
 | |
|     }
 | |
|     pub fn lift_upvars(&self, env: &Environment) {
 | |
|         let upvars = collect_upvars(&self.decl, env);
 | |
|         if let Ok(mut self_upvars) = self.upvars.try_borrow_mut() {
 | |
|             *self_upvars = upvars;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Callable for Function {
 | |
|     fn name(&self) -> Sym {
 | |
|         let FnDecl { name, .. } = *self.decl;
 | |
|         name
 | |
|     }
 | |
|     fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
 | |
|         let FnDecl { name, bind, body, sign: _ } = &*self.decl;
 | |
| 
 | |
|         // Check arg mapping
 | |
|         if args.len() != bind.len() {
 | |
|             return Err(Error::ArgNumber { want: bind.len(), got: args.len() });
 | |
|         }
 | |
|         let Some(body) = body else {
 | |
|             return Err(Error::NotDefined(*name));
 | |
|         };
 | |
| 
 | |
|         let upvars = self.upvars.take();
 | |
|         env.push_frame("upvars", upvars);
 | |
| 
 | |
|         // TODO: completely refactor data storage
 | |
|         let mut frame = env.frame("fn args");
 | |
|         for (Param { mutability: _, name }, value) in bind.iter().zip(args) {
 | |
|             frame.insert(*name, Some(value.clone()));
 | |
|         }
 | |
|         let res = body.interpret(&mut frame);
 | |
|         drop(frame);
 | |
|         if let Some((upvars, _)) = env.pop_frame() {
 | |
|             self.upvars.replace(upvars);
 | |
|         }
 | |
|         match res {
 | |
|             Err(Error::Return(value)) => Ok(value),
 | |
|             Err(Error::Break(value)) => Err(Error::BadBreak(value)),
 | |
|             result => result,
 | |
|         }
 | |
|     }
 | |
| }
 |