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

@ -15,8 +15,9 @@
*/
use crate::segment::{Ctr, Seg};
use crate::sym::{SymTable, ValueType};
use crate::sym::{SymTable, ValueType, Symbol, Args};
use crate::error::{Traceback, start_trace};
use std::rc::Rc;
fn isnumeric(arg: &Ctr) -> bool {
match arg {
@ -26,12 +27,11 @@ fn isnumeric(arg: &Ctr) -> bool {
}
}
pub const ADD_DOCSTRING: &str =
const ADD_DOCSTRING: &str =
"traverses over N args, which must all evaluate to an Integer or Float.
Adds each arg up to a final result. WARNING: does not acocunt for under/overflows.
Consult source code for a better understanding of how extreme values will be handled.";
pub fn add_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn add_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
let mut res = Ctr::Integer(0);
let mut culprit: Ctr = Ctr::None;
let type_consistent = ast.circuit(&mut |c: &Ctr| -> bool {
@ -53,11 +53,10 @@ pub fn add_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const SUB_DOCSTRING: &str = "traverses over N args, which must all evaluate to an Integer or Float.
const SUB_DOCSTRING: &str = "traverses over N args, which must all evaluate to an Integer or Float.
Subtracts each arg from the first leading to a final result. WARNING: does not acocunt for under/overflows.
Consult source code for a better understanding of how extreme values will be handled.";
pub fn sub_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn sub_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
if !isnumeric(ast.car.as_ref()) {
return Err(start_trace(
("sub", format!("{} is not a number!", ast.car.as_ref()))
@ -91,11 +90,10 @@ pub fn sub_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const DIV_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
const DIV_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
divides arg1 by arg2. WARNING: does not acocunt for under/overflows or float precision.
Consult source code for a better understanding of how extreme values will be handled.";
pub fn div_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn div_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
let first = *ast.car.clone();
if !isnumeric(&first) {
return Err(start_trace(
@ -118,12 +116,11 @@ pub fn div_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const MUL_DOCSTRING: &str =
const MUL_DOCSTRING: &str =
"traverses over N args, which must all evaluate to an Integer or Float.
Multiplies each arg up to a final result. WARNING: does not acocunt for under/overflows.
Consult source code for a better understanding of how extreme values will be handled.";
pub fn mul_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn mul_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
let mut res = Ctr::Integer(1);
let mut culprit: Ctr = Ctr::None;
let type_consistent = ast.circuit(&mut |c: &Ctr| -> bool {
@ -145,12 +142,11 @@ pub fn mul_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const INTCAST_DOCSTRING: &str = "takes a single arg and attempts to cast it to an Integer.
const INTCAST_DOCSTRING: &str = "takes a single arg and attempts to cast it to an Integer.
This will work for a float or a potentially a string.
If the cast to Integer fails, it will return Nothing and print an error.
Casting a float to an int will drop its decimal.";
pub fn intcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn intcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
// special case for float
if let Ctr::Float(f) = *ast.car {
Ok(Ctr::Integer(f as i128))
@ -170,12 +166,11 @@ pub fn intcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const FLOATCAST_DOCSTRING: &str = "takes a single arg and attempts to cast it to a float.
const FLOATCAST_DOCSTRING: &str = "takes a single arg and attempts to cast it to a float.
This will work for an integer or potentially a string.
If the cast to integer fails, this function will return nothing and print an error.
Casting an integer to a float can result in bad behaviour since float nodes are based on 64bit floats and int nodes are based on 128 bit integers.";
pub fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
// special case for float
if let Ctr::Integer(i) = *ast.car {
Ok(Ctr::Float(i as f64))
@ -195,7 +190,7 @@ pub fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback>
}
}
pub const EXP_DOCSTRING: &str = "Takes two args, both expected to be numeric.
const EXP_DOCSTRING: &str = "Takes two args, both expected to be numeric.
Returns the first arg to the power of the second arg.
Does not handle overflow or underflow.
@ -203,8 +198,7 @@ PANIC CASES:
- arg1 is a float and arg2 is greater than an int32
- an integer exceeding the size of a float64 is raised to a float power
- an integer is rased to the power of another integer exceeding the max size of an unsigned 32bit integer";
pub fn exp_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn exp_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
let first = *ast.car.clone();
if !isnumeric(&first) {
return Err(start_trace(
@ -247,7 +241,7 @@ pub fn exp_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const MOD_DOCSTRING: &str = "Takes two args, both expected to be numeric.
const MOD_DOCSTRING: &str = "Takes two args, both expected to be numeric.
Returns a list of two values: the modulus and the remainder.
Example: (mod 5 3) -> (1 2)
@ -255,8 +249,7 @@ PANIC CASES:
- A float is modulo an integer larger than a max f64
- An integer larger than a max f64 is modulo a float
";
pub fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
let first = *ast.car.clone();
if !isnumeric(&first) {
return Err(start_trace(
@ -315,11 +308,10 @@ pub fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
Ok(Ctr::Seg(ret))
}
pub const ISGT_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
const ISGT_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
Returns true or false according to whether the first argument is bigger than the second argument.
May panic if an integer larger than a max f64 is compared to a float.";
pub fn isgt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn isgt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
let first = *ast.car.clone();
if !isnumeric(&first) {
return Err(start_trace(
@ -361,11 +353,10 @@ pub fn isgt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const ISLT_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
const ISLT_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
Returns true or false according to whether the first argument is smaller than the second argument.
May panic if an integer larger than a max f64 is compared to a float.";
pub fn islt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
fn islt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
let first = *ast.car.clone();
if !isnumeric(&first) {
return Err(start_trace(
@ -409,11 +400,10 @@ pub fn islt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
}
}
pub const ISGTE_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
const ISGTE_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
Returns true or false according to whether the first argument is greater than or equal to the second argument.
May panic if an integer larger than a max f64 is compared to a float.";
pub fn isgte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
fn isgte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
match islt_callback(ast, syms) {
Ok(s) => if let Ctr::Bool(b) = s {
Ok(Ctr::Bool(!b))
@ -426,11 +416,10 @@ pub fn isgte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
}
}
pub const ISLTE_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
const ISLTE_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float.
Returns true or false according to whether the first argument is less than or equal to the second argument.
May panic if an integer larger than a max f64 is compared to a float.";
pub fn islte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
fn islte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
match isgt_callback(ast, syms) {
Ok(s) => if let Ctr::Bool(b) = s {
Ok(Ctr::Bool(!b))
@ -443,7 +432,7 @@ pub fn islte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
}
}
pub const INC_DOCSTRING: &str = "Accepts a single argument, expects it to be a symbol.
const INC_DOCSTRING: &str = "Accepts a single argument, expects it to be a symbol.
The symbol is fetched from the symbol table.
If the symbol is not an integer an error is returned.
The symbol is redefined as symbol + 1.
@ -451,8 +440,7 @@ The symbol is redefined as symbol + 1.
This call is similar to the following:
(def counter '' (add counter 1))
with the caveat that your docstring is preserved.";
pub fn inc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
fn inc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
let var_name: String;
if let Ctr::Symbol(ref s) = *ast.car {
var_name = s.clone();
@ -491,7 +479,7 @@ pub fn inc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
Ok(Ctr::None)
}
pub const DEC_DOCSTRING: &str = "Accepts a single argument, expects it to be a symbol.
const DEC_DOCSTRING: &str = "Accepts a single argument, expects it to be a symbol.
The symbol is fetched from the symbol table.
If the symbol is not an integer an error is returned.
The symbol is redefined as symbol - 1.
@ -499,8 +487,7 @@ The symbol is redefined as symbol - 1.
This call is similar to the following:
(def counter '' (sub counter 1))
with the caveat that your docstring is preserved.";
pub fn dec_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
fn dec_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
let var_name: String;
if let Ctr::Symbol(ref s) = *ast.car {
var_name = s.clone();
@ -538,3 +525,174 @@ pub fn dec_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
syms.insert(var_name, sym);
Ok(Ctr::None)
}
pub fn add_math_lib(syms: &mut SymTable) {
syms.insert(
"add".to_string(),
Symbol {
name: String::from("add"),
args: Args::Infinite,
conditional_branches: false,
docs: ADD_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(add_callback)),
..Default::default()
},
);
syms.insert(
"sub".to_string(),
Symbol {
name: String::from("sub"),
args: Args::Infinite,
conditional_branches: false,
docs: SUB_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(sub_callback)),
..Default::default()
},
);
syms.insert(
"div".to_string(),
Symbol {
name: String::from("div"),
args: Args::Lazy(2),
conditional_branches: false,
docs: DIV_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(div_callback)),
..Default::default()
},
);
syms.insert(
"mul".to_string(),
Symbol {
name: String::from("mul"),
args: Args::Infinite,
conditional_branches: false,
docs: MUL_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(mul_callback)),
..Default::default()
},
);
syms.insert(
"int".to_string(),
Symbol {
name: String::from("int"),
args: Args::Lazy(1),
conditional_branches: false,
docs: INTCAST_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(intcast_callback)),
..Default::default()
},
);
syms.insert(
"float".to_string(),
Symbol {
name: String::from("float"),
args: Args::Lazy(1),
conditional_branches: false,
docs: FLOATCAST_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(floatcast_callback)),
..Default::default()
},
);
syms.insert(
"exp".to_string(),
Symbol {
name: String::from("exp"),
args: Args::Lazy(2),
conditional_branches: false,
docs: EXP_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(exp_callback)),
..Default::default()
},
);
syms.insert(
"mod".to_string(),
Symbol {
name: String::from("mod"),
args: Args::Lazy(2),
conditional_branches: false,
docs: MOD_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(mod_callback)),
..Default::default()
},
);
syms.insert(
"gt?".to_string(),
Symbol {
name: String::from("gt?"),
args: Args::Lazy(2),
conditional_branches: false,
docs: ISGT_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(isgt_callback)),
..Default::default()
},
);
syms.insert(
"lt?".to_string(),
Symbol {
name: String::from("lt?"),
args: Args::Lazy(2),
conditional_branches: false,
docs: ISLT_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(islt_callback)),
..Default::default()
},
);
syms.insert(
"gte?".to_string(),
Symbol {
name: String::from("gt?"),
args: Args::Lazy(2),
conditional_branches: false,
docs: ISGTE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(isgte_callback)),
..Default::default()
},
);
syms.insert(
"lte?".to_string(),
Symbol {
name: String::from("lt?"),
args: Args::Lazy(2),
conditional_branches: false,
docs: ISLTE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(islte_callback)),
..Default::default()
},
);
syms.insert(
"inc".to_string(),
Symbol {
name: String::from("inc"),
args: Args::Lazy(1),
conditional_branches: true,
docs: INC_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(inc_callback)),
..Default::default()
},
);
syms.insert(
"dec".to_string(),
Symbol {
name: String::from("dec"),
args: Args::Lazy(1),
conditional_branches: true,
docs: DEC_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(dec_callback)),
..Default::default()
},
);
}