diff --git a/Readme.org b/Readme.org
index 1e46b2b..1596c93 100644
--- a/Readme.org
+++ b/Readme.org
@@ -101,16 +101,16 @@ This contains any executable target of this project. Notably the main shell file
* Current Status / TODO list
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer
*** TODO Rudimentary Control Flow
-**** TODO if clause
+**** DONE if clause
**** TODO loop clause
**** TODO while clause
**** TODO circuit clause
*** TODO Configuration
-**** TODO get_stdlibphase1 -> configuration -> get_stdlibphase2
-**** TODO Function to load configuration into Variable and Function tables
-**** TODO Configure in main shell
-**** TODO manual verification of config settings
-**** TODO manual verification of config defaults
+**** DONE get_stdlibphase1 -> configuration -> get_stdlibphase2
+**** DONE Function to load configuration into Variable and Function tables
+**** DONE Configure in main shell
+**** DONE manual verification of config settings
+**** DONE manual verification of config defaults
*** TODO Help function
*** TODO Env function
*** TODO User variable declaration tests
@@ -122,26 +122,30 @@ Will need a concatenate function for func tables
*** TODO Main shell calls Load function on arg and exits
*** TODO Custom error printing
*** TODO Custom ast pretty print
-*** TODO STDLIB
*** TODO Shell module
**** TODO Process launching with environment variables
**** TODO Foreground process TTY
**** TODO Background processes
-**** TODO append
-**** TODO string operations
-***** TODO concatenate
-***** TODO substr by index
-***** TODO tokenize by delimiter
-***** TODO sprintf / string build
-**** TODO arithmetic operations
-***** TODO
-**** TODO Serialize/Deserialize basic data types
-**** TODO file opterations
-***** TODO
-**** TODO Network library
-***** TODO HTTP Client
-***** TODO TCP Stream client
-***** TODO UDP Client
-***** TODO TCP Listener
-***** TODO HTTP Listener
-***** TODO UDP Listener
+**** DONE append
+*** TODO string operations
+**** TODO concatenate
+**** TODO substr by index
+**** TODO tokenize by delimiter
+**** TODO sprintf / string build
+*** TODO arithmetic operations
+**** TODO add
+**** TODO sub
+**** TODO div
+**** TODO mul
+**** TODO exp
+**** TODO mod
+*** TODO file operations
+**** TODO read-to-string
+**** TODO write-to-file
+*** TODO Network library
+**** TODO HTTP Client
+**** TODO TCP Stream client
+**** TODO UDP Client
+**** TODO TCP Listener
+**** TODO HTTP Listener
+**** TODO UDP Listener
diff --git a/src/bin/main.rs b/src/bin/main.rs
new file mode 100644
index 0000000..e16bdf8
--- /dev/null
+++ b/src/bin/main.rs
@@ -0,0 +1,90 @@
+/* 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 dirs::home_dir;
+use relish::ast::{eval, lex, Ctr, Seg, SymTable};
+use relish::stdlib::{static_stdlib, dynamic_stdlib};
+use relish::aux::configure;
+use rustyline::error::ReadlineError;
+use rustyline::Editor;
+use std::env;
+
+fn main() {
+ let mut rl = Editor::<()>::new();
+
+ const HIST_FILE: &str = "/.relish_hist";
+ const CONFIG_FILE_DEFAULT: &str = "/.relishrc";
+
+ let home_dir = home_dir().unwrap().to_str().unwrap().to_owned();
+ let hist_file_name = home_dir.clone() + HIST_FILE;
+ let cfg_file_name = home_dir + CONFIG_FILE_DEFAULT;
+
+ if !hist_file_name.is_empty() {
+ rl.load_history(&hist_file_name)
+ .unwrap_or_else(|err: ReadlineError| eprintln!("{}", err));
+ }
+
+ 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
+ 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));
+ }
+ 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)
+ .unwrap_or_else(|err: String| {
+ eprintln!("{}", err);
+ Box::new(Ctr::String("".to_string()))
+ });
+ let readline_prompt = s.to_string();
+
+ let user_doc = rl.readline(&readline_prompt);
+ match user_doc {
+ Ok(line) => {
+ rl.add_history_entry(line.as_str());
+ let l = line.as_str().to_owned();
+ match lex(&l) {
+ Ok(a) => match eval(&a, &mut syms) {
+ Ok(a) => println!("{}", a),
+ Err(s) => println!("{}", s),
+ },
+ Err(s) => println!("{}", s),
+ }
+ }
+
+ Err(ReadlineError::Interrupted) => break,
+ Err(ReadlineError::Eof) => return,
+ Err(err) => {
+ eprintln!("Prompt error: {:?}", err);
+ break;
+ }
+ }
+ }
+ if !hist_file_name.is_empty() {
+ rl.save_history(&hist_file_name).unwrap();
+ }
+}
diff --git a/src/config.rs b/src/config.rs
index b0af11d..02fc6aa 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,78 +16,44 @@
*/
use crate::eval::eval;
-use crate::func::{func_declare, Args, FTable, Function, Operation};
use crate::lex::lex;
-use crate::segment::{Ast, Ctr};
-use crate::stl::get_stdlib;
-use crate::vars::{define, VTable};
-use std::cell::RefCell;
+use crate::segment::{Seg, Ctr};
+use crate::sym::{SymTable, ValueType, Args, Symbol};
use std::fs;
-use std::io::{self, Write};
+use std::io;
use std::rc::Rc;
-fn prompt_default_callback(_: Ast, _: Rc>, _: Rc>) -> Ctr {
- return Ctr::String("λ ".to_string());
+fn prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result {
+ Ok(Ctr::String("λ ".to_string()))
}
-pub fn configure(filename: String, vars: Rc>) -> Result>, String> {
- let funcs;
+/* loads defaults, evaluates config script */
+pub fn configure(filename: String, syms: &mut SymTable) -> Result<(), String> {
+ 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()))),
+ });
- define(
- vars.clone(),
- String::from("CFG_RELISH_POSIX"),
- Rc::new(Ctr::String(String::from("0"))),
- );
- define(
- vars.clone(),
- String::from("CFG_RELISH_ENV"),
- Rc::new(Ctr::String(String::from("1"))),
- );
+ 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()))),
+ });
- match get_stdlib(vars.clone()) {
- Ok(f) => funcs = f,
- Err(s) => {
- funcs = Rc::new(RefCell::new(FTable::new()));
- println!("Couldnt get stdlib: {}", s)
- },
- }
+ 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)),
+ });
- match func_declare(
- funcs.clone(),
- Rc::new(RefCell::new(Function {
- name: String::from("CFG_RELISH_PROMPT"),
- loose_syms: false,
- eval_lazy: false,
- args: Args::Lazy(0),
- function: Operation::Internal(Box::new(prompt_default_callback)),
- })),
- ) {
- Some(e) => return Err(e),
- None => {},
- }
+ 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)?;
- match fs::read_to_string(filename.clone()) {
- Err(s) => {
- return Err(format!("Couldnt open configuration file: {}", s));
- }
-
- Ok(raw_config) => {
- let mut l = raw_config;
- l = "(".to_owned() + &l + ")";
-
- match lex(l) {
- Err(s) => {
- return Err(format!("Error in configuration: {}", s));
- }
-
- Ok(config) => {
- if let Err(errst) = eval(config, vars, funcs.clone(), false) {
- return Err(format!("Error loading {}: {}", filename.clone(), errst));
- }
- }
- }
- },
- }
-
- return Ok(funcs);
+ println!("config result: {config_result}");
+ Ok(())
}
diff --git a/src/lex.rs b/src/lex.rs
index a8d4bf7..af2f7ea 100644
--- a/src/lex.rs
+++ b/src/lex.rs
@@ -200,26 +200,24 @@ fn process(document: &String) -> Result, String> {
if is_str {
Err(UNMATCHED_STR_DELIM.to_string())
- } else {
- if ref_stack.is_empty() {
- let obj;
- if token == "true" {
- obj = Box::from(Ctr::Bool(true));
- } else if token == "false" {
- obj = Box::from(Ctr::Bool(false));
- } else if let Ok(i) = token.parse::() {
- obj = Box::from(Ctr::Integer(i));
- } else if let Ok(f) = token.parse::() {
- obj = Box::from(Ctr::Float(f));
- } else if let Some(s) = tok_is_symbol(&token) {
- obj = Box::from(Ctr::Symbol(s));
- } else {
- return Err(format!("Unparsable token: {}", token));
- }
- Ok(Box::new(Seg::from_mono(obj)))
+ } else if ref_stack.is_empty() {
+ let obj;
+ if token == "true" {
+ obj = Box::from(Ctr::Bool(true));
+ } else if token == "false" {
+ obj = Box::from(Ctr::Bool(false));
+ } else if let Ok(i) = token.parse::() {
+ obj = Box::from(Ctr::Integer(i));
+ } else if let Ok(f) = token.parse::() {
+ obj = Box::from(Ctr::Float(f));
+ } else if let Some(s) = tok_is_symbol(&token) {
+ obj = Box::from(Ctr::Symbol(s));
} else {
- Err(UNMATCHED_LIST_DELIM.to_string())
+ return Err(format!("Unparsable token: {}", token));
}
+ Ok(Box::new(Seg::from_mono(obj)))
+ } else {
+ Err(UNMATCHED_LIST_DELIM.to_string())
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 4dfaebe..4047f99 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,7 +16,7 @@
*/
-//mod config;
+mod config;
mod eval;
mod lex;
mod segment;
@@ -37,6 +37,6 @@ pub mod stdlib {
pub use crate::stl::{static_stdlib, dynamic_stdlib};
}
-/*pub mod aux {
+pub mod aux {
pub use crate::config::configure;
-}*/
+}
diff --git a/src/stl.rs b/src/stl.rs
index 7f3290e..09930ba 100644
--- a/src/stl.rs
+++ b/src/stl.rs
@@ -56,13 +56,20 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
/// dynamic_stdlib
/// takes configuration data and uses it to insert dynamic
/// callbacks with configuration into a symtable
-pub fn dynamic_stdlib(env: bool, syms: &mut SymTable) -> Result<(), String> {
+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)
+ .unwrap_or_else(|_: String| Box::new(Ctr::None))
+ .to_string()
+ .ne("");
+
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 {
- _store_callback(ast, syms, env)
+ _store_callback(ast, syms, env_cfg_user_form)
},
)),
});
diff --git a/tests/test_lib_append.rs b/tests/test_lib_append.rs
index 24f7591..5260fb0 100644
--- a/tests/test_lib_append.rs
+++ b/tests/test_lib_append.rs
@@ -9,7 +9,7 @@ mod append_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
@@ -27,7 +27,7 @@ mod append_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
@@ -45,7 +45,7 @@ mod append_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
@@ -63,7 +63,7 @@ mod append_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
@@ -81,7 +81,7 @@ mod append_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref s) = *eval(&tree, &mut syms).unwrap() {
diff --git a/tests/test_lib_control.rs b/tests/test_lib_control.rs
index 7a1a4c1..9212b91 100644
--- a/tests/test_lib_control.rs
+++ b/tests/test_lib_control.rs
@@ -9,7 +9,7 @@ mod control_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Integer(i) = *eval(&tree, &mut syms).unwrap() {
@@ -29,7 +29,7 @@ mod control_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Integer(i) = *eval(&tree, &mut syms).unwrap() {
@@ -50,7 +50,7 @@ mod control_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
diff --git a/tests/test_vars.rs b/tests/test_vars.rs
index ce4041f..7d2f95f 100644
--- a/tests/test_vars.rs
+++ b/tests/test_vars.rs
@@ -10,7 +10,7 @@ mod var_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&doc1.to_string()) {
let eval_result = *eval(&tree, &mut syms).unwrap();
@@ -49,7 +49,7 @@ mod var_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&doc1.to_string()) {
let eval_result = *eval(&tree, &mut syms).unwrap();
@@ -101,7 +101,7 @@ mod var_lib_tests {
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
- dynamic_stdlib(false, &mut syms).unwrap();
+ dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&doc1.to_string()) {
let eval_result = *eval(&tree, &mut syms).unwrap();