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:
parent
b3c0b80ee6
commit
3bbea6bea0
9 changed files with 753 additions and 752 deletions
597
src/stl.rs
597
src/stl.rs
|
|
@ -58,557 +58,12 @@ fn prompt_delimiter_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, T
|
|||
/// inserts all stdlib functions that can be inserted without
|
||||
/// any kind of further configuration data into a symtable
|
||||
pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
||||
syms.insert(
|
||||
"cons".to_string(),
|
||||
Symbol {
|
||||
name: String::from("cons"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: append::CONS_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append::cons_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"echo".to_string(),
|
||||
Symbol {
|
||||
name: String::from("echo"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: strings::ECHO_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strings::echo_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"concat".to_string(),
|
||||
Symbol {
|
||||
name: String::from("concat"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: strings::CONCAT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strings::concat_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"substr?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("substr?"),
|
||||
args: Args::Strict(vec![Type::String, Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: strings::SUBSTR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strings::substr_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"split".to_string(),
|
||||
Symbol {
|
||||
name: String::from("split"),
|
||||
args: Args::Strict(vec![Type::String, Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: strings::SPLIT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strings::split_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"strlen".to_string(),
|
||||
Symbol {
|
||||
name: String::from("strlen"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
docs: strings::STRLEN_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strings::strlen_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"string".to_string(),
|
||||
Symbol {
|
||||
name: String::from("string"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
docs: strings::STRCAST_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strings::strcast_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"if".to_string(),
|
||||
Symbol {
|
||||
name: String::from("if"),
|
||||
args: Args::Lazy(3),
|
||||
conditional_branches: true,
|
||||
docs: control::IF_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(control::if_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"let".to_string(),
|
||||
Symbol {
|
||||
name: String::from("let"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: control::LET_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(control::let_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"while".to_string(),
|
||||
Symbol {
|
||||
name: String::from("while"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: control::WHILE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(control::while_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"circuit".to_string(),
|
||||
Symbol {
|
||||
name: String::from("circuit"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: control::CIRCUIT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(control::circuit_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"and".to_string(),
|
||||
Symbol {
|
||||
name: String::from("and"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: boolean::AND_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(boolean::and_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"bool".to_string(),
|
||||
Symbol {
|
||||
name: String::from("bool"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: boolean::BOOLCAST_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(boolean::boolcast_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"or".to_string(),
|
||||
Symbol {
|
||||
name: String::from("or"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: boolean::OR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(boolean::or_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"not".to_string(),
|
||||
Symbol {
|
||||
name: String::from("not"),
|
||||
args: Args::Strict(vec![Type::Bool]),
|
||||
conditional_branches: false,
|
||||
docs: boolean::NOT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(boolean::not_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"eq?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("eq?"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: boolean::ISEQ_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(boolean::iseq_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"toggle".to_string(),
|
||||
Symbol {
|
||||
name: String::from("toggle"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: true,
|
||||
docs: boolean::TOGGLE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(boolean::toggle_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"help".to_string(),
|
||||
Symbol {
|
||||
name: String::from("help"),
|
||||
args: Args::Strict(vec![Type::Symbol]),
|
||||
conditional_branches: true,
|
||||
docs: decl::HELP_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(decl::help_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"set?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("set?"),
|
||||
args: Args::Strict(vec![Type::Symbol]),
|
||||
conditional_branches: true,
|
||||
docs: decl::ISSET_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(decl::isset_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"env".to_string(),
|
||||
Symbol {
|
||||
name: String::from("env"),
|
||||
args: Args::None,
|
||||
conditional_branches: false,
|
||||
docs: decl::ENV_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(decl::env_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"add".to_string(),
|
||||
Symbol {
|
||||
name: String::from("add"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: math::ADD_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::add_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"sub".to_string(),
|
||||
Symbol {
|
||||
name: String::from("sub"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: math::SUB_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::sub_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"div".to_string(),
|
||||
Symbol {
|
||||
name: String::from("div"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::DIV_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::div_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"mul".to_string(),
|
||||
Symbol {
|
||||
name: String::from("mul"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: math::MUL_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::mul_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"int".to_string(),
|
||||
Symbol {
|
||||
name: String::from("int"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
docs: math::INTCAST_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::intcast_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"float".to_string(),
|
||||
Symbol {
|
||||
name: String::from("float"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
docs: math::FLOATCAST_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::floatcast_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"len".to_string(),
|
||||
Symbol {
|
||||
name: String::from("len"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: append::LEN_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append::len_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"car".to_string(),
|
||||
Symbol {
|
||||
name: String::from("car"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: append::CAR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append::car_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"cdr".to_string(),
|
||||
Symbol {
|
||||
name: String::from("cdr"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: append::CDR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append::cdr_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"pop".to_string(),
|
||||
Symbol {
|
||||
name: String::from("pop"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: append::POP_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append::pop_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"dq".to_string(),
|
||||
Symbol {
|
||||
name: String::from("dequeue"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: append::DEQUEUE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append::dequeue_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"reverse".to_string(),
|
||||
Symbol {
|
||||
name: String::from("reverse"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: append::REVERSE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append::reverse_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"exp".to_string(),
|
||||
Symbol {
|
||||
name: String::from("exp"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::EXP_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::exp_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"mod".to_string(),
|
||||
Symbol {
|
||||
name: String::from("mod"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::MOD_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::mod_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"gt?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("gt?"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::ISGT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::isgt_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"lt?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("lt?"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::ISLT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::islt_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"gte?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("gt?"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::ISGTE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::isgte_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"lte?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("lt?"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::ISLTE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::islte_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"inc".to_string(),
|
||||
Symbol {
|
||||
name: String::from("inc"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: true,
|
||||
docs: math::INC_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::inc_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"dec".to_string(),
|
||||
Symbol {
|
||||
name: String::from("dec"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: true,
|
||||
docs: math::DEC_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::dec_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"quote".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)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
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)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"eval".to_string(),
|
||||
Symbol {
|
||||
name: String::from("eval"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: true,
|
||||
docs: decl::EVAL_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(decl::eval_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"lambda".to_string(),
|
||||
Symbol {
|
||||
name: String::from("lambda"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: true,
|
||||
docs: decl::LAMBDA_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(decl::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: decl::GETDOC_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(decl::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: decl::SETDOC_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(decl::setdoc_callback)),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
append::add_list_lib(syms);
|
||||
strings::add_string_lib(syms);
|
||||
decl::add_decl_lib_static(syms);
|
||||
control::add_control_lib(syms);
|
||||
boolean::add_bool_lib(syms);
|
||||
math::add_math_lib(syms);
|
||||
|
||||
syms.insert(
|
||||
"call".to_string(),
|
||||
|
|
@ -622,18 +77,6 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
}
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"input".to_string(),
|
||||
Symbol {
|
||||
name: String::from("input"),
|
||||
args: Args::Strict(vec![Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: strings::INPUT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strings::input_callback)),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -648,22 +91,7 @@ pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::Shell
|
|||
.to_string()
|
||||
.eq("true");
|
||||
|
||||
// this also depends on the value of CFG_RELISH_ENV
|
||||
syms.insert(
|
||||
"def".to_string(),
|
||||
Symbol {
|
||||
name: String::from("define"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: decl::STORE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(
|
||||
move |ast: &Seg, syms: &mut SymTable| -> Result<Ctr, Traceback> {
|
||||
decl::store_callback(ast, syms, env_cfg_user_form)
|
||||
},
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
decl::add_decl_lib_dynamic(syms, env_cfg_user_form);
|
||||
|
||||
// This should be replaced by actual compiler conditionals in the future
|
||||
if let Some(shell_state) = shell {
|
||||
|
|
@ -675,17 +103,6 @@ pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::Shell
|
|||
|
||||
if posix_cfg_user_form {
|
||||
posix::load_posix_shell(syms, shell_state);
|
||||
syms.insert(
|
||||
"cd".to_string(),
|
||||
Symbol {
|
||||
name: String::from("cd"),
|
||||
args: Args::Strict(vec![Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: posix::CD_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(posix::cd_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::SymTable;
|
||||
use crate::segment::{Ctr, Seg, Type};
|
||||
use crate::sym::{SymTable, Symbol, Args, ValueType};
|
||||
use crate::error::{Traceback, start_trace};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub const CONS_DOCSTRING: &str = "traverses any number of arguments collecting them into a list.
|
||||
const CONS_DOCSTRING: &str = "traverses any number of arguments collecting them into a list.
|
||||
If the first argument is a list, all other arguments are added sequentially to the end of the list contained in the first argument.";
|
||||
|
||||
pub fn cons_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn cons_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
let mut temp = s.clone();
|
||||
if let Ctr::Seg(ref list) = *ast.cdr {
|
||||
|
|
@ -51,11 +51,10 @@ pub fn cons_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback>
|
|||
}
|
||||
}
|
||||
|
||||
pub const LEN_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
const LEN_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
Returns the length of said list.
|
||||
Interpreter will panic if the length of the list is greater than the max value of a signed 128 bit integer";
|
||||
|
||||
pub fn len_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn len_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
if let Ctr::None = *s.car {
|
||||
Ok(Ctr::Integer(0))
|
||||
|
|
@ -67,11 +66,10 @@ pub fn len_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const CAR_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
const CAR_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
Returns a copy of the first value in that list.
|
||||
If the list is empty, returns an err to avoid passing back a null value.";
|
||||
|
||||
pub fn car_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn car_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
if let Ctr::None = *s.car {
|
||||
Err(start_trace(("len", "input is empty").into()))
|
||||
|
|
@ -83,11 +81,10 @@ pub fn car_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const CDR_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
const CDR_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
Returns a copy of the last value in that list.
|
||||
If the list is empty, returns an err to avoid passing back a null value.";
|
||||
|
||||
pub fn cdr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn cdr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
let mut ret = &s.car;
|
||||
let mut iter = &s.cdr;
|
||||
|
|
@ -105,14 +102,13 @@ pub fn cdr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const POP_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
const POP_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
Returns a list containing the first element, and the rest of the elements.
|
||||
|
||||
Example: (pop (1 2 3)) -> (1 (2 3)).
|
||||
|
||||
The head can then be accessed by car and the rest can be accessed by cdr.";
|
||||
|
||||
pub fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
if s.len() < 1 {
|
||||
return Err(start_trace(("pop", "input is empty").into()));
|
||||
|
|
@ -130,14 +126,13 @@ pub fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const DEQUEUE_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
const DEQUEUE_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
Returns a list containing the last element, and the rest of the elements.
|
||||
|
||||
Example: (dq (1 2 3)) -> (3 (1 2)).
|
||||
|
||||
The last element can then be accessed by car and the rest can be accessed by cdr.";
|
||||
|
||||
pub fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
if s.len() < 1 {
|
||||
return Err(start_trace(("dequeue", "expected an input").into()));
|
||||
|
|
@ -169,10 +164,9 @@ pub fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Tracebac
|
|||
}
|
||||
}
|
||||
|
||||
pub const REVERSE_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
const REVERSE_DOCSTRING: &str = "Takes a single argument, expected to be a list.
|
||||
Returns the same list, but in reverse order.";
|
||||
|
||||
pub fn reverse_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn reverse_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Seg(ref s) = *ast.car {
|
||||
let mut ret = Seg::new();
|
||||
s.circuit_reverse(&mut |arg: &Ctr| -> bool {
|
||||
|
|
@ -185,3 +179,89 @@ pub fn reverse_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Tracebac
|
|||
Err(start_trace(("reverse", "input is not a list").into()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_list_lib(syms: &mut SymTable) {
|
||||
syms.insert(
|
||||
"cons".to_string(),
|
||||
Symbol {
|
||||
name: String::from("cons"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: CONS_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(cons_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"len".to_string(),
|
||||
Symbol {
|
||||
name: String::from("len"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: LEN_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(len_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"car".to_string(),
|
||||
Symbol {
|
||||
name: String::from("car"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: CAR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(car_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"cdr".to_string(),
|
||||
Symbol {
|
||||
name: String::from("cdr"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: CDR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(cdr_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"pop".to_string(),
|
||||
Symbol {
|
||||
name: String::from("pop"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: POP_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(pop_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"dq".to_string(),
|
||||
Symbol {
|
||||
name: String::from("dequeue"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: DEQUEUE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(dequeue_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"reverse".to_string(),
|
||||
Symbol {
|
||||
name: String::from("reverse"),
|
||||
args: Args::Strict(vec![Type::Seg]),
|
||||
conditional_branches: false,
|
||||
docs: REVERSE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(reverse_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::segment::{Ctr, Seg, Type};
|
||||
use crate::error::{Traceback, start_trace};
|
||||
use crate::sym::{SymTable, ValueType};
|
||||
use crate::sym::{SymTable, ValueType, Args, Symbol};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub const AND_DOCSTRING: &str =
|
||||
const AND_DOCSTRING: &str =
|
||||
"traverses a list of N arguments, all of which are expected to be boolean.
|
||||
starts with arg1 AND arg2, and then calculates prev_result AND next_arg.
|
||||
returns final result.";
|
||||
|
||||
pub fn and_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn and_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let mut type_error = false;
|
||||
let mut cursor = 0;
|
||||
let result = ast.circuit(&mut |arg: &Ctr| -> bool {
|
||||
|
|
@ -43,12 +43,11 @@ pub fn and_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const OR_DOCSTRING: &str =
|
||||
const OR_DOCSTRING: &str =
|
||||
"traverses a list of N arguments, all of which are expected to be boolean.
|
||||
starts with arg1 OR arg2, and then calculates prev_result OR next_arg.
|
||||
returns final result.";
|
||||
|
||||
pub fn or_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn or_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let mut result = false;
|
||||
let mut cursor = 0;
|
||||
let correct_types = ast.circuit(&mut |arg: &Ctr| -> bool {
|
||||
|
|
@ -68,10 +67,9 @@ pub fn or_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const NOT_DOCSTRING: &str = "takes a single argument (expects a boolean).
|
||||
const NOT_DOCSTRING: &str = "takes a single argument (expects a boolean).
|
||||
returns false if arg is true or true if arg is false.";
|
||||
|
||||
pub fn not_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn not_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::Bool(b) = *ast.car {
|
||||
Ok(Ctr::Bool(!b))
|
||||
} else {
|
||||
|
|
@ -79,22 +77,20 @@ pub fn not_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const ISEQ_DOCSTRING: &str = "traverses a list of N arguments.
|
||||
const ISEQ_DOCSTRING: &str = "traverses a list of N arguments.
|
||||
returns true if all arguments hold the same value.
|
||||
NOTE: 1 and 1.0 are the same, but '1' 'one' or one (symbol) aren't";
|
||||
|
||||
pub fn iseq_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn iseq_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let head_ctr_ref = &*ast.car;
|
||||
Ok(Ctr::Bool(
|
||||
ast.circuit(&mut |arg: &Ctr| -> bool { arg == head_ctr_ref }),
|
||||
))
|
||||
}
|
||||
|
||||
pub const TOGGLE_DOCSTRING: &str = "switches a boolean symbol between true or false.
|
||||
const TOGGLE_DOCSTRING: &str = "switches a boolean symbol between true or false.
|
||||
Takes a single argument (a symbol). Looks it up in the variable table.
|
||||
Either sets the symbol to true if it is currently false, or vice versa.";
|
||||
|
||||
pub fn toggle_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn toggle_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();
|
||||
|
|
@ -121,13 +117,11 @@ pub fn toggle_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
|
|||
Ok(Ctr::None)
|
||||
}
|
||||
|
||||
|
||||
pub const BOOLCAST_DOCSTRING: &str = "takes one argument of any type.
|
||||
const BOOLCAST_DOCSTRING: &str = "takes one argument of any type.
|
||||
attempts to cast argument to a bool.
|
||||
Strings will cast to a bool if they are 'true' or 'false'.
|
||||
Integers and Floats will cast to true if they are 0 and false otherwise.";
|
||||
|
||||
pub fn boolcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn boolcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
match &*ast.car {
|
||||
Ctr::Bool(_) => Ok(*ast.car.clone()),
|
||||
Ctr::String(s) => {
|
||||
|
|
@ -145,3 +139,77 @@ pub fn boolcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceba
|
|||
ast.car.to_type())).into())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_bool_lib(syms: &mut SymTable) {
|
||||
syms.insert(
|
||||
"and".to_string(),
|
||||
Symbol {
|
||||
name: String::from("and"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: AND_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(and_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"bool".to_string(),
|
||||
Symbol {
|
||||
name: String::from("bool"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: BOOLCAST_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(boolcast_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"or".to_string(),
|
||||
Symbol {
|
||||
name: String::from("or"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: OR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(or_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"not".to_string(),
|
||||
Symbol {
|
||||
name: String::from("not"),
|
||||
args: Args::Strict(vec![Type::Bool]),
|
||||
conditional_branches: false,
|
||||
docs: NOT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(not_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"eq?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("eq?"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: ISEQ_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(iseq_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"toggle".to_string(),
|
||||
Symbol {
|
||||
name: String::from("toggle"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: true,
|
||||
docs: TOGGLE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(toggle_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@
|
|||
use crate::eval::eval;
|
||||
use crate::error::{Traceback, start_trace};
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::{SymTable, Symbol};
|
||||
use crate::sym::{SymTable, Symbol, ValueType, Args};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub const IF_DOCSTRING: &str =
|
||||
const IF_DOCSTRING: &str =
|
||||
"accepts three bodies, a condition, an unevaluated consequence, and an alternative consequence.
|
||||
If the condition is evaluated to true, the first consequence is evaluated.
|
||||
If the condition is evaluated to false, the second consequence is evaluated.
|
||||
|
|
@ -29,8 +30,7 @@ Otherwise, an error is thrown.
|
|||
example: (if my-state-switch
|
||||
(do-my-thing)
|
||||
(else-an-other-thing))";
|
||||
|
||||
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let cond: bool;
|
||||
match *ast.car {
|
||||
Ctr::Seg(ref cond_form) => {
|
||||
|
|
@ -119,7 +119,7 @@ pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const LET_DOCSTRING: &str = "creates a stack of local variables for a sequence of operations.
|
||||
const LET_DOCSTRING: &str = "creates a stack of local variables for a sequence of operations.
|
||||
returns the result of the final operation.
|
||||
|
||||
example: (let ((step1 'hello')
|
||||
|
|
@ -132,8 +132,7 @@ In this example step1, step2, and step3 are created sequentially.
|
|||
Then, the echo form is evaluated, printing 'hello-world'.
|
||||
Finally, the some-func form is evaluated.
|
||||
Since the call to some-func is the final form, its value is returned.";
|
||||
|
||||
pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let mut localsyms = syms.clone();
|
||||
let mut locals = vec![];
|
||||
let locals_form: &Seg;
|
||||
|
|
@ -250,15 +249,14 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|||
Ok((*result).clone())
|
||||
}
|
||||
|
||||
pub const WHILE_DOCSTRING: &str = "traverses a list of N un-evaluated forms.
|
||||
const WHILE_DOCSTRING: &str = "traverses a list of N un-evaluated forms.
|
||||
the first form is expected to evaluate to a boolean. if it evaluates to false, while will stop and return. Otherwise, while will evaluate each form in a loop.
|
||||
|
||||
example: (while (check-my-state)
|
||||
(do-thing-1 args)
|
||||
(do-thing-2 args)
|
||||
(edit-state my-state))";
|
||||
|
||||
pub fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let eval_cond: &Seg;
|
||||
let outer_maybe: Seg;
|
||||
let eval_bodies_head: &Seg;
|
||||
|
|
@ -319,7 +317,7 @@ pub fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
|
|||
Ok(*(result.unwrap()).clone())
|
||||
}
|
||||
|
||||
pub const CIRCUIT_DOCSTRING: &str = "traverses a list of N un-evaluated forms.
|
||||
const CIRCUIT_DOCSTRING: &str = "traverses a list of N un-evaluated forms.
|
||||
evaluates each one until it stops. Circuit will stop when a form errors during evaluation.
|
||||
Circuit will also stop when a form does not evaluate to a boolean, or evaluates to false.
|
||||
|
||||
|
|
@ -329,8 +327,7 @@ example: (circuit (eq? (do-operation) myresult)
|
|||
(do-another-operation))
|
||||
|
||||
in this example, do-another-operation will not be called";
|
||||
|
||||
pub fn circuit_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn circuit_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let mut cursor = 0;
|
||||
let mut err_trace = Traceback::new();
|
||||
let result = ast.circuit(&mut |form: &Ctr| -> bool {
|
||||
|
|
@ -383,3 +380,53 @@ pub fn circuit_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback
|
|||
Ok(Ctr::Bool(result))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_control_lib(syms: &mut SymTable) {
|
||||
syms.insert(
|
||||
"if".to_string(),
|
||||
Symbol {
|
||||
name: String::from("if"),
|
||||
args: Args::Lazy(3),
|
||||
conditional_branches: true,
|
||||
docs: IF_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(if_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"let".to_string(),
|
||||
Symbol {
|
||||
name: String::from("let"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: LET_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(let_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"while".to_string(),
|
||||
Symbol {
|
||||
name: String::from("while"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: WHILE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(while_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"circuit".to_string(),
|
||||
Symbol {
|
||||
name: String::from("circuit"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: true,
|
||||
docs: CIRCUIT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(circuit_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
177
src/stl/decl.rs
177
src/stl/decl.rs
|
|
@ -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()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
244
src/stl/math.rs
244
src/stl/math.rs
|
|
@ -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()
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use {
|
|||
run,
|
||||
},
|
||||
libc::{
|
||||
sigaddset, sigemptyset, sigprocmask,
|
||||
sigaddset, sigemptyset, sigprocmask, exit,
|
||||
SIGINT, SIGCHLD, SIGTTOU, SIGTTIN, SIGQUIT, SIGTSTP,
|
||||
SIG_BLOCK, SIG_UNBLOCK
|
||||
},
|
||||
|
|
@ -633,6 +633,19 @@ fn q_callback(_ast: &Seg, _syms: &SymTable, state: &mut ShellState) -> Result<Ct
|
|||
Ok(Ctr::Integer(state.last_exit_code.into()))
|
||||
}
|
||||
|
||||
const EXIT_DOCSTRING: &str = "Takes on integer input. calls libc exit() with given argument.";
|
||||
fn exit_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let mut ret = -1;
|
||||
if let Ctr::Integer(i) = *ast.car {
|
||||
ret = i;
|
||||
} else {
|
||||
eprintln!("WARNING: input was not an integer. Exiting -1.")
|
||||
}
|
||||
unsafe {
|
||||
exit(ret as i32);
|
||||
}
|
||||
}
|
||||
|
||||
const BG_DOCSTRING: &str = "Calls a binary off disk with given arguments.
|
||||
Arguments may be of any type except lambda. If a symbol is not defined it will be passed as a string.
|
||||
first argument (command name) will be found on path (or an error returned).
|
||||
|
|
@ -681,7 +694,7 @@ fn bg_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result
|
|||
}
|
||||
}
|
||||
|
||||
pub const FG_DOCSTRING: &str = "takes one argument (an integer).
|
||||
const FG_DOCSTRING: &str = "takes one argument (an integer).
|
||||
Integer is presumed to be a PID of a running background job.
|
||||
If PID corresponds with a background job, fg will try to foreground it.
|
||||
If PID is not a current running background job, fg will return an error.
|
||||
|
|
@ -689,7 +702,7 @@ If PID is not a current running background job, fg will return an error.
|
|||
Examples:
|
||||
(bg vim) (fg 13871)
|
||||
";
|
||||
pub fn fg_callback(
|
||||
fn fg_callback(
|
||||
ast: &Seg,
|
||||
_syms: &mut SymTable,
|
||||
shell_state: &mut ShellState
|
||||
|
|
@ -709,9 +722,9 @@ pub fn fg_callback(
|
|||
}
|
||||
}
|
||||
|
||||
pub const CD_DOCSTRING: &str =
|
||||
const CD_DOCSTRING: &str =
|
||||
"Expects 1 argument (a string). Changes to a new directory";
|
||||
pub fn cd_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn cd_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::String(ref dir) = *ast.car {
|
||||
let dirp = Path::new(dir);
|
||||
if let Err(s) = set_current_dir(&dirp) {
|
||||
|
|
@ -913,4 +926,28 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
|||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
String::from("exit"),
|
||||
Symbol {
|
||||
name: String::from("exit"),
|
||||
args: Args::Strict(vec![Type::Integer]),
|
||||
conditional_branches: false,
|
||||
docs: String::from(EXIT_DOCSTRING),
|
||||
value: ValueType::Internal(Rc::new(exit_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"cd".to_string(),
|
||||
Symbol {
|
||||
name: String::from("cd"),
|
||||
args: Args::Strict(vec![Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: CD_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(cd_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::segment::{Ctr, Seg};
|
||||
use crate::sym::SymTable;
|
||||
use crate::segment::{Ctr, Seg, Type};
|
||||
use crate::sym::{SymTable, Symbol, ValueType, Args};
|
||||
use crate::error::{Traceback, start_trace};
|
||||
use std::io::Write;
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub const ECHO_DOCSTRING: &str =
|
||||
const ECHO_DOCSTRING: &str =
|
||||
"traverses any number of arguments. Prints their evaluated values on a new line for each.";
|
||||
|
||||
pub fn echo_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn echo_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
ast.circuit(&mut |arg: &Ctr| match arg {
|
||||
Ctr::String(s) => print!("{}", s) == (),
|
||||
_ => print!("{}", arg) == (),
|
||||
|
|
@ -33,11 +33,10 @@ pub fn echo_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback>
|
|||
Ok(Ctr::None)
|
||||
}
|
||||
|
||||
pub const CONCAT_DOCSTRING: &str = "Iterates over N args of any type other than SYMBOL.
|
||||
const CONCAT_DOCSTRING: &str = "Iterates over N args of any type other than SYMBOL.
|
||||
converts each argument to a string. Combines all strings.
|
||||
Returns final (combined) string.";
|
||||
|
||||
pub fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let mut string = String::from("");
|
||||
if !ast.circuit(&mut |arg: &Ctr| {
|
||||
match arg {
|
||||
|
|
@ -60,11 +59,10 @@ pub fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback
|
|||
return Ok(Ctr::String(string));
|
||||
}
|
||||
|
||||
pub const STRLEN_DOCSTRING: &str = "Takes a single arg of any type.
|
||||
const STRLEN_DOCSTRING: &str = "Takes a single arg of any type.
|
||||
Arg is converted to a string if not already a string.
|
||||
Returns string length of arg.";
|
||||
|
||||
pub fn strlen_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn strlen_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
match &*ast.car {
|
||||
Ctr::Symbol(s) => Ok(Ctr::Integer(s.len() as i128)),
|
||||
Ctr::String(s) => Ok(Ctr::Integer(s.len() as i128)),
|
||||
|
|
@ -78,10 +76,9 @@ pub fn strlen_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback
|
|||
}
|
||||
}
|
||||
|
||||
pub const STRCAST_DOCSTRING: &str = "Takes a single arg of any type.
|
||||
const STRCAST_DOCSTRING: &str = "Takes a single arg of any type.
|
||||
Arg is converted to a string and returned.";
|
||||
|
||||
pub fn strcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn strcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
match &*ast.car {
|
||||
Ctr::Symbol(s) => Ok(Ctr::String(s.clone())),
|
||||
Ctr::String(_) => Ok(*ast.car.clone()),
|
||||
|
|
@ -95,10 +92,9 @@ pub fn strcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Tracebac
|
|||
}
|
||||
}
|
||||
|
||||
pub const SUBSTR_DOCSTRING: &str =
|
||||
const SUBSTR_DOCSTRING: &str =
|
||||
"Takes two strings. Returns true if string1 contains at least one instance of string2";
|
||||
|
||||
pub fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let parent_str: String;
|
||||
if let Ctr::String(ref s) = *ast.car {
|
||||
parent_str = s.to_string();
|
||||
|
|
@ -129,10 +125,9 @@ pub fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback
|
|||
Ok(Ctr::Bool(parent_str.contains(&child_str)))
|
||||
}
|
||||
|
||||
pub const SPLIT_DOCSTRING: &str = "Takes two strings. String 1 is a source string and string 2 is a delimiter.
|
||||
const SPLIT_DOCSTRING: &str = "Takes two strings. String 1 is a source string and string 2 is a delimiter.
|
||||
Returns a list of substrings from string 1 that were found delimited by string 2.";
|
||||
|
||||
pub fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
let parent_str: String;
|
||||
if let Ctr::String(ref s) = *ast.car {
|
||||
parent_str = s.to_string();
|
||||
|
|
@ -168,11 +163,10 @@ pub fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback>
|
|||
Ok(Ctr::Seg(ret))
|
||||
}
|
||||
|
||||
pub const INPUT_DOCSTRING: &str = "Takes one argument (string) and prints it.
|
||||
const INPUT_DOCSTRING: &str = "Takes one argument (string) and prints it.
|
||||
Then prompts for user input.
|
||||
User input is returned as a string";
|
||||
|
||||
pub fn input_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
fn input_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::String(ref s) = *ast.car {
|
||||
print!("{}", s);
|
||||
let _= io::stdout().flush();
|
||||
|
|
@ -185,3 +179,89 @@ pub fn input_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback>
|
|||
.into()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_string_lib(syms: &mut SymTable) {
|
||||
syms.insert(
|
||||
"echo".to_string(),
|
||||
Symbol {
|
||||
name: String::from("echo"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: ECHO_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(echo_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"concat".to_string(),
|
||||
Symbol {
|
||||
name: String::from("concat"),
|
||||
args: Args::Infinite,
|
||||
conditional_branches: false,
|
||||
docs: CONCAT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(concat_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"substr?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("substr?"),
|
||||
args: Args::Strict(vec![Type::String, Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: SUBSTR_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(substr_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"split".to_string(),
|
||||
Symbol {
|
||||
name: String::from("split"),
|
||||
args: Args::Strict(vec![Type::String, Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: SPLIT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(split_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"strlen".to_string(),
|
||||
Symbol {
|
||||
name: String::from("strlen"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
docs: STRLEN_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strlen_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"string".to_string(),
|
||||
Symbol {
|
||||
name: String::from("string"),
|
||||
args: Args::Lazy(1),
|
||||
conditional_branches: false,
|
||||
docs: STRCAST_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(strcast_callback)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"input".to_string(),
|
||||
Symbol {
|
||||
name: String::from("input"),
|
||||
args: Args::Strict(vec![Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: INPUT_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(input_callback)),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue