/* relish: versatile lisp shell * Copyright (C) 2021 Ava Affine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ use crate::func::{func_call, FTable}; use crate::segment::{new_ast, Ast, Ctr}; use crate::vars::VTable; use std::cell::RefCell; use std::rc::Rc; /* iterates over a syntax tree * returns a NEW LIST of values * representing the simplest possible form of the input */ pub fn eval( ast: Ast, vars: Rc>, funcs: Rc>, sym_loose: bool, ) -> Result { let mut car = ast.borrow().clone().car; let mut cdr = ast.borrow().clone().cdr; let ret = new_ast(Ctr::None, Ctr::None); let mut iter = ret.clone(); // doing an initial variable check here allows us // to find functions passed in as variables if let Ctr::Symbol(ref tok) = car { if let Some(val) = vars.borrow().get(tok) { car = (**val).clone(); } } // another check to detect if we may have a function call if let Ctr::Symbol(ref tok) = car { match cdr.clone() { Ctr::Seg(ast) => { if let Some(func) = funcs.borrow().get(tok) { return func_call(func.clone(), ast.clone(), vars.clone(), funcs.clone()); } else if !sym_loose { return Err(format!("Couldnt find definition of {}.", tok)); } } Ctr::None => { if let Some(func) = funcs.borrow().get(tok) { return func_call( func.clone(), new_ast(Ctr::None, Ctr::None), vars.clone(), funcs.clone(), ); } else if !sym_loose { return Err(format!("Couldnt find definition of {}.", tok)); } } _ => return Err(format!("Arguments to function not a list!")), } } let mut none = false; while !none { match car { // if LIST: call eval inner on it with first_item=true Ctr::Seg(ref inner) => { match eval(inner.clone(), vars.clone(), funcs.clone(), sym_loose) { Ok(res) => (*iter).borrow_mut().car = res, Err(e) => return Err(format!("Evaluation error: {}", e)), } } // if SYMBOL: unwrap naively Ctr::Symbol(ref tok) => { if let Some(val) = vars.borrow().get(&tok.clone()) { (*iter).borrow_mut().car = (**val).clone(); } else if sym_loose { (*iter).borrow_mut().car = Ctr::Symbol(tok.to_string()); } else { return Err(format!("Undefined variable: {}", tok)); } } // if OTHER: clone and set _ => { (*iter).borrow_mut().car = car.clone(); } } match cdr { // if SYMBOL: unwrap naively, then end Ctr::Symbol(ref tok) => { if let Some(val) = vars.borrow().get(&tok.clone()) { (*iter).borrow_mut().car = (**val).clone(); } else if sym_loose { (*iter).borrow_mut().car = Ctr::Symbol(tok.to_string()); } else { return Err(format!("Undefined variable: {}", tok)); } none = true; } // if LIST: // - iter.cdr = new_ast(None, None) // - iter = iter.cdr // - car = cdr.car // - cdr = cdr.cdr // - LOOP Ctr::Seg(next) => { let n = new_ast(Ctr::None, Ctr::None); iter.borrow_mut().cdr = Ctr::Seg(n.clone()); iter = n; car = next.borrow().clone().car; cdr = next.borrow().clone().cdr; } // if OTHER: clone and set, and then end _ => { (*iter).borrow_mut().cdr = cdr.clone(); none = true; } } if let Ctr::None = car { if let Ctr::None = cdr { none = true; } } } return Ok(Ctr::Seg(ret)); }