diff --git a/src/cli-repl.rs b/src/cli-repl.rs index 82ace64..4a01e34 100644 --- a/src/cli-repl.rs +++ b/src/cli-repl.rs @@ -1,3 +1,4 @@ +use std::f64; use std::io::{self, StdoutLock, Write, stdout}; use std::rc::Rc; @@ -5,7 +6,7 @@ use libopenbirch::environment::Environment; use libopenbirch::node::constant::Constant; use libopenbirch::node::empty::Empty; use libopenbirch::node::{Node, NodeEnum}; -use libopenbirch::parser::{Lexer, Parser, ParserError}; +use libopenbirch::parser::{Lexer, LexerError, Parser, ParserError}; use malachite::base::num::basic::traits::Zero; use malachite::rational::Rational; #[cfg(feature = "async")] @@ -167,6 +168,10 @@ fn main() -> Result<(), io::Error> { let mut env = Environment::new(); env.define_native_function("print", print); + env.define( + "pi", + Rc::new(Constant::new(f64::consts::PI.try_into().unwrap()).into()), + ); while let Some(source) = input.get()? { input.disable_raw()?; @@ -176,7 +181,9 @@ fn main() -> Result<(), io::Error> { if tokens_result.is_err() { match tokens_result.err().unwrap() { - libopenbirch::parser::LexerError::UnexpectedChar(i, exp) => print_err(i, 1, exp), + LexerError::UnexpectedChar(i, exp) | LexerError::NumberParse(i, exp) => { + print_err(i, 1, exp) + } } continue; } diff --git a/src/lib/environment.rs b/src/lib/environment.rs index 3785ce1..074e1e3 100644 --- a/src/lib/environment.rs +++ b/src/lib/environment.rs @@ -92,7 +92,8 @@ impl Environment { self.stack_depth = 0; } - pub fn define(&mut self, name: String, value: Rc) { + pub fn define(&mut self, name: impl Into, value: Rc) { + let name = name.into(); let id = if let Some(value) = self.str_to_id(&name) { *value } else { @@ -110,6 +111,7 @@ impl Environment { } pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc> { + eprintln!("Get {key}"); self.map.get(key) } @@ -123,12 +125,11 @@ impl Environment { pub fn insert(&mut self, key: EnvironmentInternalSymbolKey, value: Rc) { if self.stack_depth != 0 { let mut shadow = false; - if let Some(existing) = self.map.get(&key) { + if self.map.get(&key).is_some() { if !self.get_current_scope().contains(&key) { // We need to shadow this variable self.stack_shadows .push((key, self.map.insert(key, value.clone()).unwrap())); - self.stack.push(key); shadow = true; } } diff --git a/src/lib/node/constant.rs b/src/lib/node/constant.rs index 547c36b..0bbc633 100644 --- a/src/lib/node/constant.rs +++ b/src/lib/node/constant.rs @@ -1,5 +1,10 @@ use std::rc::Rc; +use malachite::{ + base::{num::basic::traits::Zero, rounding_modes::RoundingMode}, + rational::{Rational, conversion::primitive_float_from_rational::FloatConversionError}, +}; + use super::{Environment, Node, Precedence}; pub type ConstantValue = malachite::rational::Rational; @@ -21,7 +26,29 @@ impl Node for Constant { } fn as_string(&self, _env: Option<&Environment>) -> String { - self.value.to_string() + if self.value == Rational::ZERO { + return "0".to_owned(); + } + + if self.value.approx_log() < 50. { + let x: Result = 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::(RoundingMode::Nearest) + { + format!("{}*2^{}", man, exp) + } else { + self.value.to_string() + } } fn precedence(&self) -> Precedence { diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index a5f6c36..b5a7d72 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -101,6 +101,7 @@ pub struct Lexer<'a> { #[derive(Debug)] pub enum LexerError { UnexpectedChar(usize, String), + NumberParse(usize, String), } impl<'a> Lexer<'a> { @@ -137,7 +138,7 @@ impl<'a> Lexer<'a> { loop { let d = self.source.peek(); match d { - Some('0'..='9') => { + Some('0'..='9') | Some('e') | Some('E') => { digit.push(*d.unwrap()); self.source.next(); i += 1; @@ -160,7 +161,15 @@ impl<'a> Lexer<'a> { } } } - let number = digit.parse::().unwrap(); + let number = + if let Some(v) = ConstantValue::from_sci_string_simplest(digit.as_str()) { + v + } else { + return Err(LexerError::NumberParse( + i, + format!("Failed to convert {digit} to a number"), + )); + }; tokens.push(Token(i, TokenType::Number(number))); } @@ -511,9 +520,7 @@ impl<'a> Parser<'a> { } } - return Ok(Function::new( - FunctionType::UserFunction(right, symbols), - )); + return Ok(Function::new(FunctionType::UserFunction(right, symbols))); } _ => { return Err(ParserError::UnexpectedNode(