aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/error/mod.rs20
-rw-r--r--src/format/mod.rs23
-rw-r--r--src/lex/mod.rs127
-rw-r--r--src/main.rs112
-rw-r--r--src/parse/mod.rs44
-rw-r--r--src/readline/mod.rs66
6 files changed, 187 insertions, 205 deletions
diff --git a/src/error/mod.rs b/src/error/mod.rs
index 9ac6816..ec2b555 100644
--- a/src/error/mod.rs
+++ b/src/error/mod.rs
@@ -13,23 +13,17 @@ pub enum CalcError {
13pub enum Math { 13pub enum Math {
14 DivideByZero, 14 DivideByZero,
15 OutOfBounds, 15 OutOfBounds,
16 UnknownBase 16 UnknownBase,
17} 17}
18 18
19pub fn handler(e: CalcError) -> String { 19pub fn handler(e: CalcError) -> String {
20 match e { 20 match e {
21 CalcError::Math(math_err) => { 21 CalcError::Math(math_err) => match math_err {
22 match math_err { 22 Math::DivideByZero => "Math Error: Divide by zero error!".to_string(),
23 Math::DivideByZero => format!("Math Error: Divide by zero error!"), 23 Math::OutOfBounds => "Domain Error: Out of bounds!".to_string(),
24 Math::OutOfBounds => format!("Domain Error: Out of bounds!"), 24 Math::UnknownBase => "Base too large! Accepted ranges: 0 - 36".to_string(),
25 Math::UnknownBase => format!("Base too large! Accepted ranges: 0 - 36")
26 }
27 }, 25 },
28 CalcError::Syntax(details) => { 26 CalcError::Syntax(details) => format!("Syntax Error: {}", details),
29 format!("Syntax Error: {}", details) 27 CalcError::Parser(details) => format!("Parser Error: {}", details),
30 },
31 CalcError::Parser(details) => {
32 format!("Parser Error: {}", details)
33 }
34 } 28 }
35} 29}
diff --git a/src/format/mod.rs b/src/format/mod.rs
index 3e3ade2..45673d7 100644
--- a/src/format/mod.rs
+++ b/src/format/mod.rs
@@ -1,12 +1,8 @@
1extern crate num; 1extern crate num;
2use num::{BigInt, FromPrimitive, ToPrimitive}; 2use num::{BigInt, FromPrimitive, ToPrimitive};
3 3
4use crate::error::{CalcError, Math};
4use crate::CONFIGURATION; 5use crate::CONFIGURATION;
5use crate::error::{
6 CalcError,
7 Math
8};
9
10 6
11pub fn autobalance_parens(input: &str) -> Result<String, CalcError> { 7pub fn autobalance_parens(input: &str) -> Result<String, CalcError> {
12 let mut balanced = String::from(input); 8 let mut balanced = String::from(input);
@@ -25,7 +21,7 @@ pub fn autobalance_parens(input: &str) -> Result<String, CalcError> {
25 balanced.push_str(&extras[..]); 21 balanced.push_str(&extras[..]);
26 Ok(balanced) 22 Ok(balanced)
27 } else if left_parens < right_parens { 23 } else if left_parens < right_parens {
28 return Err(CalcError::Syntax("Mismatched parentheses!".into())) 24 Err(CalcError::Syntax("Mismatched parentheses!".into()))
29 } else { 25 } else {
30 Ok(balanced) 26 Ok(balanced)
31 } 27 }
@@ -39,10 +35,10 @@ fn radix_fmt(number: f64, obase: usize) -> Result<String, CalcError> {
39 match (number.is_infinite(), number.is_sign_positive()) { 35 match (number.is_infinite(), number.is_sign_positive()) {
40 (true, true) => return Ok("inf".to_string()), 36 (true, true) => return Ok("inf".to_string()),
41 (true, false) => return Ok("-inf".to_string()), 37 (true, false) => return Ok("-inf".to_string()),
42 _ => () 38 _ => (),
43 } 39 }
44 40
45 if number.is_nan(){ 41 if number.is_nan() {
46 return Ok("nan".to_string()); 42 return Ok("nan".to_string());
47 } 43 }
48 44
@@ -53,7 +49,7 @@ fn radix_fmt(number: f64, obase: usize) -> Result<String, CalcError> {
53 let mut obase_int = String::new(); 49 let mut obase_int = String::new();
54 let obaseb = BigInt::from_usize(obase).unwrap(); 50 let obaseb = BigInt::from_usize(obase).unwrap();
55 51
56 while &integral >= &obaseb { 52 while integral >= obaseb {
57 obase_int.push(table[(&integral % &obaseb).to_usize().unwrap()]); 53 obase_int.push(table[(&integral % &obaseb).to_usize().unwrap()]);
58 integral /= &obaseb; 54 integral /= &obaseb;
59 } 55 }
@@ -81,7 +77,7 @@ fn radix_fmt(number: f64, obase: usize) -> Result<String, CalcError> {
81 77
82fn thousand_sep(inp: &str) -> String { 78fn thousand_sep(inp: &str) -> String {
83 let mut result_string = String::new(); 79 let mut result_string = String::new();
84 for (i,c) in inp.to_string().chars().rev().enumerate() { 80 for (i, c) in inp.to_string().chars().rev().enumerate() {
85 if i % 3 == 0 && i != 0 && c.to_string() != "-" { 81 if i % 3 == 0 && i != 0 && c.to_string() != "-" {
86 result_string.push(','); 82 result_string.push(',');
87 } 83 }
@@ -92,11 +88,10 @@ fn thousand_sep(inp: &str) -> String {
92 88
93pub fn pprint(ans: f64) { 89pub fn pprint(ans: f64) {
94 let ans_string = radix_fmt(ans, CONFIGURATION.base).unwrap(); 90 let ans_string = radix_fmt(ans, CONFIGURATION.base).unwrap();
95 let ans_vector: Vec<&str> = ans_string.split(".").collect(); 91 let ans_vector: Vec<&str> = ans_string.split('.').collect();
96 match ans_vector.len() { 92 match ans_vector.len() {
97 1 => println!("{:>10}", thousand_sep(ans_vector[0])), 93 1 => println!("{:>10}", thousand_sep(ans_vector[0])),
98 2 => println!("{:>10}.{}", thousand_sep(ans_vector[0]),ans_vector[1]), 94 2 => println!("{:>10}.{}", thousand_sep(ans_vector[0]), ans_vector[1]),
99 _ => unreachable!("N-nani?!") 95 _ => unreachable!("N-nani?!"),
100 } 96 }
101} 97}
102
diff --git a/src/lex/mod.rs b/src/lex/mod.rs
index c82c17e..48e07be 100644
--- a/src/lex/mod.rs
+++ b/src/lex/mod.rs
@@ -7,10 +7,7 @@ use std::collections::HashMap;
7 7
8use crate::CONFIGURATION; 8use crate::CONFIGURATION;
9 9
10use crate::error::{ 10use crate::error::{CalcError, Math};
11 CalcError,
12 Math
13};
14 11
15#[derive(Debug, Copy, Clone, PartialEq)] 12#[derive(Debug, Copy, Clone, PartialEq)]
16pub struct Operator { 13pub struct Operator {
@@ -21,22 +18,22 @@ pub struct Operator {
21} 18}
22 19
23impl Operator { 20impl Operator {
24 fn token_from_op(token: char, 21 fn token_from_op(
25 operation: fn(f64, f64) -> f64, 22 token: char,
26 precedence: u8, 23 operation: fn(f64, f64) -> f64,
27 is_left_associative: bool) -> Token { 24 precedence: u8,
28 Token::Operator( 25 is_left_associative: bool,
29 Operator { 26 ) -> Token {
30 token, 27 Token::Operator(Operator {
31 operation, 28 token,
32 precedence, 29 operation,
33 is_left_associative 30 precedence,
34 } 31 is_left_associative,
35 ) 32 })
36 } 33 }
37 pub fn operate(self, x: f64, y: f64) -> Result<f64, CalcError> { 34 pub fn operate(self, x: f64, y: f64) -> Result<f64, CalcError> {
38 if self.token == '/' && y == 0. { 35 if self.token == '/' && y == 0. {
39 return Err(CalcError::Math(Math::DivideByZero)) 36 Err(CalcError::Math(Math::DivideByZero))
40 } else { 37 } else {
41 Ok((self.operation)(x, y)) 38 Ok((self.operation)(x, y))
42 } 39 }
@@ -51,31 +48,25 @@ pub struct Function {
51 48
52impl Function { 49impl Function {
53 fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { 50 fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token {
54 Token::Function( 51 Token::Function(Function { token, relation })
55 Function {
56 token,
57 relation
58 }
59 )
60 } 52 }
61 pub fn apply(self, arg: f64) -> Result<f64, CalcError> { 53 pub fn apply(self, arg: f64) -> Result<f64, CalcError> {
62 let result = (self.relation)(arg); 54 let result = (self.relation)(arg);
63 if !result.is_finite() { 55 if !result.is_finite() {
64 return Err(CalcError::Math(Math::OutOfBounds)); 56 Err(CalcError::Math(Math::OutOfBounds))
65 } else { 57 } else {
66 Ok(result) 58 Ok(result)
67 } 59 }
68 } 60 }
69} 61}
70 62
71
72#[derive(Debug, Clone, PartialEq)] 63#[derive(Debug, Clone, PartialEq)]
73pub enum Token { 64pub enum Token {
74 Operator(Operator), 65 Operator(Operator),
75 Num(f64), 66 Num(f64),
76 Function(Function), 67 Function(Function),
77 LParen, 68 LParen,
78 RParen 69 RParen,
79} 70}
80 71
81lazy_static! { 72lazy_static! {
@@ -128,8 +119,8 @@ lazy_static! {
128 }; 119 };
129} 120}
130 121
131fn factorial (n: f64) -> f64 { 122fn factorial(n: f64) -> f64 {
132 n.signum() * (1.. n.abs() as u64 +1).fold(1, |p, n| p*n) as f64 123 n.signum() * (1..=n.abs() as u64).fold(1, |p, n| p * n) as f64
133} 124}
134 125
135pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { 126pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> {
@@ -141,22 +132,34 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> {
141 for letter in input.chars() { 132 for letter in input.chars() {
142 match letter { 133 match letter {
143 '0'...'9' | '.' => { 134 '0'...'9' | '.' => {
144 if char_vec.len() > 0 { 135 if !char_vec.is_empty() {
145 if let Some(_) = FUNCTIONS.get(&char_vec[..]) { 136 if FUNCTIONS.get(&char_vec[..]).is_some() {
146 return Err(CalcError::Syntax(format!("Function '{}' expected parentheses", char_vec))) 137 return Err(CalcError::Syntax(format!(
138 "Function '{}' expected parentheses",
139 char_vec
140 )));
147 } else { 141 } else {
148 return Err(CalcError::Syntax(format!("Unexpected character '{}'", char_vec))) 142 return Err(CalcError::Syntax(format!(
143 "Unexpected character '{}'",
144 char_vec
145 )));
149 } 146 }
150 } 147 }
151 num_vec.push(letter); 148 num_vec.push(letter);
152 last_char_is_op = false; 149 last_char_is_op = false;
153 }, 150 }
154 '_' => { 151 '_' => {
155 if char_vec.len() > 0 { 152 if !char_vec.is_empty() {
156 if let Some(_) = FUNCTIONS.get(&char_vec[..]) { 153 if FUNCTIONS.get(&char_vec[..]).is_some() {
157 return Err(CalcError::Syntax(format!("Function '{}' expected parentheses", char_vec))) 154 return Err(CalcError::Syntax(format!(
155 "Function '{}' expected parentheses",
156 char_vec
157 )));
158 } else { 158 } else {
159 return Err(CalcError::Syntax(format!("Unexpected character '{}'", char_vec))) 159 return Err(CalcError::Syntax(format!(
160 "Unexpected character '{}'",
161 char_vec
162 )));
160 } 163 }
161 } 164 }
162 let parse_num = num_vec.parse::<f64>().ok(); 165 let parse_num = num_vec.parse::<f64>().ok();
@@ -165,7 +168,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> {
165 result.push(OPERATORS.get(&'*').unwrap().clone()); 168 result.push(OPERATORS.get(&'*').unwrap().clone());
166 num_vec.clear(); 169 num_vec.clear();
167 } 170 }
168 last_char_is_op = false; 171 last_char_is_op = false;
169 result.push(Token::Num(prev_ans)); 172 result.push(Token::Num(prev_ans));
170 } 173 }
171 'a'...'z' | 'A'...'Z' => { 174 'a'...'z' | 'A'...'Z' => {
@@ -177,7 +180,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> {
177 } 180 }
178 char_vec.push(letter); 181 char_vec.push(letter);
179 last_char_is_op = false; 182 last_char_is_op = false;
180 }, 183 }
181 '+' | '-' => { 184 '+' | '-' => {
182 let op_token = OPERATORS.get(&letter).unwrap().clone(); 185 let op_token = OPERATORS.get(&letter).unwrap().clone();
183 let parse_num = num_vec.parse::<f64>().ok(); 186 let parse_num = num_vec.parse::<f64>().ok();
@@ -194,27 +197,32 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> {
194 result.push(op_token); 197 result.push(op_token);
195 } else if last_char_is_op { 198 } else if last_char_is_op {
196 result.push(Token::LParen); 199 result.push(Token::LParen);
197 result.push(Token::Num((letter.to_string() + "1").parse::<f64>().unwrap())); 200 result.push(Token::Num(
201 (letter.to_string() + "1").parse::<f64>().unwrap(),
202 ));
198 result.push(Token::RParen); 203 result.push(Token::RParen);
199 result.push(Operator::token_from_op('*', |x, y| x * y, 10, true)); 204 result.push(Operator::token_from_op('*', |x, y| x * y, 10, true));
200 } 205 }
201 }, 206 }
202 '/' | '*' | '%' | '^' | '!' => { 207 '/' | '*' | '%' | '^' | '!' => {
203 drain_stack(&mut num_vec, &mut char_vec, &mut result); 208 drain_stack(&mut num_vec, &mut char_vec, &mut result);
204 let operator_token: Token = OPERATORS.get(&letter).unwrap().clone(); 209 let operator_token: Token = OPERATORS.get(&letter).unwrap().clone();
205 result.push(operator_token); 210 result.push(operator_token);
206 last_char_is_op = true; 211 last_char_is_op = true;
207 if letter == '!' { 212 if letter == '!' {
208 result.push(Token::Num(1.)); 213 result.push(Token::Num(1.));
209 last_char_is_op = false; 214 last_char_is_op = false;
210 } 215 }
211 }, 216 }
212 '(' => { 217 '(' => {
213 if char_vec.len() > 0 { 218 if !char_vec.is_empty() {
214 if let Some(res) = FUNCTIONS.get(&char_vec[..]) { 219 if let Some(res) = FUNCTIONS.get(&char_vec[..]) {
215 result.push(res.clone()); 220 result.push(res.clone());
216 } else { 221 } else {
217 return Err(CalcError::Syntax(format!("Unknown function '{}'", char_vec))) 222 return Err(CalcError::Syntax(format!(
223 "Unknown function '{}'",
224 char_vec
225 )));
218 } 226 }
219 char_vec.clear(); 227 char_vec.clear();
220 } else { 228 } else {
@@ -226,26 +234,19 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> {
226 } 234 }
227 } 235 }
228 236
229 if let Some(x) = result.last() { 237 if let Some(Token::RParen) = result.last() {
230 match x { 238 result.push(OPERATORS.get(&'*').unwrap().clone());
231 Token::RParen => {
232 result.push(OPERATORS.get(&'*').unwrap().clone());
233 },
234 _ => {}
235 };
236 } 239 }
237 result.push(Token::LParen); 240 result.push(Token::LParen);
238 last_char_is_op = true; 241 last_char_is_op = true;
239 }, 242 }
240 ')' => { 243 ')' => {
241 drain_stack(&mut num_vec, &mut char_vec, &mut result); 244 drain_stack(&mut num_vec, &mut char_vec, &mut result);
242 result.push(Token::RParen); 245 result.push(Token::RParen);
243 last_char_is_op = false; 246 last_char_is_op = false;
244 },
245 ' ' => {},
246 _ => {
247 return Err(CalcError::Syntax(format!("Unexpected token: '{}'", letter)))
248 } 247 }
248 ' ' => {}
249 _ => return Err(CalcError::Syntax(format!("Unexpected token: '{}'", letter))),
249 } 250 }
250 } 251 }
251 // println!("{:?}", result); 252 // println!("{:?}", result);
@@ -266,7 +267,7 @@ fn drain_stack(num_vec: &mut String, char_vec: &mut String, result: &mut Vec<Tok
266 267
267fn is_radian_mode(x: f64, is_radian: bool) -> f64 { 268fn is_radian_mode(x: f64, is_radian: bool) -> f64 {
268 if is_radian { 269 if is_radian {
269 return x 270 x
270 } else { 271 } else {
271 x.to_radians() 272 x.to_radians()
272 } 273 }
diff --git a/src/main.rs b/src/main.rs
index c3f3342..140150c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,26 +6,26 @@
6/* imports */ 6/* imports */
7// std 7// std
8use std::f64; 8use std::f64;
9use std::path::PathBuf;
10use std::fs::create_dir_all; 9use std::fs::create_dir_all;
10use std::path::PathBuf;
11 11
12// modules 12// modules
13mod lex;
14mod parse;
15mod error; 13mod error;
16mod format; 14mod format;
15mod lex;
16mod parse;
17mod readline; 17mod readline;
18use crate::error::{handler, CalcError};
19use crate::format::*;
18use crate::lex::*; 20use crate::lex::*;
19use crate::parse::*; 21use crate::parse::*;
20use crate::error::{ CalcError, handler };
21use crate::format::*;
22use crate::readline::*; 22use crate::readline::*;
23 23
24// extern crates 24// extern crates
25use rustyline::error::ReadlineError; 25use clap::{App, Arg};
26use clap::{Arg, App}; 26use directories::{ProjectDirs, UserDirs};
27use lazy_static::lazy_static; 27use lazy_static::lazy_static;
28use directories::{ ProjectDirs, UserDirs }; 28use rustyline::error::ReadlineError;
29 29
30/* end of imports */ 30/* end of imports */
31 31
@@ -33,7 +33,7 @@ struct Configuration {
33 radian_mode: bool, 33 radian_mode: bool,
34 fix: usize, 34 fix: usize,
35 base: usize, 35 base: usize,
36 input: String 36 input: String,
37} 37}
38 38
39lazy_static! { 39lazy_static! {
@@ -41,7 +41,7 @@ lazy_static! {
41} 41}
42 42
43fn main() { 43fn main() {
44 if CONFIGURATION.input.len() > 0 { 44 if !CONFIGURATION.input.is_empty() {
45 // command mode // 45 // command mode //
46 let evaled = eval_math_expression(&CONFIGURATION.input[..], 0f64); 46 let evaled = eval_math_expression(&CONFIGURATION.input[..], 0f64);
47 match evaled { 47 match evaled {
@@ -49,11 +49,11 @@ fn main() {
49 Err(e) => { 49 Err(e) => {
50 eprintln!("{}", handler(e)); 50 eprintln!("{}", handler(e));
51 std::process::exit(1); 51 std::process::exit(1);
52 }, 52 }
53 }; 53 };
54 } else { 54 } else {
55 // REPL mode // 55 // REPL mode //
56 // create fancy readline 56 // create fancy readline
57 let mut rl = create_readline(); 57 let mut rl = create_readline();
58 58
59 // previous answer 59 // previous answer
@@ -65,7 +65,7 @@ fn main() {
65 let mut history_path = PathBuf::from(eva_data_dir); 65 let mut history_path = PathBuf::from(eva_data_dir);
66 match create_dir_all(eva_data_dir) { 66 match create_dir_all(eva_data_dir) {
67 Ok(_) => history_path.push("history.txt"), 67 Ok(_) => history_path.push("history.txt"),
68 Err(_) => history_path = PathBuf::from(UserDirs::new().unwrap().home_dir()), 68 Err(_) => history_path = PathBuf::from(UserDirs::new().unwrap().home_dir()),
69 }; 69 };
70 70
71 if rl.load_history(history_path.as_path()).is_err() { 71 if rl.load_history(history_path.as_path()).is_err() {
@@ -86,17 +86,15 @@ fn main() {
86 } 86 }
87 Err(e) => println!("{}", handler(e)), 87 Err(e) => println!("{}", handler(e)),
88 }; 88 };
89 }, 89 }
90 Err(ReadlineError::Interrupted) => { 90 Err(ReadlineError::Interrupted) => {
91 println!("CTRL-C"); 91 println!("CTRL-C");
92 break 92 break;
93 }, 93 }
94 Err(ReadlineError::Eof) => { 94 Err(ReadlineError::Eof) => break,
95 break
96 },
97 Err(err) => { 95 Err(err) => {
98 println!("Error: {:?}", err); 96 println!("Error: {:?}", err);
99 break 97 break;
100 } 98 }
101 } 99 }
102 } 100 }
@@ -109,25 +107,33 @@ fn parse_arguments() -> Configuration {
109 .version(env!("CARGO_PKG_VERSION")) 107 .version(env!("CARGO_PKG_VERSION"))
110 .author(env!("CARGO_PKG_AUTHORS")) 108 .author(env!("CARGO_PKG_AUTHORS"))
111 .about(env!("CARGO_PKG_DESCRIPTION")) 109 .about(env!("CARGO_PKG_DESCRIPTION"))
112 .arg(Arg::with_name("fix") 110 .arg(
113 .short("f") 111 Arg::with_name("fix")
114 .long("fix") 112 .short("f")
115 .takes_value(true) 113 .long("fix")
116 .value_name("FIX") 114 .takes_value(true)
117 .help("set number of decimal places in the output")) 115 .value_name("FIX")
118 .arg(Arg::with_name("base") 116 .help("set number of decimal places in the output"),
119 .short("b") 117 )
120 .long("base") 118 .arg(
121 .takes_value(true) 119 Arg::with_name("base")
122 .value_name("RADIX") 120 .short("b")
123 .help("set the radix of calculation output (1 - 36)")) 121 .long("base")
124 .arg(Arg::with_name("INPUT") 122 .takes_value(true)
125 .help("optional expression string to run eva in command mode") 123 .value_name("RADIX")
126 .index(1)) 124 .help("set the radix of calculation output (1 - 36)"),
127 .arg(Arg::with_name("radian") 125 )
128 .short("r") 126 .arg(
129 .long("radian") 127 Arg::with_name("INPUT")
130 .help("set eva to radian mode")) 128 .help("optional expression string to run eva in command mode")
129 .index(1),
130 )
131 .arg(
132 Arg::with_name("radian")
133 .short("r")
134 .long("radian")
135 .help("set eva to radian mode"),
136 )
131 .get_matches(); 137 .get_matches();
132 138
133 let mut input = String::new(); 139 let mut input = String::new();
@@ -136,29 +142,25 @@ fn parse_arguments() -> Configuration {
136 }; 142 };
137 Configuration { 143 Configuration {
138 radian_mode: config.is_present("radian"), 144 radian_mode: config.is_present("radian"),
139 fix: config.value_of("fix") 145 fix: config.value_of("fix").unwrap_or("10").parse().unwrap(),
140 .unwrap_or("10") 146 base: config.value_of("base").unwrap_or("10").parse().unwrap(),
141 .parse() 147 input,
142 .unwrap(),
143 base: config.value_of("base")
144 .unwrap_or("10")
145 .parse()
146 .unwrap(),
147 input,
148 } 148 }
149} 149}
150 150
151pub fn eval_math_expression(input: &str, prev_ans: f64) -> Result<f64, CalcError> { 151pub fn eval_math_expression(input: &str, prev_ans: f64) -> Result<f64, CalcError> {
152 let input = input.trim(); 152 let input = input.trim();
153 let input = input.replace(" ", ""); 153 let input = input.replace(" ", "");
154 if input.len() == 0 { 154 if input.is_empty() {
155 return Ok(0.) 155 return Ok(0.);
156 } 156 }
157 let input = format::autobalance_parens(&input[..])?; 157 let input = format::autobalance_parens(&input[..])?;
158 let lexed = lexer(&input[..], prev_ans)?; 158 let lexed = lexer(&input[..], prev_ans)?;
159 let postfixed = to_postfix(lexed)?; 159 let postfixed = to_postfix(lexed)?;
160 let evaled = eval_postfix(postfixed)?; 160 let evaled = eval_postfix(postfixed)?;
161 let evaled_fixed = format!("{:.*}", CONFIGURATION.fix, evaled).parse::<f64>().unwrap(); 161 let evaled_fixed = format!("{:.*}", CONFIGURATION.fix, evaled)
162 .parse::<f64>()
163 .unwrap();
162 Ok(evaled_fixed) 164 Ok(evaled_fixed)
163} 165}
164 166
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 5c85172..aa8bd4b 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -2,8 +2,8 @@
2 * Refer to LICENCE for more information. 2 * Refer to LICENCE for more information.
3 * */ 3 * */
4 4
5use crate::lex::Token;
6use crate::error::CalcError; 5use crate::error::CalcError;
6use crate::lex::Token;
7 7
8pub fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, CalcError> { 8pub fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, CalcError> {
9 let mut postfixed: Vec<Token> = vec![]; 9 let mut postfixed: Vec<Token> = vec![];
@@ -12,7 +12,7 @@ pub fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, CalcError> {
12 match token { 12 match token {
13 Token::Num(_) => { 13 Token::Num(_) => {
14 postfixed.push(token); 14 postfixed.push(token);
15 }, 15 }
16 Token::Function(_) => { 16 Token::Function(_) => {
17 op_stack.push(token); 17 op_stack.push(token);
18 } 18 }
@@ -34,14 +34,16 @@ pub fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, CalcError> {
34 Token::Function(_) => { 34 Token::Function(_) => {
35 postfixed.push(op_stack.pop().unwrap()); 35 postfixed.push(op_stack.pop().unwrap());
36 } 36 }
37 _ => { unreachable!(); } 37 _ => {
38 unreachable!();
39 }
38 } 40 }
39 } 41 }
40 op_stack.push(token); 42 op_stack.push(token);
41 }, 43 }
42 Token::LParen => { 44 Token::LParen => {
43 op_stack.push(token); 45 op_stack.push(token);
44 }, 46 }
45 Token::RParen => { 47 Token::RParen => {
46 let mut push_until_paren: bool = false; 48 let mut push_until_paren: bool = false;
47 while let Some(token) = op_stack.pop() { 49 while let Some(token) = op_stack.pop() {
@@ -69,43 +71,35 @@ pub fn eval_postfix(postfixed: Vec<Token>) -> Result<f64, CalcError> {
69 match token { 71 match token {
70 Token::Num(n) => { 72 Token::Num(n) => {
71 num_stack.push(n); 73 num_stack.push(n);
72 }, 74 }
73 Token::Operator(op) => { 75 Token::Operator(op) => {
74 if let Some(n2) = num_stack.pop() { 76 if let Some(n2) = num_stack.pop() {
75 if let Some(n1) = num_stack.pop() { 77 if let Some(n1) = num_stack.pop() {
76 num_stack.push(op.operate(n1, n2)?); 78 num_stack.push(op.operate(n1, n2)?);
77 } else { 79 } else {
78 return Err( 80 return Err(CalcError::Parser(
79 CalcError::Parser( 81 "Too many operators, Too little operands".to_string(),
80 format!("Too many operators, Too little operands") 82 ));
81 )
82 )
83 } 83 }
84 } else { 84 } else {
85 return Err( 85 return Err(CalcError::Parser(
86 CalcError::Parser( 86 "Too many operators, Too little operands".to_string(),
87 format!("Too many operators, Too little operands") 87 ));
88 )
89 )
90 } 88 }
91 }, 89 }
92 Token::Function(funct) => { 90 Token::Function(funct) => {
93 if let Some(arg) = num_stack.pop() { 91 if let Some(arg) = num_stack.pop() {
94 num_stack.push(funct.apply(arg)?) 92 num_stack.push(funct.apply(arg)?)
95 } 93 }
96 } 94 }
97 _ => { 95 _ => unreachable!("wut"),
98 unreachable!("wut")
99 }
100 } 96 }
101 } 97 }
102 if num_stack.len() == 1 { 98 if num_stack.len() == 1 {
103 Ok(num_stack.pop().unwrap()) 99 Ok(num_stack.pop().unwrap())
104 } else { 100 } else {
105 return Err( 101 Err(CalcError::Parser(
106 CalcError::Parser( 102 "Too many operators, Too little operands".to_string(),
107 format!("Too many operators, Too little operands") 103 ))
108 )
109 )
110 } 104 }
111} 105}
diff --git a/src/readline/mod.rs b/src/readline/mod.rs
index e9d4b33..41cd742 100644
--- a/src/readline/mod.rs
+++ b/src/readline/mod.rs
@@ -1,11 +1,11 @@
1use std::borrow::Cow::{self,Owned}; 1use std::borrow::Cow::{self, Owned};
2 2
3use rustyline::completion::{Completer, FilenameCompleter, Pair};
4use rustyline::config::{Builder, ColorMode, CompletionType, EditMode};
3use rustyline::error::ReadlineError; 5use rustyline::error::ReadlineError;
4use rustyline::{ Editor, Context, Helper };
5use rustyline::config::{ Builder, ColorMode, EditMode, CompletionType };
6use rustyline::hint::{ Hinter, HistoryHinter };
7use rustyline::completion::{ FilenameCompleter, Completer, Pair };
8use rustyline::highlight::Highlighter; 6use rustyline::highlight::Highlighter;
7use rustyline::hint::{Hinter, HistoryHinter};
8use rustyline::{Context, Editor, Helper};
9 9
10use regex::Regex; 10use regex::Regex;
11 11
@@ -17,7 +17,7 @@ pub struct RLHelper {
17 hinter: HistoryHinter, 17 hinter: HistoryHinter,
18} 18}
19 19
20struct LineHighlighter { } 20struct LineHighlighter {}
21impl Highlighter for LineHighlighter { 21impl Highlighter for LineHighlighter {
22 fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { 22 fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
23 Owned(format!("\x1b[90m{}\x1b[0m", hint)) 23 Owned(format!("\x1b[90m{}\x1b[0m", hint))
@@ -28,14 +28,9 @@ impl Highlighter for LineHighlighter {
28 Ok(_) => { 28 Ok(_) => {
29 let constants = ["e", "pi"]; 29 let constants = ["e", "pi"];
30 let functions = [ 30 let functions = [
31 "sin" , "cos" , "tan" , 31 "sin", "cos", "tan", "csc", "sec", "cot", "sinh", "cosh", "tanh", "ln", "log",
32 "csc" , "sec" , "cot" , 32 "sqrt", "ceil", "floor", "rad", "deg", "abs", "asin", "acos", "atan", "acsc",
33 "sinh" , "cosh" , "tanh" , 33 "asec", "acot",
34 "ln" , "log" , "sqrt" ,
35 "ceil" , "floor" , "rad" ,
36 "deg" , "abs" , "asin" ,
37 "acos" , "atan" , "acsc" ,
38 "asec" , "acot"
39 ]; 34 ];
40 let ops = Regex::new(r"(?P<o>[\+-/\*%\^!])").unwrap(); 35 let ops = Regex::new(r"(?P<o>[\+-/\*%\^!])").unwrap();
41 let mut coloured: String = ops.replace_all(line, "\x1b[33m$o\x1b[0m").into(); 36 let mut coloured: String = ops.replace_all(line, "\x1b[33m$o\x1b[0m").into();
@@ -46,14 +41,14 @@ impl Highlighter for LineHighlighter {
46 for f in &functions { 41 for f in &functions {
47 coloured = coloured.replace(f, &format!("\x1b[34m{}\x1b[0m", f)); 42 coloured = coloured.replace(f, &format!("\x1b[34m{}\x1b[0m", f));
48 } 43 }
49 Owned(coloured.into()) 44 Owned(coloured)
50 }, 45 }
51 Err(_) => Owned(format!("\x1b[31m{}\x1b[0m", line)) 46 Err(_) => Owned(format!("\x1b[31m{}\x1b[0m", line)),
52 } 47 }
53 } 48 }
54} 49}
55 50
56impl Highlighter for RLHelper { 51impl Highlighter for RLHelper {
57 fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { 52 fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
58 self.highlighter.highlight_hint(hint) 53 self.highlighter.highlight_hint(hint)
59 } 54 }
@@ -69,11 +64,11 @@ impl Completer for RLHelper {
69 line: &str, 64 line: &str,
70 pos: usize, 65 pos: usize,
71 ctx: &Context<'_>, 66 ctx: &Context<'_>,
72 ) -> Result<(usize, Vec<Pair>), ReadlineError> { 67 ) -> Result<(usize, Vec<Pair>), ReadlineError> {
73 self.completer.complete(line, pos, ctx) 68 self.completer.complete(line, pos, ctx)
74 } 69 }
75} 70}
76 71
77impl Hinter for RLHelper { 72impl Hinter for RLHelper {
78 fn hint(&self, line: &str, a: usize, b: &Context) -> Option<String> { 73 fn hint(&self, line: &str, a: usize, b: &Context) -> Option<String> {
79 self.hinter.hint(line, a, b) 74 self.hinter.hint(line, a, b)
@@ -83,19 +78,20 @@ impl Hinter for RLHelper {
83impl Helper for RLHelper {} 78impl Helper for RLHelper {}
84 79
85pub fn create_readline() -> Editor<RLHelper> { 80pub fn create_readline() -> Editor<RLHelper> {
86 let config_builder = Builder::new(); 81 let config_builder = Builder::new();
87 let config = config_builder.color_mode(ColorMode::Enabled) 82 let config = config_builder
88 .edit_mode(EditMode::Emacs) 83 .color_mode(ColorMode::Enabled)
89 .history_ignore_space(true) 84 .edit_mode(EditMode::Emacs)
90 .completion_type(CompletionType::Circular) 85 .history_ignore_space(true)
91 .max_history_size(1000) 86 .completion_type(CompletionType::Circular)
92 .build(); 87 .max_history_size(1000)
93 let mut rl = Editor::with_config(config); 88 .build();
94 let h = RLHelper { 89 let mut rl = Editor::with_config(config);
95 completer: FilenameCompleter::new(), 90 let h = RLHelper {
96 highlighter: LineHighlighter {}, 91 completer: FilenameCompleter::new(),
97 hinter: HistoryHinter {} 92 highlighter: LineHighlighter {},
98 }; 93 hinter: HistoryHinter {},
99 rl.set_helper(Some(h)); 94 };
100 return rl; 95 rl.set_helper(Some(h));
96 rl
101} 97}