aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval.rs178
-rw-r--r--src/main.rs48
-rw-r--r--src/parser.rs3
3 files changed, 77 insertions, 152 deletions
diff --git a/src/eval.rs b/src/eval.rs
index 1045b17..c11614d 100644
--- a/src/eval.rs
+++ b/src/eval.rs
@@ -1,13 +1,12 @@
-use num::pow::Pow;
-use num::{BigInt, FromPrimitive, Integer, Signed, ToPrimitive};
use std::fmt::{Display, Formatter};
+#[derive(Clone, Copy)]
pub enum Num {
- Int(BigInt),
+ Int(i64),
Float(f64),
}
-pub fn int(i: BigInt) -> Num {
+pub fn int(i: i64) -> Num {
Num::Int(i)
}
@@ -15,43 +14,45 @@ pub fn float(f: f64) -> Num {
Num::Float(f)
}
-fn float_from_int(i: &BigInt) -> f64 {
- if let Some(f) = i.to_f64() {
- return f;
- }
- if i > &BigInt::ZERO {
- std::f64::INFINITY
- } else {
- std::f64::NEG_INFINITY
- }
-}
-
impl Num {
- fn as_float(&self) -> f64 {
+ fn as_float(self) -> f64 {
match self {
- Num::Int(i) => float_from_int(i),
- Num::Float(f) => *f,
+ Num::Int(i) => i as f64,
+ Num::Float(f) => f,
}
}
pub fn pow(self, other: Num) -> Num {
match (self, other) {
+ (_, Num::Int(0)) => return int(1),
+ (Num::Int(-1), Num::Int(i2)) => {
+ if i2 % 2 == 0 {
+ return int(1);
+ } else {
+ return int(-1);
+ }
+ }
+ (Num::Int(0), _) => return int(0),
+ (Num::Int(1), _) => return int(1),
(Num::Int(i1), Num::Int(i2)) => {
- if i2 < BigInt::ZERO {
- return float(float_from_int(&i1).powf(float_from_int(&i2)));
+ if let Ok(u) = u32::try_from(i2) {
+ if let Some(p) = i1.checked_pow(u) {
+ return int(p);
+ }
}
- let (_, u2) = i2.into_parts();
- int(i1.pow(u2))
}
- (n1, n2) => float(n1.as_float().powf(n2.as_float())),
+ _ => (),
}
+ float(self.as_float().powf(other.as_float()))
}
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()),
+ if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let Some(p) = i1.checked_mul(i2) {
+ return int(p);
+ }
}
+ float(self.as_float() * other.as_float())
}
pub fn div(self, other: Num) -> Num {
@@ -59,57 +60,48 @@ impl Num {
}
pub fn int_div(self, other: Num) -> Num {
- match (self, other) {
- (Num::Int(i1), Num::Int(i2)) => int(i1 / i2),
- (Num::Float(f1), Num::Float(f2)) => {
- let r = f1 / f2;
- if let Some(i) = BigInt::from_f64(r) {
- return int(i);
- }
- float(r)
- }
- (Num::Int(i), Num::Float(f)) => {
- if let Some(fi) = BigInt::from_f64(f) {
- return int(i / fi);
- }
- float(float_from_int(&i) / f)
- }
- (Num::Float(f), Num::Int(i)) => {
- if let Some(fi) = BigInt::from_f64(f) {
- return int(fi / i);
- }
- float(f / float_from_int(&i))
+ if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let Some(q) = i1.checked_div(i2) {
+ return int(q);
}
}
+ int((self.as_float() / other.as_float()) as i64)
}
pub fn modulo(self, other: Num) -> Num {
- match (self, other) {
- (Num::Int(i1), Num::Int(i2)) => int(i1.mod_floor(&i2)),
- (n1, n2) => {
- let n1 = n1.as_float();
- let n2 = n2.as_float();
- let r = n1 % n2;
- if r < 0. {
- return float(r + n2);
+ if let (Num::Int(i1), Num::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);
}
- float(r)
+ return int(r);
}
}
+ 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 {
- match (self, other) {
- (Num::Int(i1), Num::Int(i2)) => int(i1 + i2),
- (n1, n2) => float(n1.as_float() + n2.as_float()),
+ if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let Some(s) = i1.checked_add(i2) {
+ return int(s);
+ }
}
+ float(self.as_float() + other.as_float())
}
pub fn sub(self, other: Num) -> Num {
- match (self, other) {
- (Num::Int(i1), Num::Int(i2)) => int(i1 - i2),
- (n1, n2) => Num::Float(n1.as_float() - n2.as_float()),
+ if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let Some(d) = i1.checked_sub(i2) {
+ return int(d);
+ }
}
+ float(self.as_float() - other.as_float())
}
pub fn sin(self) -> Num {
@@ -126,15 +118,23 @@ impl Num {
pub fn sqrt(self) -> Num {
match self {
- Num::Int(i) if i >= BigInt::ZERO => {
- let s = i.sqrt();
- if i != &s * &s {
- return float(float_from_int(&i).sqrt());
+ Num::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);
}
- int(s)
}
- n => float(n.as_float().sqrt()),
+ _ => (),
}
+ float(self.as_float().sqrt())
}
pub fn log(self) -> Num {
@@ -152,36 +152,21 @@ impl Num {
pub fn floor(self) -> Num {
match self {
Num::Int(i) => int(i),
- Num::Float(f) => {
- if let Some(i) = BigInt::from_f64(f.floor()) {
- return int(i);
- }
- float(f)
- }
+ Num::Float(f) => int(f.floor() as i64),
}
}
pub fn ceil(self) -> Num {
match self {
Num::Int(i) => int(i),
- Num::Float(f) => {
- if let Some(i) = BigInt::from_f64(f.ceil()) {
- return int(i);
- }
- float(f)
- }
+ Num::Float(f) => int(f.ceil() as i64),
}
}
pub fn round(self) -> Num {
match self {
Num::Int(i) => int(i),
- Num::Float(f) => {
- if let Some(i) = BigInt::from_f64(f.round_ties_even()) {
- return int(i);
- }
- float(f)
- }
+ Num::Float(f) => int(f.round_ties_even() as i64),
}
}
@@ -193,31 +178,12 @@ impl Num {
}
}
-fn log10(n: &BigInt) -> u64 {
- ((n.bits() - 1) as f64 / std::f64::consts::LOG2_10) as u64
-}
-
impl Display for Num {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
- Num::Int(n) => {
- if n.bits() < 100 {
- return write!(f, "{n}");
- }
- let len = log10(n) + 1;
- let rounded = i64::try_from(n / BigInt::from(10).pow(len - 8)).unwrap();
- let rounded_str = format!("{rounded}");
- write!(
- f,
- "{}.{}e{}",
- &rounded_str[..1],
- &rounded_str[1..],
- len - 8 + rounded_str.len() as u64 - 1
- )
- }
+ Num::Int(n) => write!(f, "{n}"),
Num::Float(n) => {
- let n = *n;
- if !(-1e30..=1e30).contains(&n) {
+ if !(-1e30..=1e30).contains(n) {
return write!(f, "{n:.7e}");
}
let mut buf = format!("{n:.7}");
diff --git a/src/main.rs b/src/main.rs
index 9fe62b3..8976e17 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,17 +8,6 @@ use gtk4::prelude::{
ApplicationExt, ApplicationExtManual, EditableExt, GridExt, GtkWindowExt, WidgetExt,
};
use gtk4::{glib, Application, ApplicationWindow, Entry, EventControllerKey, Grid};
-use std::sync::{Arc, Mutex};
-
-fn send_mail<T>(m: &Mutex<Option<T>>, msg: T) {
- let mut guard = m.lock().unwrap();
- *guard = Some(msg);
-}
-
-fn get_mail<T>(m: &Mutex<Option<T>>) -> Option<T> {
- let mut guard = m.lock().unwrap();
- std::mem::take(&mut guard)
-}
fn main() -> ExitCode {
let app = Application::builder()
@@ -40,51 +29,22 @@ fn main() -> ExitCode {
let output = Entry::builder().editable(false).build();
grid.attach(&output, 0, 1, 1, 1);
- let (ping_send, ping_recv) = async_channel::bounded(1);
- let mailbox = Arc::new(Mutex::new(None));
-
let key_controller = EventControllerKey::new();
key_controller.connect_key_released(
- clone!(@weak window, @weak input, @strong mailbox => move |_, k, _, modifiers| {
+ clone!(@weak window, @weak input, @weak output => move |_, k, _, modifiers| {
if k == Key::Escape
|| k == Key::Return
|| k == Key::bracketleft && modifiers.contains(ModifierType::CONTROL_MASK)
{
window.destroy();
}
- send_mail(mailbox.as_ref(), format!("{}", input.text()));
- let _ = ping_send.try_send(());
+ if let Some(n) = parser::parse(&input.text()) {
+ output.set_text(&format!("{n}"));
+ }
}),
);
window.add_controller(key_controller);
- glib::spawn_future_local(async move {
- let mut prev_input = String::from("");
- loop {
- if ping_recv.recv().await.is_err() {
- break;
- }
- let Some(input) = get_mail(mailbox.as_ref()) else {
- continue;
- };
- if input == prev_input {
- continue;
- }
- prev_input = input.clone();
- let (output_send, output_recv) = async_channel::bounded(1);
- let thread_handle = gtk4::gio::spawn_blocking(move || {
- if let Some(result) = parser::parse(&input) {
- output_send.send_blocking(format!("{result}")).unwrap();
- }
- });
- let _ = thread_handle.await;
- let Ok(result) = output_recv.try_recv() else {
- continue;
- };
- output.set_text(&result);
- }
- });
-
window.present();
});
diff --git a/src/parser.rs b/src/parser.rs
index 2b33e0f..c0f3a9b 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,7 +1,6 @@
use crate::eval;
use crate::eval::Num;
use crate::lexer::Lexer;
-use num::BigInt;
use std::str::FromStr;
enum Op {
@@ -58,7 +57,7 @@ impl<'a> Parser<'a> {
}
return Some(eval::float(f));
}
- let Ok(i) = BigInt::from_str(t) else {
+ let Ok(i) = i64::from_str(t) else {
return None;
};
if negative {