From bb48a09cc7208d8f294cf63b4f8ede56454fc27f Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 1 Apr 2023 14:20:11 -0700 Subject: [PATCH] Added decimal -> rational parsing --- src/parser/mod.rs | 18 ++++++++++-------- src/quantity/quantity.rs | 26 +++++++++++++++++++++++++- src/quantity/rationalq.rs | 5 +++++ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 2f09658..8fae8d1 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -73,19 +73,21 @@ impl PreToken { pub fn to_token(self) -> Result{ match self { PreToken::PreNumber(l, s) => { - let n: f64 = match s.parse() { - Ok(n) => n, - Err(_) => return Err((l, ParserError::BadNumber)) - }; - return Ok(Token::Number(Quantity::new_rational_from_f64(n).unwrap())); + + let r = Quantity::new_rational_from_float_string(&s); + if r.is_none() { + return Err((l, ParserError::BadNumber)) + } + return Ok(Token::Number(r.unwrap())); }, + PreToken::PreWord(l, s) => { return Ok(match &s[..] { // Mathematical constants // 100 digits of each. - "π"|"pi" => { Token::Constant(Quantity::float_from_string("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067"), String::from("π")) }, - "e" => { Token::Constant(Quantity::float_from_string("2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713 8217852516642"), String::from("e")) }, - "phi"|"φ" => { Token::Constant(Quantity::float_from_string("1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137"), String::from("φ")) }, + "π"|"pi" => { Token::Constant(Quantity::new_float_from_string("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067"), String::from("π")) }, + "e" => { Token::Constant(Quantity::new_float_from_string("2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713 8217852516642"), String::from("e")) }, + "phi"|"φ" => { Token::Constant(Quantity::new_float_from_string("1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137"), String::from("φ")) }, _ => { return Err((l, ParserError::Undefined(s))); } }); diff --git a/src/quantity/quantity.rs b/src/quantity/quantity.rs index d8d67f3..80d3578 100644 --- a/src/quantity/quantity.rs +++ b/src/quantity/quantity.rs @@ -101,7 +101,7 @@ impl Quantity { } } - pub fn float_from_string(s: &str) -> Quantity { + pub fn new_float_from_string(s: &str) -> Quantity { let v = Float::parse(s); return Quantity::Float { v: Float::with_val(FLOAT_PRECISION, v.unwrap()) @@ -115,6 +115,12 @@ impl Quantity { } } + pub fn new_rational_from_string(s: &str) -> Quantity { + return Quantity::Rational { + v: RationalQ::from_string(s) + } + } + pub fn new_rational_from_f64(f: f64) -> Option { let r = RationalQ::from_f64(f); @@ -128,6 +134,24 @@ impl Quantity { } } + pub fn new_rational_from_float_string(s: &str) -> Option { + + let mut q = s.split("."); + let a = q.next().unwrap(); + let b = q.next(); + let b = if b.is_some() {b.unwrap()} else {""}; + + // Error conditions + if { + q.next().is_some() || // We should have at most one `.` + a.len() == 0 // We need something in the numerator + } { return None; } + + return Some(Quantity::new_rational_from_string( + &format!("{a}{b}/1{}", "0".repeat(b.len())) + )); + } + pub fn to_float(&self) -> Float { match self { Quantity::Float { v } => {v.clone()}, diff --git a/src/quantity/rationalq.rs b/src/quantity/rationalq.rs index e998034..01d789a 100644 --- a/src/quantity/rationalq.rs +++ b/src/quantity/rationalq.rs @@ -63,6 +63,11 @@ impl RationalQ { return Some(RationalQ{ val: v.unwrap() }); } + pub fn from_string(s: &str) -> RationalQ { + let v = Rational::from_str_radix(s, 10); + return RationalQ{ val: v.unwrap() }; + } + pub fn to_float(&self) -> Float { Float::with_val(FLOAT_PRECISION, self.val.numer()) / Float::with_val(FLOAT_PRECISION, self.val.denom())