add some boolean operations, tests for

Signed-off-by: Ava Hahn <ava@aidanis.online>
This commit is contained in:
Ava Hahn 2023-03-02 09:43:12 -08:00
parent c1d83a6285
commit 28e158f110
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
5 changed files with 292 additions and 4 deletions

View file

@ -127,7 +127,7 @@ This contains any executable target of this project. Notably the main shell file
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer
*** TODO Rudimentary Control Flow *** TODO Rudimentary Control Flow
**** DONE if clause **** DONE if clause
**** TODO let clause **** DONE let clause
**** TODO while clause **** TODO while clause
**** TODO circuit clause **** TODO circuit clause
*** TODO Help function *** TODO Help function
@ -143,22 +143,26 @@ Will need a concatenate function for tables
*** TODO Custom ast pretty print *** TODO Custom ast pretty print
*** TODO Shell module *** TODO Shell module
**** TODO Process launching with environment variables **** TODO Process launching with environment variables
**** TODO Optional form of process which allows fd redirecting
**** TODO Foreground process TTY **** TODO Foreground process TTY
**** TODO Background processes **** TODO Background processes
*** TODO list operations *** TODO list operations
**** DONE append
**** DONE expand
**** TODO head (returns (head rest)) **** TODO head (returns (head rest))
**** TODO tail (returns (rest tail)) **** TODO tail (returns (rest tail))
**** TODO queue (append to front) **** TODO queue (append to front)
**** TODO snippet for dequeue **** TODO snippet for dequeue
**** TODO snippet for pop **** TODO snippet for pop
*** TODO boolean operations *** TODO boolean operations
**** TODO and (circuit) **** DONE and (circuit)
**** TODO or **** DONE or
**** TODO xor **** TODO xor
**** TODO no **** DONE no
**** TODO eq? **** TODO eq?
**** TODO toggle **** TODO toggle
*** TODO string operations *** TODO string operations
**** TODO typecast (string)
**** TODO contains **** TODO contains
**** TODO len **** TODO len
**** TODO concat **** TODO concat
@ -166,6 +170,8 @@ Will need a concatenate function for tables
**** TODO split (on delimiter) **** TODO split (on delimiter)
**** TODO strcons (sprintf but its all string tokens under the hood) **** TODO strcons (sprintf but its all string tokens under the hood)
*** TODO arithmetic operations *** TODO arithmetic operations
**** TODO typecast (int)
**** TODO typecast (float)
**** TODO add **** TODO add
**** TODO sub **** TODO sub
**** TODO div **** TODO div

View file

@ -23,6 +23,7 @@ use std::rc::Rc;
pub mod append; pub mod append;
pub mod control; pub mod control;
pub mod boolean;
//pub mod str; //pub mod str;
/// static_stdlib /// static_stdlib
@ -79,6 +80,66 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
}, },
); );
syms.insert(
"and".to_string(),
Symbol {
name: String::from("and"),
args: Args::Infinite,
conditional_branches: false,
value: ValueType::Internal(Rc::new(boolean::bool_and_callback)),
}
);
syms.insert(
"or".to_string(),
Symbol {
name: String::from("or"),
args: Args::Infinite,
conditional_branches: false,
value: ValueType::Internal(Rc::new(boolean::bool_or_callback)),
}
);
syms.insert(
"xor".to_string(),
Symbol {
name: String::from("xor"),
args: Args::Infinite,
conditional_branches: false,
value: ValueType::Internal(Rc::new(boolean::bool_xor_callback)),
}
);
syms.insert(
"not".to_string(),
Symbol {
name: String::from("not"),
args: Args::Strict(vec![Type::Bool]),
conditional_branches: false,
value: ValueType::Internal(Rc::new(boolean::bool_not_callback)),
}
);
syms.insert(
"eq?".to_string(),
Symbol {
name: String::from("eq?"),
args: Args::Infinite,
conditional_branches: false,
value: ValueType::Internal(Rc::new(boolean::bool_iseq_callback)),
}
);
syms.insert(
"toggle".to_string(),
Symbol {
name: String::from("toggle"),
args: Args::Lazy(1),
conditional_branches: true,
value: ValueType::Internal(Rc::new(boolean::bool_toggle_callback)),
}
);
Ok(()) Ok(())
} }

76
src/stl/boolean.rs Normal file
View file

@ -0,0 +1,76 @@
/* Copyright (C) 2021 Aidan Hahn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::segment::{Ctr, Seg};
use crate::sym::SymTable;
pub fn bool_and_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
let mut type_error = false;
let result = ast.circuit(&mut |arg: &Ctr| -> bool {
if let Ctr::Bool(b) = *arg {
b
} else {
eprintln!("{} is not a boolean", arg);
type_error = true;
false
}
});
if type_error {
Err("all arguments to and must evaluate to boolean".to_string())
} else {
Ok(Ctr::Bool(result))
}
}
pub fn bool_or_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
let mut result = false;
let correct_types = ast.circuit(&mut |arg: &Ctr| -> bool {
if let Ctr::Bool(b) = *arg {
result = result || b;
true
} else {
eprintln!("{} is not a boolean", arg);
false
}
});
if !correct_types {
Err("all arguments to 'or' must evaluate to boolean".to_string())
} else {
Ok(Ctr::Bool(result))
}
}
pub fn bool_xor_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!()
}
pub fn bool_not_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
if let Ctr::Bool(b) = *ast.car {
Ok(Ctr::Bool(!b))
} else {
Err("impossible state: non bool given to not".to_string())
}
}
pub fn bool_iseq_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!()
}
pub fn bool_toggle_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!()
}

144
tests/test_lib_bools.rs Normal file
View file

@ -0,0 +1,144 @@
mod bool_lib_tests {
use relish::ast::{eval, lex, Ctr, SymTable};
use relish::stdlib::{dynamic_stdlib, static_stdlib};
#[test]
fn test_and_true_chain() {
let document = "(and true true true true true)";
let result = true;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(b) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(b, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_and_true_chain_with_false() {
let document = "(and true true false true true)";
let result = false;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_and_false_chain() {
let document = "(and false false false false false)";
let result = false;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_or_true_chain() {
let document = "(or true true true true true)";
let result = true;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(b) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(b, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_or_true_chain_with_false() {
let document = "(or true true false true true)";
let result = true;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_or_false_chain() {
let document = "(or false false false false)";
let result = false;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_not() {
let document = "(not true)";
let result = false;
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Bool(i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i, result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
}

View file

@ -108,6 +108,7 @@ mod control_lib_tests {
#[test] #[test]
fn test_let_multiphase_local_multibody_evals() { fn test_let_multiphase_local_multibody_evals() {
// prints 'first body' and then returns ('1' '2' '3')
let document = "(let ( let document = "(let (
(temp '1') (temp '1')
(temp (append () temp '2'))) (temp (append () temp '2')))