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
|
|
@ -488,11 +488,6 @@ This contains any executable target of this project. Notably [[file:src/bin/reli
|
||||||
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer.
|
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer.
|
||||||
Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered.
|
Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered.
|
||||||
|
|
||||||
** TODO alpha tasks
|
|
||||||
- exit function (causes program to shut down and return code)
|
|
||||||
- probably push the symtable inserts into functions in individual stl modules (like posix.rs does)
|
|
||||||
- tag and release v0.3.0
|
|
||||||
|
|
||||||
** TODO v1.0 tasks
|
** TODO v1.0 tasks
|
||||||
- Be able to use features to compile without env or posix stuff
|
- Be able to use features to compile without env or posix stuff
|
||||||
- add a new binary target that is a simple posix repl demo
|
- add a new binary target that is a simple posix repl demo
|
||||||
|
|
|
||||||
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
|
/// inserts all stdlib functions that can be inserted without
|
||||||
/// any kind of further configuration data into a symtable
|
/// any kind of further configuration data into a symtable
|
||||||
pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
||||||
syms.insert(
|
append::add_list_lib(syms);
|
||||||
"cons".to_string(),
|
strings::add_string_lib(syms);
|
||||||
Symbol {
|
decl::add_decl_lib_static(syms);
|
||||||
name: String::from("cons"),
|
control::add_control_lib(syms);
|
||||||
args: Args::Infinite,
|
boolean::add_bool_lib(syms);
|
||||||
conditional_branches: false,
|
math::add_math_lib(syms);
|
||||||
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()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
syms.insert(
|
syms.insert(
|
||||||
"call".to_string(),
|
"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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -648,22 +91,7 @@ pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::Shell
|
||||||
.to_string()
|
.to_string()
|
||||||
.eq("true");
|
.eq("true");
|
||||||
|
|
||||||
// this also depends on the value of CFG_RELISH_ENV
|
decl::add_decl_lib_dynamic(syms, env_cfg_user_form);
|
||||||
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()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// This should be replaced by actual compiler conditionals in the future
|
// This should be replaced by actual compiler conditionals in the future
|
||||||
if let Some(shell_state) = shell {
|
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 {
|
if posix_cfg_user_form {
|
||||||
posix::load_posix_shell(syms, shell_state);
|
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/>.
|
* 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::sym::SymTable;
|
use crate::sym::{SymTable, Symbol, Args, ValueType};
|
||||||
use crate::error::{Traceback, start_trace};
|
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.";
|
If the first argument is a list, all other arguments are added sequentially to the end of the list contained in the first argument.";
|
||||||
|
fn cons_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn cons_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
let mut temp = s.clone();
|
let mut temp = s.clone();
|
||||||
if let Ctr::Seg(ref list) = *ast.cdr {
|
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.
|
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";
|
Interpreter will panic if the length of the list is greater than the max value of a signed 128 bit integer";
|
||||||
|
fn len_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn len_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
if let Ctr::None = *s.car {
|
if let Ctr::None = *s.car {
|
||||||
Ok(Ctr::Integer(0))
|
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.
|
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.";
|
If the list is empty, returns an err to avoid passing back a null value.";
|
||||||
|
fn car_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn car_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
if let Ctr::None = *s.car {
|
if let Ctr::None = *s.car {
|
||||||
Err(start_trace(("len", "input is empty").into()))
|
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.
|
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.";
|
If the list is empty, returns an err to avoid passing back a null value.";
|
||||||
|
fn cdr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn cdr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
let mut ret = &s.car;
|
let mut ret = &s.car;
|
||||||
let mut iter = &s.cdr;
|
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.
|
Returns a list containing the first element, and the rest of the elements.
|
||||||
|
|
||||||
Example: (pop (1 2 3)) -> (1 (2 3)).
|
Example: (pop (1 2 3)) -> (1 (2 3)).
|
||||||
|
|
||||||
The head can then be accessed by car and the rest can be accessed by cdr.";
|
The head can then be accessed by car and the rest can be accessed by cdr.";
|
||||||
|
fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
if s.len() < 1 {
|
if s.len() < 1 {
|
||||||
return Err(start_trace(("pop", "input is empty").into()));
|
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.
|
Returns a list containing the last element, and the rest of the elements.
|
||||||
|
|
||||||
Example: (dq (1 2 3)) -> (3 (1 2)).
|
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.";
|
The last element can then be accessed by car and the rest can be accessed by cdr.";
|
||||||
|
fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
if s.len() < 1 {
|
if s.len() < 1 {
|
||||||
return Err(start_trace(("dequeue", "expected an input").into()));
|
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.";
|
Returns the same list, but in reverse order.";
|
||||||
|
fn reverse_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn reverse_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
let mut ret = Seg::new();
|
let mut ret = Seg::new();
|
||||||
s.circuit_reverse(&mut |arg: &Ctr| -> bool {
|
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()))
|
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/>.
|
* 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::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.
|
"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.
|
starts with arg1 AND arg2, and then calculates prev_result AND next_arg.
|
||||||
returns final result.";
|
returns final result.";
|
||||||
|
fn and_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn and_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let mut type_error = false;
|
let mut type_error = false;
|
||||||
let mut cursor = 0;
|
let mut cursor = 0;
|
||||||
let result = ast.circuit(&mut |arg: &Ctr| -> bool {
|
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.
|
"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.
|
starts with arg1 OR arg2, and then calculates prev_result OR next_arg.
|
||||||
returns final result.";
|
returns final result.";
|
||||||
|
fn or_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn or_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let mut result = false;
|
let mut result = false;
|
||||||
let mut cursor = 0;
|
let mut cursor = 0;
|
||||||
let correct_types = ast.circuit(&mut |arg: &Ctr| -> bool {
|
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.";
|
returns false if arg is true or true if arg is false.";
|
||||||
|
fn not_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn not_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Bool(b) = *ast.car {
|
if let Ctr::Bool(b) = *ast.car {
|
||||||
Ok(Ctr::Bool(!b))
|
Ok(Ctr::Bool(!b))
|
||||||
} else {
|
} 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.
|
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";
|
NOTE: 1 and 1.0 are the same, but '1' 'one' or one (symbol) aren't";
|
||||||
|
fn iseq_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn iseq_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let head_ctr_ref = &*ast.car;
|
let head_ctr_ref = &*ast.car;
|
||||||
Ok(Ctr::Bool(
|
Ok(Ctr::Bool(
|
||||||
ast.circuit(&mut |arg: &Ctr| -> bool { arg == head_ctr_ref }),
|
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.
|
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.";
|
Either sets the symbol to true if it is currently false, or vice versa.";
|
||||||
|
fn toggle_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn toggle_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let var_name: String;
|
let var_name: String;
|
||||||
if let Ctr::Symbol(ref s) = *ast.car {
|
if let Ctr::Symbol(ref s) = *ast.car {
|
||||||
var_name = s.clone();
|
var_name = s.clone();
|
||||||
|
|
@ -121,13 +117,11 @@ pub fn toggle_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback>
|
||||||
Ok(Ctr::None)
|
Ok(Ctr::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BOOLCAST_DOCSTRING: &str = "takes one argument of any type.
|
||||||
pub const BOOLCAST_DOCSTRING: &str = "takes one argument of any type.
|
|
||||||
attempts to cast argument to a bool.
|
attempts to cast argument to a bool.
|
||||||
Strings will cast to a bool if they are 'true' or 'false'.
|
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.";
|
Integers and Floats will cast to true if they are 0 and false otherwise.";
|
||||||
|
fn boolcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn boolcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
match &*ast.car {
|
match &*ast.car {
|
||||||
Ctr::Bool(_) => Ok(*ast.car.clone()),
|
Ctr::Bool(_) => Ok(*ast.car.clone()),
|
||||||
Ctr::String(s) => {
|
Ctr::String(s) => {
|
||||||
|
|
@ -145,3 +139,77 @@ pub fn boolcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceba
|
||||||
ast.car.to_type())).into())),
|
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::eval::eval;
|
||||||
use crate::error::{Traceback, start_trace};
|
use crate::error::{Traceback, start_trace};
|
||||||
use crate::segment::{Ctr, Seg};
|
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.
|
"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 true, the first consequence is evaluated.
|
||||||
If the condition is evaluated to false, the second 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
|
example: (if my-state-switch
|
||||||
(do-my-thing)
|
(do-my-thing)
|
||||||
(else-an-other-thing))";
|
(else-an-other-thing))";
|
||||||
|
fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let cond: bool;
|
let cond: bool;
|
||||||
match *ast.car {
|
match *ast.car {
|
||||||
Ctr::Seg(ref cond_form) => {
|
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.
|
returns the result of the final operation.
|
||||||
|
|
||||||
example: (let ((step1 'hello')
|
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'.
|
Then, the echo form is evaluated, printing 'hello-world'.
|
||||||
Finally, the some-func form is evaluated.
|
Finally, the some-func form is evaluated.
|
||||||
Since the call to some-func is the final form, its value is returned.";
|
Since the call to some-func is the final form, its value is returned.";
|
||||||
|
fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let mut localsyms = syms.clone();
|
let mut localsyms = syms.clone();
|
||||||
let mut locals = vec![];
|
let mut locals = vec![];
|
||||||
let locals_form: &Seg;
|
let locals_form: &Seg;
|
||||||
|
|
@ -250,15 +249,14 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
Ok((*result).clone())
|
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.
|
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)
|
example: (while (check-my-state)
|
||||||
(do-thing-1 args)
|
(do-thing-1 args)
|
||||||
(do-thing-2 args)
|
(do-thing-2 args)
|
||||||
(edit-state my-state))";
|
(edit-state my-state))";
|
||||||
|
fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let eval_cond: &Seg;
|
let eval_cond: &Seg;
|
||||||
let outer_maybe: Seg;
|
let outer_maybe: Seg;
|
||||||
let eval_bodies_head: &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())
|
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.
|
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.
|
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))
|
(do-another-operation))
|
||||||
|
|
||||||
in this example, do-another-operation will not be called";
|
in this example, do-another-operation will not be called";
|
||||||
|
fn circuit_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn circuit_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let mut cursor = 0;
|
let mut cursor = 0;
|
||||||
let mut err_trace = Traceback::new();
|
let mut err_trace = Traceback::new();
|
||||||
let result = ast.circuit(&mut |form: &Ctr| -> bool {
|
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))
|
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::error::{Traceback, start_trace};
|
||||||
use crate::segment::{Ctr, Seg, Type};
|
use crate::segment::{Ctr, Seg, Type};
|
||||||
use crate::stdlib::{CONSOLE_XDIM_VNAME, RELISH_DEFAULT_CONS_WIDTH};
|
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::env;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub const QUOTE_DOCSTRING: &str = "takes a single unevaluated tree and returns it as it is: unevaluated.";
|
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> {
|
||||||
pub fn quote_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if ast.len() > 1 {
|
if ast.len() > 1 {
|
||||||
Err(start_trace(("quote", "do not quote more than one thing at a time").into()))
|
Err(start_trace(("quote", "do not quote more than one thing at a time").into()))
|
||||||
} else {
|
} 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.
|
Specifically, does one pass of the tree simplification algorithm.
|
||||||
If you have a variable referencing another variable you will get the
|
If you have a variable referencing another variable you will get the
|
||||||
referenced variable.";
|
referenced variable.";
|
||||||
|
fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if ast.len() > 1 {
|
if ast.len() > 1 {
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("eval", "do not eval more than one thing at a time")
|
("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.";
|
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> {
|
||||||
pub fn help_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if ast.len() != 1 {
|
if ast.len() != 1 {
|
||||||
return Err(start_trace(("help", "expected one input").into()));
|
return Err(start_trace(("help", "expected one input").into()));
|
||||||
}
|
}
|
||||||
|
|
@ -129,10 +127,9 @@ CURRENT VALUE AND/OR BODY:
|
||||||
Ok(Ctr::None)
|
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.";
|
returns true or false according to whether or not the symbol is found in the symbol table.";
|
||||||
|
fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if ast.len() != 1 {
|
if ast.len() != 1 {
|
||||||
Err(start_trace(("set?", "expcted one input").into()))
|
Err(start_trace(("set?", "expcted one input").into()))
|
||||||
} else {
|
} 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";
|
prints out all available symbols and their associated values";
|
||||||
|
fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
// get width of current output
|
// get width of current output
|
||||||
let xdim: i128;
|
let xdim: i128;
|
||||||
if let Ctr::Integer(dim) = *syms
|
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)
|
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.
|
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.
|
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.
|
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)
|
((lambda (x y) (add x y)) 1 2)
|
||||||
which is functionally equivalent to:
|
which is functionally equivalent to:
|
||||||
(add 1 2)";
|
(add 1 2)";
|
||||||
|
fn lambda_callback(
|
||||||
pub fn lambda_callback(
|
|
||||||
ast: &Seg,
|
ast: &Seg,
|
||||||
_syms: &mut SymTable
|
_syms: &mut SymTable
|
||||||
) -> Result<Ctr, Traceback> {
|
) -> 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.
|
Returns an error if symbol is undefined.
|
||||||
|
|
||||||
Note: make sure to quote the input like this:
|
Note: make sure to quote the input like this:
|
||||||
(get-doc (quote symbol-name))";
|
(get-doc (quote symbol-name))";
|
||||||
|
fn getdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn getdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::Symbol(ref symbol) = *ast.car {
|
if let Ctr::Symbol(ref symbol) = *ast.car {
|
||||||
if let Some(sym) = syms.get(symbol) {
|
if let Some(sym) = syms.get(symbol) {
|
||||||
Ok(Ctr::String(sym.docs.clone()))
|
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.
|
Returns an error if symbol is undefined, otherwise sets the symbols docstring to the argument.
|
||||||
|
|
||||||
Note: make sure to quote the input like this:
|
Note: make sure to quote the input like this:
|
||||||
(set-doc (quote symbol-name) my-new-docs)";
|
(set-doc (quote symbol-name) my-new-docs)";
|
||||||
|
fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if ast.len() != 2 {
|
if ast.len() != 2 {
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("set-doc", "expected two inputs")
|
("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:
|
A call may take one of three forms:
|
||||||
1. variable declaration:
|
1. variable declaration:
|
||||||
Takes a name, doc string, and a value.
|
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
|
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 ";
|
a value from it. If it does not return a ";
|
||||||
|
fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr, Traceback> {
|
||||||
|
|
||||||
pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr, Traceback> {
|
|
||||||
let is_var = ast.len() == 3;
|
let is_var = ast.len() == 3;
|
||||||
let name: String;
|
let name: String;
|
||||||
let docs: String;
|
let docs: String;
|
||||||
|
|
@ -509,3 +500,131 @@ pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<C
|
||||||
.into()))
|
.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::segment::{Ctr, Seg};
|
||||||
use crate::sym::{SymTable, ValueType};
|
use crate::sym::{SymTable, ValueType, Symbol, Args};
|
||||||
use crate::error::{Traceback, start_trace};
|
use crate::error::{Traceback, start_trace};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn isnumeric(arg: &Ctr) -> bool {
|
fn isnumeric(arg: &Ctr) -> bool {
|
||||||
match arg {
|
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.
|
"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.
|
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.";
|
Consult source code for a better understanding of how extreme values will be handled.";
|
||||||
|
fn add_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn add_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let mut res = Ctr::Integer(0);
|
let mut res = Ctr::Integer(0);
|
||||||
let mut culprit: Ctr = Ctr::None;
|
let mut culprit: Ctr = Ctr::None;
|
||||||
let type_consistent = ast.circuit(&mut |c: &Ctr| -> bool {
|
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.
|
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.";
|
Consult source code for a better understanding of how extreme values will be handled.";
|
||||||
|
fn sub_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn sub_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if !isnumeric(ast.car.as_ref()) {
|
if !isnumeric(ast.car.as_ref()) {
|
||||||
return Err(start_trace(
|
return Err(start_trace(
|
||||||
("sub", format!("{} is not a number!", ast.car.as_ref()))
|
("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.
|
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.";
|
Consult source code for a better understanding of how extreme values will be handled.";
|
||||||
|
fn div_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn div_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let first = *ast.car.clone();
|
let first = *ast.car.clone();
|
||||||
if !isnumeric(&first) {
|
if !isnumeric(&first) {
|
||||||
return Err(start_trace(
|
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.
|
"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.
|
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.";
|
Consult source code for a better understanding of how extreme values will be handled.";
|
||||||
|
fn mul_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn mul_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let mut res = Ctr::Integer(1);
|
let mut res = Ctr::Integer(1);
|
||||||
let mut culprit: Ctr = Ctr::None;
|
let mut culprit: Ctr = Ctr::None;
|
||||||
let type_consistent = ast.circuit(&mut |c: &Ctr| -> bool {
|
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.
|
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.
|
If the cast to Integer fails, it will return Nothing and print an error.
|
||||||
Casting a float to an int will drop its decimal.";
|
Casting a float to an int will drop its decimal.";
|
||||||
|
fn intcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn intcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
// special case for float
|
// special case for float
|
||||||
if let Ctr::Float(f) = *ast.car {
|
if let Ctr::Float(f) = *ast.car {
|
||||||
Ok(Ctr::Integer(f as i128))
|
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.
|
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.
|
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.";
|
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.";
|
||||||
|
fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
// special case for float
|
// special case for float
|
||||||
if let Ctr::Integer(i) = *ast.car {
|
if let Ctr::Integer(i) = *ast.car {
|
||||||
Ok(Ctr::Float(i as f64))
|
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.
|
Returns the first arg to the power of the second arg.
|
||||||
Does not handle overflow or underflow.
|
Does not handle overflow or underflow.
|
||||||
|
|
||||||
|
|
@ -203,8 +198,7 @@ PANIC CASES:
|
||||||
- arg1 is a float and arg2 is greater than an int32
|
- 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 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";
|
- an integer is rased to the power of another integer exceeding the max size of an unsigned 32bit integer";
|
||||||
|
fn exp_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn exp_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let first = *ast.car.clone();
|
let first = *ast.car.clone();
|
||||||
if !isnumeric(&first) {
|
if !isnumeric(&first) {
|
||||||
return Err(start_trace(
|
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.
|
Returns a list of two values: the modulus and the remainder.
|
||||||
Example: (mod 5 3) -> (1 2)
|
Example: (mod 5 3) -> (1 2)
|
||||||
|
|
||||||
|
|
@ -255,8 +249,7 @@ PANIC CASES:
|
||||||
- A float is modulo an integer larger than a max f64
|
- A float is modulo an integer larger than a max f64
|
||||||
- An integer larger than a max f64 is modulo a float
|
- An integer larger than a max f64 is modulo a float
|
||||||
";
|
";
|
||||||
|
fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let first = *ast.car.clone();
|
let first = *ast.car.clone();
|
||||||
if !isnumeric(&first) {
|
if !isnumeric(&first) {
|
||||||
return Err(start_trace(
|
return Err(start_trace(
|
||||||
|
|
@ -315,11 +308,10 @@ pub fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
Ok(Ctr::Seg(ret))
|
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.
|
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.";
|
May panic if an integer larger than a max f64 is compared to a float.";
|
||||||
|
fn isgt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn isgt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let first = *ast.car.clone();
|
let first = *ast.car.clone();
|
||||||
if !isnumeric(&first) {
|
if !isnumeric(&first) {
|
||||||
return Err(start_trace(
|
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.
|
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.";
|
May panic if an integer larger than a max f64 is compared to a float.";
|
||||||
|
fn islt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn islt_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let first = *ast.car.clone();
|
let first = *ast.car.clone();
|
||||||
if !isnumeric(&first) {
|
if !isnumeric(&first) {
|
||||||
return Err(start_trace(
|
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.
|
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.";
|
May panic if an integer larger than a max f64 is compared to a float.";
|
||||||
|
fn isgte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn isgte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
match islt_callback(ast, syms) {
|
match islt_callback(ast, syms) {
|
||||||
Ok(s) => if let Ctr::Bool(b) = s {
|
Ok(s) => if let Ctr::Bool(b) = s {
|
||||||
Ok(Ctr::Bool(!b))
|
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.
|
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.";
|
May panic if an integer larger than a max f64 is compared to a float.";
|
||||||
|
fn islte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn islte_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
match isgt_callback(ast, syms) {
|
match isgt_callback(ast, syms) {
|
||||||
Ok(s) => if let Ctr::Bool(b) = s {
|
Ok(s) => if let Ctr::Bool(b) = s {
|
||||||
Ok(Ctr::Bool(!b))
|
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.
|
The symbol is fetched from the symbol table.
|
||||||
If the symbol is not an integer an error is returned.
|
If the symbol is not an integer an error is returned.
|
||||||
The symbol is redefined as symbol + 1.
|
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:
|
This call is similar to the following:
|
||||||
(def counter '' (add counter 1))
|
(def counter '' (add counter 1))
|
||||||
with the caveat that your docstring is preserved.";
|
with the caveat that your docstring is preserved.";
|
||||||
|
fn inc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn inc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let var_name: String;
|
let var_name: String;
|
||||||
if let Ctr::Symbol(ref s) = *ast.car {
|
if let Ctr::Symbol(ref s) = *ast.car {
|
||||||
var_name = s.clone();
|
var_name = s.clone();
|
||||||
|
|
@ -491,7 +479,7 @@ pub fn inc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
Ok(Ctr::None)
|
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.
|
The symbol is fetched from the symbol table.
|
||||||
If the symbol is not an integer an error is returned.
|
If the symbol is not an integer an error is returned.
|
||||||
The symbol is redefined as symbol - 1.
|
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:
|
This call is similar to the following:
|
||||||
(def counter '' (sub counter 1))
|
(def counter '' (sub counter 1))
|
||||||
with the caveat that your docstring is preserved.";
|
with the caveat that your docstring is preserved.";
|
||||||
|
fn dec_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn dec_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let var_name: String;
|
let var_name: String;
|
||||||
if let Ctr::Symbol(ref s) = *ast.car {
|
if let Ctr::Symbol(ref s) = *ast.car {
|
||||||
var_name = s.clone();
|
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);
|
syms.insert(var_name, sym);
|
||||||
Ok(Ctr::None)
|
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,
|
run,
|
||||||
},
|
},
|
||||||
libc::{
|
libc::{
|
||||||
sigaddset, sigemptyset, sigprocmask,
|
sigaddset, sigemptyset, sigprocmask, exit,
|
||||||
SIGINT, SIGCHLD, SIGTTOU, SIGTTIN, SIGQUIT, SIGTSTP,
|
SIGINT, SIGCHLD, SIGTTOU, SIGTTIN, SIGQUIT, SIGTSTP,
|
||||||
SIG_BLOCK, SIG_UNBLOCK
|
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()))
|
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.
|
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.
|
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).
|
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.
|
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 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.
|
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:
|
Examples:
|
||||||
(bg vim) (fg 13871)
|
(bg vim) (fg 13871)
|
||||||
";
|
";
|
||||||
pub fn fg_callback(
|
fn fg_callback(
|
||||||
ast: &Seg,
|
ast: &Seg,
|
||||||
_syms: &mut SymTable,
|
_syms: &mut SymTable,
|
||||||
shell_state: &mut ShellState
|
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";
|
"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 {
|
if let Ctr::String(ref dir) = *ast.car {
|
||||||
let dirp = Path::new(dir);
|
let dirp = Path::new(dir);
|
||||||
if let Err(s) = set_current_dir(&dirp) {
|
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()
|
..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/>.
|
* 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::sym::SymTable;
|
use crate::sym::{SymTable, Symbol, ValueType, Args};
|
||||||
use crate::error::{Traceback, start_trace};
|
use crate::error::{Traceback, start_trace};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io;
|
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.";
|
"traverses any number of arguments. Prints their evaluated values on a new line for each.";
|
||||||
|
fn echo_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn echo_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
ast.circuit(&mut |arg: &Ctr| match arg {
|
ast.circuit(&mut |arg: &Ctr| match arg {
|
||||||
Ctr::String(s) => print!("{}", s) == (),
|
Ctr::String(s) => print!("{}", s) == (),
|
||||||
_ => print!("{}", arg) == (),
|
_ => print!("{}", arg) == (),
|
||||||
|
|
@ -33,11 +33,10 @@ pub fn echo_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback>
|
||||||
Ok(Ctr::None)
|
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.
|
converts each argument to a string. Combines all strings.
|
||||||
Returns final (combined) string.";
|
Returns final (combined) string.";
|
||||||
|
fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let mut string = String::from("");
|
let mut string = String::from("");
|
||||||
if !ast.circuit(&mut |arg: &Ctr| {
|
if !ast.circuit(&mut |arg: &Ctr| {
|
||||||
match arg {
|
match arg {
|
||||||
|
|
@ -60,11 +59,10 @@ pub fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback
|
||||||
return Ok(Ctr::String(string));
|
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.
|
Arg is converted to a string if not already a string.
|
||||||
Returns string length of arg.";
|
Returns string length of arg.";
|
||||||
|
fn strlen_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn strlen_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
match &*ast.car {
|
match &*ast.car {
|
||||||
Ctr::Symbol(s) => Ok(Ctr::Integer(s.len() as i128)),
|
Ctr::Symbol(s) => Ok(Ctr::Integer(s.len() as i128)),
|
||||||
Ctr::String(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.";
|
Arg is converted to a string and returned.";
|
||||||
|
fn strcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn strcast_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
match &*ast.car {
|
match &*ast.car {
|
||||||
Ctr::Symbol(s) => Ok(Ctr::String(s.clone())),
|
Ctr::Symbol(s) => Ok(Ctr::String(s.clone())),
|
||||||
Ctr::String(_) => Ok(*ast.car.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";
|
"Takes two strings. Returns true if string1 contains at least one instance of string2";
|
||||||
|
fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn substr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let parent_str: String;
|
let parent_str: String;
|
||||||
if let Ctr::String(ref s) = *ast.car {
|
if let Ctr::String(ref s) = *ast.car {
|
||||||
parent_str = s.to_string();
|
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)))
|
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.";
|
Returns a list of substrings from string 1 that were found delimited by string 2.";
|
||||||
|
fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
let parent_str: String;
|
let parent_str: String;
|
||||||
if let Ctr::String(ref s) = *ast.car {
|
if let Ctr::String(ref s) = *ast.car {
|
||||||
parent_str = s.to_string();
|
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))
|
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.
|
Then prompts for user input.
|
||||||
User input is returned as a string";
|
User input is returned as a string";
|
||||||
|
fn input_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
pub fn input_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
|
||||||
if let Ctr::String(ref s) = *ast.car {
|
if let Ctr::String(ref s) = *ast.car {
|
||||||
print!("{}", s);
|
print!("{}", s);
|
||||||
let _= io::stdout().flush();
|
let _= io::stdout().flush();
|
||||||
|
|
@ -185,3 +179,89 @@ pub fn input_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback>
|
||||||
.into()))
|
.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