This MR finishes up all remaining Pre V1 goals

* add a posix exit() builtin
* improve separation of concerns regarding standard library structure
This commit is contained in:
Ava Apples Affine 2023-05-25 23:08:44 +00:00
parent b3c0b80ee6
commit 3bbea6bea0
9 changed files with 753 additions and 752 deletions

View file

@ -19,12 +19,12 @@ use crate::eval::eval;
use crate::error::{Traceback, start_trace};
use crate::segment::{Ctr, Seg, Type};
use crate::stdlib::{CONSOLE_XDIM_VNAME, RELISH_DEFAULT_CONS_WIDTH};
use crate::sym::{SymTable, Symbol, UserFn, ValueType};
use crate::sym::{SymTable, Symbol, UserFn, ValueType, Args};
use std::env;
use std::rc::Rc;
pub const QUOTE_DOCSTRING: &str = "takes a single unevaluated tree and returns it as it is: unevaluated.";
pub fn quote_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
const QUOTE_DOCSTRING: &str = "takes a single unevaluated tree and returns it as it is: unevaluated.";
fn quote_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
if ast.len() > 1 {
Err(start_trace(("quote", "do not quote more than one thing at a time").into()))
} else {
@ -32,12 +32,11 @@ pub fn quote_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback>
}
}
pub const EVAL_DOCSTRING: &str = "takes an unevaluated argument and evaluates it.
const EVAL_DOCSTRING: &str = "takes an unevaluated argument and evaluates it.
Specifically, does one pass of the tree simplification algorithm.
If you have a variable referencing another variable you will get the
referenced variable.";
pub fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
if ast.len() > 1 {
Err(start_trace(
("eval", "do not eval more than one thing at a time")
@ -96,9 +95,8 @@ pub fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const HELP_DOCSTRING: &str = "prints help text for a given symbol. Expects only one argument.";
pub fn help_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
const HELP_DOCSTRING: &str = "prints help text for a given symbol. Expects only one argument.";
fn help_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
if ast.len() != 1 {
return Err(start_trace(("help", "expected one input").into()));
}
@ -129,10 +127,9 @@ CURRENT VALUE AND/OR BODY:
Ok(Ctr::None)
}
pub const ISSET_DOCSTRING: &str = "accepts a single argument: a symbol.
const ISSET_DOCSTRING: &str = "accepts a single argument: a symbol.
returns true or false according to whether or not the symbol is found in the symbol table.";
pub fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
if ast.len() != 1 {
Err(start_trace(("set?", "expcted one input").into()))
} else {
@ -148,10 +145,9 @@ pub fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
}
}
pub const ENV_DOCSTRING: &str = "takes no arguments
const ENV_DOCSTRING: &str = "takes no arguments
prints out all available symbols and their associated values";
pub fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
// get width of current output
let xdim: i128;
if let Ctr::Integer(dim) = *syms
@ -226,7 +222,7 @@ pub fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
Ok(Ctr::None)
}
pub const LAMBDA_DOCSTRING: &str = "Takes two arguments of any type.
const LAMBDA_DOCSTRING: &str = "Takes two arguments of any type.
No args are evaluated when lambda is called.
Lambda makes sure the first argument is a list of symbols (or 'arguments') to the lambda function.
The next arg is stored in a tree to evaluate on demand.
@ -236,8 +232,7 @@ This can then be evaluated like so:
((lambda (x y) (add x y)) 1 2)
which is functionally equivalent to:
(add 1 2)";
pub fn lambda_callback(
fn lambda_callback(
ast: &Seg,
_syms: &mut SymTable
) -> Result<Ctr, Traceback> {
@ -274,13 +269,12 @@ pub fn lambda_callback(
}
}
pub const GETDOC_DOCSTRING: &str = "accepts an unevaluated symbol, returns the doc string.
const GETDOC_DOCSTRING: &str = "accepts an unevaluated symbol, returns the doc string.
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, Traceback> {
fn getdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
if let Ctr::Symbol(ref symbol) = *ast.car {
if let Some(sym) = syms.get(symbol) {
Ok(Ctr::String(sym.docs.clone()))
@ -292,13 +286,12 @@ pub fn getdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
}
}
pub const SETDOC_DOCSTRING: &str = "accepts a symbol and a doc string.
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.
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, Traceback> {
fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
if ast.len() != 2 {
Err(start_trace(
("set-doc", "expected two inputs")
@ -336,7 +329,7 @@ pub fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
}
}
pub const STORE_DOCSTRING: &str = "allows user to define functions and variables.
const STORE_DOCSTRING: &str = "allows user to define functions and variables.
A call may take one of three forms:
1. variable declaration:
Takes a name, doc string, and a value.
@ -351,9 +344,7 @@ pub const STORE_DOCSTRING: &str = "allows user to define functions and variables
Additionally, passing a tree as a name will trigger def to evaluate the tree and try to derive
a value from it. If it does not return a ";
pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr, Traceback> {
fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr, Traceback> {
let is_var = ast.len() == 3;
let name: String;
let docs: String;
@ -509,3 +500,131 @@ pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<C
.into()))
}
}
pub fn add_decl_lib_static(syms: &mut SymTable) {
syms.insert(
"help".to_string(),
Symbol {
name: String::from("help"),
args: Args::Strict(vec![Type::Symbol]),
conditional_branches: true,
docs: HELP_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(help_callback)),
..Default::default()
},
);
syms.insert(
"set?".to_string(),
Symbol {
name: String::from("set?"),
args: Args::Strict(vec![Type::Symbol]),
conditional_branches: true,
docs: ISSET_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(isset_callback)),
..Default::default()
},
);
syms.insert(
"env".to_string(),
Symbol {
name: String::from("env"),
args: Args::None,
conditional_branches: false,
docs: ENV_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(env_callback)),
..Default::default()
},
);
syms.insert(
"quote".to_string(),
Symbol {
name: String::from("quote"),
args: Args::Lazy(1),
conditional_branches: true,
docs: QUOTE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(quote_callback)),
..Default::default()
},
);
syms.insert(
"q".to_string(),
Symbol {
name: String::from("quote"),
args: Args::Lazy(1),
conditional_branches: true,
docs: QUOTE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(quote_callback)),
..Default::default()
},
);
syms.insert(
"eval".to_string(),
Symbol {
name: String::from("eval"),
args: Args::Lazy(1),
conditional_branches: true,
docs: EVAL_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(eval_callback)),
..Default::default()
},
);
syms.insert(
"lambda".to_string(),
Symbol {
name: String::from("lambda"),
args: Args::Lazy(2),
conditional_branches: true,
docs: LAMBDA_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(lambda_callback)),
..Default::default()
}
);
syms.insert(
"get-doc".to_string(),
Symbol {
name: String::from("get-doc"),
args: Args::Strict(vec![Type::Symbol]),
conditional_branches: false,
docs: GETDOC_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(getdoc_callback)),
..Default::default()
}
);
syms.insert(
"set-doc".to_string(),
Symbol {
name: String::from("get-doc"),
args: Args::Strict(vec![Type::Symbol, Type::String]),
conditional_branches: false,
docs: SETDOC_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(setdoc_callback)),
..Default::default()
}
);
}
pub fn add_decl_lib_dynamic(syms: &mut SymTable, env: bool) {
syms.insert(
"def".to_string(),
Symbol {
name: String::from("define"),
args: Args::Infinite,
conditional_branches: true,
docs: STORE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(
move |ast: &Seg, syms: &mut SymTable| -> Result<Ctr, Traceback> {
store_callback(ast, syms, env)
},
)),
..Default::default()
},
);
}