2021-02-14 16:33:17 -08:00
|
|
|
/* 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/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2023-02-17 21:00:07 -08:00
|
|
|
use crate::sym::{SYM_TABLE, Symbol, ValueType};
|
2023-02-15 23:27:00 -08:00
|
|
|
use crate::segment::{Seg, Ctr};
|
2021-02-14 16:33:17 -08:00
|
|
|
|
|
|
|
|
/* iterates over a syntax tree
|
|
|
|
|
* returns a NEW LIST of values
|
|
|
|
|
* representing the simplest possible form of the input
|
|
|
|
|
*/
|
2023-02-17 21:00:07 -08:00
|
|
|
pub fn eval (
|
2023-02-15 23:27:00 -08:00
|
|
|
ast: &Seg,
|
2023-02-17 21:00:07 -08:00
|
|
|
expect_all_symbols_defined: bool,
|
|
|
|
|
simplify_function_branches: bool,
|
2023-02-15 23:27:00 -08:00
|
|
|
) -> Result<Box<Ctr>, String> {
|
|
|
|
|
// data to return
|
|
|
|
|
let mut ret = Box::from(Ctr::None);
|
2023-02-17 21:00:07 -08:00
|
|
|
let mut first = true;
|
2023-02-15 23:27:00 -08:00
|
|
|
|
|
|
|
|
// to be assigned from cloned/evaled data
|
|
|
|
|
let mut car;
|
|
|
|
|
let mut cdr = Box::from(Ctr::None);
|
|
|
|
|
|
|
|
|
|
// lets me redirect the input
|
2023-02-20 19:42:48 -08:00
|
|
|
let table_handle = SYM_TABLE.read().unwrap();
|
2023-02-15 23:27:00 -08:00
|
|
|
let mut arg_car = &ast.car;
|
|
|
|
|
let mut arg_cdr = &ast.cdr;
|
|
|
|
|
|
2023-02-17 21:00:07 -08:00
|
|
|
// iterate over ast and build out ret
|
|
|
|
|
let mut none = false;
|
|
|
|
|
while !none {
|
|
|
|
|
let mut prefetched_function: Option<&Symbol> = None;
|
|
|
|
|
while let Ctr::Symbol(ref tok) = **arg_car {
|
|
|
|
|
prefetched_function = table_handle.get(tok);
|
|
|
|
|
if let Some(sym_ref) = prefetched_function {
|
|
|
|
|
if let ValueType::VarForm(ref value) = sym_ref.value {
|
|
|
|
|
arg_car = value;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
2021-11-02 19:18:11 -07:00
|
|
|
}
|
2023-02-17 21:00:07 -08:00
|
|
|
} else if !expect_all_symbols_defined {
|
|
|
|
|
return Err(format!("evaluation error: undefined symbol {}", tok))
|
|
|
|
|
} else {
|
|
|
|
|
break
|
2022-01-16 22:02:40 -08:00
|
|
|
}
|
2021-06-22 00:50:37 -07:00
|
|
|
}
|
|
|
|
|
|
2023-02-17 21:00:07 -08:00
|
|
|
match **arg_car {
|
2021-06-22 00:50:37 -07:00
|
|
|
Ctr::Seg(ref inner) => {
|
2023-02-17 21:00:07 -08:00
|
|
|
match eval(inner, expect_all_symbols_defined, simplify_function_branches) {
|
2023-02-15 23:27:00 -08:00
|
|
|
Ok(res) => car = res,
|
2023-02-17 21:00:07 -08:00
|
|
|
Err(e) => return Err(format!("evaluation error: {}", e)),
|
2021-06-22 00:50:37 -07:00
|
|
|
}
|
2022-01-16 22:02:40 -08:00
|
|
|
}
|
2021-06-22 00:50:37 -07:00
|
|
|
|
2023-02-17 21:00:07 -08:00
|
|
|
Ctr::Symbol(_) => {
|
|
|
|
|
if simplify_function_branches && first {
|
|
|
|
|
if let Some(func) = prefetched_function {
|
|
|
|
|
if let Ctr::Seg(ref candidates) = **arg_cdr {
|
|
|
|
|
let fc: Result<Box<Ctr>, String>;
|
|
|
|
|
match eval(candidates, expect_all_symbols_defined, false) {
|
|
|
|
|
Ok(res) => {
|
|
|
|
|
match *res {
|
|
|
|
|
Ctr::Seg(ref args) => {
|
|
|
|
|
fc = func.call(args);
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
fc = func.call(&Seg::from_mono(res.clone()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
match fc {
|
|
|
|
|
Ok(datum) => car = datum,
|
|
|
|
|
Err(e) => return Err(format!("call to {} failed: {}", func.name, e))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(e) => return Err(format!("evaluation error: {}", e))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
match func.call(&Seg::new()) {
|
|
|
|
|
Ok(res) => car = res,
|
|
|
|
|
Err(e) => return Err(format!("call to {} failed: {}", func.name, e))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
car = arg_car.clone();
|
|
|
|
|
}
|
2021-06-22 00:50:37 -07:00
|
|
|
} else {
|
2023-02-17 21:00:07 -08:00
|
|
|
car = arg_car.clone();
|
2021-06-22 00:50:37 -07:00
|
|
|
}
|
2022-01-16 22:02:40 -08:00
|
|
|
}
|
2021-06-22 00:50:37 -07:00
|
|
|
|
|
|
|
|
_ => {
|
2023-02-15 23:27:00 -08:00
|
|
|
car = arg_car.clone();
|
2021-06-22 00:50:37 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-17 21:00:07 -08:00
|
|
|
// weird tree but okay
|
|
|
|
|
while let Ctr::Symbol(ref tok) = **arg_cdr {
|
|
|
|
|
prefetched_function = table_handle.get(tok);
|
|
|
|
|
if let Some(sym_ref) = prefetched_function {
|
|
|
|
|
if let ValueType::VarForm(ref value) = sym_ref.value {
|
|
|
|
|
arg_cdr = value;
|
2021-06-22 00:50:37 -07:00
|
|
|
} else {
|
2023-02-17 21:00:07 -08:00
|
|
|
break;
|
2021-06-22 00:50:37 -07:00
|
|
|
}
|
2023-02-17 21:00:07 -08:00
|
|
|
} else if !expect_all_symbols_defined {
|
|
|
|
|
return Err(format!("evaluation error: undefined symbol {}", tok))
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-22 00:50:37 -07:00
|
|
|
|
2023-02-17 21:00:07 -08:00
|
|
|
match **arg_cdr {
|
|
|
|
|
Ctr::Symbol(_) => {
|
|
|
|
|
cdr = arg_cdr.clone();
|
2021-06-22 00:50:37 -07:00
|
|
|
none = true;
|
2022-01-16 22:02:40 -08:00
|
|
|
}
|
2021-06-22 00:50:37 -07:00
|
|
|
|
2023-02-15 23:27:00 -08:00
|
|
|
Ctr::Seg(ref next) => {
|
|
|
|
|
if let Ctr::None = *ret {
|
|
|
|
|
*ret = Ctr::Seg(Seg::from(car, cdr.clone()))
|
|
|
|
|
} else if let Ctr::Seg(ref mut s) = *ret {
|
|
|
|
|
s.append(Box::from(Ctr::Seg(Seg::from(car, cdr.clone()))))
|
|
|
|
|
}
|
|
|
|
|
arg_car = &next.car;
|
|
|
|
|
arg_cdr = &next.cdr
|
2021-06-22 00:50:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ => {
|
2023-02-15 23:27:00 -08:00
|
|
|
cdr = ast.cdr.clone();
|
2021-06-22 00:50:37 -07:00
|
|
|
none = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-15 23:27:00 -08:00
|
|
|
if let Ctr::None = **arg_car {
|
|
|
|
|
if let Ctr::None = **arg_cdr {
|
2021-06-22 00:50:37 -07:00
|
|
|
none = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-17 21:00:07 -08:00
|
|
|
|
|
|
|
|
first = false;
|
2021-06-22 00:50:37 -07:00
|
|
|
}
|
|
|
|
|
|
2023-02-17 21:00:07 -08:00
|
|
|
Ok(ret)
|
2021-03-16 22:43:46 -07:00
|
|
|
}
|
2023-02-17 21:00:07 -08:00
|
|
|
|