/* Flesh: Flexible 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 alloc::boxed::Box; use crate::segment::{Ctr, Seg}; use crate::sym::{SymTable, call_lambda}; use crate::error::Traceback; /* iterates over a syntax tree * returns a NEW LIST of values * representing the simplest possible form of the input */ pub fn eval(ast: &Seg, syms: &mut SymTable) -> Result, Traceback> { // data to return let mut ret = Box::from(Ctr::None); let mut first = true; // to be assigned from cloned/evaled data let mut car; let mut cdr; // lets me redirect the input let mut arg_car = &ast.car; let mut arg_cdr = &ast.cdr; // iterate over ast and build out ret let mut none = false; while !none { match &**arg_car { Ctr::Seg(ref inner) => { let interm = eval(inner, syms)?; if let Ctr::Lambda(ref l) = *interm { return call_lambda(l, arg_cdr, syms) } else { car = interm; } }, Ctr::Lambda(ref l) => return Ok(call_lambda(l, arg_cdr, syms)?), Ctr::Symbol(ref tok) => { let outer_scope_seg_holder: Seg; let args: &Seg; if let Ctr::Seg(ref candidate_args) = **arg_cdr { args = candidate_args; } else { outer_scope_seg_holder = Seg::from_mono(arg_cdr.clone()); args = &outer_scope_seg_holder; } car = syms.call_symbol(tok, args, first)?; if let Some(b) = syms.is_function_type(tok) { if b { return Ok(car); } } } _ => { car = arg_car.clone(); } } match **arg_cdr { Ctr::Symbol(ref tok) => { let blank = Seg::new(); cdr = syms.call_symbol(tok, &blank, false)?; none = true; } Ctr::Seg(ref next) => { cdr = Box::from(Ctr::None); arg_car = &next.car; arg_cdr = &next.cdr } _ => { cdr = arg_cdr.clone(); none = true; } } if let Ctr::None = *ret { *ret = Ctr::Seg(Seg::from(car, cdr)) } else if let Ctr::Seg(ref mut s) = *ret { s.append(car); if let Ctr::None = *cdr { } else { s.append(cdr); } } first = false; } Ok(ret) }