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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
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]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
@ -38,7 +50,7 @@ dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
"clang-sys",
|
"clang-sys",
|
||||||
"itertools",
|
"itertools 0.12.1",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lazycell",
|
"lazycell",
|
||||||
"log",
|
"log",
|
||||||
|
@ -369,10 +381,19 @@ version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf"
|
checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash 0.3.8",
|
||||||
"autocfg",
|
"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]]
|
[[package]]
|
||||||
name = "hibitset"
|
name = "hibitset"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
|
@ -388,6 +409,15 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"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]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -425,6 +455,12 @@ dependencies = [
|
||||||
"windows-targets 0.52.6",
|
"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]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
@ -458,6 +494,51 @@ version = "0.4.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
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]]
|
[[package]]
|
||||||
name = "maybe-uninit"
|
name = "maybe-uninit"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -511,6 +592,7 @@ dependencies = [
|
||||||
"clay-layout",
|
"clay-layout",
|
||||||
"enum_dispatch",
|
"enum_dispatch",
|
||||||
"font-kit",
|
"font-kit",
|
||||||
|
"malachite",
|
||||||
"raylib",
|
"raylib",
|
||||||
"termion",
|
"termion",
|
||||||
"test-case",
|
"test-case",
|
||||||
|
@ -708,6 +790,12 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"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]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -742,7 +830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5f08237e667ac94ad20f8878b5943d91a93ccb231428446c57c21c57779016d"
|
checksum = "c5f08237e667ac94ad20f8878b5943d91a93ccb231428446c57c21c57779016d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"hashbrown",
|
"hashbrown 0.7.2",
|
||||||
"mopa",
|
"mopa",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tynm",
|
"tynm",
|
||||||
|
@ -767,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fff28a29366aff703d5da8a7e2c8875dc8453ac1118f842cbc0fa70c7db51240"
|
checksum = "fff28a29366aff703d5da8a7e2c8875dc8453ac1118f842cbc0fa70c7db51240"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"hashbrown",
|
"hashbrown 0.7.2",
|
||||||
"hibitset",
|
"hibitset",
|
||||||
"log",
|
"log",
|
||||||
"shred",
|
"shred",
|
||||||
|
@ -894,6 +982,12 @@ version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -1111,3 +1205,23 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pkg-config",
|
"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" }
|
clay-layout = { path = "../clay-ui-rust" }
|
||||||
enum_dispatch = "0.3.13"
|
enum_dispatch = "0.3.13"
|
||||||
font-kit = "0.14.2"
|
font-kit = "0.14.2"
|
||||||
|
malachite = "0.5.0"
|
||||||
raylib = { version = "5.0.2", features = ["wayland"] }
|
raylib = { version = "5.0.2", features = ["wayland"] }
|
||||||
termion = "4.0.3"
|
termion = "4.0.3"
|
||||||
test-case = "3.3.1"
|
test-case = "3.3.1"
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
use std::io::{self, StdoutLock, Write, stdout};
|
use std::io::{self, StdoutLock, Write, stdout};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use libopenbirch::environment::Environment;
|
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 libopenbirch::parser::{Lexer, Parser, ParserError};
|
||||||
|
use malachite::base::num::basic::traits::Zero;
|
||||||
|
use malachite::rational::Rational;
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
use termion::AsyncReader;
|
use termion::AsyncReader;
|
||||||
use termion::color;
|
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> {
|
fn main() -> Result<(), io::Error> {
|
||||||
let mut input = Input::new();
|
let mut input = Input::new();
|
||||||
|
|
||||||
let mut env = Environment::new();
|
let mut env = Environment::new();
|
||||||
|
|
||||||
|
env.define_native_function("print", print);
|
||||||
|
|
||||||
while let Some(source) = input.get()? {
|
while let Some(source) = input.get()? {
|
||||||
|
input.disable_raw()?;
|
||||||
|
|
||||||
let mut lexer = Lexer::new(&source);
|
let mut lexer = Lexer::new(&source);
|
||||||
let tokens_result = lexer.lex();
|
let tokens_result = lexer.lex();
|
||||||
|
|
||||||
|
@ -164,9 +181,6 @@ fn main() -> Result<(), io::Error> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
input.disable_raw()?;
|
|
||||||
|
|
||||||
let tokens = tokens_result.unwrap();
|
let tokens = tokens_result.unwrap();
|
||||||
let mut parser = Parser::new(tokens, &mut env);
|
let mut parser = Parser::new(tokens, &mut env);
|
||||||
|
|
||||||
|
@ -193,7 +207,6 @@ fn main() -> Result<(), io::Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
input.enable_raw()?;
|
input.enable_raw()?;
|
||||||
|
|
||||||
print!("{}", color::Fg(color::Reset));
|
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 EnvironmentInternalSymbolKey = u16;
|
||||||
// pub type Environment = HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>;
|
// pub type Environment = HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>;
|
||||||
|
|
||||||
|
struct Scope {
|
||||||
|
pub stack_len: usize,
|
||||||
|
pub shadow_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
map: HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>,
|
map: HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>,
|
||||||
stack_depth: usize,
|
stack_depth: usize,
|
||||||
max_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>,
|
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
||||||
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
|
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
|
||||||
unique_keys: EnvironmentInternalSymbolKey,
|
unique_keys: EnvironmentInternalSymbolKey,
|
||||||
|
@ -22,7 +34,10 @@ impl Environment {
|
||||||
map: HashMap::new(),
|
map: HashMap::new(),
|
||||||
stack_depth: 0,
|
stack_depth: 0,
|
||||||
max_stack_depth: 5000,
|
max_stack_depth: 5000,
|
||||||
stack: vec![vec![]],
|
|
||||||
|
stack_sizes: vec![],
|
||||||
|
stack: vec![],
|
||||||
|
stack_shadows: vec![],
|
||||||
|
|
||||||
symbol_to_id: HashMap::new(),
|
symbol_to_id: HashMap::new(),
|
||||||
id_to_symbol: HashMap::new(),
|
id_to_symbol: HashMap::new(),
|
||||||
|
@ -31,61 +46,101 @@ impl Environment {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_stack(&mut self) -> Result<(), String> {
|
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 {
|
if self.stack_depth == self.max_stack_depth {
|
||||||
self.unwind_stack();
|
self.unwind_stack();
|
||||||
return Err("Max Stack depth exceeded".to_owned());
|
return Err("Max Stack depth exceeded".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stack_depth += 1;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_stack(&mut self) -> Result<(), String> {
|
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 {
|
if self.stack_depth == 0 {
|
||||||
return Err("Trying to pop empty stack".to_owned());
|
return Err("Trying to pop empty stack".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
|
let scope = self.stack_sizes.pop().unwrap();
|
||||||
for item in self.stack.pop().unwrap() {
|
for _ in 0..scope.stack_len {
|
||||||
self.map.remove(&item);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwind_stack(&mut self) {
|
fn unwind_stack(&mut self) {
|
||||||
for stack in &self.stack {
|
for scope in &self.stack_sizes {
|
||||||
for item in stack {
|
for _ in 0..scope.stack_len {
|
||||||
self.map.remove(&item);
|
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>> {
|
pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc<NodeEnum>> {
|
||||||
self.map.get(key)
|
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>) {
|
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);
|
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> {
|
pub fn str_to_id(&self, value: &String) -> Option<&EnvironmentInternalSymbolKey> {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
||||||
|
|
||||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
|
@ -15,20 +17,16 @@ impl Node for Add {
|
||||||
|
|
||||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||||
// Zero rule
|
// Zero rule
|
||||||
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right),
|
(NodeEnum::Constant(zero), _) if zero.get_value() == &Rational::ZERO => 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_left),
|
||||||
|
|
||||||
|
|
||||||
// Constant + Constant = Constant
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() + b.get_value()).into()))
|
Ok(Rc::new(Constant::new(a.get_value() + b.get_value()).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symbol + Constant we just return the same
|
// Move constants after symbols in add
|
||||||
(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
|
|
||||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
||||||
Ok(Rc::new(Add::new(evaluated_right, evaluated_left).into()))
|
Ok(Rc::new(Add::new(evaluated_right, evaluated_left).into()))
|
||||||
}
|
}
|
||||||
|
@ -61,6 +59,10 @@ impl Add {
|
||||||
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> {
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||||
self.left.clone()
|
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
|
// Call function body with arguments
|
||||||
match func.get_body() {
|
match func.get_body() {
|
||||||
// Pass arguments to native function
|
// Pass arguments to native function
|
||||||
FunctionType::Native(_name, native_function) => native_function(&arguments),
|
FunctionType::Native(_name, native_function) => native_function(&arguments, env),
|
||||||
FunctionType::UserFunction(node_enum) => {
|
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()?;
|
env.push_stack()?;
|
||||||
// Define variables
|
// Define variables
|
||||||
fargs.iter().zip(arguments).for_each(|(symbol, value)| {
|
fargs.iter().zip(arguments).for_each(|(symbol, value)| {
|
||||||
env.insert(symbol.get_value(), value.clone());
|
env.insert(symbol.get_value(), value.clone());
|
||||||
});
|
});
|
||||||
let ev = node_enum.evaluate(env)?;
|
let ev = body.evaluate(env)?;
|
||||||
env.pop_stack()?;
|
env.pop_stack()?;
|
||||||
// Return evaluated return value for function
|
// Return evaluated return value for function
|
||||||
Ok(ev)
|
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};
|
use super::{Environment, Node, Precedence};
|
||||||
|
|
||||||
pub type ConstantValue = f64;
|
pub type ConstantValue = malachite::rational::Rational;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Constant {
|
pub struct Constant {
|
||||||
|
@ -34,8 +34,8 @@ impl Constant {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(&self) -> ConstantValue {
|
pub fn get_value(&self) -> &ConstantValue {
|
||||||
self.value
|
&self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_value(&mut self, value: ConstantValue) {
|
pub fn set_value(&mut self, value: ConstantValue) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::rc::Rc;
|
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)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Divide {
|
pub struct Divide {
|
||||||
|
@ -15,27 +17,20 @@ impl Node for Divide {
|
||||||
|
|
||||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||||
// Error if dividing by zero
|
// 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())
|
Err("Division by Zero".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(_, _) if evaluated_left == evaluated_right => Ok(Rc::new(Constant::new(Rational::ZERO).into())),
|
||||||
|
|
||||||
// Zero rule
|
// Zero rule
|
||||||
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => {
|
(NodeEnum::Constant(zero), _) if zero.get_value() == &Rational::ZERO => Ok(evaluated_left),
|
||||||
Ok(evaluated_left)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constant + Constant = Constant
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() / b.get_value()).into()))
|
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
|
// Divide a set with a constant
|
||||||
(NodeEnum::Set(s), NodeEnum::Constant(c)) => {
|
(NodeEnum::Set(s), NodeEnum::Constant(c)) => {
|
||||||
let old_values = s.get_values();
|
let old_values = s.get_values();
|
||||||
|
@ -90,6 +85,10 @@ impl Divide {
|
||||||
Self { left, right }
|
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> {
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||||
self.left.clone()
|
self.left.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,18 @@ use std::{rc::Rc, sync::LazyLock};
|
||||||
|
|
||||||
use super::{Environment, Node, NodeEnum, Precedence};
|
use super::{Environment, Node, NodeEnum, Precedence};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialOrd)]
|
||||||
pub struct Empty {
|
pub struct Empty {
|
||||||
message: Option<String>,
|
message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Empty {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for Empty {}
|
||||||
|
|
||||||
impl Node for Empty {
|
impl Node for Empty {
|
||||||
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
Ok(Empty::EMPTY.clone())
|
Ok(Empty::EMPTY.clone())
|
||||||
|
|
|
@ -5,25 +5,31 @@ use super::{Environment, Node, NodeEnum, Precedence, if_else::Bool};
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Equals {
|
pub struct Equals {
|
||||||
left: Rc<NodeEnum>,
|
left: Rc<NodeEnum>,
|
||||||
right: Rc<NodeEnum>,
|
right: Vec<Rc<NodeEnum>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Equals {
|
impl Node for Equals {
|
||||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
let left = self.left.evaluate(env)?;
|
let left = self.left.evaluate(env)?;
|
||||||
let right = self.right.evaluate(env)?;
|
|
||||||
|
|
||||||
match left == right {
|
for expr in &self.right {
|
||||||
true => Ok(Rc::new(Bool::True.into())),
|
if left != expr.evaluate(env)? {
|
||||||
false => Ok(Rc::new(Bool::False.into())),
|
return Ok(Rc::new(Bool::False.into()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Ok(Rc::new(Bool::True.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
format!(
|
format!(
|
||||||
"({}={})",
|
"{} = {}",
|
||||||
self.left.as_string(env),
|
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 {
|
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 }
|
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};
|
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)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
pub enum FunctionType {
|
pub enum FunctionType {
|
||||||
Native(
|
Native(&'static str, NativeFunctionType),
|
||||||
&'static str,
|
UserFunction(Rc<NodeEnum>, Vec<Symbol>),
|
||||||
fn(&Vec<Rc<NodeEnum>>) -> Result<Rc<NodeEnum>, String>,
|
|
||||||
),
|
|
||||||
UserFunction(Rc<NodeEnum>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
function: FunctionType,
|
function: FunctionType,
|
||||||
// TODO: Finish reasoning about whether or not this is
|
|
||||||
// the right way to implement functions
|
|
||||||
arguments: Vec<Symbol>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Function {
|
impl Node for Function {
|
||||||
|
@ -27,16 +23,16 @@ impl Node for Function {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
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 {
|
match &self.function {
|
||||||
FunctionType::Native(name, _) => name.to_owned().to_owned(),
|
FunctionType::Native(name, _) => format!("(Native Function `{name}`)"),
|
||||||
FunctionType::UserFunction(body) => format!("({args} -> {})", body.as_string(env)),
|
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 {
|
impl Function {
|
||||||
pub fn new(t: FunctionType, args: Vec<Symbol>) -> Rc<NodeEnum> {
|
pub fn new(t: FunctionType) -> Rc<NodeEnum> {
|
||||||
Rc::new(
|
Rc::new(Self { function: t }.into())
|
||||||
Self {
|
|
||||||
function: t,
|
|
||||||
arguments: args,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_body(&self) -> &FunctionType {
|
pub fn get_body(&self) -> &FunctionType {
|
||||||
&self.function
|
&self.function
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_arguments(&self) -> &Vec<Symbol> {
|
|
||||||
&self.arguments
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,12 +64,12 @@ impl Node for IfElse {
|
||||||
for expr in to_evaluate {
|
for expr in to_evaluate {
|
||||||
expr.evaluate(env)?;
|
expr.evaluate(env)?;
|
||||||
}
|
}
|
||||||
last.evaluate(env)
|
last.evaluate(env)?
|
||||||
} else {
|
} else {
|
||||||
Ok(Empty::EMPTY.clone())
|
Empty::EMPTY.clone()
|
||||||
};
|
};
|
||||||
env.pop_stack()?;
|
env.pop_stack()?;
|
||||||
ret
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
match condition {
|
match condition {
|
||||||
|
|
|
@ -3,38 +3,42 @@ use std::{fmt::Display, rc::Rc};
|
||||||
use add::Add;
|
use add::Add;
|
||||||
use assign::Assign;
|
use assign::Assign;
|
||||||
use call::Call;
|
use call::Call;
|
||||||
|
use comparison::{Greater, GreaterEquals, Less, LessEquals};
|
||||||
use constant::Constant;
|
use constant::Constant;
|
||||||
use divide::Divide;
|
use divide::Divide;
|
||||||
use empty::Empty;
|
use empty::Empty;
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use equals::Equals;
|
||||||
|
use exponent::Exponent;
|
||||||
use function::Function;
|
use function::Function;
|
||||||
use if_else::{Bool, IfElse};
|
use if_else::{Bool, IfElse};
|
||||||
use multiply::Multiply;
|
use multiply::Multiply;
|
||||||
|
use set::Set;
|
||||||
use subtract::Subtract;
|
use subtract::Subtract;
|
||||||
use symbol::Symbol;
|
use symbol::Symbol;
|
||||||
use equals::Equals;
|
|
||||||
use set::Set;
|
|
||||||
|
|
||||||
use crate::environment::Environment;
|
use crate::environment::Environment;
|
||||||
|
|
||||||
pub mod add;
|
pub mod add;
|
||||||
|
pub mod assign;
|
||||||
|
pub mod call;
|
||||||
|
pub mod comparison;
|
||||||
pub mod constant;
|
pub mod constant;
|
||||||
pub mod divide;
|
pub mod divide;
|
||||||
|
pub mod empty;
|
||||||
|
pub mod equals;
|
||||||
|
pub mod exponent;
|
||||||
|
pub mod function;
|
||||||
|
pub mod if_else;
|
||||||
pub mod multiply;
|
pub mod multiply;
|
||||||
|
pub mod node_ref;
|
||||||
|
pub mod set;
|
||||||
pub mod subtract;
|
pub mod subtract;
|
||||||
pub mod symbol;
|
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]
|
||||||
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum NodeEnum {
|
pub enum NodeEnum {
|
||||||
Constant,
|
Constant,
|
||||||
|
|
||||||
|
@ -43,6 +47,7 @@ pub enum NodeEnum {
|
||||||
Subtract,
|
Subtract,
|
||||||
Multiply,
|
Multiply,
|
||||||
Divide,
|
Divide,
|
||||||
|
Exponent,
|
||||||
|
|
||||||
Symbol,
|
Symbol,
|
||||||
// NodeRef, // DEPRECATED, use Symbol
|
// NodeRef, // DEPRECATED, use Symbol
|
||||||
|
@ -57,17 +62,15 @@ pub enum NodeEnum {
|
||||||
Set,
|
Set,
|
||||||
|
|
||||||
Equals,
|
Equals,
|
||||||
// Greater,
|
Greater,
|
||||||
// GreaterEquals,
|
GreaterEquals,
|
||||||
// Less,
|
Less,
|
||||||
// LessEquals
|
LessEquals, // Logical operators
|
||||||
|
// In,
|
||||||
// Logical operators
|
// Where,
|
||||||
// In,
|
// Not,
|
||||||
// Where,
|
// Or,
|
||||||
// Not,
|
// And
|
||||||
// Or,
|
|
||||||
// And
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -79,6 +82,7 @@ pub enum Precedence {
|
||||||
Term,
|
Term,
|
||||||
Factor,
|
Factor,
|
||||||
Unary,
|
Unary,
|
||||||
|
Exponent,
|
||||||
Call,
|
Call,
|
||||||
Primary,
|
Primary,
|
||||||
}
|
}
|
||||||
|
@ -95,3 +99,55 @@ impl Display for NodeEnum {
|
||||||
write!(f, "{}", Node::as_string(self, None))
|
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 std::rc::Rc;
|
||||||
|
|
||||||
|
use malachite::{base::num::basic::traits::{One, Zero}, rational::Rational};
|
||||||
|
|
||||||
use crate::environment::Environment;
|
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)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Multiply {
|
pub struct Multiply {
|
||||||
|
@ -18,26 +23,57 @@ impl Node for Multiply {
|
||||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||||
// Zero rule
|
// Zero rule
|
||||||
(NodeEnum::Constant(zero), _) | (_, NodeEnum::Constant(zero))
|
(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
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() * b.get_value()).into()))
|
Ok(Rc::new(Constant::new(a.get_value() * b.get_value()).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symbol + Constant we just return the same
|
// Move constant infront of symbols
|
||||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
(NodeEnum::Symbol(_), NodeEnum::Constant(_))
|
||||||
|
| (NodeEnum::Exponent(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
||||||
Multiply::new(evaluated_right, evaluated_left).into(),
|
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
|
// Multiply a set with a constant
|
||||||
(NodeEnum::Set(s), NodeEnum::Constant(c))
|
(NodeEnum::Set(s), NodeEnum::Constant(c))
|
||||||
| (NodeEnum::Constant(c), NodeEnum::Set(s)) => {
|
| (NodeEnum::Constant(c), NodeEnum::Set(s)) => {
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl Node for Set {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.as_string(env))
|
.map(|x| x.as_string(env))
|
||||||
.reduce(|a, b| a + ", " + &b)
|
.reduce(|a, b| a + ", " + &b)
|
||||||
.unwrap()
|
.unwrap_or("".to_owned())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
||||||
|
|
||||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
|
@ -15,24 +17,24 @@ impl Node for Subtract {
|
||||||
|
|
||||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||||
// Zero rule
|
// Zero rule
|
||||||
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right),
|
(NodeEnum::Constant(zero), _) if zero.get_value() == &Rational::ZERO => 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_left),
|
||||||
|
|
||||||
// Constant + Constant = Constant
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() - b.get_value()).into()))
|
Ok(Rc::new(Constant::new(a.get_value() - b.get_value()).into()))
|
||||||
}
|
}
|
||||||
// Symbol + Constant we just return the same
|
// Symbol + Constant we just return the same
|
||||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => {
|
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
||||||
Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into()))
|
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||||
}
|
)),
|
||||||
// Constant + Symbol we switch them around so the constant is last
|
// Constant + Symbol we switch them around so the constant is last
|
||||||
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
||||||
Ok(Rc::new(Subtract::new(evaluated_right, evaluated_left).into()))
|
Subtract::new(evaluated_right, evaluated_left).into(),
|
||||||
}
|
)),
|
||||||
_ => {
|
_ => Ok(Rc::new(
|
||||||
Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into()))
|
Subtract::new(evaluated_left, evaluated_right).into(),
|
||||||
}
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +59,11 @@ impl Node for Subtract {
|
||||||
|
|
||||||
impl Subtract {
|
impl Subtract {
|
||||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||||
Self {
|
Self { left, right }
|
||||||
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> {
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::rc::Rc;
|
||||||
use super::{Environment, Node, NodeEnum, Precedence};
|
use super::{Environment, Node, NodeEnum, Precedence};
|
||||||
use crate::environment::EnvironmentInternalSymbolKey;
|
use crate::environment::EnvironmentInternalSymbolKey;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
value: EnvironmentInternalSymbolKey,
|
value: EnvironmentInternalSymbolKey,
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,10 @@ impl Node for Symbol {
|
||||||
} else {
|
} else {
|
||||||
env.id_to_str(&self.value)
|
env.id_to_str(&self.value)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(format!("{{#SYMBOL {}}}", self.value))
|
.unwrap_or(format!("{{#SYMBOL {:?}}}", self.value))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
format!("{{#SYMBOL {}}}", self.value)
|
format!("{{#SYMBOL {:?}}}", self.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,3 +58,9 @@ impl Symbol {
|
||||||
self.value
|
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::{
|
use crate::{
|
||||||
environment::Environment,
|
environment::Environment,
|
||||||
node::{
|
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,
|
Minus,
|
||||||
Star,
|
Star,
|
||||||
Slash,
|
Slash,
|
||||||
|
Hat,
|
||||||
|
|
||||||
Equals,
|
Equals,
|
||||||
|
Greater,
|
||||||
|
Less,
|
||||||
|
GreaterEquals,
|
||||||
|
LessEquals,
|
||||||
|
|
||||||
ColonEquals,
|
ColonEquals,
|
||||||
LeftArrow,
|
LeftArrow,
|
||||||
|
@ -36,7 +55,7 @@ pub enum TokenType {
|
||||||
End,
|
End,
|
||||||
|
|
||||||
True,
|
True,
|
||||||
False
|
False,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenType {
|
impl TokenType {
|
||||||
|
@ -49,7 +68,13 @@ impl TokenType {
|
||||||
TokenType::Minus => 1,
|
TokenType::Minus => 1,
|
||||||
TokenType::Star => 1,
|
TokenType::Star => 1,
|
||||||
TokenType::Slash => 1,
|
TokenType::Slash => 1,
|
||||||
|
TokenType::Hat => 1,
|
||||||
|
|
||||||
TokenType::Equals => 1,
|
TokenType::Equals => 1,
|
||||||
|
TokenType::Greater => 1,
|
||||||
|
TokenType::Less => 1,
|
||||||
|
TokenType::GreaterEquals => 2,
|
||||||
|
TokenType::LessEquals => 2,
|
||||||
|
|
||||||
TokenType::ColonEquals => 2,
|
TokenType::ColonEquals => 2,
|
||||||
TokenType::LeftArrow => 2,
|
TokenType::LeftArrow => 2,
|
||||||
|
@ -108,26 +133,26 @@ impl<'a> Lexer<'a> {
|
||||||
// Numbers with decimal points
|
// Numbers with decimal points
|
||||||
'0'..='9' | '.' => {
|
'0'..='9' | '.' => {
|
||||||
let mut digit = String::from(c);
|
let mut digit = String::from(c);
|
||||||
|
let mut has_decimal = c == '.';
|
||||||
loop {
|
loop {
|
||||||
let d = self.source.peek();
|
let d = self.source.peek();
|
||||||
let mut has_decimal = c == '.';
|
|
||||||
match d {
|
match d {
|
||||||
Some('0'..='9') => {
|
Some('0'..='9') => {
|
||||||
digit.push(*d.unwrap());
|
digit.push(*d.unwrap());
|
||||||
self.source.next();
|
self.source.next();
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
#[allow(unused_assignments)] // For some reason it thinks has_decimal
|
|
||||||
// is never read
|
|
||||||
Some('.') => {
|
Some('.') => {
|
||||||
if has_decimal {
|
if has_decimal {
|
||||||
return Err(LexerError::UnexpectedChar(
|
return Err(LexerError::UnexpectedChar(
|
||||||
i,
|
i + 1,
|
||||||
"Invalid digit with multiple decimal points".into(),
|
"Invalid digit with multiple decimal points".into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
digit.push(*d.unwrap());
|
digit.push(*d.unwrap());
|
||||||
|
self.source.next();
|
||||||
|
i += 1;
|
||||||
has_decimal = true;
|
has_decimal = true;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -147,12 +172,26 @@ impl<'a> Lexer<'a> {
|
||||||
tokens.push(Token(i, TokenType::LeftArrow));
|
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::Plus)),
|
||||||
'-' => tokens.push(Token(i, TokenType::Minus)),
|
'-' => tokens.push(Token(i, TokenType::Minus)),
|
||||||
'*' => tokens.push(Token(i, TokenType::Star)),
|
'*' => tokens.push(Token(i, TokenType::Star)),
|
||||||
'/' => tokens.push(Token(i, TokenType::Slash)),
|
'/' => tokens.push(Token(i, TokenType::Slash)),
|
||||||
'=' => tokens.push(Token(i, TokenType::Equals)),
|
'=' => tokens.push(Token(i, TokenType::Equals)),
|
||||||
',' => tokens.push(Token(i, TokenType::Comma)),
|
',' => tokens.push(Token(i, TokenType::Comma)),
|
||||||
|
'^' => tokens.push(Token(i, TokenType::Hat)),
|
||||||
|
|
||||||
':' if self.source.peek() == Some(&'=') => {
|
':' if self.source.peek() == Some(&'=') => {
|
||||||
self.source.next();
|
self.source.next();
|
||||||
|
@ -314,16 +353,56 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
// TODO: Implement equality
|
// TODO: Implement equality
|
||||||
let expr = self.comparison();
|
let expr = self.comparison()?;
|
||||||
if self.matchType(TokenType::Equals) {
|
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> {
|
fn comparison(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
// TODO: Implement comparison
|
// 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> {
|
fn term(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
|
@ -356,7 +435,14 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exponent(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
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> {
|
fn call(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
|
@ -403,10 +489,10 @@ impl<'a> Parser<'a> {
|
||||||
let right = self.equality()?;
|
let right = self.equality()?;
|
||||||
match expr.clone().as_ref() {
|
match expr.clone().as_ref() {
|
||||||
NodeEnum::Symbol(symbol) => {
|
NodeEnum::Symbol(symbol) => {
|
||||||
return Ok(Function::new(
|
return Ok(Function::new(FunctionType::UserFunction(
|
||||||
FunctionType::UserFunction(right),
|
right,
|
||||||
vec![symbol.clone()],
|
vec![symbol.clone()],
|
||||||
));
|
)));
|
||||||
}
|
}
|
||||||
NodeEnum::Set(set) => {
|
NodeEnum::Set(set) => {
|
||||||
let mut symbols = vec![];
|
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(
|
return Err(ParserError::UnexpectedNode(
|
||||||
|
@ -505,6 +593,11 @@ impl<'a> Parser<'a> {
|
||||||
TokenType::False => Ok(Rc::new(Bool::False.into())),
|
TokenType::False => Ok(Rc::new(Bool::False.into())),
|
||||||
|
|
||||||
TokenType::LParen => {
|
TokenType::LParen => {
|
||||||
|
// Empty set
|
||||||
|
if self.matchType(TokenType::RParen) {
|
||||||
|
return Ok(Set::new(vec![]));
|
||||||
|
}
|
||||||
|
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() {
|
let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() {
|
||||||
(i, x)
|
(i, x)
|
||||||
|
|
|
@ -1,133 +1,135 @@
|
||||||
mod arithmetic {
|
// TODO: Test case this: `x*0*5*y*z`
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use crate::{environment, node::{
|
// mod arithmetic {
|
||||||
add::Add, constant::{Constant, ConstantValue}, divide::Divide, multiply::Multiply, subtract::Subtract, Node, NodeEnum
|
// use std::rc::Rc;
|
||||||
}};
|
//
|
||||||
use environment::Environment;
|
// use crate::{environment, node::{
|
||||||
|
// add::Add, constant::{Constant, ConstantValue}, divide::Divide, multiply::Multiply, subtract::Subtract, Node, NodeEnum
|
||||||
use test_case::test_case;
|
// }};
|
||||||
|
// use environment::Environment;
|
||||||
#[test_case(69.0, 420.0, 489.0 ; "when both are positive")]
|
//
|
||||||
#[test_case(-2.0, -4.0, -6.0 ; "when both are negative")]
|
// use test_case::test_case;
|
||||||
#[test_case(0.0, 0.0, 0.0 ; "when both are zero")]
|
//
|
||||||
#[test_case(ConstantValue::INFINITY, 0.0, ConstantValue::INFINITY ; "infinity")]
|
// #[test_case(69.0, 420.0, 489.0 ; "when both are positive")]
|
||||||
// #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
// #[test_case(-2.0, -4.0, -6.0 ; "when both are negative")]
|
||||||
fn addition(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
// #[test_case(0.0, 0.0, 0.0 ; "when both are zero")]
|
||||||
let mut env = Environment::new();
|
// #[test_case(ConstantValue::INFINITY, 0.0, ConstantValue::INFINITY ; "infinity")]
|
||||||
|
// // #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
||||||
let a = Rc::new(Constant::new(a).into());
|
// fn addition(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||||
let b = Rc::new(Constant::new(b).into());
|
// let mut env = Environment::new();
|
||||||
let d: NodeEnum = Add::new(a, b).into();
|
//
|
||||||
|
// let a = Rc::new(Constant::new(a).into());
|
||||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
// let b = Rc::new(Constant::new(b).into());
|
||||||
|
// let d: NodeEnum = Add::new(a, b).into();
|
||||||
assert!(
|
//
|
||||||
value == Constant::new(e).into(),
|
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||||
"Expected {} got {}",
|
//
|
||||||
e,
|
// assert!(
|
||||||
value
|
// 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(69.0, 420.0, -351.0 ; "when both are positive")]
|
||||||
// #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
// #[test_case(-2.0, -4.0, 2.0 ; "when both are negative")]
|
||||||
fn subtraction(aa: ConstantValue, bb: ConstantValue, e: ConstantValue) {
|
// #[test_case(0.0, 0.0, 0.0 ; "when both are zero")]
|
||||||
let mut env = Environment::new();
|
// #[test_case(ConstantValue::INFINITY, 0.0, ConstantValue::INFINITY ; "infinity")]
|
||||||
|
// // #[test_case(ConstantValue::NAN, 0.0, ConstantValue::NAN ; "NaN")] // cant test NaN because NaN != NaN
|
||||||
let a = Rc::new(Constant::new(0.0).into());
|
// fn subtraction(aa: ConstantValue, bb: ConstantValue, e: ConstantValue) {
|
||||||
let b = Rc::new(Constant::new(aa).into());
|
// let mut env = Environment::new();
|
||||||
let c = Rc::new(Constant::new(bb).into());
|
//
|
||||||
let d: NodeEnum = Subtract::new(Rc::new(Add::new(a, b).into()), c).into();
|
// let a = Rc::new(Constant::new(0.0).into());
|
||||||
|
// let b = Rc::new(Constant::new(aa).into());
|
||||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
// let c = Rc::new(Constant::new(bb).into());
|
||||||
|
// let d: NodeEnum = Subtract::new(Rc::new(Add::new(a, b).into()), c).into();
|
||||||
assert!(
|
//
|
||||||
value == Constant::new(e).into(),
|
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||||
"Expected {} got {}",
|
//
|
||||||
e,
|
// assert!(
|
||||||
value
|
// 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(5.0, 10.0, 50.0 ; "when both are positive")]
|
||||||
#[test_case(2734589235234.23, 0.0, 0.0 ; "when 0 is involved")]
|
// #[test_case(-5.0, 10.0, -50.0 ; "when left is negative")]
|
||||||
fn multiplication(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
// #[test_case(5.0, -10.0, -50.0 ; "when right is negative")]
|
||||||
let mut env = Environment::new();
|
// #[test_case(-5.0, -10.0, 50.0 ; "when both are negative")]
|
||||||
|
// #[test_case(2734589235234.23, 0.0, 0.0 ; "when 0 is involved")]
|
||||||
let a = Rc::new(Constant::new(a).into());
|
// fn multiplication(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||||
let b = Rc::new(Constant::new(b).into());
|
// let mut env = Environment::new();
|
||||||
let d: NodeEnum = Multiply::new(a, b).into();
|
//
|
||||||
|
// let a = Rc::new(Constant::new(a).into());
|
||||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
// let b = Rc::new(Constant::new(b).into());
|
||||||
|
// let d: NodeEnum = Multiply::new(a, b).into();
|
||||||
assert!(
|
//
|
||||||
value == Constant::new(e).into(),
|
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||||
"Expected {} got {}",
|
//
|
||||||
e,
|
// assert!(
|
||||||
value
|
// 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")]
|
// #[test_case(5.0, 10.0, 0.5 ; "when both are positive")]
|
||||||
fn division(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
// #[test_case(-5.0, 10.0, -0.5 ; "when left is negative")]
|
||||||
let mut env = Environment::new();
|
// #[test_case(5.0, -10.0, -0.5 ; "when right is negative")]
|
||||||
|
// #[test_case(-5.0, -10.0, 0.5 ; "when both are negative")]
|
||||||
let a = Rc::new(Constant::new(a).into());
|
// fn division(a: ConstantValue, b: ConstantValue, e: ConstantValue) {
|
||||||
let b = Rc::new(Constant::new(b).into());
|
// let mut env = Environment::new();
|
||||||
let d: NodeEnum = Divide::new(a, b).into();
|
//
|
||||||
|
// let a = Rc::new(Constant::new(a).into());
|
||||||
let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
// let b = Rc::new(Constant::new(b).into());
|
||||||
|
// let d: NodeEnum = Divide::new(a, b).into();
|
||||||
assert!(
|
//
|
||||||
value == Constant::new(e).into(),
|
// let value = Rc::<NodeEnum>::try_unwrap(d.evaluate(&mut env).unwrap()).unwrap();
|
||||||
"Expected {} got {}",
|
//
|
||||||
e,
|
// assert!(
|
||||||
value
|
// value == Constant::new(e).into(),
|
||||||
)
|
// "Expected {} got {}",
|
||||||
}
|
// e,
|
||||||
}
|
// value
|
||||||
|
// )
|
||||||
mod functions {
|
// }
|
||||||
#[test]
|
// }
|
||||||
fn stringification() {
|
//
|
||||||
// let f = Function
|
// mod functions {
|
||||||
}
|
// #[test]
|
||||||
}
|
// fn stringification() {
|
||||||
|
// // let f = Function
|
||||||
mod expected_errors {
|
// }
|
||||||
use test_case::test_case;
|
// }
|
||||||
|
//
|
||||||
use crate::node::constant::ConstantValue;
|
// mod expected_errors {
|
||||||
|
// use test_case::test_case;
|
||||||
#[test_case(5.0, 0.0 ; "divide by zero")]
|
//
|
||||||
fn division(a: ConstantValue, b: ConstantValue) {
|
// use crate::node::constant::ConstantValue;
|
||||||
let _ = a+b;
|
//
|
||||||
}
|
// #[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;
|
// mod misc {
|
||||||
|
// use test_case::test_case;
|
||||||
#[test_case(30, '+', 60, '-', 20, "(30+60)-20" ; "add and subtract")]
|
//
|
||||||
fn convert_to_string(
|
// use crate::node::constant::ConstantValue;
|
||||||
a: impl Into<ConstantValue>,
|
//
|
||||||
op1: char,
|
// #[test_case(30, '+', 60, '-', 20, "(30+60)-20" ; "add and subtract")]
|
||||||
b: impl Into<ConstantValue>,
|
// fn convert_to_string(
|
||||||
op2: char,
|
// a: impl Into<ConstantValue>,
|
||||||
c: impl Into<ConstantValue>,
|
// op1: char,
|
||||||
e: &'static str,
|
// b: impl Into<ConstantValue>,
|
||||||
) {
|
// op2: char,
|
||||||
}
|
// c: impl Into<ConstantValue>,
|
||||||
}
|
// e: &'static str,
|
||||||
|
// ) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
Loading…
Reference in a new issue