diff --git a/src/bin/main.rs b/src/bin/main.rs
new file mode 100644
index 0000000..7a8e0a8
--- /dev/null
+++ b/src/bin/main.rs
@@ -0,0 +1,100 @@
+/* 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 rustyline::error::ReadlineError;
+use rustyline::Editor;
+use dirs::home_dir;
+use std::rc::Rc;
+use std::cell::RefCell;
+use relish::ast::{VTable, FTable, Ctr, lex, eval, ast_to_string};
+use relish::stdlib::{get_stdlib};
+
+fn main() {
+ let mut rl = Editor::<()>::new();
+
+ const HIST_FILE: &str = ".relish_hist";
+ //const CONFIG_FILE: &str = ".relishrc";
+
+ let mut hist: String = "".to_owned();
+
+ if let Some(home) = home_dir() {
+ if let Some(h) = home.to_str() {
+ hist = h.to_owned() + HIST_FILE;
+ }
+ }
+
+ if hist != "" {
+ // ignore result. it loads or it doesnt.
+ let _ = rl.load_history(&hist);
+ }
+
+ let mut vt = Rc::new(RefCell::new(VTable::new()));
+ // if we fail to get stdlib we can just use this one
+ let mut ft = Rc::new(RefCell::new(FTable::new()));
+ match get_stdlib() {
+ Ok(f) => ft = f,
+ Err(s) => println!("{}", s)
+ }
+
+ loop {
+ // todo: configurable prompt
+ let readline = rl.readline("λ ");
+ match readline {
+ Ok(line) => {
+ rl.add_history_entry(line.as_str());
+ match lex(line.as_str().to_owned()) {
+ Ok(a) => {
+ match eval(a.clone(), vt.clone(), ft.clone(), false) {
+ Ok(a) => {
+ match a {
+ Ctr::Symbol(s) => println!("{}", s),
+ Ctr::String(s) => println!("{}", s),
+ Ctr::Integer(i) => println!("{}", i),
+ Ctr::Float(f) => println!("{}", f),
+ Ctr::Bool(b) => println!("{}", b),
+ Ctr::Seg(c) => println!("{}", ast_to_string(c.clone())),
+ Ctr::None => ()
+ }
+ },
+ Err(s) => {
+ println!("{}", s);
+ }
+ }
+ },
+ Err(s) => {
+ println!("{}", s);
+ }
+ }
+ },
+
+ Err(ReadlineError::Interrupted) => {
+ break
+ },
+
+ Err(ReadlineError::Eof) => {
+ return
+ },
+ Err(err) => {
+ println!("Prompt error: {:?}", err);
+ break
+ }
+ }
+ }
+ if hist != "" {
+ rl.save_history(&hist).unwrap();
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 9c4bc73..c441a1e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,6 +20,8 @@ mod lex;
mod func;
mod eval;
mod vars;
+mod stl;
+mod str;
pub mod ast {
pub use crate::segment::{Seg, Ctr, ast_to_string, Type, Ast, new_ast};
@@ -30,3 +32,8 @@ pub mod ast {
pub use crate::vars::{VTable, define};
pub use crate::eval::eval;
}
+
+pub mod stdlib {
+ pub use crate::stl::{get_stdlib};
+ pub use crate::str::{get_echo};
+}
diff --git a/src/stl.rs b/src/stl.rs
new file mode 100644
index 0000000..0ffeed6
--- /dev/null
+++ b/src/stl.rs
@@ -0,0 +1,29 @@
+/* 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::str::get_echo;
+use crate::func::{FTable, func_declare};
+use std::rc::Rc;
+use std::cell::RefCell;
+
+pub fn get_stdlib() -> Result>, String> {
+ let ft = Rc::new(RefCell::new(FTable::new()));
+ if let Some(s) = func_declare(ft.clone(), Rc::new(RefCell::new(get_echo()))) {
+ return Err(s)
+ }
+
+ return Ok(ft)
+}
diff --git a/src/str.rs b/src/str.rs
new file mode 100644
index 0000000..6969ece
--- /dev/null
+++ b/src/str.rs
@@ -0,0 +1,55 @@
+/* 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::func::{FTable, Function, Args, Operation};
+use crate::vars::{VTable};
+use crate::segment::{Ctr, Ast, circuit, ast_as_string};
+use std::rc::Rc;
+use std::cell::RefCell;
+
+pub fn get_echo() -> Function {
+ return Function{
+ name: String::from("echo"),
+ loose_syms: false,
+ eval_lazy: false,
+ args: Args::Lazy(-1),
+ function: Operation::Internal(
+ |a: Ast, _b: Rc>, _c: Rc>| -> Ctr {
+ let mut string = String::from("echo");
+ if !circuit(a, &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(ast_as_string(c.clone(), true).as_str()),
+ Ctr::None => ()
+ }
+
+ return true;
+ }) {
+ // TODO: use custom logger
+ println!("Echo failure!")
+ }
+
+ return Ctr::String(string);
+ }
+ )
+ };
+}