/* Copyright (C) 2021 Aidan Hahn * * 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::segment::{Ctr, Seg}; use crate::sym::SymTable; fn isnumeric(arg: &Ctr) -> bool { match arg { Ctr::Integer(_) => true, Ctr::Float(_) => true, _ => false, } } pub const ADD_DOCSTRING: &str = "traverses over N args, which must all evaluate to an Integer or Float. Adds each arg up to a final result. WARNING: does not acocunt for under/overflows. Consult source code for a better understanding of how extreme values will be handled."; pub fn add_callback(ast: &Seg, _: &mut SymTable) -> Result { let mut res = Ctr::Integer(0); let mut culprit: Ctr = Ctr::None; let type_consistent = ast.circuit(&mut |c: &Ctr| -> bool { if !isnumeric(c) { culprit = c.clone(); false } else { res = res.clone() + c.clone(); true } }); if !type_consistent { Err(format!("{} is not a number!", culprit)) } else { Ok(res) } } pub const SUB_DOCSTRING: &str = "traverses over N args, which must all evaluate to an Integer or Float. Subtracts each arg from the first leading to a final result. WARNING: does not acocunt for under/overflows. Consult source code for a better understanding of how extreme values will be handled."; pub fn sub_callback(ast: &Seg, _: &mut SymTable) -> Result { if !isnumeric(&*ast.car) { return Err(format!("{} is not a number", &*ast.car)) } let mut res = *ast.car.clone(); let mut culprit: Ctr = Ctr::None; if let Ctr::Seg(ref subsequent_operands) = *ast.cdr { let type_consistent = subsequent_operands.circuit(&mut |c: &Ctr| -> bool { if !isnumeric(c) { culprit = c.clone(); false } else { res = res.clone() - c.clone(); true } }); if !type_consistent { Err(format!("{} is not a number", culprit)) } else { Ok(res) } } else { Err("requires at least two operands".to_string()) } } pub const DIV_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float. divides arg1 by arg2. WARNING: does not acocunt for under/overflows or float precision. Consult source code for a better understanding of how extreme values will be handled."; pub fn div_callback(ast: &Seg, _: &mut SymTable) -> Result { let first = *ast.car.clone(); if !isnumeric(&first) { return Err("first argument must be numeric".to_string()); } let second: Ctr; if let Ctr::Seg(ref s) = *ast.cdr { second = *s.car.clone(); if !isnumeric(&second) { return Err("second argument must be numeric".to_string()); } Ok(first / second) } else { Err("impossible error: needs two arguments".to_string()) } } pub const MUL_DOCSTRING: &str = "traverses over N args, which must all evaluate to an Integer or Float. Multiplies each arg up to a final result. WARNING: does not acocunt for under/overflows. Consult source code for a better understanding of how extreme values will be handled."; pub fn mul_callback(ast: &Seg, _: &mut SymTable) -> Result { let mut res = Ctr::Integer(1); let mut culprit: Ctr = Ctr::None; let type_consistent = ast.circuit(&mut |c: &Ctr| -> bool { if !isnumeric(c) { culprit = c.clone(); false } else { res = res.clone() * c.clone(); true } }); if !type_consistent { Err(format!("{} is not a number!", culprit)) } else { Ok(res) } }