/* 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; pub const APPEND_DOCSTRING: &str = "traverses any number of arguments collecting them into a list. If the first argument is a list, all other arguments are added sequentially to the end of the list contained in the first argument."; pub fn append_callback(ast: &Seg, _syms: &mut SymTable) -> Result { if let Ctr::Seg(ref s) = *ast.car { let mut temp = s.clone(); if let Ctr::Seg(ref list) = *ast.cdr { list.circuit(&mut |c: &Ctr| -> bool { temp.append(Box::new(c.clone())); true }); } else { temp.append(Box::new(*ast.cdr.clone())); } Ok(Ctr::Seg(temp)) } else { let mut temp = Seg::new(); let mut car_iter = &ast.car; let mut cdr_iter = &ast.cdr; loop { temp.append(car_iter.clone()); if let Ctr::Seg(ref s) = **cdr_iter { car_iter = &s.car; cdr_iter = &s.cdr; } else { break; } } Ok(Ctr::Seg(temp)) } } pub const LEN_DOCSTRING: &str = "Takes a single argument, expected to be a list. Returns the length of said list. Interpreter will panic if the length of the list is greater than the max value of a signed 128 bit integer"; pub fn len_callback(ast: &Seg, _syms: &mut SymTable) -> Result { if let Ctr::Seg(ref s) = *ast.car { if let Ctr::None = *s.car { Ok(Ctr::Integer(0)) } else { Ok(Ctr::Integer(s.len() as i128)) } } else { Err("impossible condition: argument to len not a list".to_string()) } } pub const CAR_DOCSTRING: &str = "Takes a single argument, expected to be a list. Returns a copy of the first value in that list. If the list is empty, returns an err to avoid passing back a null value."; pub fn car_callback(ast: &Seg, _syms: &mut SymTable) -> Result { if let Ctr::Seg(ref s) = *ast.car { if let Ctr::None = *s.car { Err("argument is empty".to_string()) } else { Ok(*s.car.clone()) } } else { Err("impossible condition: argument to car not a list".to_string()) } } pub const CDR_DOCSTRING: &str = "Takes a single argument, expected to be a list. Returns a copy of the last value in that list. If the list is empty, returns an err to avoid passing back a null value."; pub fn cdr_callback(ast: &Seg, _syms: &mut SymTable) -> Result { if let Ctr::Seg(ref s) = *ast.car { let mut ret = &s.car; let mut iter = &s.cdr; while let Ctr::Seg(ref next) = **iter { ret = &next.car; iter = &next.cdr; } if let Ctr::None = **ret { Err("argument is empty".to_string()) } else { Ok(*ret.clone()) } } else { Err("impossible condition: argument to cdr not a list".to_string()) } }