Added USERLIB with prepend and set.

Added a q shortcut to quote
get-doc and set-doc no longer conditionally evaluate args
Fixed bug in let, documented potential performance improvements
upped default history to 5k lines
This commit is contained in:
Ava Apples Affine 2023-03-17 13:06:27 -07:00
parent a01df6b7b2
commit 1ee9ba55fb
Signed by: affine
GPG key ID: 3A4645B8CF806069
7 changed files with 70 additions and 25 deletions

View file

@ -470,8 +470,6 @@ This contains any executable target of this project. Notably the main shell file
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer.
Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered.
*** TODO Symbols defined within let by def statements must be pulled out and made global
*** TODO Def must eval args for symbol and doc
*** TODO Shell prompt is fully configurable (L, R, and Delim)
*** TODO Load (load a script) function
Pull/Refactor the logic out of the configure functions.

30
snippets/userlib.rls Normal file
View file

@ -0,0 +1,30 @@
;; 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/>.
;;
;; USERLIB
;; This file contains a plethora of useful features that are not shipped in the STL
(def prepend
'takes a list and appends an element to the back of it.
returns prepended list'
(elem list)
(reverse (append (reverse list) elem)))
(def set
'sets an existing variable without touching its docstring'
(var val)
(let ((doc (get-doc var)))
(def (eval var) doc val)))

View file

@ -78,7 +78,7 @@ fn main() -> ! {
let mut rl = Reedline::create();
let maybe_hist: Box<FileBackedHistory>;
if !hist_file_name.is_empty() {
maybe_hist = Box::new(FileBackedHistory::with_file(5, hist_file_name.into())
maybe_hist = Box::new(FileBackedHistory::with_file(5000, hist_file_name.into())
.expect("error reading history!"));
rl = rl.with_history(maybe_hist);
}

View file

@ -481,6 +481,17 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
},
);
syms.insert(
"q".to_string(),
Symbol {
name: String::from("quote"),
args: Args::Lazy(1),
conditional_branches: true,
docs: decl::QUOTE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(decl::quote_callback)),
},
);
syms.insert(
"eval".to_string(),
Symbol {
@ -507,8 +518,8 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
"get-doc".to_string(),
Symbol {
name: String::from("get-doc"),
args: Args::Lazy(1),
conditional_branches: true,
args: Args::Strict(vec![Type::Symbol]),
conditional_branches: false,
docs: decl::GETDOC_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(decl::getdoc_callback)),
}
@ -518,8 +529,8 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
"set-doc".to_string(),
Symbol {
name: String::from("get-doc"),
args: Args::Lazy(2),
conditional_branches: true,
args: Args::Strict(vec![Type::Symbol, Type::String]),
conditional_branches: false,
docs: decl::SETDOC_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(decl::setdoc_callback)),
}

View file

@ -205,8 +205,13 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
// we need to get any var declared from within the let eval forms
// those need to exist in the outside context
// TODO: make this more optimal
// How can we skip iterations?
// implement a counter for number of calls to def
// store it inside the SymTable and Symbol
// only re-insert into global scope what is most recent
for i in localsyms.iter() {
if !locals.contains(i.0) && !syms.contains_key(i.0) {
if !locals.contains(i.0) {
syms.insert(
i.0.clone(),
i.1.clone(),

View file

@ -69,7 +69,7 @@ pub fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
}
},
_ => Ok(arguments)
}*/
}*/
}
}
@ -195,27 +195,28 @@ pub fn lambda_callback(
}
pub const GETDOC_DOCSTRING: &str = "accepts an unevaluated symbol, returns the doc string.
Returns an error if symbol is undefined";
Returns an error if symbol is undefined.
Note: make sure to quote the input like this:
(get-doc (quote symbol-name))";
pub fn getdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
if ast.len() != 1 {
Err("get-doc only takes a single argument".to_string())
} else {
if let Ctr::Symbol(ref symbol) = *ast.car {
if let Some(sym) = syms.get(symbol) {
Ok(Ctr::String(sym.docs.clone()))
} else {
Err("undefined symbol".to_string())
}
if let Ctr::Symbol(ref symbol) = *ast.car {
if let Some(sym) = syms.get(symbol) {
Ok(Ctr::String(sym.docs.clone()))
} else {
Err("get-doc should only be called on a symbol".to_string())
Err("undefined symbol".to_string())
}
} else {
Err("get-doc should only be called on a symbol".to_string())
}
}
pub const SETDOC_DOCSTRING: &str = "accepts a symbol and a doc string.
Returns an error if symbol is undefined, otherwise sets the symbols docstring to the argument.";
Returns an error if symbol is undefined, otherwise sets the symbols docstring to the argument.
Note: make sure to quote the input like this:
(set-doc (quote symbol-name) my-new-docs)";
pub fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
if ast.len() != 2 {

View file

@ -112,7 +112,7 @@ mod decl_lib_tests {
let doc1 = "(def test-doc 'docs for test' 'test tests tests test')";
let doc2 = "(def test test-doc 'one')";
let doc3 = "(eq? (and
(eq? (get-doc test) test-doc)
(eq? (get-doc (quote test)) test-doc)
(eq? test 'one')))";
let mut syms = SymTable::new();
@ -337,8 +337,8 @@ mod decl_lib_tests {
#[test]
fn test_setget_doc_string() {
let highly_inadvisable = "(set-doc help 'help')";
let document = "(get-doc help)";
let highly_inadvisable = "(set-doc (q help) 'help')";
let document = "(get-doc (q help))";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();