flesh/src/sym.rs

444 lines
14 KiB
Rust
Raw Normal View History

/* 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 <http://www.gnu.org/licenses/>.
*/
use crate::eval::eval;
use crate::segment::{Ctr, Seg, Type};
use std::collections::HashMap;
use std::fmt;
2023-03-05 22:21:18 -08:00
use std::rc::Rc;
#[derive(Clone)]
pub struct SymTable(HashMap<String, Symbol>);
#[derive(Debug, Clone)]
pub struct UserFn {
// Un-evaluated abstract syntax tree
// TODO: Intermediate evaluation to simplify branches with no argument in them
// Simplified branches must not have side effects.
// TODO: Apply Memoization?
pub ast: Box<Seg>,
// list of argument string tokens
pub arg_syms: Vec<String>,
}
/* A symbol may either be a pointer to a function
* or a syntax tree to eval with the arguments or
* a simple variable declaration (which can also
* be a macro)
*/
#[derive(Clone)]
pub enum ValueType {
Internal(Rc<dyn Fn(&Seg, &mut SymTable) -> Result<Ctr, String>>),
FuncForm(UserFn),
VarForm(Box<Ctr>),
}
/* Function Args
* If Lazy, is an integer denoting number of args
* If Strict, is a list of type tags denoting argument type.
*/
#[derive(Clone)]
pub enum Args {
Lazy(u128),
Strict(Vec<Type>),
Infinite,
None,
}
#[derive(Clone)]
pub struct Symbol {
pub value: ValueType,
pub name: String,
pub args: Args,
// for internal control flow constructs
// eval() will not eval the args
pub conditional_branches: bool,
pub docs: String,
}
impl SymTable {
pub fn new() -> SymTable {
SymTable(HashMap::<String, Symbol>::new())
}
pub fn get(&self, arg: &String) -> Option<&Symbol> {
self.0.get(arg)
}
pub fn contains_key(&self, arg: &String) -> bool {
self.0.contains_key(arg)
}
pub fn insert(&mut self, k: String, v: Symbol) -> Option<Symbol> {
self.0.insert(k, v)
}
pub fn remove(&mut self, arg: &String) -> Option<Symbol> {
self.0.remove(arg)
}
2023-03-06 15:50:02 -08:00
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, String, Symbol> {
self.0.iter()
}
pub fn call_symbol(
&mut self,
name: &String,
args: &Seg,
call_func: bool,
) -> Result<Box<Ctr>, String> {
let symbol = match self.remove(name) {
Some(s) => s,
None => return Err(format!("undefined symbol: {}", name)),
};
self.insert(name.to_string(), symbol.clone());
let cond_args: &Seg;
let outer_scope_seg_holder: Seg;
if let ValueType::VarForm(ref val) = symbol.value {
match **val {
Ctr::Lambda(ref l) if call_func => {
return call_lambda(
l,
&Box::new(Ctr::Seg(args.clone())),
self
)
},
_ => return Ok(val.clone()),
}
} else if call_func {
cond_args = args
} else {
outer_scope_seg_holder = Seg::new();
cond_args = &outer_scope_seg_holder;
}
symbol.call(cond_args, self)
}
pub fn is_function_type(&self, name: &String) -> Option<bool> {
if let ValueType::VarForm(ref val) = self.get(name)?.value {
if let Ctr::Lambda(_) = **val {
Some(true)
} else {
Some(false)
}
} else {
Some(true)
}
}
}
impl Default for SymTable {
fn default() -> Self {
Self::new()
}
}
impl Args {
fn validate_inputs(&self, args: &Seg) -> Result<(), String> {
match self {
Args::None => {
2023-03-01 11:33:30 -08:00
if args.len() == 1 {
if let Ctr::None = *args.car {
return Ok(());
2023-03-01 11:33:30 -08:00
} else {
return Err("expected no args".to_string());
2023-03-01 11:33:30 -08:00
}
} else {
return Err("expected no args".to_string());
}
}
2023-03-07 14:29:31 -08:00
Args::Infinite => {
if !args.is_empty() {
return Ok(());
} else {
return Err("expected args but none were provided".to_string());
}
}
Args::Lazy(ref num) => {
let called_arg_count = args.len();
if *num == 0 {
if let Ctr::None = *args.car {
//pass
} else {
return Err("expected 0 args. Got one or more.".to_string());
}
} else if *num != called_arg_count {
return Err(format!("expected {} args. Got {}.", num, called_arg_count));
} else if let Ctr::None = *args.car {
return Err(format!("expected {} args. Got 0.", num,));
}
}
Args::Strict(ref arg_types) => {
let mut idx: usize = 0;
let mut mismatch = false;
let passes = args.circuit(&mut |c: &Ctr| -> bool {
if idx >= arg_types.len() {
return false;
}
if let Ctr::None = c {
return false;
}
if arg_types[idx] == c.to_type() {
idx += 1;
return true;
}
mismatch = true;
false
});
if passes && idx < (arg_types.len() - 1) {
return Err(format!("{} too few arguments", arg_types.len() - (idx + 1)));
}
if !passes {
if mismatch {
return Err(format!("arg {} expected to be {}", idx + 1, arg_types[idx]));
}
if idx > (arg_types.len() - 1) {
return Err("too many arguments".to_string());
}
if idx < (arg_types.len() - 1) {
return Err("too few arguments".to_string());
}
}
}
}
Ok(())
}
}
impl fmt::Display for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Args::None => write!(f, "none"),
Args::Infinite => write!(f, "infinite, untyped"),
Args::Lazy(n) => write!(f, "{} args of any type", n),
Args::Strict(s) => {
write!(f, "types: ")?;
for arg in s {
write!(f, "{} ", arg)?
}
Ok(())
}
}
}
}
impl fmt::Display for UserFn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(lambda (")?;
let mut arg_iter = (&self.arg_syms).into_iter();
if let Some(elem) = arg_iter.next() {
write!(f, "{}", elem)?;
for i in arg_iter {
write!(f, " {}", i)?;
}
}
write!(f, ") {})", self.ast.car)?;
Ok(())
}
}
impl fmt::Display for ValueType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ValueType::VarForm(ref s) => write!(f, "{}", s),
ValueType::Internal(_) => write!(f, "<builtin>"),
ValueType::FuncForm(ref form) => {
write!(f, "args: ")?;
for sym in form.arg_syms.clone() {
write!(f, "{} ", sym)?;
}
write!(f, "\nform: {}", form.ast)?;
Ok(())
}
}
}
}
impl Symbol {
/* call
* routine is called by eval when a symbol is expanded
*/
pub fn call(&self, args: &Seg, syms: &mut SymTable) -> Result<Box<Ctr>, String> {
let evaluated_args: &Seg;
let mut outer_scope_seg_storage = Seg::new();
let mut errcon: String = String::new();
if !self.conditional_branches {
if !args.circuit(&mut |arg: &Ctr| -> bool {
if let Ctr::Seg(ref s) = arg {
let eval_res = eval(s, syms);
if eval_res.is_err() {
errcon = eval_res.err().unwrap();
return false
}
outer_scope_seg_storage.append(eval_res.unwrap().clone());
} else if let Ctr::Symbol(ref s) = arg {
let eval_res = syms.call_symbol(
s,
&outer_scope_seg_storage,
false
);
if eval_res.is_err() {
errcon = eval_res.err().unwrap();
return false
}
outer_scope_seg_storage.append(eval_res.unwrap().clone());
} else {
outer_scope_seg_storage.append(Box::new(arg.clone()));
}
true
}) {
return Err(format!("error evaluating args: {}", errcon))
}
evaluated_args = &outer_scope_seg_storage;
} else {
evaluated_args = args;
}
self.args.validate_inputs(evaluated_args)?;
match &self.value {
ValueType::VarForm(ref f) => Ok(Box::new(*f.clone())),
ValueType::Internal(ref f) => Ok(Box::new(f(evaluated_args, syms)?)),
ValueType::FuncForm(ref f) => {
// stores any value overwritten by local state
// If this ever becomes ASYNC this will need to
// become a more traditional stack design, and the
// global table will need to be released
let mut holding_table = SymTable::new();
// Prep var table for function execution
for n in 0..f.arg_syms.len() {
if let Some(old) = syms.insert(
f.arg_syms[n].clone(),
Symbol {
name: f.arg_syms[n].clone(),
value: ValueType::VarForm(Box::new(evaluated_args[n].clone())),
args: Args::None,
docs: format!("local argument to {}", f.arg_syms[n].clone()),
conditional_branches: false,
},
) {
holding_table.insert(f.arg_syms[n].clone(), old);
}
}
// execute function
let mut result: Box<Ctr>;
let mut iterate = &*(f.ast);
loop {
if let Ctr::Seg(ref data) = *iterate.car {
match eval(data, syms) {
Ok(ctr) => result = ctr,
Err(e) => return Err(format!("evaluation failure\n{}", e)),
}
} else {
let temp = Seg::from_mono(iterate.car.clone());
match eval(&temp, syms) {
Ok(ctr) => {
if let Ctr::Seg(s) = *ctr {
result = s.car.clone();
} else {
result = ctr;
}
}
Err(e) => return Err(format!("evaluation failure\n{}", e)),
}
}
match *iterate.cdr {
Ctr::Seg(ref next) => iterate = next,
Ctr::None => break,
_ => panic!("function body not in standard form!"),
}
}
// clear local vars and restore previous values
for n in 0..f.arg_syms.len() {
syms.remove(&f.arg_syms[n]);
if let Some(val) = holding_table.remove(&f.arg_syms[n]) {
syms.insert(f.arg_syms[n].clone(), val);
}
}
Ok(result)
}
}
}
pub fn from_ast(
id: &String,
doc: &String,
ast: &Seg,
arg_list: Option<Vec<String>>,
) -> Symbol {
let args: Args;
let value: ValueType;
if let Some(ref arg_syms) = arg_list {
value = ValueType::FuncForm(UserFn{
ast: Box::new(ast.clone()),
arg_syms: arg_syms.clone(),
});
args = Args::Lazy(arg_syms.len() as u128);
} else {
args = Args::None;
value = ValueType::VarForm(ast.car.clone());
}
Symbol {
name: id.clone(),
docs: doc.clone(),
conditional_branches: false,
args, value,
}
}
}
pub fn call_lambda(
lam: &UserFn,
args_ctr: &Box<Ctr>,
syms: &mut SymTable,
) -> Result<Box<Ctr>, String> {
let temp_sym = Symbol {
name: String::from("anonymous"),
conditional_branches: false,
docs: String::from("user defined lambda"),
args: Args::Lazy(lam.arg_syms.len() as u128),
value: ValueType::FuncForm(lam.clone()),
};
let args: &Seg;
let outer_scope_maybe_args: Seg;
if let Ctr::Seg(ref args_head) = **args_ctr {
args = args_head;
} else {
outer_scope_maybe_args = Seg::from_mono(
Box::new(*args_ctr.clone()));
args = &outer_scope_maybe_args;
}
temp_sym.call(args, syms)
}