did shit
This commit is contained in:
parent
b8f2963769
commit
fa8aae88b4
122
Cargo.lock
generated
122
Cargo.lock
generated
|
@ -8,6 +8,18 @@ version = "0.3.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
|
@ -38,7 +50,7 @@ dependencies = [
|
|||
"bitflags 2.8.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
|
@ -369,10 +381,19 @@ version = "0.7.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.3.8",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hibitset"
|
||||
version = "0.6.4"
|
||||
|
@ -388,6 +409,15 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
|
@ -425,6 +455,12 @@ dependencies = [
|
|||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
|
@ -458,6 +494,51 @@ version = "0.4.25"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "malachite"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aa282d5c3914eba1e50fd81012e04cfd5a79a08c29ece0fa20ef73afcbd7804"
|
||||
dependencies = [
|
||||
"malachite-base",
|
||||
"malachite-nz",
|
||||
"malachite-q",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malachite-base"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef157484a1d7246fbff1a4fd2c148b83ac7324161963af61001ea43dc9086076"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
"itertools 0.11.0",
|
||||
"libm",
|
||||
"ryu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malachite-nz"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de4451b2e0e0ec6e4f39ee311b72154d291b185f5450474ace5663e37d7f8360"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"libm",
|
||||
"malachite-base",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malachite-q"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fa9bd8eccda7ff0959d48e00e03ee3626817414442725b2cc1f1b2f215ceee9"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"malachite-base",
|
||||
"malachite-nz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
|
@ -511,6 +592,7 @@ dependencies = [
|
|||
"clay-layout",
|
||||
"enum_dispatch",
|
||||
"font-kit",
|
||||
"malachite",
|
||||
"raylib",
|
||||
"termion",
|
||||
"test-case",
|
||||
|
@ -708,6 +790,12 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
@ -742,7 +830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c5f08237e667ac94ad20f8878b5943d91a93ccb231428446c57c21c57779016d"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"hashbrown",
|
||||
"hashbrown 0.7.2",
|
||||
"mopa",
|
||||
"smallvec",
|
||||
"tynm",
|
||||
|
@ -767,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "fff28a29366aff703d5da8a7e2c8875dc8453ac1118f842cbc0fa70c7db51240"
|
||||
dependencies = [
|
||||
"crossbeam-queue",
|
||||
"hashbrown",
|
||||
"hashbrown 0.7.2",
|
||||
"hibitset",
|
||||
"log",
|
||||
"shred",
|
||||
|
@ -894,6 +982,12 @@ version = "1.0.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
|
@ -1111,3 +1205,23 @@ dependencies = [
|
|||
"once_cell",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2024"
|
|||
clay-layout = { path = "../clay-ui-rust" }
|
||||
enum_dispatch = "0.3.13"
|
||||
font-kit = "0.14.2"
|
||||
malachite = "0.5.0"
|
||||
raylib = { version = "5.0.2", features = ["wayland"] }
|
||||
termion = "4.0.3"
|
||||
test-case = "3.3.1"
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
use std::io::{self, StdoutLock, Write, stdout};
|
||||
use std::rc::Rc;
|
||||
|
||||
use libopenbirch::environment::Environment;
|
||||
use libopenbirch::node::Node;
|
||||
use libopenbirch::node::constant::Constant;
|
||||
use libopenbirch::node::empty::Empty;
|
||||
use libopenbirch::node::{Node, NodeEnum};
|
||||
use libopenbirch::parser::{Lexer, Parser, ParserError};
|
||||
use malachite::base::num::basic::traits::Zero;
|
||||
use malachite::rational::Rational;
|
||||
#[cfg(feature = "async")]
|
||||
use termion::AsyncReader;
|
||||
use termion::color;
|
||||
|
@ -148,12 +153,24 @@ fn print_err(i: usize, len: usize, exp: String) {
|
|||
);
|
||||
}
|
||||
|
||||
fn print(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
for expr in args {
|
||||
println!("\r{}", expr.as_string(Some(env)));
|
||||
}
|
||||
|
||||
Ok(Empty::new(""))
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let mut input = Input::new();
|
||||
|
||||
let mut env = Environment::new();
|
||||
|
||||
env.define_native_function("print", print);
|
||||
|
||||
while let Some(source) = input.get()? {
|
||||
input.disable_raw()?;
|
||||
|
||||
let mut lexer = Lexer::new(&source);
|
||||
let tokens_result = lexer.lex();
|
||||
|
||||
|
@ -164,9 +181,6 @@ fn main() -> Result<(), io::Error> {
|
|||
continue;
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
input.disable_raw()?;
|
||||
|
||||
let tokens = tokens_result.unwrap();
|
||||
let mut parser = Parser::new(tokens, &mut env);
|
||||
|
||||
|
@ -193,7 +207,6 @@ fn main() -> Result<(), io::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
input.enable_raw()?;
|
||||
|
||||
print!("{}", color::Fg(color::Reset));
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
use std::{collections::HashMap, rc::Rc};
|
||||
use std::{collections::HashMap, rc::Rc, thread::current};
|
||||
|
||||
use crate::node::NodeEnum;
|
||||
use crate::node::{
|
||||
NodeEnum,
|
||||
function::{self, Function, FunctionType, NativeFunctionType},
|
||||
};
|
||||
|
||||
pub type EnvironmentInternalSymbolKey = u16;
|
||||
// pub type Environment = HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>;
|
||||
|
||||
struct Scope {
|
||||
pub stack_len: usize,
|
||||
pub shadow_len: usize,
|
||||
}
|
||||
|
||||
pub struct Environment {
|
||||
map: HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>,
|
||||
stack_depth: usize,
|
||||
max_stack_depth: usize,
|
||||
stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
|
||||
|
||||
stack_sizes: Vec<Scope>,
|
||||
stack: Vec<EnvironmentInternalSymbolKey>,
|
||||
stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
||||
|
||||
// stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
|
||||
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
||||
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
|
||||
unique_keys: EnvironmentInternalSymbolKey,
|
||||
|
@ -22,7 +34,10 @@ impl Environment {
|
|||
map: HashMap::new(),
|
||||
stack_depth: 0,
|
||||
max_stack_depth: 5000,
|
||||
stack: vec![vec![]],
|
||||
|
||||
stack_sizes: vec![],
|
||||
stack: vec![],
|
||||
stack_shadows: vec![],
|
||||
|
||||
symbol_to_id: HashMap::new(),
|
||||
id_to_symbol: HashMap::new(),
|
||||
|
@ -31,61 +46,101 @@ impl Environment {
|
|||
}
|
||||
|
||||
pub fn push_stack(&mut self) -> Result<(), String> {
|
||||
debug_assert!(self.stack_depth == self.stack.len() - 1);
|
||||
|
||||
if self.stack_depth == self.max_stack_depth {
|
||||
self.unwind_stack();
|
||||
return Err("Max Stack depth exceeded".to_owned());
|
||||
}
|
||||
|
||||
self.stack_depth += 1;
|
||||
self.stack.push(vec![]);
|
||||
self.stack_sizes.push(Scope {
|
||||
stack_len: 0,
|
||||
shadow_len: 0,
|
||||
});
|
||||
|
||||
debug_assert!(self.stack_depth == self.stack.len() - 1);
|
||||
// debug_assert!(self.stack_depth == self.stack.len() - 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pop_stack(&mut self) -> Result<(), String> {
|
||||
debug_assert!(
|
||||
self.stack_depth == self.stack.len() - 1,
|
||||
"Expected stack len: {}, stack_depth: {}",
|
||||
self.stack.len(),
|
||||
self.stack_depth
|
||||
);
|
||||
|
||||
if self.stack_depth == 0 {
|
||||
return Err("Trying to pop empty stack".to_owned());
|
||||
}
|
||||
|
||||
self.stack_depth -= 1;
|
||||
|
||||
for item in self.stack.pop().unwrap() {
|
||||
self.map.remove(&item);
|
||||
let scope = self.stack_sizes.pop().unwrap();
|
||||
for _ in 0..scope.stack_len {
|
||||
self.map.remove(&self.stack.pop().unwrap());
|
||||
}
|
||||
for _ in 0..scope.shadow_len {
|
||||
let (id, value) = self.stack_shadows.pop().unwrap();
|
||||
self.map.insert(id, value);
|
||||
}
|
||||
|
||||
debug_assert!(self.stack_depth == self.stack.len() - 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unwind_stack(&mut self) {
|
||||
for stack in &self.stack {
|
||||
for item in stack {
|
||||
self.map.remove(&item);
|
||||
for scope in &self.stack_sizes {
|
||||
for _ in 0..scope.stack_len {
|
||||
self.map.remove(&self.stack.pop().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
self.stack = vec![vec![]];
|
||||
self.stack_sizes = vec![];
|
||||
self.stack_shadows = vec![];
|
||||
self.stack_depth = 0;
|
||||
}
|
||||
|
||||
pub fn define(&mut self, name: String, value: Rc<NodeEnum>) {
|
||||
let id = if let Some(value) = self.str_to_id(&name) {
|
||||
*value
|
||||
} else {
|
||||
self.get_new_id()
|
||||
};
|
||||
|
||||
self.map.insert(id, value);
|
||||
self.insert_id_to_str(id, name);
|
||||
}
|
||||
|
||||
pub fn define_native_function(&mut self, name: &'static str, func: NativeFunctionType) {
|
||||
let f = Function::new(FunctionType::Native(name, func));
|
||||
|
||||
self.define(name.to_owned(), f);
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc<NodeEnum>> {
|
||||
self.map.get(key)
|
||||
}
|
||||
|
||||
fn get_current_scope(&mut self) -> &[u16] {
|
||||
let len = self.stack.len();
|
||||
let current_scope_size = self.stack_sizes.last().unwrap().stack_len;
|
||||
let start = len - current_scope_size;
|
||||
self.stack.get(start..len).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: EnvironmentInternalSymbolKey, value: Rc<NodeEnum>) {
|
||||
if self.stack_depth != 0 {
|
||||
let mut shadow = false;
|
||||
if let Some(existing) = self.map.get(&key) {
|
||||
if !self.get_current_scope().contains(&key) {
|
||||
// We need to shadow this variable
|
||||
self.stack_shadows
|
||||
.push((key, self.map.insert(key, value.clone()).unwrap()));
|
||||
self.stack.push(key);
|
||||
shadow = true;
|
||||
}
|
||||
}
|
||||
let scope = unsafe { self.stack_sizes.get_unchecked_mut(self.stack_depth - 1) };
|
||||
scope.stack_len += 1;
|
||||
self.stack.push(key);
|
||||
if shadow {
|
||||
scope.shadow_len += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.map.insert(key, value);
|
||||
unsafe { self.stack.get_unchecked_mut(self.stack_depth).push(key) }
|
||||
}
|
||||
|
||||
pub fn str_to_id(&self, value: &String) -> Option<&EnvironmentInternalSymbolKey> {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
|
@ -15,20 +17,16 @@ impl Node for Add {
|
|||
|
||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||
// Zero rule
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right),
|
||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => Ok(evaluated_left),
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == &Rational::ZERO => Ok(evaluated_right),
|
||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == &Rational::ZERO => Ok(evaluated_left),
|
||||
|
||||
|
||||
// Constant + Constant = Constant
|
||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||
Ok(Rc::new(Constant::new(a.get_value() + b.get_value()).into()))
|
||||
}
|
||||
|
||||
// Symbol + Constant we just return the same
|
||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => {
|
||||
Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into()))
|
||||
}
|
||||
|
||||
// Constant + Symbol we switch them around so the constant is last
|
||||
// Move constants after symbols in add
|
||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
||||
Ok(Rc::new(Add::new(evaluated_right, evaluated_left).into()))
|
||||
}
|
||||
|
@ -61,6 +59,10 @@ impl Add {
|
|||
Self { left, right }
|
||||
}
|
||||
|
||||
pub fn new_rc(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { left, right }.into())
|
||||
}
|
||||
|
||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||
self.left.clone()
|
||||
}
|
||||
|
|
|
@ -35,27 +35,24 @@ impl Node for Call {
|
|||
);
|
||||
};
|
||||
|
||||
// Check if argument counts match
|
||||
let fargs = func.get_arguments();
|
||||
if fargs.len() != arguments.len() {
|
||||
return Err(format!(
|
||||
"Error calling function. Expected {} arguments, but got {}",
|
||||
func.get_arguments().len(),
|
||||
arguments.len()
|
||||
));
|
||||
}
|
||||
|
||||
// Call function body with arguments
|
||||
match func.get_body() {
|
||||
// Pass arguments to native function
|
||||
FunctionType::Native(_name, native_function) => native_function(&arguments),
|
||||
FunctionType::UserFunction(node_enum) => {
|
||||
FunctionType::Native(_name, native_function) => native_function(&arguments, env),
|
||||
FunctionType::UserFunction(body, fargs) => {
|
||||
if fargs.len() != arguments.len() {
|
||||
return Err(format!(
|
||||
"Error calling function. Expected {} arguments, but got {}",
|
||||
fargs.len(),
|
||||
arguments.len()
|
||||
));
|
||||
}
|
||||
env.push_stack()?;
|
||||
// Define variables
|
||||
fargs.iter().zip(arguments).for_each(|(symbol, value)| {
|
||||
env.insert(symbol.get_value(), value.clone());
|
||||
});
|
||||
let ev = node_enum.evaluate(env)?;
|
||||
let ev = body.evaluate(env)?;
|
||||
env.pop_stack()?;
|
||||
// Return evaluated return value for function
|
||||
Ok(ev)
|
||||
|
|
237
src/lib/node/comparison.rs
Normal file
237
src/lib/node/comparison.rs
Normal file
|
@ -0,0 +1,237 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::environment::Environment;
|
||||
|
||||
use super::{Node, NodeEnum, Precedence, if_else::Bool};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Greater {
|
||||
left: Rc<NodeEnum>,
|
||||
right: Vec<Rc<NodeEnum>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Less {
|
||||
left: Rc<NodeEnum>,
|
||||
right: Vec<Rc<NodeEnum>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct GreaterEquals {
|
||||
left: Rc<NodeEnum>,
|
||||
right: Vec<Rc<NodeEnum>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct LessEquals {
|
||||
left: Rc<NodeEnum>,
|
||||
right: Vec<Rc<NodeEnum>>,
|
||||
}
|
||||
|
||||
impl Node for Greater {
|
||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut expr = self.left.evaluate(env)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
let evaluation = expr.partial_cmp(&e);
|
||||
match evaluation {
|
||||
Some(cmp) if cmp != std::cmp::Ordering::Greater => {
|
||||
return Ok(Rc::new(Bool::False.into()));
|
||||
}
|
||||
None => {
|
||||
return self.abort(env);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
expr = e;
|
||||
}
|
||||
return Ok(Rc::new(Bool::True.into()));
|
||||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
format!(
|
||||
"{} > {}",
|
||||
self.left.as_string(env),
|
||||
self.right
|
||||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + " > " + &b)
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
fn precedence(&self) -> Precedence {
|
||||
Precedence::Compare
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for Less {
|
||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut expr = self.left.evaluate(env)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
let evaluation = expr.partial_cmp(&e);
|
||||
match evaluation {
|
||||
Some(cmp) if cmp != std::cmp::Ordering::Less => {
|
||||
return Ok(Rc::new(Bool::False.into()));
|
||||
}
|
||||
None => {
|
||||
return self.abort(env);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
expr = e;
|
||||
}
|
||||
return Ok(Rc::new(Bool::True.into()));
|
||||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
format!(
|
||||
"{} < {}",
|
||||
self.left.as_string(env),
|
||||
self.right
|
||||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + " < " + &b)
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
fn precedence(&self) -> Precedence {
|
||||
Precedence::Compare
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for GreaterEquals {
|
||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut expr = self.left.evaluate(env)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
let evaluation = expr.partial_cmp(&e);
|
||||
match evaluation {
|
||||
Some(cmp)
|
||||
if cmp != std::cmp::Ordering::Equal || cmp != std::cmp::Ordering::Greater =>
|
||||
{
|
||||
return Ok(Rc::new(Bool::False.into()));
|
||||
}
|
||||
None => {
|
||||
return self.abort(env);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
expr = e;
|
||||
}
|
||||
return Ok(Rc::new(Bool::True.into()));
|
||||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
format!(
|
||||
"{} >= {}",
|
||||
self.left.as_string(env),
|
||||
self.right
|
||||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + " >= " + &b)
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
fn precedence(&self) -> Precedence {
|
||||
Precedence::Compare
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for LessEquals {
|
||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut expr = self.left.evaluate(env)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
let evaluation = expr.partial_cmp(&e);
|
||||
match evaluation {
|
||||
Some(cmp)
|
||||
if cmp != std::cmp::Ordering::Equal || cmp != std::cmp::Ordering::Less =>
|
||||
{
|
||||
return Ok(Rc::new(Bool::False.into()));
|
||||
}
|
||||
None => {
|
||||
return self.abort(env);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
expr = e;
|
||||
}
|
||||
return Ok(Rc::new(Bool::True.into()));
|
||||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
format!(
|
||||
"{} <= {}",
|
||||
self.left.as_string(env),
|
||||
self.right
|
||||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + " <= " + &b)
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
fn precedence(&self) -> Precedence {
|
||||
Precedence::Compare
|
||||
}
|
||||
}
|
||||
|
||||
impl Greater {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Vec<Rc<NodeEnum>>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { left, right }.into())
|
||||
}
|
||||
|
||||
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut arguments = vec![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
}
|
||||
Ok(Self::new(self.left.evaluate(env)?, arguments))
|
||||
}
|
||||
}
|
||||
|
||||
impl Less {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Vec<Rc<NodeEnum>>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { left, right }.into())
|
||||
}
|
||||
|
||||
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut arguments = vec![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
}
|
||||
Ok(Self::new(self.left.evaluate(env)?, arguments))
|
||||
}
|
||||
}
|
||||
|
||||
impl LessEquals {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Vec<Rc<NodeEnum>>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { left, right }.into())
|
||||
}
|
||||
|
||||
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut arguments = vec![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
}
|
||||
Ok(Self::new(self.left.evaluate(env)?, arguments))
|
||||
}
|
||||
}
|
||||
|
||||
impl GreaterEquals {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Vec<Rc<NodeEnum>>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { left, right }.into())
|
||||
}
|
||||
|
||||
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let mut arguments = vec![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
}
|
||||
Ok(Self::new(self.left.evaluate(env)?, arguments))
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
use super::{Environment, Node, Precedence};
|
||||
|
||||
pub type ConstantValue = f64;
|
||||
pub type ConstantValue = malachite::rational::Rational;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Constant {
|
||||
|
@ -34,8 +34,8 @@ impl Constant {
|
|||
Self { value }
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> ConstantValue {
|
||||
self.value
|
||||
pub fn get_value(&self) -> &ConstantValue {
|
||||
&self.value
|
||||
}
|
||||
|
||||
pub fn set_value(&mut self, value: ConstantValue) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use super::{constant::Constant, set::Set, Node, NodeEnum, Precedence};
|
||||
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
||||
|
||||
use super::{Node, NodeEnum, Precedence, constant::Constant, set::Set};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Divide {
|
||||
|
@ -15,27 +17,20 @@ impl Node for Divide {
|
|||
|
||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||
// Error if dividing by zero
|
||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => {
|
||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == &Rational::ZERO => {
|
||||
Err("Division by Zero".into())
|
||||
}
|
||||
|
||||
(_, _) if evaluated_left == evaluated_right => Ok(Rc::new(Constant::new(Rational::ZERO).into())),
|
||||
|
||||
// Zero rule
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => {
|
||||
Ok(evaluated_left)
|
||||
}
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == &Rational::ZERO => Ok(evaluated_left),
|
||||
|
||||
// Constant + Constant = Constant
|
||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||
Ok(Rc::new(Constant::new(a.get_value() / b.get_value()).into()))
|
||||
}
|
||||
// Symbol + Constant we just return the same
|
||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => {
|
||||
Ok(Rc::new(Divide::new(evaluated_left, evaluated_right).into()))
|
||||
}
|
||||
// Constant + Symbol we switch them around so the constant is last
|
||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
||||
Ok(Rc::new(Divide::new(evaluated_right, evaluated_left).into()))
|
||||
}
|
||||
|
||||
// Divide a set with a constant
|
||||
(NodeEnum::Set(s), NodeEnum::Constant(c)) => {
|
||||
let old_values = s.get_values();
|
||||
|
@ -90,6 +85,10 @@ impl Divide {
|
|||
Self { left, right }
|
||||
}
|
||||
|
||||
pub fn new_rc(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self::new(left, right).into())
|
||||
}
|
||||
|
||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||
self.left.clone()
|
||||
}
|
||||
|
|
|
@ -2,11 +2,18 @@ use std::{rc::Rc, sync::LazyLock};
|
|||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialOrd)]
|
||||
pub struct Empty {
|
||||
message: Option<String>,
|
||||
}
|
||||
|
||||
impl PartialEq for Empty {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
impl Eq for Empty {}
|
||||
|
||||
impl Node for Empty {
|
||||
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
Ok(Empty::EMPTY.clone())
|
||||
|
|
|
@ -5,25 +5,31 @@ use super::{Environment, Node, NodeEnum, Precedence, if_else::Bool};
|
|||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Equals {
|
||||
left: Rc<NodeEnum>,
|
||||
right: Rc<NodeEnum>,
|
||||
right: Vec<Rc<NodeEnum>>,
|
||||
}
|
||||
|
||||
impl Node for Equals {
|
||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||
let left = self.left.evaluate(env)?;
|
||||
let right = self.right.evaluate(env)?;
|
||||
|
||||
match left == right {
|
||||
true => Ok(Rc::new(Bool::True.into())),
|
||||
false => Ok(Rc::new(Bool::False.into())),
|
||||
for expr in &self.right {
|
||||
if left != expr.evaluate(env)? {
|
||||
return Ok(Rc::new(Bool::False.into()));
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(Rc::new(Bool::True.into()));
|
||||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
format!(
|
||||
"({}={})",
|
||||
"{} = {}",
|
||||
self.left.as_string(env),
|
||||
self.right.as_string(env)
|
||||
self.right
|
||||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + " = " + &b)
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -33,7 +39,7 @@ impl Node for Equals {
|
|||
}
|
||||
|
||||
impl Equals {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Vec<Rc<NodeEnum>>) -> Self {
|
||||
Self { left, right }
|
||||
}
|
||||
}
|
||||
|
|
68
src/lib/node/exponent.rs
Normal file
68
src/lib/node/exponent.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use malachite::{Natural, rational::Rational, rational::arithmetic::pow};
|
||||
|
||||
use malachite::base::num::arithmetic::traits::Pow;
|
||||
|
||||
use malachite::rational::conversion::integer_from_rational;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Exponent {
|
||||
left: Rc<NodeEnum>,
|
||||
right: Rc<NodeEnum>,
|
||||
}
|
||||
|
||||
impl Node for Exponent {
|
||||
fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> {
|
||||
let evaluated_left = self.left.evaluate(env)?;
|
||||
let evaluated_right = self.right.evaluate(env)?;
|
||||
|
||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||
let v = b.get_value();
|
||||
let exp: u64 = if let Ok(u) = v.try_into() {
|
||||
u
|
||||
} else {
|
||||
return Err("Exponent was too large".into());
|
||||
};
|
||||
Ok(Rc::new(Constant::new(a.get_value().pow(exp)).into()))
|
||||
}
|
||||
|
||||
_ => Ok(Self::new(evaluated_left, evaluated_right)),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
let left_string = if self.left.precedence() <= self.precedence() {
|
||||
format!("({})", self.left.as_string(env))
|
||||
} else {
|
||||
self.left.as_string(env)
|
||||
};
|
||||
let right_string = if self.right.precedence() <= self.precedence() {
|
||||
format!("({})", self.right.as_string(env))
|
||||
} else {
|
||||
self.right.as_string(env)
|
||||
};
|
||||
format!("{}^{}", left_string, right_string)
|
||||
}
|
||||
|
||||
fn precedence(&self) -> Precedence {
|
||||
Precedence::Exponent
|
||||
}
|
||||
}
|
||||
|
||||
impl Exponent {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { left, right }.into())
|
||||
}
|
||||
|
||||
pub fn get_left(&self) -> &Rc<NodeEnum> {
|
||||
&self.left
|
||||
}
|
||||
|
||||
pub fn get_right(&self) -> &Rc<NodeEnum> {
|
||||
&self.right
|
||||
}
|
||||
}
|
|
@ -4,21 +4,17 @@ use crate::environment::Environment;
|
|||
|
||||
use super::{Node, NodeEnum, Precedence, symbol::Symbol};
|
||||
|
||||
pub type NativeFunctionType = fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum FunctionType {
|
||||
Native(
|
||||
&'static str,
|
||||
fn(&Vec<Rc<NodeEnum>>) -> Result<Rc<NodeEnum>, String>,
|
||||
),
|
||||
UserFunction(Rc<NodeEnum>),
|
||||
Native(&'static str, NativeFunctionType),
|
||||
UserFunction(Rc<NodeEnum>, Vec<Symbol>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Function {
|
||||
function: FunctionType,
|
||||
// TODO: Finish reasoning about whether or not this is
|
||||
// the right way to implement functions
|
||||
arguments: Vec<Symbol>,
|
||||
}
|
||||
|
||||
impl Node for Function {
|
||||
|
@ -27,16 +23,16 @@ impl Node for Function {
|
|||
}
|
||||
|
||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||
let args = self
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|x| Node::as_string(x, env))
|
||||
.reduce(|acc, e| format!("{acc}, {e}"))
|
||||
.unwrap_or("()".to_owned());
|
||||
|
||||
match &self.function {
|
||||
FunctionType::Native(name, _) => name.to_owned().to_owned(),
|
||||
FunctionType::UserFunction(body) => format!("({args} -> {})", body.as_string(env)),
|
||||
FunctionType::Native(name, _) => format!("(Native Function `{name}`)"),
|
||||
FunctionType::UserFunction(body, args) => format!(
|
||||
"({} -> {})",
|
||||
args.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|acc, e| format!("{acc}, {e}"))
|
||||
.unwrap_or("()".to_owned()),
|
||||
body.as_string(env)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,21 +42,11 @@ impl Node for Function {
|
|||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(t: FunctionType, args: Vec<Symbol>) -> Rc<NodeEnum> {
|
||||
Rc::new(
|
||||
Self {
|
||||
function: t,
|
||||
arguments: args,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
pub fn new(t: FunctionType) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { function: t }.into())
|
||||
}
|
||||
|
||||
pub fn get_body(&self) -> &FunctionType {
|
||||
&self.function
|
||||
}
|
||||
|
||||
pub fn get_arguments(&self) -> &Vec<Symbol> {
|
||||
&self.arguments
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,12 +64,12 @@ impl Node for IfElse {
|
|||
for expr in to_evaluate {
|
||||
expr.evaluate(env)?;
|
||||
}
|
||||
last.evaluate(env)
|
||||
last.evaluate(env)?
|
||||
} else {
|
||||
Ok(Empty::EMPTY.clone())
|
||||
Empty::EMPTY.clone()
|
||||
};
|
||||
env.pop_stack()?;
|
||||
ret
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
match condition {
|
||||
|
|
|
@ -3,38 +3,42 @@ use std::{fmt::Display, rc::Rc};
|
|||
use add::Add;
|
||||
use assign::Assign;
|
||||
use call::Call;
|
||||
use comparison::{Greater, GreaterEquals, Less, LessEquals};
|
||||
use constant::Constant;
|
||||
use divide::Divide;
|
||||
use empty::Empty;
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use equals::Equals;
|
||||
use exponent::Exponent;
|
||||
use function::Function;
|
||||
use if_else::{Bool, IfElse};
|
||||
use multiply::Multiply;
|
||||
use set::Set;
|
||||
use subtract::Subtract;
|
||||
use symbol::Symbol;
|
||||
use equals::Equals;
|
||||
use set::Set;
|
||||
|
||||
use crate::environment::Environment;
|
||||
|
||||
pub mod add;
|
||||
pub mod assign;
|
||||
pub mod call;
|
||||
pub mod comparison;
|
||||
pub mod constant;
|
||||
pub mod divide;
|
||||
pub mod empty;
|
||||
pub mod equals;
|
||||
pub mod exponent;
|
||||
pub mod function;
|
||||
pub mod if_else;
|
||||
pub mod multiply;
|
||||
pub mod node_ref;
|
||||
pub mod set;
|
||||
pub mod subtract;
|
||||
pub mod symbol;
|
||||
pub mod node_ref;
|
||||
pub mod assign;
|
||||
pub mod empty;
|
||||
pub mod function;
|
||||
pub mod call;
|
||||
pub mod if_else;
|
||||
pub mod equals;
|
||||
pub mod set;
|
||||
|
||||
#[enum_dispatch]
|
||||
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum NodeEnum {
|
||||
Constant,
|
||||
|
||||
|
@ -43,6 +47,7 @@ pub enum NodeEnum {
|
|||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Exponent,
|
||||
|
||||
Symbol,
|
||||
// NodeRef, // DEPRECATED, use Symbol
|
||||
|
@ -57,17 +62,15 @@ pub enum NodeEnum {
|
|||
Set,
|
||||
|
||||
Equals,
|
||||
// Greater,
|
||||
// GreaterEquals,
|
||||
// Less,
|
||||
// LessEquals
|
||||
|
||||
// Logical operators
|
||||
// In,
|
||||
// Where,
|
||||
// Not,
|
||||
// Or,
|
||||
// And
|
||||
Greater,
|
||||
GreaterEquals,
|
||||
Less,
|
||||
LessEquals, // Logical operators
|
||||
// In,
|
||||
// Where,
|
||||
// Not,
|
||||
// Or,
|
||||
// And
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -79,6 +82,7 @@ pub enum Precedence {
|
|||
Term,
|
||||
Factor,
|
||||
Unary,
|
||||
Exponent,
|
||||
Call,
|
||||
Primary,
|
||||
}
|
||||
|
@ -95,3 +99,55 @@ impl Display for NodeEnum {
|
|||
write!(f, "{}", Node::as_string(self, None))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for NodeEnum {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
match (self, other) {
|
||||
(NodeEnum::Constant(constant1), NodeEnum::Constant(constant2)) => {
|
||||
constant1.partial_cmp(constant2)
|
||||
}
|
||||
|
||||
(NodeEnum::Add(add1), NodeEnum::Add(add2)) => add1.partial_cmp(add2),
|
||||
(NodeEnum::Subtract(subtract1), NodeEnum::Subtract(subtract2)) => {
|
||||
subtract1.partial_cmp(subtract2)
|
||||
}
|
||||
(NodeEnum::Multiply(multiply1), NodeEnum::Multiply(multiply2)) => {
|
||||
multiply1.partial_cmp(multiply2)
|
||||
}
|
||||
(NodeEnum::Divide(divide1), NodeEnum::Divide(divide2)) => divide1.partial_cmp(divide2),
|
||||
(NodeEnum::Exponent(exponent1), NodeEnum::Exponent(exponent2)) => {
|
||||
exponent1.partial_cmp(exponent2)
|
||||
}
|
||||
|
||||
(NodeEnum::Symbol(symbol1), NodeEnum::Symbol(symbol2)) => symbol1.partial_cmp(symbol2),
|
||||
(NodeEnum::Assign(assign1), NodeEnum::Assign(assign2)) => assign1.partial_cmp(assign2),
|
||||
(NodeEnum::Empty(empty1), NodeEnum::Empty(empty2)) => empty1.partial_cmp(empty2),
|
||||
(NodeEnum::Function(function1), NodeEnum::Function(function2)) => {
|
||||
function1.partial_cmp(function2)
|
||||
}
|
||||
(NodeEnum::Call(call1), NodeEnum::Call(call2)) => call1.partial_cmp(call2),
|
||||
|
||||
(NodeEnum::Bool(bool1), NodeEnum::Bool(bool2)) => bool1.partial_cmp(bool2),
|
||||
(NodeEnum::IfElse(if_else1), NodeEnum::IfElse(if_else2)) => {
|
||||
if_else1.partial_cmp(if_else2)
|
||||
}
|
||||
|
||||
(NodeEnum::Set(set1), NodeEnum::Set(set2)) => set1.partial_cmp(set2),
|
||||
|
||||
(NodeEnum::Equals(equals1), NodeEnum::Equals(equals2)) => equals1.partial_cmp(equals2),
|
||||
(NodeEnum::Greater(greater1), NodeEnum::Greater(greater2)) => {
|
||||
greater1.partial_cmp(greater2)
|
||||
}
|
||||
(
|
||||
NodeEnum::GreaterEquals(greater_equals1),
|
||||
NodeEnum::GreaterEquals(greater_equals2),
|
||||
) => greater_equals1.partial_cmp(greater_equals2),
|
||||
(NodeEnum::Less(less1), NodeEnum::Less(less2)) => less1.partial_cmp(less2),
|
||||
(NodeEnum::LessEquals(less_equals1), NodeEnum::LessEquals(less_equals2)) => {
|
||||
less_equals1.partial_cmp(less_equals2)
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use malachite::{base::num::basic::traits::{One, Zero}, rational::Rational};
|
||||
|
||||
use crate::environment::Environment;
|
||||
|
||||
use super::{Node, NodeEnum, Precedence, constant::Constant, set::Set};
|
||||
use super::{
|
||||
Node, NodeEnum, Precedence, add::Add, constant::Constant, divide::Divide, set::Set,
|
||||
subtract::Subtract,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Multiply {
|
||||
|
@ -18,26 +23,57 @@ impl Node for Multiply {
|
|||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||
// Zero rule
|
||||
(NodeEnum::Constant(zero), _) | (_, NodeEnum::Constant(zero))
|
||||
if zero.get_value() == 0. =>
|
||||
if zero.get_value() == &Rational::ZERO =>
|
||||
{
|
||||
Ok(Rc::new(Constant::new(0.).into()))
|
||||
Ok(Rc::new(Constant::new(Rational::ZERO).into()))
|
||||
}
|
||||
|
||||
// Identity rule
|
||||
(NodeEnum::Constant(one), _) if one.get_value() == &Rational::ONE => Ok(evaluated_right),
|
||||
(_, NodeEnum::Constant(one)) if one.get_value() == &Rational::ONE => Ok(evaluated_left),
|
||||
|
||||
// Multiply into parenthesis (add)
|
||||
(_, NodeEnum::Add(add)) => Ok(Add::new_rc(
|
||||
Self::new_rc(evaluated_left.clone(), add.get_left()).evaluate(env)?,
|
||||
Self::new_rc(evaluated_left, add.get_right()).evaluate(env)?,
|
||||
)),
|
||||
(NodeEnum::Add(add), _) => Ok(Add::new_rc(
|
||||
Self::new_rc(evaluated_right.clone(), add.get_left()).evaluate(env)?,
|
||||
Self::new_rc(evaluated_right, add.get_right()).evaluate(env)?,
|
||||
)),
|
||||
|
||||
// Multiply into parenthesis (sub)
|
||||
(_, NodeEnum::Subtract(sub)) => Ok(Subtract::new_rc(
|
||||
Self::new_rc(evaluated_left.clone(), sub.get_left()).evaluate(env)?,
|
||||
Self::new_rc(evaluated_left, sub.get_right()).evaluate(env)?,
|
||||
)),
|
||||
(NodeEnum::Subtract(sub), _) => Ok(Subtract::new_rc(
|
||||
Self::new_rc(evaluated_right.clone(), sub.get_left()).evaluate(env)?,
|
||||
Self::new_rc(evaluated_right, sub.get_right()).evaluate(env)?,
|
||||
)),
|
||||
|
||||
// Multiply fraction
|
||||
(NodeEnum::Divide(div), _) => Ok(Divide::new_rc(
|
||||
Self::new_rc(evaluated_right, div.get_left()).evaluate(env)?,
|
||||
div.get_right(),
|
||||
)),
|
||||
|
||||
(_, NodeEnum::Divide(div)) => Ok(Divide::new_rc(
|
||||
Self::new_rc(evaluated_left, div.get_left()).evaluate(env)?,
|
||||
div.get_right(),
|
||||
)),
|
||||
|
||||
// Constant + Constant = Constant
|
||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||
Ok(Rc::new(Constant::new(a.get_value() * b.get_value()).into()))
|
||||
}
|
||||
|
||||
// Symbol + Constant we just return the same
|
||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
||||
// Move constant infront of symbols
|
||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_))
|
||||
| (NodeEnum::Exponent(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
||||
Multiply::new(evaluated_right, evaluated_left).into(),
|
||||
)),
|
||||
|
||||
// Constant + Symbol we switch them around so the constant is last
|
||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
||||
Multiply::new(evaluated_left, evaluated_right).into(),
|
||||
)),
|
||||
|
||||
// Multiply a set with a constant
|
||||
(NodeEnum::Set(s), NodeEnum::Constant(c))
|
||||
| (NodeEnum::Constant(c), NodeEnum::Set(s)) => {
|
||||
|
|
|
@ -25,7 +25,7 @@ impl Node for Set {
|
|||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + ", " + &b)
|
||||
.unwrap()
|
||||
.unwrap_or("".to_owned())
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
|
@ -15,24 +17,24 @@ impl Node for Subtract {
|
|||
|
||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||
// Zero rule
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right),
|
||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => Ok(evaluated_left),
|
||||
(NodeEnum::Constant(zero), _) if zero.get_value() == &Rational::ZERO => Ok(evaluated_right),
|
||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == &Rational::ZERO => Ok(evaluated_left),
|
||||
|
||||
// Constant + Constant = Constant
|
||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||
Ok(Rc::new(Constant::new(a.get_value() - b.get_value()).into()))
|
||||
}
|
||||
// Symbol + Constant we just return the same
|
||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => {
|
||||
Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into()))
|
||||
}
|
||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
||||
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||
)),
|
||||
// Constant + Symbol we switch them around so the constant is last
|
||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
||||
Ok(Rc::new(Subtract::new(evaluated_right, evaluated_left).into()))
|
||||
}
|
||||
_ => {
|
||||
Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into()))
|
||||
}
|
||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
||||
Subtract::new(evaluated_right, evaluated_left).into(),
|
||||
)),
|
||||
_ => Ok(Rc::new(
|
||||
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,10 +59,11 @@ impl Node for Subtract {
|
|||
|
||||
impl Subtract {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||
Self {
|
||||
left,
|
||||
right,
|
||||
}
|
||||
Self { left, right }
|
||||
}
|
||||
|
||||
pub fn new_rc(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
||||
Rc::new(Self { left, right }.into())
|
||||
}
|
||||
|
||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::rc::Rc;
|
|||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
use crate::environment::EnvironmentInternalSymbolKey;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Symbol {
|
||||
value: EnvironmentInternalSymbolKey,
|
||||
}
|
||||
|
@ -26,10 +26,10 @@ impl Node for Symbol {
|
|||
} else {
|
||||
env.id_to_str(&self.value)
|
||||
.cloned()
|
||||
.unwrap_or(format!("{{#SYMBOL {}}}", self.value))
|
||||
.unwrap_or(format!("{{#SYMBOL {:?}}}", self.value))
|
||||
}
|
||||
} else {
|
||||
format!("{{#SYMBOL {}}}", self.value)
|
||||
format!("{{#SYMBOL {:?}}}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,3 +58,9 @@ impl Symbol {
|
|||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Symbol {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,21 @@ use std::{iter::Peekable, rc::Rc, slice::Iter, str::Chars, vec::IntoIter};
|
|||
use crate::{
|
||||
environment::Environment,
|
||||
node::{
|
||||
add::Add, assign::Assign, call::Call, constant::{Constant, ConstantValue}, divide::Divide, equals::Equals, function::{Function, FunctionType}, if_else::{Bool, ElseBranchEnum, IfElse}, multiply::Multiply, set::Set, subtract::Subtract, symbol::Symbol, NodeEnum
|
||||
NodeEnum,
|
||||
add::Add,
|
||||
assign::Assign,
|
||||
call::Call,
|
||||
comparison::{Greater, GreaterEquals, Less, LessEquals},
|
||||
constant::{Constant, ConstantValue},
|
||||
divide::Divide,
|
||||
equals::Equals,
|
||||
exponent::Exponent,
|
||||
function::{Function, FunctionType},
|
||||
if_else::{Bool, ElseBranchEnum, IfElse},
|
||||
multiply::Multiply,
|
||||
set::Set,
|
||||
subtract::Subtract,
|
||||
symbol::Symbol,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -20,8 +34,13 @@ pub enum TokenType {
|
|||
Minus,
|
||||
Star,
|
||||
Slash,
|
||||
Hat,
|
||||
|
||||
Equals,
|
||||
Greater,
|
||||
Less,
|
||||
GreaterEquals,
|
||||
LessEquals,
|
||||
|
||||
ColonEquals,
|
||||
LeftArrow,
|
||||
|
@ -36,7 +55,7 @@ pub enum TokenType {
|
|||
End,
|
||||
|
||||
True,
|
||||
False
|
||||
False,
|
||||
}
|
||||
|
||||
impl TokenType {
|
||||
|
@ -49,7 +68,13 @@ impl TokenType {
|
|||
TokenType::Minus => 1,
|
||||
TokenType::Star => 1,
|
||||
TokenType::Slash => 1,
|
||||
TokenType::Hat => 1,
|
||||
|
||||
TokenType::Equals => 1,
|
||||
TokenType::Greater => 1,
|
||||
TokenType::Less => 1,
|
||||
TokenType::GreaterEquals => 2,
|
||||
TokenType::LessEquals => 2,
|
||||
|
||||
TokenType::ColonEquals => 2,
|
||||
TokenType::LeftArrow => 2,
|
||||
|
@ -108,26 +133,26 @@ impl<'a> Lexer<'a> {
|
|||
// Numbers with decimal points
|
||||
'0'..='9' | '.' => {
|
||||
let mut digit = String::from(c);
|
||||
let mut has_decimal = c == '.';
|
||||
loop {
|
||||
let d = self.source.peek();
|
||||
let mut has_decimal = c == '.';
|
||||
match d {
|
||||
Some('0'..='9') => {
|
||||
digit.push(*d.unwrap());
|
||||
self.source.next();
|
||||
i += 1;
|
||||
}
|
||||
#[allow(unused_assignments)] // For some reason it thinks has_decimal
|
||||
// is never read
|
||||
Some('.') => {
|
||||
if has_decimal {
|
||||
return Err(LexerError::UnexpectedChar(
|
||||
i,
|
||||
i + 1,
|
||||
"Invalid digit with multiple decimal points".into(),
|
||||
));
|
||||
}
|
||||
|
||||
digit.push(*d.unwrap());
|
||||
self.source.next();
|
||||
i += 1;
|
||||
has_decimal = true;
|
||||
}
|
||||
_ => {
|
||||
|
@ -147,12 +172,26 @@ impl<'a> Lexer<'a> {
|
|||
tokens.push(Token(i, TokenType::LeftArrow));
|
||||
}
|
||||
|
||||
'<' if self.source.peek() == Some(&'=') => {
|
||||
self.source.next();
|
||||
i += 1;
|
||||
tokens.push(Token(i, TokenType::LessEquals));
|
||||
}
|
||||
'>' if self.source.peek() == Some(&'=') => {
|
||||
self.source.next();
|
||||
i += 1;
|
||||
tokens.push(Token(i, TokenType::GreaterEquals));
|
||||
}
|
||||
'<' => tokens.push(Token(i, TokenType::Less)),
|
||||
'>' => tokens.push(Token(i, TokenType::Greater)),
|
||||
|
||||
'+' => tokens.push(Token(i, TokenType::Plus)),
|
||||
'-' => tokens.push(Token(i, TokenType::Minus)),
|
||||
'*' => tokens.push(Token(i, TokenType::Star)),
|
||||
'/' => tokens.push(Token(i, TokenType::Slash)),
|
||||
'=' => tokens.push(Token(i, TokenType::Equals)),
|
||||
',' => tokens.push(Token(i, TokenType::Comma)),
|
||||
'^' => tokens.push(Token(i, TokenType::Hat)),
|
||||
|
||||
':' if self.source.peek() == Some(&'=') => {
|
||||
self.source.next();
|
||||
|
@ -314,16 +353,56 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
// TODO: Implement equality
|
||||
let expr = self.comparison();
|
||||
let expr = self.comparison()?;
|
||||
if self.matchType(TokenType::Equals) {
|
||||
return Ok(Rc::new(Equals::new(expr?, self.equality()?).into()));
|
||||
let mut expressions = vec![];
|
||||
loop {
|
||||
expressions.push(self.comparison()?);
|
||||
if !self.matchType(TokenType::Equals) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Ok(Rc::new(Equals::new(expr, expressions).into()));
|
||||
}
|
||||
expr
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn comparison(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
// TODO: Implement comparison
|
||||
self.term()
|
||||
let expr = self.term()?;
|
||||
|
||||
let t = if let Some(Token(i, t)) = self.tokens.peek() {
|
||||
t.clone()
|
||||
} else {
|
||||
return Ok(expr);
|
||||
};
|
||||
|
||||
if match t {
|
||||
TokenType::Greater => true,
|
||||
TokenType::Less => true,
|
||||
TokenType::GreaterEquals => true,
|
||||
TokenType::LessEquals => true,
|
||||
_ => false,
|
||||
} {
|
||||
self.consume();
|
||||
let mut expressions = vec![];
|
||||
loop {
|
||||
expressions.push(self.term()?);
|
||||
if !self.matchType(t.clone()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return match t {
|
||||
TokenType::Greater => Ok(Greater::new(expr, expressions)),
|
||||
TokenType::Less => Ok(Less::new(expr, expressions)),
|
||||
TokenType::GreaterEquals => Ok(GreaterEquals::new(expr, expressions)),
|
||||
TokenType::LessEquals => Ok(LessEquals::new(expr, expressions)),
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn term(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
|
@ -356,7 +435,14 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn exponent(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
self.call()
|
||||
let expr = self.call();
|
||||
|
||||
if self.matchType(TokenType::Hat) {
|
||||
let right = self.unary()?;
|
||||
return Ok(Exponent::new(expr?, right));
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn call(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
|
@ -403,10 +489,10 @@ impl<'a> Parser<'a> {
|
|||
let right = self.equality()?;
|
||||
match expr.clone().as_ref() {
|
||||
NodeEnum::Symbol(symbol) => {
|
||||
return Ok(Function::new(
|
||||
FunctionType::UserFunction(right),
|
||||
return Ok(Function::new(FunctionType::UserFunction(
|
||||
right,
|
||||
vec![symbol.clone()],
|
||||
));
|
||||
)));
|
||||
}
|
||||
NodeEnum::Set(set) => {
|
||||
let mut symbols = vec![];
|
||||
|
@ -425,7 +511,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
return Ok(Function::new(FunctionType::UserFunction(right), symbols));
|
||||
return Ok(Function::new(
|
||||
FunctionType::UserFunction(right, symbols),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
return Err(ParserError::UnexpectedNode(
|
||||
|
@ -505,6 +593,11 @@ impl<'a> Parser<'a> {
|
|||
TokenType::False => Ok(Rc::new(Bool::False.into())),
|
||||
|
||||
TokenType::LParen => {
|
||||
// Empty set
|
||||
if self.matchType(TokenType::RParen) {
|
||||
return Ok(Set::new(vec![]));
|
||||
}
|
||||
|
||||
let expr = self.expression()?;
|
||||
let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() {
|
||||
(i, x)
|
||||
|
|
|
@ -1,133 +1,135 @@
|
|||
mod arithmetic {
|
||||
use std::rc::Rc;
|
||||
// TODO: Test case this: `x*0*5*y*z`
|
||||
|
||||
use crate::{environment, node::{
|
||||
add::Add, constant::{Constant, ConstantValue}, divide::Divide, multiply::Multiply, subtract::Subtract, Node, NodeEnum
|
||||
}};
|
||||
use environment::Environment;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
#[test_case(69.0, 420.0, 489.0 ; "when both are positive")]
|
||||
#[test_case(-2.0, -4.0, -6.0 ; "when both are negative")]
|
||||
#[test_case(0.0, 0.0, 0.0 ; "when both are zero")]
|
||||
#[test_case(ConstantValue::INFINITY, 0.0, ConstantValue::INFINITY ; "infinity")]
|
||||
// #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
||||
fn addition(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||
let mut env = Environment::new();
|
||||
|
||||
let a = Rc::new(Constant::new(a).into());
|
||||
let b = Rc::new(Constant::new(b).into());
|
||||
let d: NodeEnum = Add::new(a, b).into();
|
||||
|
||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
|
||||
assert!(
|
||||
value == Constant::new(e).into(),
|
||||
"Expected {} got {}",
|
||||
e,
|
||||
value
|
||||
)
|
||||
}
|
||||
|
||||
#[test_case(69.0, 420.0, -351.0 ; "when both are positive")]
|
||||
#[test_case(-2.0, -4.0, 2.0 ; "when both are negative")]
|
||||
#[test_case(0.0, 0.0, 0.0 ; "when both are zero")]
|
||||
#[test_case(ConstantValue::INFINITY, 0.0, ConstantValue::INFINITY ; "infinity")]
|
||||
// #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
||||
fn subtraction(aa: ConstantValue, bb: ConstantValue, e: ConstantValue) {
|
||||
let mut env = Environment::new();
|
||||
|
||||
let a = Rc::new(Constant::new(0.0).into());
|
||||
let b = Rc::new(Constant::new(aa).into());
|
||||
let c = Rc::new(Constant::new(bb).into());
|
||||
let d: NodeEnum = Subtract::new(Rc::new(Add::new(a, b).into()), c).into();
|
||||
|
||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
|
||||
assert!(
|
||||
value == Constant::new(e).into(),
|
||||
"Expected {} got {}",
|
||||
e,
|
||||
value
|
||||
)
|
||||
}
|
||||
|
||||
#[test_case(5.0, 10.0, 50.0 ; "when both are positive")]
|
||||
#[test_case(-5.0, 10.0, -50.0 ; "when left is negative")]
|
||||
#[test_case(5.0, -10.0, -50.0 ; "when right is negative")]
|
||||
#[test_case(-5.0, -10.0, 50.0 ; "when both are negative")]
|
||||
#[test_case(2734589235234.23, 0.0, 0.0 ; "when 0 is involved")]
|
||||
fn multiplication(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||
let mut env = Environment::new();
|
||||
|
||||
let a = Rc::new(Constant::new(a).into());
|
||||
let b = Rc::new(Constant::new(b).into());
|
||||
let d: NodeEnum = Multiply::new(a, b).into();
|
||||
|
||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
|
||||
assert!(
|
||||
value == Constant::new(e).into(),
|
||||
"Expected {} got {}",
|
||||
e,
|
||||
value
|
||||
)
|
||||
}
|
||||
|
||||
#[test_case(5.0, 10.0, 0.5 ; "when both are positive")]
|
||||
#[test_case(-5.0, 10.0, -0.5 ; "when left is negative")]
|
||||
#[test_case(5.0, -10.0, -0.5 ; "when right is negative")]
|
||||
#[test_case(-5.0, -10.0, 0.5 ; "when both are negative")]
|
||||
fn division(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||
let mut env = Environment::new();
|
||||
|
||||
let a = Rc::new(Constant::new(a).into());
|
||||
let b = Rc::new(Constant::new(b).into());
|
||||
let d: NodeEnum = Divide::new(a, b).into();
|
||||
|
||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
|
||||
assert!(
|
||||
value == Constant::new(e).into(),
|
||||
"Expected {} got {}",
|
||||
e,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mod functions {
|
||||
#[test]
|
||||
fn stringification() {
|
||||
// let f = Function
|
||||
}
|
||||
}
|
||||
|
||||
mod expected_errors {
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::node::constant::ConstantValue;
|
||||
|
||||
#[test_case(5.0, 0.0 ; "divide by zero")]
|
||||
fn division(a: ConstantValue, b: ConstantValue) {
|
||||
let _ = a+b;
|
||||
}
|
||||
}
|
||||
|
||||
mod misc {
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::node::constant::ConstantValue;
|
||||
|
||||
#[test_case(30, '+', 60, '-', 20, "(30+60)-20" ; "add and subtract")]
|
||||
fn convert_to_string(
|
||||
a: impl Into<ConstantValue>,
|
||||
op1: char,
|
||||
b: impl Into<ConstantValue>,
|
||||
op2: char,
|
||||
c: impl Into<ConstantValue>,
|
||||
e: &'static str,
|
||||
) {
|
||||
}
|
||||
}
|
||||
// mod arithmetic {
|
||||
// use std::rc::Rc;
|
||||
//
|
||||
// use crate::{environment, node::{
|
||||
// add::Add, constant::{Constant, ConstantValue}, divide::Divide, multiply::Multiply, subtract::Subtract, Node, NodeEnum
|
||||
// }};
|
||||
// use environment::Environment;
|
||||
//
|
||||
// use test_case::test_case;
|
||||
//
|
||||
// #[test_case(69.0, 420.0, 489.0 ; "when both are positive")]
|
||||
// #[test_case(-2.0, -4.0, -6.0 ; "when both are negative")]
|
||||
// #[test_case(0.0, 0.0, 0.0 ; "when both are zero")]
|
||||
// #[test_case(ConstantValue::INFINITY, 0.0, ConstantValue::INFINITY ; "infinity")]
|
||||
// // #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
||||
// fn addition(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||
// let mut env = Environment::new();
|
||||
//
|
||||
// let a = Rc::new(Constant::new(a).into());
|
||||
// let b = Rc::new(Constant::new(b).into());
|
||||
// let d: NodeEnum = Add::new(a, b).into();
|
||||
//
|
||||
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
//
|
||||
// assert!(
|
||||
// value == Constant::new(e).into(),
|
||||
// "Expected {} got {}",
|
||||
// e,
|
||||
// value
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// #[test_case(69.0, 420.0, -351.0 ; "when both are positive")]
|
||||
// #[test_case(-2.0, -4.0, 2.0 ; "when both are negative")]
|
||||
// #[test_case(0.0, 0.0, 0.0 ; "when both are zero")]
|
||||
// #[test_case(ConstantValue::INFINITY, 0.0, ConstantValue::INFINITY ; "infinity")]
|
||||
// // #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
||||
// fn subtraction(aa: ConstantValue, bb: ConstantValue, e: ConstantValue) {
|
||||
// let mut env = Environment::new();
|
||||
//
|
||||
// let a = Rc::new(Constant::new(0.0).into());
|
||||
// let b = Rc::new(Constant::new(aa).into());
|
||||
// let c = Rc::new(Constant::new(bb).into());
|
||||
// let d: NodeEnum = Subtract::new(Rc::new(Add::new(a, b).into()), c).into();
|
||||
//
|
||||
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
//
|
||||
// assert!(
|
||||
// value == Constant::new(e).into(),
|
||||
// "Expected {} got {}",
|
||||
// e,
|
||||
// value
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// #[test_case(5.0, 10.0, 50.0 ; "when both are positive")]
|
||||
// #[test_case(-5.0, 10.0, -50.0 ; "when left is negative")]
|
||||
// #[test_case(5.0, -10.0, -50.0 ; "when right is negative")]
|
||||
// #[test_case(-5.0, -10.0, 50.0 ; "when both are negative")]
|
||||
// #[test_case(2734589235234.23, 0.0, 0.0 ; "when 0 is involved")]
|
||||
// fn multiplication(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||
// let mut env = Environment::new();
|
||||
//
|
||||
// let a = Rc::new(Constant::new(a).into());
|
||||
// let b = Rc::new(Constant::new(b).into());
|
||||
// let d: NodeEnum = Multiply::new(a, b).into();
|
||||
//
|
||||
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
//
|
||||
// assert!(
|
||||
// value == Constant::new(e).into(),
|
||||
// "Expected {} got {}",
|
||||
// e,
|
||||
// value
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// #[test_case(5.0, 10.0, 0.5 ; "when both are positive")]
|
||||
// #[test_case(-5.0, 10.0, -0.5 ; "when left is negative")]
|
||||
// #[test_case(5.0, -10.0, -0.5 ; "when right is negative")]
|
||||
// #[test_case(-5.0, -10.0, 0.5 ; "when both are negative")]
|
||||
// fn division(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||
// let mut env = Environment::new();
|
||||
//
|
||||
// let a = Rc::new(Constant::new(a).into());
|
||||
// let b = Rc::new(Constant::new(b).into());
|
||||
// let d: NodeEnum = Divide::new(a, b).into();
|
||||
//
|
||||
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||
//
|
||||
// assert!(
|
||||
// value == Constant::new(e).into(),
|
||||
// "Expected {} got {}",
|
||||
// e,
|
||||
// value
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// mod functions {
|
||||
// #[test]
|
||||
// fn stringification() {
|
||||
// // let f = Function
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// mod expected_errors {
|
||||
// use test_case::test_case;
|
||||
//
|
||||
// use crate::node::constant::ConstantValue;
|
||||
//
|
||||
// #[test_case(5.0, 0.0 ; "divide by zero")]
|
||||
// fn division(a: ConstantValue, b: ConstantValue) {
|
||||
// let _ = a+b;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// mod misc {
|
||||
// use test_case::test_case;
|
||||
//
|
||||
// use crate::node::constant::ConstantValue;
|
||||
//
|
||||
// #[test_case(30, '+', 60, '-', 20, "(30+60)-20" ; "add and subtract")]
|
||||
// fn convert_to_string(
|
||||
// a: impl Into<ConstantValue>,
|
||||
// op1: char,
|
||||
// b: impl Into<ConstantValue>,
|
||||
// op2: char,
|
||||
// c: impl Into<ConstantValue>,
|
||||
// e: &'static str,
|
||||
// ) {
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Reference in a new issue