rustfmt
Signed-off-by: Ava Hahn <ava@aidanis.online>
This commit is contained in:
parent
ecbc47d4fe
commit
bc09cb07b1
17 changed files with 236 additions and 217 deletions
|
|
@ -4,6 +4,7 @@ default:
|
|||
fmt:
|
||||
stage: build
|
||||
script:
|
||||
- rustup component add rustfmt
|
||||
- rustfmt --check tests/*
|
||||
- rustfmt --check src/*.rs
|
||||
- rustfmt --check src/stl/*
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
use dirs::home_dir;
|
||||
use relish::ast::{eval, lex, Ctr, Seg, SymTable};
|
||||
use relish::stdlib::{static_stdlib, dynamic_stdlib};
|
||||
use relish::aux::configure;
|
||||
use relish::stdlib::{dynamic_stdlib, static_stdlib};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
use std::env;
|
||||
|
|
@ -39,23 +39,19 @@ fn main() {
|
|||
}
|
||||
|
||||
let mut syms = SymTable::new();
|
||||
static_stdlib(&mut syms)
|
||||
.unwrap_or_else(|err: String| eprintln!("{}", err));
|
||||
dynamic_stdlib(&mut syms)
|
||||
.unwrap_or_else(|err: String| eprintln!("{}", err));
|
||||
{ // scope the below borrow of syms
|
||||
static_stdlib(&mut syms).unwrap_or_else(|err: String| eprintln!("{}", err));
|
||||
dynamic_stdlib(&mut syms).unwrap_or_else(|err: String| eprintln!("{}", err));
|
||||
{
|
||||
// scope the below borrow of syms
|
||||
let cfg_file = env::var("RELISH_CFG_FILE").unwrap_or(cfg_file_name);
|
||||
configure(
|
||||
cfg_file.clone(),
|
||||
&mut syms,
|
||||
).unwrap_or_else(|err: String| eprintln!("failed to load script {}\n{}",
|
||||
cfg_file, err));
|
||||
configure(cfg_file.clone(), &mut syms)
|
||||
.unwrap_or_else(|err: String| eprintln!("failed to load script {}\n{}", cfg_file, err));
|
||||
}
|
||||
dynamic_stdlib(&mut syms)
|
||||
.unwrap_or_else(|err: String| eprintln!("{}", err));
|
||||
dynamic_stdlib(&mut syms).unwrap_or_else(|err: String| eprintln!("{}", err));
|
||||
|
||||
loop {
|
||||
let s = *syms.call_symbol(&"CFG_RELISH_PROMPT".to_string(), &Seg::new(), true)
|
||||
let s = *syms
|
||||
.call_symbol(&"CFG_RELISH_PROMPT".to_string(), &Seg::new(), true)
|
||||
.unwrap_or_else(|err: String| {
|
||||
eprintln!("{}", err);
|
||||
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
use crate::eval::eval;
|
||||
use crate::lex::lex;
|
||||
use crate::segment::{Seg, Ctr};
|
||||
use crate::sym::{SymTable, ValueType, Args, Symbol};
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::{Args, SymTable, Symbol, ValueType};
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -29,28 +29,38 @@ fn prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
|||
|
||||
/* loads defaults, evaluates config script */
|
||||
pub fn configure(filename: String, syms: &mut SymTable) -> Result<(), String> {
|
||||
syms.insert("CFG_RELISH_POSIX".to_string(), Symbol {
|
||||
syms.insert(
|
||||
"CFG_RELISH_POSIX".to_string(),
|
||||
Symbol {
|
||||
name: String::from("CFG_RELISH_POSIX"),
|
||||
args: Args::None,
|
||||
conditional_branches: false,
|
||||
value: ValueType::VarForm(Box::new(Ctr::String("0".to_string()))),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert("CFG_RELISH_ENV".to_string(), Symbol {
|
||||
syms.insert(
|
||||
"CFG_RELISH_ENV".to_string(),
|
||||
Symbol {
|
||||
name: String::from("CFG_RELISH_ENV"),
|
||||
args: Args::None,
|
||||
conditional_branches: false,
|
||||
value: ValueType::VarForm(Box::new(Ctr::String("1".to_string()))),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert("CFG_RELISH_PROMPT".to_string(), Symbol {
|
||||
syms.insert(
|
||||
"CFG_RELISH_PROMPT".to_string(),
|
||||
Symbol {
|
||||
name: String::from("default relish prompt"),
|
||||
args: Args::None,
|
||||
conditional_branches: false,
|
||||
value: ValueType::Internal(Rc::new(prompt_default_callback)),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let config_document = fs::read_to_string(filename).unwrap_or_else(|err: io::Error| err.to_string());
|
||||
let config_document =
|
||||
fs::read_to_string(filename).unwrap_or_else(|err: io::Error| err.to_string());
|
||||
let config_tree = lex(&config_document)?;
|
||||
let config_result = eval(&config_tree, syms)?;
|
||||
|
||||
|
|
|
|||
13
src/eval.rs
13
src/eval.rs
|
|
@ -15,17 +15,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::SymTable;
|
||||
use crate::segment::{Seg, Ctr};
|
||||
|
||||
/* iterates over a syntax tree
|
||||
* returns a NEW LIST of values
|
||||
* representing the simplest possible form of the input
|
||||
*/
|
||||
pub fn eval (
|
||||
ast: &Seg,
|
||||
syms: &mut SymTable,
|
||||
) -> Result<Box<Ctr>, String> {
|
||||
pub fn eval(ast: &Seg, syms: &mut SymTable) -> Result<Box<Ctr>, String> {
|
||||
// data to return
|
||||
let mut ret = Box::from(Ctr::None);
|
||||
let mut first = true;
|
||||
|
|
@ -42,12 +39,10 @@ pub fn eval (
|
|||
let mut none = false;
|
||||
while !none {
|
||||
match &**arg_car {
|
||||
Ctr::Seg(ref inner) => {
|
||||
match eval(inner, syms) {
|
||||
Ctr::Seg(ref inner) => match eval(inner, syms) {
|
||||
Ok(res) => car = res,
|
||||
Err(e) => return Err(format!("evaluation error: {}", e)),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Ctr::Symbol(ref tok) => {
|
||||
let outer_scope_seg_holder: Seg;
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ fn process(document: &String) -> Result<Box<Seg>, String> {
|
|||
return Err("Empty token".to_string());
|
||||
}
|
||||
|
||||
let mut current_seg = ref_stack.pop().unwrap();
|
||||
let mut current_seg = ref_stack.pop().unwrap_or(Seg::new());
|
||||
let obj;
|
||||
if is_str {
|
||||
obj = Box::from(Ctr::String(token));
|
||||
|
|
|
|||
10
src/lib.rs
10
src/lib.rs
|
|
@ -15,26 +15,22 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
mod config;
|
||||
mod eval;
|
||||
mod lex;
|
||||
mod segment;
|
||||
mod sym;
|
||||
mod stl;
|
||||
mod sym;
|
||||
|
||||
pub mod ast {
|
||||
pub use crate::eval::eval;
|
||||
pub use crate::lex::lex;
|
||||
pub use crate::segment::{Ctr, Seg, Type};
|
||||
pub use crate::sym::{
|
||||
SymTable, Symbol,
|
||||
UserFn, ValueType, Args
|
||||
};
|
||||
pub use crate::sym::{Args, SymTable, Symbol, UserFn, ValueType};
|
||||
}
|
||||
|
||||
pub mod stdlib {
|
||||
pub use crate::stl::{static_stdlib, dynamic_stdlib};
|
||||
pub use crate::stl::{dynamic_stdlib, static_stdlib};
|
||||
}
|
||||
|
||||
pub mod aux {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ pub struct Seg {
|
|||
* How this is an acceptable solution I have
|
||||
* not a single clue.
|
||||
*/
|
||||
_lifetime_variance_determinant: PhantomData<()>
|
||||
_lifetime_variance_determinant: PhantomData<()>,
|
||||
}
|
||||
|
||||
static NOTHING: Ctr = Ctr::None;
|
||||
|
|
@ -83,7 +83,6 @@ impl Ctr {
|
|||
Ctr::None => Type::None,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Seg {
|
||||
|
|
@ -96,12 +95,12 @@ impl Seg {
|
|||
pub fn append(&mut self, obj: Box<Ctr>) {
|
||||
if let Ctr::None = &*(self.car) {
|
||||
self.car = obj;
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ctr::Seg(s) = &mut *(self.cdr) {
|
||||
s.append(obj);
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ctr::None = &mut *(self.cdr) {
|
||||
|
|
@ -148,7 +147,10 @@ impl Seg {
|
|||
*/
|
||||
pub fn len(&self) -> u128 {
|
||||
let mut len = 0;
|
||||
self.circuit(&mut |_c: &Ctr| -> bool { len += 1; true });
|
||||
self.circuit(&mut |_c: &Ctr| -> bool {
|
||||
len += 1;
|
||||
true
|
||||
});
|
||||
len
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +169,9 @@ impl Seg {
|
|||
|
||||
fn seg_to_string(s: &Seg, parens: bool) -> String {
|
||||
let mut string = String::new();
|
||||
if parens { string.push('('); }
|
||||
if parens {
|
||||
string.push('(');
|
||||
}
|
||||
match *(s.car) {
|
||||
Ctr::None => string.push_str("<nil>"),
|
||||
_ => string.push_str(&s.car.to_string()),
|
||||
|
|
@ -175,10 +179,14 @@ fn seg_to_string(s: &Seg, parens: bool) -> String {
|
|||
string.push(' ');
|
||||
match &*(s.cdr) {
|
||||
Ctr::Seg(inner) => string.push_str(&seg_to_string(inner, false)),
|
||||
Ctr::None => {string.pop();},
|
||||
Ctr::None => {
|
||||
string.pop();
|
||||
}
|
||||
_ => string.push_str(&s.cdr.to_string()),
|
||||
}
|
||||
if parens { string.push(')'); }
|
||||
if parens {
|
||||
string.push(')');
|
||||
}
|
||||
|
||||
string
|
||||
}
|
||||
|
|
@ -202,7 +210,7 @@ impl Index<usize> for Seg {
|
|||
}
|
||||
|
||||
if let Ctr::Seg(ref s) = *self.cdr {
|
||||
return s.index(idx - 1)
|
||||
return s.index(idx - 1);
|
||||
}
|
||||
|
||||
&NOTHING
|
||||
|
|
@ -236,7 +244,7 @@ impl fmt::Display for Ctr {
|
|||
} else {
|
||||
write!(f, "F")
|
||||
}
|
||||
},
|
||||
}
|
||||
Ctr::Seg(s) => write!(f, "{}", s),
|
||||
Ctr::None => Ok(()),
|
||||
}
|
||||
|
|
|
|||
82
src/stl.rs
82
src/stl.rs
|
|
@ -15,40 +15,49 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::segment::{Ctr, Seg, Type};
|
||||
use crate::eval::eval;
|
||||
use crate::sym::{SymTable, Symbol, ValueType, Args, UserFn};
|
||||
use crate::segment::{Ctr, Seg, Type};
|
||||
use crate::sym::{Args, SymTable, Symbol, UserFn, ValueType};
|
||||
use std::env;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub mod control;
|
||||
pub mod append;
|
||||
pub mod control;
|
||||
//pub mod str;
|
||||
|
||||
/// static_stdlib
|
||||
/// inserts all stdlib functions that can be inserted without
|
||||
/// any kind of further configuration data into a symtable
|
||||
pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
||||
syms.insert("append".to_string(), Symbol {
|
||||
syms.insert(
|
||||
"append".to_string(),
|
||||
Symbol {
|
||||
name: String::from("append"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
value: ValueType::Internal(Rc::new(append::append_callback)),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert("expand".to_string(), Symbol {
|
||||
syms.insert(
|
||||
"expand".to_string(),
|
||||
Symbol {
|
||||
name: String::from("expand"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
value: ValueType::Internal(Rc::new(append::expand_callback)),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert("if".to_string(), Symbol {
|
||||
syms.insert(
|
||||
"if".to_string(),
|
||||
Symbol {
|
||||
name: String::from("if"),
|
||||
args: Args::Lazy(3),
|
||||
conditional_branches: true,
|
||||
value: ValueType::Internal(Rc::new(control::if_callback)),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -58,43 +67,52 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
/// callbacks with configuration into a symtable
|
||||
pub fn dynamic_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
||||
//get CFG_RELISH_ENV from syms
|
||||
let env_cfg_user_form = syms.call_symbol(
|
||||
&"CFG_RELISH_ENV".to_string(), &Seg::new(), true)
|
||||
let env_cfg_user_form = syms
|
||||
.call_symbol(&"CFG_RELISH_ENV".to_string(), &Seg::new(), true)
|
||||
.unwrap_or_else(|_: String| Box::new(Ctr::None))
|
||||
.to_string()
|
||||
.ne("");
|
||||
|
||||
syms.insert("def".to_string(), Symbol {
|
||||
syms.insert(
|
||||
"def".to_string(),
|
||||
Symbol {
|
||||
name: String::from("define"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
value: ValueType::Internal(Rc::new( move |ast: &Seg, syms: &mut SymTable| -> Result<Ctr, String> {
|
||||
value: ValueType::Internal(Rc::new(
|
||||
move |ast: &Seg, syms: &mut SymTable| -> Result<Ctr, String> {
|
||||
_store_callback(ast, syms, env_cfg_user_form)
|
||||
},
|
||||
)),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _store_callback (ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr, String> {
|
||||
fn _store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr, String> {
|
||||
let is_var = ast.len() == 2;
|
||||
if let Ctr::Symbol(ref identifier) = *ast.car {
|
||||
match &*ast.cdr {
|
||||
Ctr::Seg(data_tree) if is_var => match eval(&Box::new(data_tree), syms) {
|
||||
Ok(seg) => if let Ctr::Seg(ref val) = *seg {
|
||||
syms.insert(identifier.clone(), Symbol{
|
||||
Ok(seg) => {
|
||||
if let Ctr::Seg(ref val) = *seg {
|
||||
syms.insert(
|
||||
identifier.clone(),
|
||||
Symbol {
|
||||
value: ValueType::VarForm(val.car.clone()),
|
||||
name: identifier.clone(),
|
||||
args: Args::None,
|
||||
conditional_branches: false,
|
||||
});
|
||||
},
|
||||
);
|
||||
if env_cfg {
|
||||
env::set_var(identifier.clone(), val.car.to_string());
|
||||
}
|
||||
} else {
|
||||
return Err("impossible args to export".to_string());
|
||||
},
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(format!("couldnt eval symbol: {}", e)),
|
||||
},
|
||||
Ctr::Seg(data_tree) if !is_var => {
|
||||
|
|
@ -108,24 +126,29 @@ fn _store_callback (ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr
|
|||
false
|
||||
}
|
||||
}) {
|
||||
return Err("all arguments defined for function must be of type symbol".to_string());
|
||||
return Err(
|
||||
"all arguments defined for function must be of type symbol".to_string()
|
||||
);
|
||||
};
|
||||
|
||||
if let Ctr::Seg(ref bodies) = *data_tree.cdr {
|
||||
syms.insert(identifier.clone(), Symbol{
|
||||
value: ValueType::FuncForm(UserFn{
|
||||
syms.insert(
|
||||
identifier.clone(),
|
||||
Symbol {
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
ast: Box::new(bodies.clone()),
|
||||
arg_syms: arg_list.clone(),
|
||||
}),
|
||||
name: identifier.clone(),
|
||||
args: Args::Strict(arg_list
|
||||
.into_iter()
|
||||
.map(Type::from)
|
||||
.collect()),
|
||||
args: Args::Strict(arg_list.into_iter().map(Type::from).collect()),
|
||||
conditional_branches: false,
|
||||
});
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return Err("expected one or more function bodies in function definition".to_string());
|
||||
return Err(
|
||||
"expected one or more function bodies in function definition"
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return Err("expected list of arguments in function definition".to_string());
|
||||
|
|
@ -136,7 +159,7 @@ fn _store_callback (ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr
|
|||
if env_cfg {
|
||||
env::remove_var(identifier);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => return Err("args not in standard form".to_string()),
|
||||
}
|
||||
} else {
|
||||
|
|
@ -144,4 +167,3 @@ fn _store_callback (ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr
|
|||
}
|
||||
Ok(Ctr::None)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::SymTable;
|
||||
|
||||
pub fn append_callback (ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
pub fn append_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
let mut temp = s.clone();
|
||||
if let Ctr::Seg(ref list) = *ast.cdr {
|
||||
|
|
@ -47,7 +47,7 @@ pub fn append_callback (ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String>
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expand_callback (ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
pub fn expand_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
if let Ctr::Seg(_) = *ast.car {
|
||||
Ok(*ast.car.clone())
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -15,32 +15,30 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::eval::eval;
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::SymTable;
|
||||
|
||||
pub fn if_callback (ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
let cond: bool;
|
||||
match *ast.car {
|
||||
Ctr::Seg(ref cond_form) => {
|
||||
if let Ctr::Bool(cond_from_eval) = *eval(cond_form, syms)? {
|
||||
cond = cond_from_eval;
|
||||
} else {
|
||||
return Err("first argument to if must evaluate to be a boolean".to_string())
|
||||
return Err("first argument to if must evaluate to be a boolean".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Ctr::Bool(cond_from_car) => cond = cond_from_car,
|
||||
_ => {
|
||||
return Err("first argument to if must evaluate to be a boolean".to_string())
|
||||
}
|
||||
_ => return Err("first argument to if must evaluate to be a boolean".to_string()),
|
||||
}
|
||||
|
||||
let then_form: &Seg;
|
||||
if let Ctr::Seg(ref s) = *ast.cdr {
|
||||
then_form = s;
|
||||
} else {
|
||||
return Err("impossible condition: not enough args to if".to_string())
|
||||
return Err("impossible condition: not enough args to if".to_string());
|
||||
}
|
||||
|
||||
if cond {
|
||||
|
|
@ -56,9 +54,8 @@ pub fn if_callback (ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
} else {
|
||||
Err("impossible condition: list evals to non list".to_string())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
// else
|
||||
if let Ctr::Seg(ref else_form) = *then_form.cdr {
|
||||
|
|
@ -73,7 +70,7 @@ pub fn if_callback (ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
} else {
|
||||
Err("impossible condition: list evals to non list".to_string())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err("impossible condition: args not in standard form".to_string())
|
||||
|
|
@ -81,18 +78,18 @@ pub fn if_callback (ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn let_callback (_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
pub fn let_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn while_callback (_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
pub fn while_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn map_callback (_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
pub fn map_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn circuit_callback (_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
pub fn circuit_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
|||
60
src/sym.rs
60
src/sym.rs
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
use crate::eval::eval;
|
||||
use crate::segment::{Seg, Ctr, Type};
|
||||
use crate::segment::{Ctr, Seg, Type};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
pub struct SymTable(HashMap<String, Symbol>);
|
||||
|
|
@ -41,7 +41,7 @@ pub struct UserFn {
|
|||
pub enum ValueType {
|
||||
Internal(Rc<dyn Fn(&Seg, &mut SymTable) -> Result<Ctr, String>>),
|
||||
FuncForm(UserFn),
|
||||
VarForm(Box<Ctr>)
|
||||
VarForm(Box<Ctr>),
|
||||
}
|
||||
|
||||
/* Function Args
|
||||
|
|
@ -53,7 +53,7 @@ pub enum Args {
|
|||
Lazy(u128),
|
||||
Strict(Vec<Type>),
|
||||
Infinite,
|
||||
None
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -83,7 +83,12 @@ impl SymTable {
|
|||
self.0.remove(arg)
|
||||
}
|
||||
|
||||
pub fn call_symbol(&mut self, name: &String, args: &Seg, call_func: bool) -> Result<Box<Ctr>, String> {
|
||||
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)),
|
||||
|
|
@ -125,21 +130,21 @@ impl Args {
|
|||
Args::None => {
|
||||
if args.len() == 1 {
|
||||
if let Ctr::None = *args.car {
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err("expected no args".to_string())
|
||||
return Err("expected no args".to_string());
|
||||
}
|
||||
} else {
|
||||
return Err("expected no args".to_string())
|
||||
return Err("expected no args".to_string());
|
||||
}
|
||||
}
|
||||
},
|
||||
Args::Infinite => {
|
||||
if !args.is_empty() {
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err("expected args but none were provided".to_string())
|
||||
return Err("expected args but none were provided".to_string());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Args::Lazy(ref num) => {
|
||||
let called_arg_count = args.len();
|
||||
|
|
@ -150,15 +155,9 @@ impl Args {
|
|||
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
|
||||
));
|
||||
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,
|
||||
));
|
||||
return Err(format!("expected {} args. Got 0.", num,));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,15 +180,12 @@ impl Args {
|
|||
});
|
||||
|
||||
if passes && idx < (arg_types.len() - 1) {
|
||||
return Err(format!(
|
||||
"{} too few arguments",
|
||||
arg_types.len() - (idx + 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]));
|
||||
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());
|
||||
|
|
@ -209,11 +205,7 @@ 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> {
|
||||
pub fn call(&self, args: &Seg, syms: &mut SymTable) -> Result<Box<Ctr>, String> {
|
||||
let evaluated_args: &Seg;
|
||||
let outer_scope_seg_storage: Seg;
|
||||
let outer_scope_eval: Box<Ctr>;
|
||||
|
|
@ -251,13 +243,15 @@ impl Symbol {
|
|||
|
||||
// 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{
|
||||
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,
|
||||
conditional_branches: false,
|
||||
})
|
||||
{
|
||||
},
|
||||
) {
|
||||
holding_table.insert(f.arg_syms[n].clone(), old);
|
||||
}
|
||||
}
|
||||
|
|
@ -280,7 +274,7 @@ impl Symbol {
|
|||
} else {
|
||||
result = ctr;
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
mod eval_tests {
|
||||
use relish::ast::{eval, lex, SymTable};
|
||||
use relish::ast::{Args, Symbol, Ctr, Seg, ValueType, UserFn};
|
||||
use relish::ast::{Args, Ctr, Seg, Symbol, UserFn, ValueType};
|
||||
|
||||
#[test]
|
||||
fn eval_simple() {
|
||||
|
|
@ -58,11 +58,12 @@ mod eval_tests {
|
|||
name: String::from("echo"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
value: ValueType::FuncForm( UserFn {
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
arg_syms: vec!["input".to_string()],
|
||||
ast: Box::new(Seg::from(
|
||||
Box::from(Ctr::Symbol("input".to_string())),
|
||||
Box::from(Ctr::None))),
|
||||
Box::from(Ctr::None),
|
||||
)),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -93,15 +94,16 @@ mod eval_tests {
|
|||
let output = "('one' 'unwrap_me')";
|
||||
let mut syms = SymTable::new();
|
||||
|
||||
let test_external_func: Symbol = Symbol{
|
||||
let test_external_func: Symbol = Symbol {
|
||||
name: String::from("echo"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
value: ValueType::FuncForm( UserFn {
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
arg_syms: vec!["input".to_string()],
|
||||
ast: Box::new(Seg::from(
|
||||
Box::from(Ctr::Symbol("input".to_string())),
|
||||
Box::from(Ctr::None))),
|
||||
Box::from(Ctr::None),
|
||||
)),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -137,7 +139,7 @@ mod eval_tests {
|
|||
|
||||
Ok(initial_ast) => match eval(&initial_ast, &mut syms) {
|
||||
Err(e) => {
|
||||
assert_eq!(e,"error in call to undefined: undefined symbol: undefined")
|
||||
assert_eq!(e, "error in call to undefined: undefined symbol: undefined")
|
||||
}
|
||||
|
||||
Ok(reduced) => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
mod func_tests {
|
||||
use std::rc::Rc;
|
||||
use relish::ast::lex;
|
||||
use relish::ast::{Args, Ctr, Seg, Symbol, ValueType};
|
||||
use relish::ast::{SymTable, Type, UserFn};
|
||||
use relish::ast::{Args, Symbol, Ctr, Seg, ValueType};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn decl_and_call_internal_func() {
|
||||
|
|
@ -22,10 +22,7 @@ mod func_tests {
|
|||
},
|
||||
)),
|
||||
};
|
||||
let args = Seg::from(
|
||||
Box::new(Ctr::Bool(true)),
|
||||
Box::new(Ctr::None)
|
||||
);
|
||||
let args = Seg::from(Box::new(Ctr::Bool(true)), Box::new(Ctr::None));
|
||||
|
||||
syms.insert(String::from("test_func_in"), test_internal_func);
|
||||
|
||||
|
|
@ -53,7 +50,7 @@ mod func_tests {
|
|||
name: String::from("echo"),
|
||||
conditional_branches: false,
|
||||
args: Args::Lazy(1),
|
||||
value: ValueType::FuncForm(UserFn{
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
arg_syms: vec!["input".to_string()],
|
||||
ast: finner,
|
||||
}),
|
||||
|
|
@ -61,7 +58,7 @@ mod func_tests {
|
|||
|
||||
let args = Seg::from(
|
||||
Box::new(Ctr::String("test".to_string())),
|
||||
Box::new(Ctr::None)
|
||||
Box::new(Ctr::None),
|
||||
);
|
||||
|
||||
syms.insert(String::from("test_func_in"), test_external_func);
|
||||
|
|
@ -89,11 +86,11 @@ mod func_tests {
|
|||
match lex(&"(input input)".to_string()) {
|
||||
Err(e) => panic!("{}", e),
|
||||
Ok(finner) => {
|
||||
let test_external_func: Symbol = Symbol{
|
||||
let test_external_func: Symbol = Symbol {
|
||||
name: String::from("echo_2"),
|
||||
conditional_branches: false,
|
||||
args: Args::Lazy(1),
|
||||
value: ValueType::FuncForm(UserFn{
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
arg_syms: vec!["input".to_string()],
|
||||
ast: finner,
|
||||
}),
|
||||
|
|
@ -101,7 +98,7 @@ mod func_tests {
|
|||
|
||||
let args = Seg::from(
|
||||
Box::new(Ctr::String("test".to_string())),
|
||||
Box::new(Ctr::None)
|
||||
Box::new(Ctr::None),
|
||||
);
|
||||
|
||||
syms.insert(String::from("echo_2"), test_external_func);
|
||||
|
|
@ -147,16 +144,13 @@ mod func_tests {
|
|||
name: String::from("test_outer"),
|
||||
conditional_branches: false,
|
||||
args: Args::Lazy(1),
|
||||
value: ValueType::FuncForm(UserFn{
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
arg_syms: vec!["input".to_string()],
|
||||
ast: finner,
|
||||
}),
|
||||
};
|
||||
|
||||
let args = Seg::from(
|
||||
Box::new(Ctr::Bool(true)),
|
||||
Box::new(Ctr::None)
|
||||
);
|
||||
let args = Seg::from(Box::new(Ctr::Bool(true)), Box::new(Ctr::None));
|
||||
|
||||
syms.insert(String::from("test_inner"), inner_func);
|
||||
syms.insert(String::from("test_outer"), outer_func);
|
||||
|
|
@ -196,10 +190,7 @@ mod func_tests {
|
|||
},
|
||||
)),
|
||||
};
|
||||
let args = Seg::from(
|
||||
Box::new(Ctr::Integer(1)),
|
||||
Box::new(Ctr::None)
|
||||
);
|
||||
let args = Seg::from(Box::new(Ctr::Integer(1)), Box::new(Ctr::None));
|
||||
|
||||
syms.insert(String::from("test_func_in"), test_internal_func);
|
||||
|
||||
|
|
@ -221,7 +212,7 @@ mod func_tests {
|
|||
name: String::from("echo"),
|
||||
conditional_branches: false,
|
||||
args: Args::Lazy(1),
|
||||
value: ValueType::FuncForm(UserFn{
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
arg_syms: vec!["input".to_string()],
|
||||
ast: finner,
|
||||
}),
|
||||
|
|
@ -229,7 +220,7 @@ mod func_tests {
|
|||
|
||||
let args = Seg::from(
|
||||
Box::new(Ctr::String("test".to_string())),
|
||||
Box::new(Ctr::Seg(Seg::from_mono(Box::new(Ctr::Integer(1)))))
|
||||
Box::new(Ctr::Seg(Seg::from_mono(Box::new(Ctr::Integer(1))))),
|
||||
);
|
||||
|
||||
syms.insert(String::from("test_func_in"), test_external_func);
|
||||
|
|
@ -254,7 +245,7 @@ mod func_tests {
|
|||
name: String::from("echo"),
|
||||
conditional_branches: false,
|
||||
args: Args::Lazy(1),
|
||||
value: ValueType::FuncForm(UserFn{
|
||||
value: ValueType::FuncForm(UserFn {
|
||||
arg_syms: vec!["input".to_string()],
|
||||
ast: finner,
|
||||
}),
|
||||
|
|
@ -293,13 +284,16 @@ mod func_tests {
|
|||
};
|
||||
let args = Seg::from(
|
||||
Box::new(Ctr::Symbol("undefined-symbol".to_string())),
|
||||
Box::new(Ctr::None)
|
||||
Box::new(Ctr::None),
|
||||
);
|
||||
|
||||
syms.insert(String::from("test_func_in"), test_internal_func);
|
||||
|
||||
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
|
||||
assert_eq!(s, "error in call to undefined-symbol: undefined symbol: undefined-symbol");
|
||||
assert_eq!(
|
||||
s,
|
||||
"error in call to undefined-symbol: undefined symbol: undefined-symbol"
|
||||
);
|
||||
} else {
|
||||
print!("call to function succeeded (shouldnt have)");
|
||||
assert!(false);
|
||||
|
|
|
|||
|
|
@ -133,7 +133,8 @@ mod lex_tests {
|
|||
|
||||
#[test]
|
||||
fn test_postline_comment() {
|
||||
let document = String::from("#!/bin/relish\n((one two)# another doc comment\n(three four))");
|
||||
let document =
|
||||
String::from("#!/bin/relish\n((one two)# another doc comment\n(three four))");
|
||||
let output: &str = "((one two) (three four))";
|
||||
match lex(&document) {
|
||||
Ok(tree) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
mod append_lib_tests {
|
||||
use relish::ast::{Ctr, eval, lex, SymTable};
|
||||
use relish::stdlib::{static_stdlib, dynamic_stdlib};
|
||||
use relish::ast::{eval, lex, Ctr, SymTable};
|
||||
use relish::stdlib::{dynamic_stdlib, static_stdlib};
|
||||
|
||||
#[test]
|
||||
fn test_append_to_empty_list() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
mod control_lib_tests {
|
||||
use relish::ast::{Ctr, eval, lex, SymTable};
|
||||
use relish::stdlib::{static_stdlib, dynamic_stdlib};
|
||||
use relish::ast::{eval, lex, Ctr, SymTable};
|
||||
use relish::stdlib::{dynamic_stdlib, static_stdlib};
|
||||
|
||||
#[test]
|
||||
fn test_if_first_case_singlet() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
mod var_lib_tests {
|
||||
use relish::ast::{eval, lex, SymTable, Ctr};
|
||||
use relish::stdlib::{static_stdlib, dynamic_stdlib};
|
||||
use relish::ast::{eval, lex, Ctr, SymTable};
|
||||
use relish::stdlib::{dynamic_stdlib, static_stdlib};
|
||||
|
||||
#[test]
|
||||
fn test_variable_def_and_lookup() {
|
||||
|
|
@ -134,7 +134,10 @@ mod var_lib_tests {
|
|||
println!("tree: {tree}");
|
||||
let eval_result = eval(&tree, &mut syms);
|
||||
if let Err(s) = eval_result {
|
||||
assert_eq!(s.to_string(), "error in call to test: undefined symbol: test".to_string());
|
||||
assert_eq!(
|
||||
s.to_string(),
|
||||
"error in call to test: undefined symbol: test".to_string()
|
||||
);
|
||||
} else {
|
||||
let res = eval_result.unwrap();
|
||||
eprintln!("shouldn't have suceeded: {res}");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue