cleaned up some code
This commit is contained in:
parent
04af1e291c
commit
2c38fb391b
154
Cargo.lock
generated
154
Cargo.lock
generated
|
@ -8,18 +8,6 @@ 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"
|
||||||
|
@ -41,6 +29,12 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "az"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.69.5"
|
version = "0.69.5"
|
||||||
|
@ -50,7 +44,7 @@ dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
"clang-sys",
|
"clang-sys",
|
||||||
"itertools 0.12.1",
|
"itertools",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lazycell",
|
"lazycell",
|
||||||
"log",
|
"log",
|
||||||
|
@ -375,25 +369,26 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gmp-mpfr-sys"
|
||||||
|
version = "1.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0205cd82059bc63b63cf516d714352a30c44f2c74da9961dfda2617ae6b5918"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.7.2"
|
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 0.3.8",
|
"ahash",
|
||||||
"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"
|
||||||
|
@ -409,15 +404,6 @@ 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"
|
||||||
|
@ -494,51 +480,6 @@ 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"
|
||||||
|
@ -592,8 +533,8 @@ dependencies = [
|
||||||
"clay-layout",
|
"clay-layout",
|
||||||
"enum_dispatch",
|
"enum_dispatch",
|
||||||
"font-kit",
|
"font-kit",
|
||||||
"malachite",
|
|
||||||
"raylib",
|
"raylib",
|
||||||
|
"rug",
|
||||||
"termion",
|
"termion",
|
||||||
"test-case",
|
"test-case",
|
||||||
]
|
]
|
||||||
|
@ -762,6 +703,18 @@ version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rug"
|
||||||
|
version = "1.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4207e8d668e5b8eb574bda8322088ccd0d7782d3d03c7e8d562e82ed82bdcbc3"
|
||||||
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"gmp-mpfr-sys",
|
||||||
|
"libc",
|
||||||
|
"libm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -790,12 +743,6 @@ 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"
|
||||||
|
@ -830,7 +777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5f08237e667ac94ad20f8878b5943d91a93ccb231428446c57c21c57779016d"
|
checksum = "c5f08237e667ac94ad20f8878b5943d91a93ccb231428446c57c21c57779016d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"hashbrown 0.7.2",
|
"hashbrown",
|
||||||
"mopa",
|
"mopa",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tynm",
|
"tynm",
|
||||||
|
@ -855,7 +802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fff28a29366aff703d5da8a7e2c8875dc8453ac1118f842cbc0fa70c7db51240"
|
checksum = "fff28a29366aff703d5da8a7e2c8875dc8453ac1118f842cbc0fa70c7db51240"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"hashbrown 0.7.2",
|
"hashbrown",
|
||||||
"hibitset",
|
"hibitset",
|
||||||
"log",
|
"log",
|
||||||
"shred",
|
"shred",
|
||||||
|
@ -982,12 +929,6 @@ 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"
|
||||||
|
@ -1056,6 +997,15 @@ dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
|
@ -1205,23 +1155,3 @@ 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,8 +8,8 @@ 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"] }
|
||||||
|
rug = "1.27.0"
|
||||||
termion = "4.0.3"
|
termion = "4.0.3"
|
||||||
test-case = "3.3.1"
|
test-case = "3.3.1"
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,8 @@
|
||||||
libclang
|
libclang
|
||||||
libllvm
|
libllvm
|
||||||
nerd-fonts.mononoki
|
nerd-fonts.mononoki
|
||||||
|
|
||||||
|
m4
|
||||||
];
|
];
|
||||||
|
|
||||||
LD_LIBRARY_PATH =
|
LD_LIBRARY_PATH =
|
||||||
|
|
210
src/cli-repl.rs
210
src/cli-repl.rs
|
@ -1,14 +1,16 @@
|
||||||
|
use std::f32::consts;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::io::{self, StdoutLock, Write, stdout};
|
use std::io::{self, StdoutLock, Write, stdout};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use libopenbirch::environment::Environment;
|
use libopenbirch::environment::Environment;
|
||||||
|
use libopenbirch::node::call::Call;
|
||||||
|
use libopenbirch::node::closure::Closure;
|
||||||
use libopenbirch::node::constant::Constant;
|
use libopenbirch::node::constant::Constant;
|
||||||
use libopenbirch::node::empty::Empty;
|
use libopenbirch::node::empty::Empty;
|
||||||
|
use libopenbirch::node::set::Set;
|
||||||
use libopenbirch::node::{Node, NodeEnum};
|
use libopenbirch::node::{Node, NodeEnum};
|
||||||
use libopenbirch::parser::{Lexer, LexerError, Parser, ParserError};
|
use libopenbirch::parser::{Lexer, LexerError, 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;
|
||||||
|
@ -23,6 +25,9 @@ pub struct Input {
|
||||||
stdout: RawTerminal<StdoutLock<'static>>,
|
stdout: RawTerminal<StdoutLock<'static>>,
|
||||||
buffer: String,
|
buffer: String,
|
||||||
current_char: usize,
|
current_char: usize,
|
||||||
|
|
||||||
|
history: Vec<String>,
|
||||||
|
history_idx: Option<usize>,
|
||||||
}
|
}
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
@ -35,6 +40,9 @@ impl Input {
|
||||||
stdout,
|
stdout,
|
||||||
buffer: "".into(),
|
buffer: "".into(),
|
||||||
current_char: 0,
|
current_char: 0,
|
||||||
|
|
||||||
|
history: vec![],
|
||||||
|
history_idx: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,9 +76,11 @@ impl Input {
|
||||||
return Err(io::Error::from(io::ErrorKind::Interrupted));
|
return Err(io::Error::from(io::ErrorKind::Interrupted));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.history.insert(0, self.buffer.clone());
|
||||||
let r = self.buffer.clone();
|
let r = self.buffer.clone();
|
||||||
self.buffer.clear();
|
self.buffer.clear();
|
||||||
self.current_char = 0;
|
self.current_char = 0;
|
||||||
|
self.history_idx = None;
|
||||||
print!("\n\r");
|
print!("\n\r");
|
||||||
return Ok(Some(r));
|
return Ok(Some(r));
|
||||||
}
|
}
|
||||||
|
@ -107,6 +117,45 @@ impl Input {
|
||||||
print!("{}", termion::cursor::Right(1));
|
print!("{}", termion::cursor::Right(1));
|
||||||
let _ = self.stdout.flush();
|
let _ = self.stdout.flush();
|
||||||
}
|
}
|
||||||
|
Key::Up => {
|
||||||
|
match self.history_idx {
|
||||||
|
Some(i) => self.history_idx = Some((i + 1) % self.history.len()),
|
||||||
|
None => {
|
||||||
|
if self.history.len() > 0 {
|
||||||
|
self.history_idx = Some(0)
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buffer =
|
||||||
|
self.history.get(self.history_idx.unwrap()).unwrap().clone();
|
||||||
|
self.current_char = self.buffer.len();
|
||||||
|
Self::draw_line(&self.buffer, &mut self.stdout, self.current_char);
|
||||||
|
}
|
||||||
|
Key::Down => {
|
||||||
|
match self.history_idx {
|
||||||
|
Some(i) => {
|
||||||
|
let i = if i == 0 { self.history.len() } else { i };
|
||||||
|
self.history_idx = Some((i - 1) % self.history.len())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if self.history.len() > 0 {
|
||||||
|
self.history_idx = Some(self.history.len() - 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buffer =
|
||||||
|
self.history.get(self.history_idx.unwrap()).unwrap().clone();
|
||||||
|
self.current_char = self.buffer.len();
|
||||||
|
Self::draw_line(&self.buffer, &mut self.stdout, self.current_char);
|
||||||
|
}
|
||||||
|
Key::Home => self.current_char = 0,
|
||||||
|
Key::End => self.current_char = self.buffer.len(),
|
||||||
Key::Char(char) => {
|
Key::Char(char) => {
|
||||||
self.buffer.insert(self.current_char, char);
|
self.buffer.insert(self.current_char, char);
|
||||||
self.current_char += 1;
|
self.current_char += 1;
|
||||||
|
@ -169,23 +218,168 @@ fn unset(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>
|
||||||
env.undefine(*id);
|
env.undefine(*id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Cannot undefine the expression {arg}"));
|
return Err(format!(
|
||||||
|
"Expected strings, but one of the arguments was a {}",
|
||||||
|
arg.type_str()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Empty::new(format!("Undefined {} symbols", args.len())))
|
Ok(Empty::new(format!("Undefined {} symbols", args.len())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_float_precision(
|
||||||
|
args: &Vec<Rc<NodeEnum>>,
|
||||||
|
env: &mut Environment,
|
||||||
|
) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
match args.len() {
|
||||||
|
0 => Ok(Rc::new(
|
||||||
|
Constant::new_from_float(env.get_float_precision() as f64, &env).into(),
|
||||||
|
)),
|
||||||
|
1 => {
|
||||||
|
let arg = args.first().unwrap();
|
||||||
|
if let NodeEnum::Constant(constant) = arg.as_ref() {
|
||||||
|
let prec = constant.get_value().prec_64() as f64;
|
||||||
|
|
||||||
|
Ok(Rc::new(Constant::new_from_float(prec, &env).into()))
|
||||||
|
} else {
|
||||||
|
Err(format!(
|
||||||
|
"Expected argument of type Constant, but got {}",
|
||||||
|
arg.type_str()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(format!("Expected 0 or 1 arguments, got {}", args.len()))?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_float_precision(
|
||||||
|
args: &Vec<Rc<NodeEnum>>,
|
||||||
|
env: &mut Environment,
|
||||||
|
) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
if args.len() != 1 {
|
||||||
|
Err(format!("Expected 1 arguments, got {}", args.len()))?
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg = args.first().unwrap();
|
||||||
|
|
||||||
|
let precision: u64 = if let NodeEnum::Constant(value) = arg.as_ref() {
|
||||||
|
value.get_value().to_u32_saturating().unwrap().into()
|
||||||
|
} else {
|
||||||
|
Err(format!(
|
||||||
|
"Expected argument of type Constant, but got {}",
|
||||||
|
arg.type_str()
|
||||||
|
))?
|
||||||
|
};
|
||||||
|
|
||||||
|
env.set_float_precision(precision);
|
||||||
|
|
||||||
|
Ok(Empty::new(format!("Set float precision to {precision}")))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
if args.len() != 2 {
|
||||||
|
Err(format!("Expected 2 argument but got {}", args.len()))?
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg = args.first().unwrap();
|
||||||
|
let func = match arg.as_ref() {
|
||||||
|
NodeEnum::Function(_) | NodeEnum::Closure(_) => arg,
|
||||||
|
_ => Err(format!(
|
||||||
|
"Argument 1 expected a Function but got {}",
|
||||||
|
arg.type_str()
|
||||||
|
))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let arg = args.get(1).unwrap().as_ref();
|
||||||
|
let set = if let NodeEnum::Set(set) = arg {
|
||||||
|
set.get_values()
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"Argument 1 expected a Set but got {}",
|
||||||
|
arg.type_str()
|
||||||
|
))?;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut out = Vec::with_capacity(set.len());
|
||||||
|
|
||||||
|
for expr in set.iter() {
|
||||||
|
out.push(Call::new(func.clone(), vec![expr.clone()]).evaluate(env)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Set::new(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
if args.len() != 2 {
|
||||||
|
Err(format!("Expected 2 argument but got {}", args.len()))?
|
||||||
|
}
|
||||||
|
|
||||||
|
let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() {
|
||||||
|
set.get_values()
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"Argument 1 expected Set but got {}",
|
||||||
|
args.first().unwrap().type_str()
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let idx = if let NodeEnum::Constant(c) = args.get(1).unwrap().as_ref() {
|
||||||
|
if let Some(u) = c.get_value().to_u32_saturating() {
|
||||||
|
u as usize
|
||||||
|
} else {
|
||||||
|
return Err(
|
||||||
|
"Error occured while trying to convert second argument to integer".to_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err("Argument 1 is expected to be a Set".to_owned());
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(v) = set.get(idx) {
|
||||||
|
return Ok(v.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(format!(
|
||||||
|
"Index was out of bounds for Set of length {}",
|
||||||
|
set.len()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn length(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
if args.len() != 1 {
|
||||||
|
Err(format!("Expected 1 argument but got {}", args.len()))?
|
||||||
|
}
|
||||||
|
|
||||||
|
let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() {
|
||||||
|
set.get_values()
|
||||||
|
} else {
|
||||||
|
return Err("Argument 1 is expected to be a Set".to_owned());
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Rc::new(
|
||||||
|
Constant::new_from_float(set.len() as f32, &env).into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
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.set_float_precision(128);
|
||||||
|
|
||||||
env.define_native_function("print", print);
|
env.define_native_function("print", print);
|
||||||
env.define_native_function("unset", unset);
|
env.define_native_function("unset", unset);
|
||||||
|
env.define_native_function("get_float_precision", get_float_precision);
|
||||||
|
env.define_native_function("set_float_precision", set_float_precision);
|
||||||
|
env.define_native_function("map", map);
|
||||||
|
env.define_native_function("get", get);
|
||||||
|
env.define_native_function("length", length);
|
||||||
|
|
||||||
env.define(
|
env.define(
|
||||||
"pi",
|
"pi",
|
||||||
Rc::new(Constant::new(f64::consts::PI.try_into().unwrap()).into()),
|
Rc::new(Constant::new_from_float(std::f64::consts::PI, &env).into()),
|
||||||
);
|
);
|
||||||
|
|
||||||
while let Some(source) = input.get()? {
|
while let Some(source) = input.get()? {
|
||||||
|
@ -196,9 +390,7 @@ fn main() -> Result<(), io::Error> {
|
||||||
|
|
||||||
if tokens_result.is_err() {
|
if tokens_result.is_err() {
|
||||||
match tokens_result.err().unwrap() {
|
match tokens_result.err().unwrap() {
|
||||||
LexerError::UnexpectedChar(i, exp) | LexerError::NumberParse(i, exp) => {
|
LexerError::UnexpectedChar(i, exp) => print_err(i, 1, exp),
|
||||||
print_err(i, 1, exp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +405,9 @@ fn main() -> Result<(), io::Error> {
|
||||||
ParserError::UnexpectedEndOfTokens(exp) => print_err(source.len(), 1, exp),
|
ParserError::UnexpectedEndOfTokens(exp) => print_err(source.len(), 1, exp),
|
||||||
ParserError::UnexpectedToken(i, len, exp)
|
ParserError::UnexpectedToken(i, len, exp)
|
||||||
| ParserError::Unimplemented(i, len, exp) => print_err(i, len, exp),
|
| ParserError::Unimplemented(i, len, exp) => print_err(i, len, exp),
|
||||||
ParserError::UnexpectedNode(i, exp) => print_err(i, 1, exp),
|
ParserError::UnexpectedNode(i, exp) | ParserError::NumberParse(i, exp) => {
|
||||||
|
print_err(i, 1, exp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@ pub struct Environment {
|
||||||
stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
||||||
|
|
||||||
hidden: Vec<EnvironmentInternalSymbolKey>,
|
hidden: Vec<EnvironmentInternalSymbolKey>,
|
||||||
disable_calls: bool,
|
enable_closures: bool,
|
||||||
|
|
||||||
|
float_precision: u64,
|
||||||
|
|
||||||
// stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
|
// stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
|
||||||
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
||||||
|
@ -42,7 +44,9 @@ impl Environment {
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
stack_shadows: vec![],
|
stack_shadows: vec![],
|
||||||
hidden: vec![],
|
hidden: vec![],
|
||||||
disable_calls: false,
|
enable_closures: false,
|
||||||
|
|
||||||
|
float_precision: 64,
|
||||||
|
|
||||||
symbol_to_id: HashMap::new(),
|
symbol_to_id: HashMap::new(),
|
||||||
id_to_symbol: HashMap::new(),
|
id_to_symbol: HashMap::new(),
|
||||||
|
@ -66,16 +70,24 @@ impl Environment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_calls(&mut self) {
|
pub fn get_float_precision(&self) -> u64 {
|
||||||
self.disable_calls = true;
|
self.float_precision
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_calls(&mut self) {
|
pub fn set_float_precision(&mut self, precision: u64) {
|
||||||
self.disable_calls = false;
|
self.float_precision = precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calls_disabled(&self) -> bool {
|
pub fn disable_closures(&mut self) {
|
||||||
self.disable_calls
|
self.enable_closures = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_closures(&mut self) {
|
||||||
|
self.enable_closures = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn closures_enabled(&self) -> bool {
|
||||||
|
self.enable_closures
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_stack(&mut self) -> Result<(), String> {
|
pub fn push_stack(&mut self) -> Result<(), String> {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
use rug::Float;
|
||||||
|
|
||||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant, set::Set};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Add {
|
pub struct Add {
|
||||||
|
@ -17,20 +17,33 @@ 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() == &Rational::ZERO => Ok(evaluated_right),
|
(NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => Ok(evaluated_right),
|
||||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == &Rational::ZERO => Ok(evaluated_left),
|
(_, NodeEnum::Constant(zero)) if zero.get_value() == &0.0 => Ok(evaluated_left),
|
||||||
|
|
||||||
|
|
||||||
// Constant + Constant = Constant
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => Ok(Rc::new(
|
||||||
Ok(Rc::new(Constant::new(a.get_value() + b.get_value()).into()))
|
Constant::new(Float::with_val_64(
|
||||||
}
|
env.get_float_precision(),
|
||||||
|
a.get_value() + b.get_value(),
|
||||||
|
))
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
|
|
||||||
// Move constants after symbols in add
|
// Move constants after symbols in add
|
||||||
(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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Concatenate sets
|
||||||
|
(NodeEnum::Set(s1), NodeEnum::Set(s2)) => {
|
||||||
|
let values = {
|
||||||
|
let mut v = s1.get_values().clone();
|
||||||
|
v.append(&mut s2.get_values().clone());
|
||||||
|
v
|
||||||
|
};
|
||||||
|
Ok(Set::new(values))
|
||||||
|
}
|
||||||
|
|
||||||
_ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())),
|
_ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,57 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{environment::Environment, node::function::FunctionType};
|
use crate::{
|
||||||
|
environment::Environment,
|
||||||
|
node::{closure::Closure, function::FunctionType},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{Node, NodeEnum, Precedence};
|
use super::{Node, NodeEnum, Precedence, closure};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
pub struct Call {
|
pub struct Call {
|
||||||
function: Rc<NodeEnum>,
|
function: Rc<NodeEnum>,
|
||||||
arguments: Rc<NodeEnum>,
|
arguments: Vec<Rc<NodeEnum>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Call {
|
impl Node for Call {
|
||||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
if env.calls_disabled() {
|
if env.closures_enabled() {
|
||||||
return Ok(Rc::new(self.clone().into()));
|
return Ok(Rc::new(self.clone().into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate callee and error if its not a function
|
// Evaluate callee and error if its not a function
|
||||||
let evaluated = self.function.evaluate(env)?;
|
let evaluated = self.function.evaluate(env)?;
|
||||||
let func = if let NodeEnum::Function(func) = evaluated.as_ref() {
|
// let func = if let NodeEnum::Function(func) = evaluated.as_ref() {
|
||||||
func
|
// func
|
||||||
} else {
|
// } else {
|
||||||
// return Err(format!(
|
// return Ok(Rc::new(self.clone().into()));
|
||||||
// "Cannot call {} as a function",
|
// };
|
||||||
// evaluated.as_string(Some(env))
|
|
||||||
// ));
|
env.push_stack()?;
|
||||||
return Ok(Rc::new(self.clone().into()));
|
|
||||||
|
let func = match evaluated.as_ref() {
|
||||||
|
NodeEnum::Function(func) => func,
|
||||||
|
NodeEnum::Closure(closure) => {
|
||||||
|
for (k, v) in closure.get_captured_variables() {
|
||||||
|
env.insert(*k, v.clone());
|
||||||
|
}
|
||||||
|
closure.get_function()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Ok(Rc::new(self.clone().into()));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let arguments = if let NodeEnum::Set(set) = self.arguments.as_ref() {
|
let arguments = {
|
||||||
let mut arguments = vec![];
|
let mut arguments = vec![];
|
||||||
for value in set.get_values().iter() {
|
for value in self.arguments.iter() {
|
||||||
arguments.push(value.evaluate(env)?);
|
arguments.push(value.evaluate(env)?);
|
||||||
}
|
}
|
||||||
arguments
|
arguments
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"This shoulnd not be possible, but call constructed with arguments of type that is not set"
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call function body with arguments
|
// Call function body with arguments
|
||||||
match func.get_body() {
|
let ret = match func.get_body() {
|
||||||
// Pass arguments to native function
|
// Pass arguments to native function
|
||||||
FunctionType::Native(_name, native_function) => native_function(&arguments, env),
|
FunctionType::Native(_name, native_function) => native_function(&arguments, env),
|
||||||
FunctionType::UserFunction(body, fargs) => {
|
FunctionType::UserFunction(body, fargs) => {
|
||||||
|
@ -52,21 +62,36 @@ impl Node for Call {
|
||||||
arguments.len()
|
arguments.len()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
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 = body.evaluate(env)?;
|
let ev = body.evaluate(env)?;
|
||||||
env.pop_stack()?;
|
|
||||||
// Return evaluated return value for function
|
// Return evaluated return value for function
|
||||||
Ok(ev)
|
Ok(match ev.as_ref() {
|
||||||
|
NodeEnum::Function(hof) => {
|
||||||
|
let captures = fargs.iter().map(|a| a.get_value()).zip(arguments).collect();
|
||||||
|
Closure::new(hof.clone(), captures)
|
||||||
|
}
|
||||||
|
_ => ev,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
env.pop_stack()?;
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
let arguments = self.arguments.as_string(env);
|
let arguments = format!(
|
||||||
|
"{}",
|
||||||
|
self.arguments
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.as_string(env))
|
||||||
|
.reduce(|a, b| a + ", " + &b)
|
||||||
|
.unwrap_or("".to_owned())
|
||||||
|
);
|
||||||
format!("{}({})", self.function.as_string(env), arguments)
|
format!("{}({})", self.function.as_string(env), arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +101,7 @@ impl Node for Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Call {
|
impl Call {
|
||||||
pub fn new(function: Rc<NodeEnum>, arguments: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
pub fn new(function: Rc<NodeEnum>, arguments: Vec<Rc<NodeEnum>>) -> Rc<NodeEnum> {
|
||||||
Rc::new(
|
Rc::new(
|
||||||
Self {
|
Self {
|
||||||
function,
|
function,
|
||||||
|
|
67
src/lib/node/closure.rs
Normal file
67
src/lib/node/closure.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::environment::{Environment, EnvironmentInternalSymbolKey};
|
||||||
|
|
||||||
|
use super::{Node, NodeEnum, Precedence, function::Function};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub struct Closure {
|
||||||
|
function: Function,
|
||||||
|
captured_variables: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for Closure {
|
||||||
|
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
Ok(Rc::new(self.clone().into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
|
if let Some(env) = env {
|
||||||
|
let captures = self
|
||||||
|
.captured_variables
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
format!(
|
||||||
|
"{}: {}",
|
||||||
|
env.id_to_str(k).expect("Failed to get variable name"),
|
||||||
|
v.as_string(Some(env))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.reduce(|a, b| format!("{}, {}", a, b))
|
||||||
|
.unwrap();
|
||||||
|
format!(
|
||||||
|
"( ({captures}) => {})",
|
||||||
|
self.function.as_string(Some(env))
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("<Closure {}>", self.function.as_string(env))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn precedence(&self) -> Precedence {
|
||||||
|
Precedence::Call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Closure {
|
||||||
|
pub fn new(
|
||||||
|
function: Function,
|
||||||
|
captured_variables: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
|
||||||
|
) -> Rc<NodeEnum> {
|
||||||
|
Rc::new(
|
||||||
|
Self {
|
||||||
|
function,
|
||||||
|
captured_variables,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_captured_variables(&self) -> &Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)> {
|
||||||
|
&self.captured_variables
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_function(&self) -> &Function {
|
||||||
|
&self.function
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,10 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use malachite::{
|
use rug::Float;
|
||||||
base::{num::basic::traits::Zero, rounding_modes::RoundingMode},
|
|
||||||
rational::{Rational, conversion::primitive_float_from_rational::FloatConversionError},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Environment, Node, Precedence};
|
use super::{Environment, Node, Precedence};
|
||||||
|
|
||||||
pub type ConstantValue = malachite::rational::Rational;
|
pub type ConstantValue = Float;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Constant {
|
pub struct Constant {
|
||||||
|
@ -26,29 +23,15 @@ impl Node for Constant {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self, _env: Option<&Environment>) -> String {
|
fn as_string(&self, _env: Option<&Environment>) -> String {
|
||||||
if self.value == Rational::ZERO {
|
if self.value.is_zero() {
|
||||||
return "0".to_owned();
|
"0".to_string();
|
||||||
}
|
|
||||||
|
|
||||||
if self.value.approx_log() < 50. {
|
|
||||||
let x: Result<f64, FloatConversionError> = self.value.clone().try_into();
|
|
||||||
|
|
||||||
match x {
|
|
||||||
Ok(v) => {
|
|
||||||
return v.to_string();
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((man, exp, _)) = self
|
|
||||||
.value
|
|
||||||
.sci_mantissa_and_exponent_round_ref::<f64>(RoundingMode::Nearest)
|
|
||||||
{
|
|
||||||
format!("{}*2^{}", man, exp)
|
|
||||||
} else {
|
|
||||||
self.value.to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.value
|
||||||
|
.to_string_radix(10, Some(8))
|
||||||
|
.trim_end_matches('0')
|
||||||
|
.trim_end_matches('.')
|
||||||
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precedence(&self) -> Precedence {
|
fn precedence(&self) -> Precedence {
|
||||||
|
@ -61,6 +44,12 @@ impl Constant {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_from_float(value: impl Into<f64>, env: &Environment) -> Self {
|
||||||
|
Self {
|
||||||
|
value: Float::with_val_64(env.get_float_precision(), value.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_value(&self) -> &ConstantValue {
|
pub fn get_value(&self) -> &ConstantValue {
|
||||||
&self.value
|
&self.value
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
use rug::Float;
|
||||||
|
|
||||||
use super::{Node, NodeEnum, Precedence, constant::Constant, set::Set};
|
use super::{Node, NodeEnum, Precedence, constant::Constant, set::Set};
|
||||||
|
|
||||||
|
@ -17,20 +17,28 @@ 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() == &Rational::ZERO => {
|
(_, NodeEnum::Constant(zero)) if zero.get_value() == &0.0 => {
|
||||||
Err("Division by Zero".into())
|
Err("Division by Zero".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, _) if evaluated_left == evaluated_right => Ok(Rc::new(Constant::new(Rational::ZERO).into())),
|
(_, _) if evaluated_left == evaluated_right => {
|
||||||
|
Ok(Rc::new(Constant::new_from_float(0.0, &env).into()))
|
||||||
|
}
|
||||||
|
|
||||||
// Zero rule
|
// Zero rule
|
||||||
(NodeEnum::Constant(zero), _) if zero.get_value() == &Rational::ZERO => Ok(evaluated_left),
|
(NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => {
|
||||||
|
Ok(evaluated_left)
|
||||||
// Constant + Constant = Constant
|
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
|
||||||
Ok(Rc::new(Constant::new(a.get_value() / b.get_value()).into()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constant / Constant = Constant
|
||||||
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => Ok(Rc::new(
|
||||||
|
Constant::new(Float::with_val_64(
|
||||||
|
env.get_float_precision(),
|
||||||
|
a.get_value() / b.get_value(),
|
||||||
|
))
|
||||||
|
.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();
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use malachite::{Natural, rational::Rational, rational::arithmetic::pow};
|
use rug::{Float, ops::Pow};
|
||||||
|
|
||||||
use malachite::base::num::arithmetic::traits::Pow;
|
|
||||||
|
|
||||||
use malachite::rational::conversion::integer_from_rational;
|
|
||||||
|
|
||||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||||
|
|
||||||
|
@ -20,15 +16,13 @@ impl Node for Exponent {
|
||||||
let evaluated_right = self.right.evaluate(env)?;
|
let evaluated_right = self.right.evaluate(env)?;
|
||||||
|
|
||||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => Ok(Rc::new(
|
||||||
let v = b.get_value();
|
Constant::new(Float::with_val_64(
|
||||||
let exp: u64 = if let Ok(u) = v.try_into() {
|
env.get_float_precision(),
|
||||||
u
|
a.get_value().pow(b.get_value()),
|
||||||
} else {
|
))
|
||||||
return Err("Exponent was too large".into());
|
.into(),
|
||||||
};
|
)),
|
||||||
Ok(Rc::new(Constant::new(a.get_value().pow(exp)).into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => Ok(Self::new(evaluated_left, evaluated_right)),
|
_ => Ok(Self::new(evaluated_left, evaluated_right)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use crate::environment::Environment;
|
use crate::environment::Environment;
|
||||||
|
|
||||||
use super::{Node, NodeEnum, Precedence, symbol::Symbol};
|
use super::{closure::Closure, symbol::Symbol, Node, NodeEnum, Precedence};
|
||||||
|
|
||||||
pub type NativeFunctionType =
|
pub type NativeFunctionType =
|
||||||
fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>;
|
fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>;
|
||||||
|
@ -20,22 +20,22 @@ pub struct Function {
|
||||||
|
|
||||||
impl Node for Function {
|
impl Node for Function {
|
||||||
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
// Ok(Rc::new(self.clone().into()))
|
Ok(Rc::new(self.clone().into()))
|
||||||
|
|
||||||
Ok(Rc::new(
|
// Ok(Rc::new(
|
||||||
Self {
|
// Self {
|
||||||
function: match &self.function {
|
// function: match &self.function {
|
||||||
FunctionType::Native(_, _) => self.function.clone(),
|
// FunctionType::Native(_, _) => self.function.clone(),
|
||||||
FunctionType::UserFunction(node_enum, symbols) => {
|
// FunctionType::UserFunction(node_enum, symbols) => {
|
||||||
env.disable_calls();
|
// env.disable_calls();
|
||||||
let evaluated = node_enum.evaluate(env)?;
|
// let evaluated = node_enum.evaluate(env)?;
|
||||||
env.enable_calls();
|
// env.enable_calls();
|
||||||
FunctionType::UserFunction(evaluated, symbols.clone())
|
// FunctionType::UserFunction(evaluated, symbols.clone())
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
.into(),
|
// .into(),
|
||||||
))
|
// ))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
|
|
|
@ -17,6 +17,7 @@ use set::Set;
|
||||||
use subtract::Subtract;
|
use subtract::Subtract;
|
||||||
use symbol::Symbol;
|
use symbol::Symbol;
|
||||||
use string_node::StringNode;
|
use string_node::StringNode;
|
||||||
|
use closure::Closure;
|
||||||
|
|
||||||
use crate::environment::Environment;
|
use crate::environment::Environment;
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ pub mod set;
|
||||||
pub mod subtract;
|
pub mod subtract;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod string_node;
|
pub mod string_node;
|
||||||
|
pub mod closure;
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
||||||
|
@ -56,7 +58,7 @@ pub enum NodeEnum {
|
||||||
Assign,
|
Assign,
|
||||||
Empty,
|
Empty,
|
||||||
Function,
|
Function,
|
||||||
// Closure // IMPLEMENT THIS SO CURRYING WORKS
|
Closure, // IMPLEMENT THIS SO CURRYING WORKS
|
||||||
Call,
|
Call,
|
||||||
|
|
||||||
Bool,
|
Bool,
|
||||||
|
@ -155,3 +157,31 @@ impl PartialOrd for NodeEnum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NodeEnum {
|
||||||
|
pub fn type_str(&self) -> String {
|
||||||
|
match self {
|
||||||
|
NodeEnum::Constant(_) => "Constant",
|
||||||
|
NodeEnum::StringNode(_) => "String",
|
||||||
|
NodeEnum::Add(_) => "Add",
|
||||||
|
NodeEnum::Subtract(_) => "Subtract",
|
||||||
|
NodeEnum::Multiply(_) => "Multiply",
|
||||||
|
NodeEnum::Divide(_) => "Divide",
|
||||||
|
NodeEnum::Exponent(_) => "Exponent",
|
||||||
|
NodeEnum::Symbol(_) => "Symbol",
|
||||||
|
NodeEnum::Assign(_) => "Assign",
|
||||||
|
NodeEnum::Empty(_) => "Empty",
|
||||||
|
NodeEnum::Function(_) => "Function",
|
||||||
|
NodeEnum::Closure(_) => "Closure",
|
||||||
|
NodeEnum::Call(_) => "Call",
|
||||||
|
NodeEnum::Bool(_) => "Bool",
|
||||||
|
NodeEnum::IfElse(_) => "If",
|
||||||
|
NodeEnum::Set(_) => "Set",
|
||||||
|
NodeEnum::Equals(_) => "Equals",
|
||||||
|
NodeEnum::Greater(_) => "Greater",
|
||||||
|
NodeEnum::GreaterEquals(_) => "Greater Equals",
|
||||||
|
NodeEnum::Less(_) => "Less",
|
||||||
|
NodeEnum::LessEquals(_) => "Less Equals"
|
||||||
|
}.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use malachite::{base::num::basic::traits::{One, Zero}, rational::Rational};
|
use rug::Float;
|
||||||
|
|
||||||
use crate::environment::Environment;
|
use crate::environment::Environment;
|
||||||
|
|
||||||
|
@ -23,14 +23,14 @@ 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() == &Rational::ZERO =>
|
if zero.get_value() == &0.0 =>
|
||||||
{
|
{
|
||||||
Ok(Rc::new(Constant::new(Rational::ZERO).into()))
|
Ok(Rc::new(Constant::new_from_float(0.0, &env).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identity rule
|
// Identity rule
|
||||||
(NodeEnum::Constant(one), _) if one.get_value() == &Rational::ONE => Ok(evaluated_right),
|
(NodeEnum::Constant(one), _) if one.get_value() == &0.0 => Ok(evaluated_right),
|
||||||
(_, NodeEnum::Constant(one)) if one.get_value() == &Rational::ONE => Ok(evaluated_left),
|
(_, NodeEnum::Constant(one)) if one.get_value() == &0.0 => Ok(evaluated_left),
|
||||||
|
|
||||||
// Multiply into parenthesis (add)
|
// Multiply into parenthesis (add)
|
||||||
(_, NodeEnum::Add(add)) => Ok(Add::new_rc(
|
(_, NodeEnum::Add(add)) => Ok(Add::new_rc(
|
||||||
|
@ -63,9 +63,12 @@ impl Node for Multiply {
|
||||||
div.get_right(),
|
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(NodeEnum::from(Constant::new(Float::with_val_64(
|
||||||
|
env.get_float_precision(),
|
||||||
|
a.get_value() * b.get_value(),
|
||||||
|
)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move constant infront of symbols
|
// Move constant infront of symbols
|
||||||
|
@ -146,14 +149,22 @@ impl Multiply {
|
||||||
) -> Result<Rc<NodeEnum>, String> {
|
) -> Result<Rc<NodeEnum>, String> {
|
||||||
match (multiply.left.as_ref(), multiply.right.as_ref()) {
|
match (multiply.left.as_ref(), multiply.right.as_ref()) {
|
||||||
(NodeEnum::Constant(c2), _) => {
|
(NodeEnum::Constant(c2), _) => {
|
||||||
let new_const = Constant::new(constant.get_value() * c2.get_value()).into();
|
let new_const = Constant::new(Float::with_val_64(
|
||||||
|
env.get_float_precision(),
|
||||||
|
constant.get_value() * c2.get_value(),
|
||||||
|
))
|
||||||
|
.into();
|
||||||
Ok(Rc::new(
|
Ok(Rc::new(
|
||||||
Multiply::new(Rc::new(new_const), multiply.right.clone()).into(),
|
Multiply::new(Rc::new(new_const), multiply.right.clone()).into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, NodeEnum::Constant(c2)) => {
|
(_, NodeEnum::Constant(c2)) => {
|
||||||
let new_const = Constant::new(constant.get_value() * c2.get_value()).into();
|
let new_const = Constant::new(Float::with_val_64(
|
||||||
|
env.get_float_precision(),
|
||||||
|
constant.get_value() * c2.get_value(),
|
||||||
|
))
|
||||||
|
.into();
|
||||||
Ok(Rc::new(
|
Ok(Rc::new(
|
||||||
Multiply::new(Rc::new(new_const), multiply.right.clone()).into(),
|
Multiply::new(Rc::new(new_const), multiply.right.clone()).into(),
|
||||||
))
|
))
|
||||||
|
|
|
@ -20,7 +20,7 @@ impl Node for Set {
|
||||||
|
|
||||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
format!(
|
format!(
|
||||||
"({})",
|
"[{}]",
|
||||||
self.values
|
self.values
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.as_string(env))
|
.map(|x| x.as_string(env))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use malachite::{base::num::basic::traits::Zero, rational::Rational};
|
use rug::Float;
|
||||||
|
|
||||||
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
|
||||||
|
|
||||||
|
@ -17,18 +17,21 @@ 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() == &Rational::ZERO => Ok(evaluated_right),
|
(NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => Ok(evaluated_right),
|
||||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == &Rational::ZERO => Ok(evaluated_left),
|
(_, NodeEnum::Constant(zero)) if zero.get_value() == &0.0 => 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(NodeEnum::from(Constant::new(Float::with_val_64(
|
||||||
|
env.get_float_precision(),
|
||||||
|
a.get_value() - b.get_value(),
|
||||||
|
)))))
|
||||||
}
|
}
|
||||||
// Symbol + Constant we just return the same
|
// Symbol - Constant we just return the same
|
||||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => 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(_)) => Ok(Rc::new(
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
||||||
Subtract::new(evaluated_right, evaluated_left).into(),
|
Subtract::new(evaluated_right, evaluated_left).into(),
|
||||||
)),
|
)),
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
use std::{iter::Peekable, rc::Rc, slice::Iter, str::Chars, vec::IntoIter};
|
use std::{env, iter::Peekable, rc::Rc, slice::Iter, str::Chars, vec::IntoIter};
|
||||||
|
|
||||||
|
use rug::Float;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
environment::Environment,
|
environment::Environment,
|
||||||
node::{
|
node::{
|
||||||
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, string_node::StringNode, 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,
|
||||||
|
string_node::StringNode,
|
||||||
|
subtract::Subtract,
|
||||||
|
symbol::Symbol,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,7 +30,7 @@ pub struct Token(usize, TokenType);
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
// Space,
|
// Space,
|
||||||
Number(ConstantValue),
|
Number(String),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
String(String),
|
String(String),
|
||||||
|
|
||||||
|
@ -34,6 +51,9 @@ pub enum TokenType {
|
||||||
|
|
||||||
RParen,
|
RParen,
|
||||||
LParen,
|
LParen,
|
||||||
|
|
||||||
|
RSquare,
|
||||||
|
LSquare,
|
||||||
Comma,
|
Comma,
|
||||||
|
|
||||||
If,
|
If,
|
||||||
|
@ -68,6 +88,9 @@ impl TokenType {
|
||||||
|
|
||||||
TokenType::RParen => 1,
|
TokenType::RParen => 1,
|
||||||
TokenType::LParen => 1,
|
TokenType::LParen => 1,
|
||||||
|
|
||||||
|
TokenType::RSquare => 1,
|
||||||
|
TokenType::LSquare => 1,
|
||||||
TokenType::Comma => 1,
|
TokenType::Comma => 1,
|
||||||
|
|
||||||
TokenType::If => 2,
|
TokenType::If => 2,
|
||||||
|
@ -88,7 +111,6 @@ pub struct Lexer<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LexerError {
|
pub enum LexerError {
|
||||||
UnexpectedChar(usize, String),
|
UnexpectedChar(usize, String),
|
||||||
NumberParse(usize, String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lexer<'a> {
|
impl<'a> Lexer<'a> {
|
||||||
|
@ -125,7 +147,7 @@ impl<'a> Lexer<'a> {
|
||||||
loop {
|
loop {
|
||||||
let d = self.source.peek();
|
let d = self.source.peek();
|
||||||
match d {
|
match d {
|
||||||
Some('0'..='9') | Some('e') | Some('E') => {
|
Some('0'..='9') => {
|
||||||
digit.push(*d.unwrap());
|
digit.push(*d.unwrap());
|
||||||
self.source.next();
|
self.source.next();
|
||||||
i += 1;
|
i += 1;
|
||||||
|
@ -148,41 +170,41 @@ impl<'a> Lexer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let number =
|
// if let Some(v) = {
|
||||||
if let Some(v) = ConstantValue::from_sci_string_simplest(digit.as_str()) {
|
// v
|
||||||
v
|
// } else {
|
||||||
} else {
|
// return Err(LexerError::NumberParse(
|
||||||
return Err(LexerError::NumberParse(
|
// i,
|
||||||
i,
|
// format!("Failed to convert {digit} to a number"),
|
||||||
format!("Failed to convert {digit} to a number"),
|
// ));
|
||||||
));
|
// };
|
||||||
};
|
|
||||||
|
|
||||||
tokens.push(Token(i, TokenType::Number(number)));
|
tokens.push(Token(i, TokenType::Number(digit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
'"' => {
|
'"' => {
|
||||||
let mut buffer = "".to_owned();
|
let mut buffer = "".to_owned();
|
||||||
loop {
|
loop {
|
||||||
let next = self.source.peek();
|
let next = self.source.peek();
|
||||||
|
|
||||||
match next {
|
match next {
|
||||||
Some('"') => {
|
Some('"') => {
|
||||||
tokens.push(Token(i, TokenType::String(buffer.clone())));
|
tokens.push(Token(i, TokenType::String(buffer.clone())));
|
||||||
self.source.next();
|
self.source.next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
buffer.push(self.source.next().unwrap());
|
buffer.push(self.source.next().unwrap());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return Err(LexerError::UnexpectedChar(
|
return Err(LexerError::UnexpectedChar(
|
||||||
i,
|
i,
|
||||||
"Unexpected End of file".to_owned(),
|
"Unexpected End of file".to_owned(),
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}},
|
}
|
||||||
|
|
||||||
// LeftArrow (->)
|
// LeftArrow (->)
|
||||||
'-' if self.source.peek() == Some(&'>') => {
|
'-' if self.source.peek() == Some(&'>') => {
|
||||||
|
@ -221,6 +243,9 @@ impl<'a> Lexer<'a> {
|
||||||
'(' => tokens.push(Token(i, TokenType::LParen)),
|
'(' => tokens.push(Token(i, TokenType::LParen)),
|
||||||
')' => tokens.push(Token(i, TokenType::RParen)),
|
')' => tokens.push(Token(i, TokenType::RParen)),
|
||||||
|
|
||||||
|
'[' => tokens.push(Token(i, TokenType::LSquare)),
|
||||||
|
']' => tokens.push(Token(i, TokenType::RSquare)),
|
||||||
|
|
||||||
_ if c.is_alphabetic() || c == '_' => {
|
_ if c.is_alphabetic() || c == '_' => {
|
||||||
tokens.push(self.lex_identifier(&mut i, c)?);
|
tokens.push(self.lex_identifier(&mut i, c)?);
|
||||||
}
|
}
|
||||||
|
@ -273,6 +298,7 @@ pub enum ParserError {
|
||||||
UnexpectedToken(usize, usize, String),
|
UnexpectedToken(usize, usize, String),
|
||||||
Unimplemented(usize, usize, String),
|
Unimplemented(usize, usize, String),
|
||||||
UnexpectedNode(usize, String),
|
UnexpectedNode(usize, String),
|
||||||
|
NumberParse(usize, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursive descent parser
|
/// Recursive descent parser
|
||||||
|
@ -464,34 +490,95 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn call(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
let mut expr = self.function();
|
// Left hand side
|
||||||
|
let mut expr = self.function()?;
|
||||||
|
|
||||||
|
// Calls are right-associative, so we evaluate right-to-left
|
||||||
loop {
|
loop {
|
||||||
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.clone())
|
(*i, x.clone())
|
||||||
} else {
|
} else {
|
||||||
return expr;
|
return Ok(expr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If the next token is a parenthesis then we construct a call
|
||||||
if t == TokenType::LParen {
|
if t == TokenType::LParen {
|
||||||
let potential_parameters = self.primary()?;
|
self.consume();
|
||||||
let parameters = if let NodeEnum::Set(set) = potential_parameters.as_ref() {
|
|
||||||
potential_parameters
|
|
||||||
} else {
|
|
||||||
// return Err(ParserError::UnexpectedNode(
|
|
||||||
// i,
|
|
||||||
// format!("Expected a Set here, but got a {potential_parameters:?}"),
|
|
||||||
// ));
|
|
||||||
Set::new(vec![potential_parameters])
|
|
||||||
};
|
|
||||||
|
|
||||||
expr = Ok(Call::new(expr?, parameters));
|
// Calls can have 0 arguments, so check and return early
|
||||||
|
if self.matchType(TokenType::RParen) {
|
||||||
|
expr = Call::new(expr, vec![]);
|
||||||
|
} else {
|
||||||
|
// Parse expressions until a patching Right-Parenthesis is found
|
||||||
|
let mut parameters = vec![self.equality()?];
|
||||||
|
|
||||||
|
while self.matchType(TokenType::Comma) {
|
||||||
|
parameters.push(self.equality()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.matchType(TokenType::RParen) {
|
||||||
|
return Err(ParserError::UnexpectedToken(
|
||||||
|
i,
|
||||||
|
t.len(),
|
||||||
|
"Unclosed right parenthesis".to_owned(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the next token is a ColonEquals (assignment) then
|
||||||
|
// the user wants function assignment sugar
|
||||||
|
//
|
||||||
|
// Ie f(x) := x*5 => f := x -> x*5
|
||||||
|
if self.matchType(TokenType::ColonEquals) {
|
||||||
|
if let NodeEnum::Symbol(_) = expr.as_ref() {
|
||||||
|
} else {
|
||||||
|
let Token(i, token) = self.previous.as_ref().unwrap();
|
||||||
|
return Err(ParserError::UnexpectedToken(
|
||||||
|
*i,
|
||||||
|
token.len(),
|
||||||
|
format!(
|
||||||
|
"Expected an Identifier here but found a {}",
|
||||||
|
expr.type_str()
|
||||||
|
),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse body
|
||||||
|
let body = self.equality()?;
|
||||||
|
|
||||||
|
// Convert vector of expressions to vector of symbols
|
||||||
|
let mut arguments = Vec::with_capacity(parameters.len());
|
||||||
|
for param in parameters.into_iter() {
|
||||||
|
if let NodeEnum::Symbol(symbol) =
|
||||||
|
Rc::<NodeEnum>::try_unwrap(param).unwrap()
|
||||||
|
{
|
||||||
|
arguments.push(symbol);
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedToken(
|
||||||
|
i,
|
||||||
|
t.len(),
|
||||||
|
format!("One or more argument is not a Symbol",),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Early exit with new desugared expression
|
||||||
|
return Ok(Rc::new(
|
||||||
|
Assign::new(
|
||||||
|
expr,
|
||||||
|
Function::new(FunctionType::UserFunction(body, arguments)),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
expr = Call::new(expr, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expr
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn function(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
|
@ -588,6 +675,48 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(IfElse::new(condition, expressions, else_branch));
|
return Ok(IfElse::new(condition, expressions, else_branch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.set()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
|
if self.matchType(TokenType::LSquare) {
|
||||||
|
// Empty set
|
||||||
|
if self.matchType(TokenType::RSquare) {
|
||||||
|
return Ok(Set::new(vec![]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut values = vec![self.equality()?];
|
||||||
|
while {
|
||||||
|
if let Some(Token(_, TokenType::RSquare)) = self.tokens.peek() {
|
||||||
|
self.consume();
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
let (i, token) = if let Some(Token(i, x)) = self.tokens.peek() {
|
||||||
|
(i, x)
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedEndOfTokens(
|
||||||
|
"Expected comma here".into(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if *token == TokenType::Comma {
|
||||||
|
self.consume();
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedToken(
|
||||||
|
*i,
|
||||||
|
token.len(),
|
||||||
|
format!("Expected comma here, but got {token:?}"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
values.push(self.equality()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(Set::new(values));
|
||||||
|
}
|
||||||
self.primary()
|
self.primary()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,7 +730,17 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
TokenType::Number(value) => Ok(Rc::new(Constant::new(value).into())),
|
TokenType::Number(value) => {
|
||||||
|
let value = if let Ok(incomplete) = Float::parse(&value) {
|
||||||
|
Float::with_val_64(self.environment.get_float_precision(), incomplete)
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::NumberParse(
|
||||||
|
i,
|
||||||
|
format!("Failed to convert `{value}` to a number"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
Ok(Rc::new(Constant::new(value).into()))
|
||||||
|
}
|
||||||
TokenType::Identifier(string) => Ok(Rc::new(
|
TokenType::Identifier(string) => Ok(Rc::new(
|
||||||
Symbol::new_from_str(string, self.environment).into(),
|
Symbol::new_from_str(string, self.environment).into(),
|
||||||
)),
|
)),
|
||||||
|
@ -611,70 +750,25 @@ impl<'a> Parser<'a> {
|
||||||
TokenType::String(s) => Ok(StringNode::new(s)),
|
TokenType::String(s) => Ok(StringNode::new(s)),
|
||||||
|
|
||||||
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() {
|
|
||||||
(i, x)
|
|
||||||
} else {
|
|
||||||
return Err(ParserError::UnexpectedEndOfTokens(
|
|
||||||
"Unclosed right parenthesis".into(),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
match t {
|
if !self.matchType(TokenType::RParen) {
|
||||||
TokenType::RParen => {
|
if let Some(Token(i, t)) = self.tokens.peek() {
|
||||||
self.consume();
|
return Err(ParserError::UnexpectedToken(
|
||||||
Ok(expr)
|
*i,
|
||||||
|
t.len(),
|
||||||
|
format!("Expected right parenthesis here, but got {t:?}"),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedToken(
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
"Unclosed right parenthesis".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
TokenType::Comma => {
|
|
||||||
let mut values = vec![expr];
|
|
||||||
while {
|
|
||||||
if let Some(Token(_, TokenType::RParen)) = self.tokens.peek() {
|
|
||||||
self.consume();
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} {
|
|
||||||
let (i, token) = if let Some(Token(i, x)) = self.tokens.peek() {
|
|
||||||
(i, x)
|
|
||||||
} else {
|
|
||||||
return Err(ParserError::UnexpectedEndOfTokens(
|
|
||||||
"Expected comma here".into(),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
if *token == TokenType::Comma {
|
|
||||||
self.consume();
|
|
||||||
} else {
|
|
||||||
return Err(ParserError::UnexpectedToken(
|
|
||||||
*i,
|
|
||||||
token.len(),
|
|
||||||
format!("Expected comma here, but got {token:?}"),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
values.push(self.equality()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Set::new(values))
|
|
||||||
}
|
|
||||||
_ => Err(ParserError::Unimplemented(
|
|
||||||
*i,
|
|
||||||
t.len(),
|
|
||||||
format!("Expected either a comma or a right parenthesis here. Got {t:?}"),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if t != TokenType::RParen {
|
Ok(expr)
|
||||||
// Err(ParserError::UnexpectedToken(i, t.len(), format!("")))
|
|
||||||
// } else {
|
|
||||||
// Ok(expr)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
_ => Err(ParserError::UnexpectedToken(
|
_ => Err(ParserError::UnexpectedToken(
|
||||||
i,
|
i,
|
||||||
|
|
Loading…
Reference in a new issue