aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2024-06-07 09:01:40 -0700
committerRose Hogenson <rosehogenson@posteo.net>2024-06-07 09:01:40 -0700
commit6f49283f8a8cd60b329a63fa46c7112c4e4bbb4f (patch)
treeec82142d7981eee19875a761370748363362154d
parentdbc36c472daeab34f7f71193d3b69edea19d9a23 (diff)
downloadqc-6f49283f8a8cd60b329a63fa46c7112c4e4bbb4f.tar.zst
Bring back bigint.
-rw-r--r--Cargo.lock130
-rw-r--r--Cargo.toml3
-rw-r--r--src/eval.rs380
-rw-r--r--src/main.rs34
-rw-r--r--src/op.rs44
-rw-r--r--src/parser.rs11
6 files changed, 436 insertions, 166 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 771e9ea..92ac6ec 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,6 +3,18 @@
version = 3
[[package]]
+name = "async-channel"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
+dependencies = [
+ "concurrent-queue",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -49,12 +61,48 @@ dependencies = [
]
[[package]]
+name = "concurrent-queue"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
+name = "event-listener"
+version = "5.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
+dependencies = [
+ "event-listener",
+ "pin-project-lite",
+]
+
+[[package]]
name = "field-offset"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -421,6 +469,79 @@ dependencies = [
]
[[package]]
+name = "num"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
+dependencies = [
+ "num-bigint",
+ "num-complex",
+ "num-integer",
+ "num-iter",
+ "num-rational",
+ "num-traits",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
+dependencies = [
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "pango"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -445,6 +566,12 @@ dependencies = [
]
[[package]]
+name = "parking"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
+
+[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -484,8 +611,11 @@ dependencies = [
name = "qc"
version = "0.1.0"
dependencies = [
+ "async-channel",
"gdk4",
+ "gio",
"gtk4",
+ "num",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 121cdee..aaaba50 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,5 +7,8 @@ license = "GPL3"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+async-channel = "2.3.1"
gdk4 = "0.8.2"
+gio = "0.19.5"
gtk4 = "0.8.2"
+num = "0.4.3"
diff --git a/src/eval.rs b/src/eval.rs
index e40743b..d9fb184 100644
--- a/src/eval.rs
+++ b/src/eval.rs
@@ -1,195 +1,244 @@
+use num::bigint::Sign;
+use num::{BigInt, FromPrimitive, Integer, Signed, ToPrimitive, Zero};
use std::fmt::{Display, Formatter};
-use Num::{Float, Int};
-#[derive(Clone, Copy, Debug, PartialEq)]
+fn int_to_float(i: &BigInt) -> f64 {
+ match i.sign() {
+ Sign::Minus => return -int_to_float(&-i),
+ Sign::NoSign => return 0.,
+ _ => (),
+ }
+ let mut exponent = i.bits() - 1;
+ if exponent > 1023 {
+ return f64::INFINITY;
+ }
+ let mut fraction;
+ if exponent <= 52 {
+ fraction = i.to_u64().unwrap() << 52 - exponent;
+ } else {
+ let power = BigInt::from(1) << exponent - 52;
+ let (fraction_big, rem) = i.div_rem(&power);
+ fraction = fraction_big.to_u64().unwrap();
+ let half = power >> 1;
+ if rem > half || rem == half && fraction % 2 == 1 {
+ fraction += 1;
+ if fraction == 1 << 53 {
+ exponent += 1;
+ if exponent > 1023 {
+ return f64::INFINITY;
+ }
+ fraction = 1 << 53;
+ }
+ }
+ }
+
+ let u = (exponent + 1023) << 52 | fraction & !(1 << 52);
+ f64::from_bits(u)
+}
+
+#[derive(Debug, PartialEq)]
pub enum Num {
- Int(i128),
+ Int(BigInt),
Float(f64),
}
+fn int(i: BigInt) -> Num {
+ if i.bits() > 1 << 30 {
+ return Num::Float(int_to_float(&i));
+ }
+ Num::Int(i)
+}
+
+fn float(f: f64) -> Num {
+ Num::Float(f)
+}
+
impl Num {
- fn as_float(self) -> f64 {
+ fn as_float(&self) -> f64 {
match self {
- Int(i) => i as f64,
- Float(f) => f,
+ Num::Int(i) => int_to_float(i),
+ &Num::Float(f) => f,
}
}
- fn powi(self, p: i128) -> Num {
- if p == 0 {
- return Int(1);
- }
- if p == 1 {
- return self;
+ fn square(self) -> Num {
+ match self {
+ Num::Int(i) => int(i.pow(2)),
+ Num::Float(f) => float(f * f),
}
- if p % 2 == 0 {
- return self.mul(self).powi(p / 2);
+ }
+
+ fn powi(self, p: BigInt) -> Num {
+ let mut n = self;
+ let mut p = p;
+ let mut acc = int(BigInt::from(1));
+ loop {
+ if p.is_odd() {
+ acc = acc.mul(&n);
+ }
+ p >>= 1;
+ if p.is_zero() {
+ return acc;
+ }
+ n = n.square();
}
- self.mul(self).powi(p / 2).mul(self)
}
pub fn pow(self, other: Num) -> Num {
match other {
- Int(i) => {
- if i >= 0 {
+ Num::Int(i) => {
+ if !i.is_negative() {
return self.powi(i);
}
- if let Ok(i_32) = i32::try_from(i) {
- return Float(self.as_float().powi(i_32));
+ if let Ok(i_32) = i32::try_from(&i) {
+ return float(self.as_float().powi(i_32));
}
- Float(1.).div(self).powi(-i)
+ float(1.).div(self).powi(-i)
}
- Float(f) => Float(self.as_float().powf(f)),
+ Num::Float(f) => float(self.as_float().powf(f)),
}
}
- pub fn mul(self, other: Num) -> Num {
- if let (Int(i1), Int(i2)) = (self, other) {
- if let Some(p) = i1.checked_mul(i2) {
- return Int(p);
- }
+ pub fn mul(self, other: &Num) -> Num {
+ match (self, other) {
+ (Num::Int(i1), Num::Int(i2)) => int(i1 * i2),
+ (n1, n2) => float(n1.as_float() * n2.as_float()),
}
- Float(self.as_float() * other.as_float())
}
pub fn div(self, other: Num) -> Num {
- Float(self.as_float() / other.as_float())
+ float(self.as_float() / other.as_float())
}
pub fn int_div(self, other: Num) -> Num {
- if let (Int(i1), Int(i2)) = (self, other) {
- if let Some(q) = i1.checked_div(i2) {
- return Int(q);
+ match (self, other) {
+ (Num::Int(i1), Num::Int(i2)) if !i2.is_zero() => int(i1.div_floor(&i2)),
+ (n1, n2) => {
+ let f = (n1.as_float() / n2.as_float()).floor();
+ let Some(i) = BigInt::from_f64(f) else {
+ return float(f);
+ };
+ int(i)
}
}
- Int((self.as_float() / other.as_float()) as i128)
}
pub fn modulo(self, other: Num) -> Num {
- if let (Int(i1), Int(i2)) = (self, other) {
- if let Some(r) = i1.checked_rem(i2) {
- if i2 > 0 && r < 0 || i2 < 0 && r > 0 {
- return Int(r + i2);
- }
- return Int(r);
- }
+ match (self, other) {
+ (Num::Int(i1), Num::Int(i2)) if !i2.is_zero() => int(i1.mod_floor(&i2)),
+ (n1, n2) => float(n1.as_float() % n2.as_float()),
}
- let n1 = self.as_float();
- let n2 = other.as_float();
- let r = n1 % n2;
- if n2 > 0. && r < 0. || n2 < 0. && r > 0. {
- return Float(r + n2);
- }
- Float(r)
}
pub fn add(self, other: Num) -> Num {
- if let (Int(i1), Int(i2)) = (self, other) {
- if let Some(s) = i1.checked_add(i2) {
- return Int(s);
- }
+ match (self, other) {
+ (Num::Int(i1), Num::Int(i2)) => int(i1 + i2),
+ (n1, n2) => float(n1.as_float() + n2.as_float()),
}
- Float(self.as_float() + other.as_float())
}
pub fn sub(self, other: Num) -> Num {
- if let (Int(i1), Int(i2)) = (self, other) {
- if let Some(d) = i1.checked_sub(i2) {
- return Int(d);
- }
+ match (self, other) {
+ (Num::Int(i1), Num::Int(i2)) => int(i1 - i2),
+ (n1, n2) => float(n1.as_float() - n2.as_float()),
}
- Float(self.as_float() - other.as_float())
}
pub fn sin(self) -> Num {
- Float(self.as_float().sin())
+ float(self.as_float().sin())
}
pub fn cos(self) -> Num {
- Float(self.as_float().cos())
+ float(self.as_float().cos())
}
pub fn tan(self) -> Num {
- Float(self.as_float().tan())
+ float(self.as_float().tan())
}
pub fn asin(self) -> Num {
- Float(self.as_float().asin())
+ float(self.as_float().asin())
}
pub fn acos(self) -> Num {
- Float(self.as_float().acos())
+ float(self.as_float().acos())
}
pub fn atan(self) -> Num {
- Float(self.as_float().atan())
+ float(self.as_float().atan())
}
pub fn sqrt(self) -> Num {
match self {
- Int(i) if i >= 0 => {
- if i <= 1 {
- return Int(i);
- }
- let mut x0 = i / 2;
- let mut x1 = (x0 + i / x0) / 2;
- while x1 < x0 {
- x0 = x1;
- x1 = (x0 + i / x0) / 2;
- }
- if x0 * x0 == i {
- return Int(x0);
+ Num::Int(i) if !i.is_negative() => {
+ let s = i.sqrt();
+ if &s * &s == i {
+ return int(s);
}
+ float(int_to_float(&i).sqrt())
}
- _ => (),
+ n => float(n.as_float().sqrt()),
}
- Float(self.as_float().sqrt())
}
pub fn log(self) -> Num {
- Float(self.as_float().ln())
+ float(self.as_float().ln())
}
pub fn log10(self) -> Num {
- Float(self.as_float().log10())
+ float(self.as_float().log10())
}
pub fn log2(self) -> Num {
- Float(self.as_float().log2())
+ float(self.as_float().log2())
}
pub fn floor(self) -> Num {
match self {
- Int(i) => Int(i),
- Float(f) => Int(f.floor() as i128),
+ Num::Int(i) => int(i),
+ Num::Float(f) => {
+ let f = f.floor();
+ if let Some(i) = BigInt::from_f64(f) {
+ int(i)
+ } else {
+ float(f)
+ }
+ }
}
}
pub fn ceil(self) -> Num {
match self {
- Int(i) => Int(i),
- Float(f) => Int(f.ceil() as i128),
+ Num::Int(i) => int(i),
+ Num::Float(f) => {
+ let f = f.ceil();
+ if let Some(i) = BigInt::from_f64(f) {
+ int(i)
+ } else {
+ float(f)
+ }
+ }
}
}
pub fn round(self) -> Num {
match self {
- Int(i) => Int(i),
- Float(f) => Int(f.round_ties_even() as i128),
- }
- }
-
- pub fn trunc(self) -> Num {
- match self {
- Int(i) => Int(i),
- Float(f) => Int(f as i128),
+ Num::Int(i) => int(i),
+ Num::Float(f) => {
+ let f = f.round_ties_even();
+ if let Some(i) = BigInt::from_f64(f) {
+ int(i)
+ } else {
+ float(f)
+ }
+ }
}
}
pub fn abs(self) -> Num {
match self {
- Int(i) => Int(i.abs()),
- Float(f) => Float(f.abs()),
+ Num::Int(i) => int(i.abs()),
+ Num::Float(f) => float(f.abs()),
}
}
}
@@ -197,16 +246,13 @@ impl Num {
impl Display for Num {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
- Int(n) => write!(f, "{n}"),
- Float(n) => {
- if !(-1e30..=1e30).contains(n) {
- return write!(f, "{n:.7e}");
+ Num::Int(n) if n.bits() <= 100 => write!(f, "{n}"),
+ n => {
+ let n = n.as_float();
+ if (-(1i128 << 100) as f64) < n && n < (1i128 << 100) as f64 {
+ return write!(f, "{}", format!("{n:.7}").trim_end_matches('0'));
}
- let mut buf = format!("{n:.7}");
- while let Some(b'0') = buf.as_bytes().get(buf.len() - 1) {
- buf.truncate(buf.len() - 1);
- }
- write!(f, "{buf}")
+ write!(f, "{n:.7e}")
}
}
}
@@ -216,78 +262,146 @@ impl Display for Num {
mod tests {
use super::*;
+ fn int(i: i128) -> Num {
+ super::int(BigInt::from(i))
+ }
+
#[test]
- fn pow_positive_int() {
- assert_eq!(Int(2).pow(Int(16)), Int(65536));
+ fn int_to_float_small() {
+ for n in -(1 << 16)..1 << 16 {
+ assert_eq!(
+ int_to_float(&BigInt::from(n)),
+ n as f64,
+ "int_to_float({}) is not equal to {}",
+ n,
+ n as f64
+ );
+ }
}
#[test]
- fn pow_negative_int() {
- assert_eq!(Int(2).pow(Int(-3)), Float(0.125));
+ fn int_to_float_medium() {
+ let n = BigInt::from(2).pow(1023) + BigInt::from(2).pow(1022);
+ assert_eq!(int_to_float(&n), n.to_f64().unwrap());
}
#[test]
- fn pow_float() {
- assert_eq!(Int(4).pow(Float(0.5)), Float(2.));
+ fn int_to_float_round_up() {
+ assert_eq!(
+ int_to_float(&BigInt::from(0x7f_ffff_ffff_ffffu64)),
+ 0x80_0000_0000_0000u64 as f64
+ );
}
#[test]
- fn pow_overflow() {
- assert_eq!(Int(2).pow(Int(1 << 126)), Float(f64::INFINITY));
+ fn int_to_float_round_up_easy() {
+ assert_eq!(
+ int_to_float(&BigInt::from(0x40_0000_0000_0003u64)),
+ 0x40_0000_0000_0004u64 as f64
+ );
}
#[test]
- fn pow_underflow() {
- assert_eq!(Int(2).pow(Int(-(1 << 126))), Float(0.));
+ fn int_to_float_round_down() {
+ assert_eq!(
+ int_to_float(&BigInt::from(0x40_0000_0000_0001u64)),
+ 0x40_0000_0000_0000u64 as f64
+ );
}
#[test]
- fn modulo_pos() {
- assert_eq!(Int(5).modulo(Int(3)), Int(2));
+ fn int_to_float_round_to_even_down() {
+ assert_eq!(
+ int_to_float(&BigInt::from(0x40_0000_0000_0002u64)),
+ 0x40_0000_0000_0000u64 as f64
+ );
}
#[test]
- fn modulo_pos_neg() {
- assert_eq!(Int(5).modulo(Int(-3)), Int(-1));
+ fn int_to_float_round_to_even_up() {
+ assert_eq!(
+ int_to_float(&BigInt::from(0x40_0000_0000_0006u64)),
+ 0x40_0000_0000_0008u64 as f64
+ );
}
#[test]
- fn modulo_neg_pos() {
- assert_eq!(Int(-5).modulo(Int(3)), Int(1));
+ fn int_to_float_large() {
+ assert_eq!(
+ int_to_float(
+ &((BigInt::from(0x1f_ffff_ffff_ffffu64) << 971) + (BigInt::from(1) << 970) - 1)
+ ),
+ f64::MAX
+ );
}
#[test]
- fn modulo_neg() {
- assert_eq!(Int(-5).modulo(Int(-3)), Int(-2));
+ fn int_to_float_overflow() {
+ assert_eq!(
+ int_to_float(
+ &((BigInt::from(0x1f_ffff_ffff_ffffu64) << 971) + (BigInt::from(1) << 970))
+ ),
+ f64::INFINITY
+ );
+ }
+
+ #[test]
+ fn pow_positive_int() {
+ assert_eq!(int(2).pow(int(16)), int(65536));
+ }
+
+ #[test]
+ fn pow_negative_int() {
+ assert_eq!(int(2).pow(int(-3)), float(0.125));
+ }
+
+ #[test]
+ fn pow_float() {
+ assert_eq!(int(4).pow(float(0.5)), float(2.));
+ }
+
+ #[test]
+ fn pow_overflow() {
+ assert_eq!(int(2).pow(int(1 << 126)), float(f64::INFINITY));
+ }
+
+ #[test]
+ fn pow_underflow() {
+ assert_eq!(int(2).pow(int(-(1 << 126))), float(0.));
+ }
+
+ #[test]
+ fn modulo_pos() {
+ assert_eq!(int(5).modulo(int(3)), int(2));
}
#[test]
- fn modulo_float_pos() {
- assert_eq!(Float(5.).modulo(Int(3)), Float(2.));
+ fn modulo_pos_neg() {
+ assert_eq!(int(5).modulo(int(-3)), int(-1));
}
#[test]
- fn modulo_float_pos_neg() {
- assert_eq!(Float(5.).modulo(Int(-3)), Float(-1.));
+ fn modulo_neg_pos() {
+ assert_eq!(int(-5).modulo(int(3)), int(1));
}
#[test]
- fn modulo_float_neg_pos() {
- assert_eq!(Float(-5.).modulo(Int(3)), Float(1.));
+ fn modulo_neg() {
+ assert_eq!(int(-5).modulo(int(-3)), int(-2));
}
#[test]
- fn modulo_float_neg() {
- assert_eq!(Float(-5.).modulo(Int(-3)), Float(-2.));
+ fn modulo_float() {
+ assert_eq!(float(5.).modulo(int(3)), float(2.));
}
#[test]
fn sqrt() {
for n in 0..65536 {
assert_eq!(
- Int(n * n).sqrt(),
- Int(n),
- "Int({}).sqrt() is not equal to {}",
+ int(n * n).sqrt(),
+ int(n),
+ "int({}).sqrt() is not equal to {}",
n * n,
n
);
@@ -296,6 +410,6 @@ mod tests {
#[test]
fn sqrt_big() {
- assert_eq!(Int(1 << 126).sqrt(), Int(1 << 63));
+ assert_eq!(int(1 << 126).sqrt(), int(1 << 63));
}
}
diff --git a/src/main.rs b/src/main.rs
index 9c1e107..a372735 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,6 +9,7 @@ use gtk4::prelude::{
ApplicationExt, ApplicationExtManual, EditableExt, GridExt, GtkWindowExt, WidgetExt,
};
use gtk4::{glib, Application, ApplicationWindow, Entry, EventControllerKey, Grid};
+use std::sync::{Arc, Mutex};
fn main() -> ExitCode {
let app = Application::builder()
@@ -30,18 +31,43 @@ fn main() -> ExitCode {
let output = Entry::builder().editable(false).build();
grid.attach(&output, 0, 1, 1, 1);
+ let mailbox = Arc::new(Mutex::new(String::from("")));
+ let (flag_send, flag_recv) = async_channel::bounded(1);
+
+ glib::spawn_future_local({
+ let mailbox = mailbox.clone();
+ async move {
+ while let Ok(()) = flag_recv.recv().await {
+ let input = std::mem::take(&mut *mailbox.lock().unwrap());
+ let (result_send, result_recv) = async_channel::bounded(1);
+ gio::spawn_blocking(move || {
+ let Some(bytecode) = parser::parse(&input) else {
+ return;
+ };
+ result_send
+ .send_blocking(format!("{}", op::eval(bytecode.into_iter())))
+ .unwrap();
+ })
+ .await
+ .unwrap();
+ if let Ok(result) = result_recv.try_recv() {
+ output.set_text(&result);
+ }
+ }
+ }
+ });
+
let key_controller = EventControllerKey::new();
key_controller.connect_key_released(
- clone!(@weak window, @weak input, @weak output => move |_, k, _, modifiers| {
+ clone!(@weak window, @weak input => move |_, k, _, modifiers| {
if k == Key::Escape
|| k == Key::Return
|| k == Key::bracketleft && modifiers.contains(ModifierType::CONTROL_MASK)
{
window.destroy();
}
- if let Some(bytecode) = parser::parse(&input.text()) {
- output.set_text(&format!("{}", op::eval(&bytecode)));
- }
+ *mailbox.lock().unwrap() = input.text().to_string();
+ let _ = flag_send.try_send(());
}),
);
window.add_controller(key_controller);
diff --git a/src/op.rs b/src/op.rs
index b2f2a3f..e29de52 100644
--- a/src/op.rs
+++ b/src/op.rs
@@ -1,4 +1,5 @@
use crate::eval::Num;
+use num::BigInt;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UnOp {
@@ -16,29 +17,28 @@ pub enum UnOp {
Floor,
Ceil,
Round,
- Trunc,
Abs,
}
impl UnOp {
fn eval(self, x: Num) -> Num {
+ use UnOp::*;
match self {
- UnOp::Neg => Num::Int(0).sub(x),
- UnOp::Sin => x.sin(),
- UnOp::Cos => x.cos(),
- UnOp::Tan => x.tan(),
- UnOp::Asin => x.asin(),
- UnOp::Acos => x.acos(),
- UnOp::Atan => x.atan(),
- UnOp::Sqrt => x.sqrt(),
- UnOp::Log => x.log(),
- UnOp::Log10 => x.log10(),
- UnOp::Log2 => x.log2(),
- UnOp::Floor => x.floor(),
- UnOp::Ceil => x.ceil(),
- UnOp::Round => x.round(),
- UnOp::Trunc => x.trunc(),
- UnOp::Abs => x.abs(),
+ Neg => Num::Int(BigInt::from(0)).sub(x),
+ Sin => x.sin(),
+ Cos => x.cos(),
+ Tan => x.tan(),
+ Asin => x.asin(),
+ Acos => x.acos(),
+ Atan => x.atan(),
+ Sqrt => x.sqrt(),
+ Log => x.log(),
+ Log10 => x.log10(),
+ Log2 => x.log2(),
+ Floor => x.floor(),
+ Ceil => x.ceil(),
+ Round => x.round(),
+ Abs => x.abs(),
}
}
}
@@ -58,7 +58,7 @@ impl BinOp {
fn eval(self, x: Num, y: Num) -> Num {
match self {
BinOp::Pow => x.pow(y),
- BinOp::Mul => x.mul(y),
+ BinOp::Mul => x.mul(&y),
BinOp::Div => x.div(y),
BinOp::IntDiv => x.int_div(y),
BinOp::Mod => x.modulo(y),
@@ -68,18 +68,18 @@ impl BinOp {
}
}
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Debug, PartialEq)]
pub enum Op {
Num(Num),
Un(UnOp),
Bin(BinOp),
}
-pub fn eval(ops: &[Op]) -> Num {
+pub fn eval(ops: impl Iterator<Item = Op>) -> Num {
let mut stack = Vec::new();
for op in ops {
match op {
- Op::Num(n) => stack.push(*n),
+ Op::Num(n) => stack.push(n),
Op::Un(op) => {
let n = stack.pop().unwrap();
stack.push(op.eval(n));
@@ -91,5 +91,5 @@ pub fn eval(ops: &[Op]) -> Num {
}
}
}
- stack[0]
+ stack.pop().unwrap()
}
diff --git a/src/parser.rs b/src/parser.rs
index 1e271a4..19e8e47 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,6 +1,7 @@
use crate::eval::Num;
use crate::lexer::Lexer;
use crate::op::{BinOp, Op, UnOp};
+use num::BigInt;
use std::str::FromStr;
enum Pending {
@@ -54,7 +55,7 @@ impl<'a> Parser<'a> {
self.result.push(Op::Num(Num::Float(f)));
return Some(());
}
- let Ok(i) = i128::from_str(t) else {
+ let Ok(i) = BigInt::from_str(t) else {
return None;
};
self.result.push(Op::Num(Num::Int(i)));
@@ -130,10 +131,6 @@ impl<'a> Parser<'a> {
self.stack.push(Pending::Un(UnOp::Round));
return true;
}
- if self.symbol("trunc") {
- self.stack.push(Pending::Un(UnOp::Trunc));
- return true;
- }
if self.symbol("abs") {
self.stack.push(Pending::Un(UnOp::Abs));
return true;
@@ -261,8 +258,8 @@ pub fn parse(expr: &str) -> Option<Vec<Op>> {
mod tests {
use super::*;
- fn int(i: i128) -> Op {
- Op::Num(Num::Int(i))
+ fn int(i: i64) -> Op {
+ Op::Num(Num::Int(BigInt::from(i)))
}
fn float(f: f64) -> Op {