/* relish: versatile lisp shell * 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 ECHO_DOCSTRING: &str = "traverses any number of arguments. Prints their evaluated values on a new line for each."; pub fn echo_callback(ast: &Seg, _syms: &mut SymTable) -> Result { ast.circuit(&mut |arg: &Ctr| match arg { Ctr::String(s) => print!("{}", s) == (), _ => print!("{}", arg) == (), }); println!(); Ok(Ctr::None) } pub const CONCAT_DOCSTRING: &str = "Iterates over N args of any type other than SYMBOL. converts each argument to a string. Combines all strings. Returns final (combined) string."; pub fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result { let mut string = String::from(""); if !ast.circuit(&mut |arg: &Ctr| { match arg { // should be a thing here Ctr::Symbol(_) => return false, Ctr::String(s) => string.push_str(&s), Ctr::Integer(i) => string.push_str(&i.to_string()), Ctr::Float(f) => string.push_str(&f.to_string()), Ctr::Bool(b) => string.push_str(&b.to_string()), Ctr::Seg(c) => string.push_str(&c.to_string()), Ctr::Lambda(l) => string.push_str(&l.to_string()), Ctr::None => (), } true }) { eprintln!("dont know what to do witha symbol here") } return Ok(Ctr::String(string)); } pub const STRLEN_DOCSTRING: &str = "Takes a single arg of any type. Arg is converted to a string if not already a string. Returns string length of arg."; pub fn strlen_callback(ast: &Seg, _syms: &mut SymTable) -> Result { match &*ast.car { Ctr::Symbol(s) => Ok(Ctr::Integer(s.len() as i128)), Ctr::String(s) => Ok(Ctr::Integer(s.len() as i128)), Ctr::Integer(i) => Ok(Ctr::Integer(i.to_string().len() as i128)), Ctr::Float(f) => Ok(Ctr::Integer(f.to_string().len() as i128)), Ctr::Bool(b) => Ok(Ctr::Integer(b.to_string().len() as i128)), Ctr::Seg(c) => Ok(Ctr::Integer(c.to_string().len() as i128)), Ctr::Lambda(l) => Ok(Ctr::Integer(l.to_string().len() as i128)), // highly suspicious case below Ctr::None => Ok(Ctr::Integer(0)), } } pub const STRCAST_DOCSTRING: &str = "Takes a single arg of any type. Arg is converted to a string and returned."; pub fn strcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result { match &*ast.car { Ctr::Symbol(s) => Ok(Ctr::String(s.clone())), Ctr::String(_) => Ok(*ast.car.clone()), Ctr::Integer(i) => Ok(Ctr::String(i.to_string())), Ctr::Float(f) => Ok(Ctr::String(f.to_string())), Ctr::Bool(b) => Ok(Ctr::String(b.to_string())), Ctr::Seg(c) => Ok(Ctr::String(c.to_string())), Ctr::Lambda(l) => Ok(Ctr::String(l.to_string())), // highly suspicious case below Ctr::None => Ok(Ctr::String(String::new())), } } pub const CONTAINS_DOCSTRING: &str = "Takes two strings. Returns true if string1 contains at least one instance of string2"; pub fn contains_callback(ast: &Seg, _syms: &mut SymTable) -> Result { let parent_str: String; if let Ctr::String(ref s) = *ast.car { parent_str = s.to_string(); } else { return Err("first argument must be a string".to_string()); } let second_arg_obj: &Ctr; let child_str: String; if let Ctr::Seg(ref s) = *ast.cdr { second_arg_obj = &*s.car; } else { return Err("impossible error: needs two arguments".to_string()); } if let Ctr::String(ref s) = &*second_arg_obj { child_str = s.clone(); } else { return Err("second argument must be a string".to_string()); } Ok(Ctr::Bool(parent_str.contains(&child_str))) } pub const SPLIT_DOCSTRING: &str = "Takes two strings. String 1 is a source string and string 2 is a delimiter. Returns a list of substrings from string 1 that were found delimited by string 2."; pub fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result { let parent_str: String; if let Ctr::String(ref s) = *ast.car { parent_str = s.to_string(); } else { return Err("first argument must be a string".to_string()); } let second_arg_obj: &Ctr; let delim_str: String; if let Ctr::Seg(ref s) = *ast.cdr { second_arg_obj = &*s.car; } else { return Err("impossible error: needs two arguments".to_string()); } if let Ctr::String(ref s) = &*second_arg_obj { delim_str = s.clone(); } else { return Err("second argument must be a string".to_string()); } let mut ret = Seg::new(); for substr in parent_str.split(&delim_str) { ret.append(Box::new(Ctr::String(substr.to_string()))); } Ok(Ctr::Seg(ret)) }