diff options
author | NerdyPepper <[email protected]> | 2019-07-09 08:14:35 +0100 |
---|---|---|
committer | NerdyPepper <[email protected]> | 2019-07-09 08:14:35 +0100 |
commit | 8b49603f0c6d06bcb444bd0ee14aa5c1fbc4648c (patch) | |
tree | ff5fd41b489538f80b22930e4d8365505b610b8a | |
parent | c6b03d82daa4d6b4856c4b33244f5261b0bbdaeb (diff) |
add previous answer access
-rw-r--r-- | src/lex/mod.rs | 22 | ||||
-rw-r--r-- | src/main.rs | 27 | ||||
-rw-r--r-- | src/parse/mod.rs | 2 | ||||
-rw-r--r-- | src/readline/mod.rs | 25 |
4 files changed, 43 insertions, 33 deletions
diff --git a/src/lex/mod.rs b/src/lex/mod.rs index 5e7a346..cac16ca 100644 --- a/src/lex/mod.rs +++ b/src/lex/mod.rs | |||
@@ -122,7 +122,7 @@ fn factorial (n: f64) -> f64 { | |||
122 | n.signum() * (1.. n.abs() as u64 +1).fold(1, |p, n| p*n) as f64 | 122 | n.signum() * (1.. n.abs() as u64 +1).fold(1, |p, n| p*n) as f64 |
123 | } | 123 | } |
124 | 124 | ||
125 | pub fn lexer(input: &str) -> Result<Vec<Token>, CalcError> { | 125 | pub fn lexer(input: &str, prev_ans: &mut f64) -> Result<Vec<Token>, CalcError> { |
126 | let functions: HashMap<&str, Token> = get_functions(); | 126 | let functions: HashMap<&str, Token> = get_functions(); |
127 | let operators: HashMap<char, Token> = get_operators(); | 127 | let operators: HashMap<char, Token> = get_operators(); |
128 | 128 | ||
@@ -144,6 +144,23 @@ pub fn lexer(input: &str) -> Result<Vec<Token>, CalcError> { | |||
144 | num_vec.push(letter); | 144 | num_vec.push(letter); |
145 | last_char_is_op = false; | 145 | last_char_is_op = false; |
146 | }, | 146 | }, |
147 | '_' => { | ||
148 | if char_vec.len() > 0 { | ||
149 | if let Some(_) = functions.get(&char_vec[..]) { | ||
150 | return Err(CalcError::Syntax(format!("Function '{}' expected parentheses", char_vec))) | ||
151 | } else { | ||
152 | return Err(CalcError::Syntax(format!("Unexpected character '{}'", char_vec))) | ||
153 | } | ||
154 | } | ||
155 | let parse_num = num_vec.parse::<f64>().ok(); | ||
156 | if let Some(x) = parse_num { | ||
157 | result.push(Token::Num(x)); | ||
158 | result.push(operators.get(&'*').unwrap().clone()); | ||
159 | num_vec.clear(); | ||
160 | } | ||
161 | last_char_is_op = false; | ||
162 | result.push(Token::Num(*prev_ans)); | ||
163 | } | ||
147 | 'a'...'z' | 'A'...'Z' => { | 164 | 'a'...'z' | 'A'...'Z' => { |
148 | let parse_num = num_vec.parse::<f64>().ok(); | 165 | let parse_num = num_vec.parse::<f64>().ok(); |
149 | if let Some(x) = parse_num { | 166 | if let Some(x) = parse_num { |
@@ -216,10 +233,11 @@ pub fn lexer(input: &str) -> Result<Vec<Token>, CalcError> { | |||
216 | }, | 233 | }, |
217 | ' ' => {}, | 234 | ' ' => {}, |
218 | _ => { | 235 | _ => { |
219 | return Err(CalcError::Syntax(format!("Unexpected character: '{}'", letter))) | 236 | return Err(CalcError::Syntax(format!("Unexpected token: '{}'", letter))) |
220 | } | 237 | } |
221 | } | 238 | } |
222 | } | 239 | } |
240 | // println!("{:?}", result); | ||
223 | drain_num_stack(&mut num_vec, &mut result); | 241 | drain_num_stack(&mut num_vec, &mut result); |
224 | Ok(result) | 242 | Ok(result) |
225 | } | 243 | } |
diff --git a/src/main.rs b/src/main.rs index 91d91e5..0742ee8 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -43,7 +43,7 @@ lazy_static! { | |||
43 | fn main() { | 43 | fn main() { |
44 | if CONFIGURATION.input.len() > 0 { | 44 | if CONFIGURATION.input.len() > 0 { |
45 | // command mode // | 45 | // command mode // |
46 | let evaled = eval_math_expression(&CONFIGURATION.input[..]); | 46 | let evaled = eval_math_expression(&CONFIGURATION.input[..], &mut 0f64); |
47 | match evaled { | 47 | match evaled { |
48 | Ok(ans) => pprint(ans), | 48 | Ok(ans) => pprint(ans), |
49 | Err(e) => { | 49 | Err(e) => { |
@@ -56,6 +56,9 @@ fn main() { | |||
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 | ||
60 | let mut prev_ans = 0f64; | ||
61 | |||
59 | // handle history storage | 62 | // handle history storage |
60 | let eva_dirs = ProjectDirs::from("com", "NerdyPepper", "eva").unwrap(); | 63 | let eva_dirs = ProjectDirs::from("com", "NerdyPepper", "eva").unwrap(); |
61 | let eva_data_dir = eva_dirs.data_dir(); | 64 | let eva_data_dir = eva_dirs.data_dir(); |
@@ -75,7 +78,7 @@ fn main() { | |||
75 | match readline { | 78 | match readline { |
76 | Ok(line) => { | 79 | Ok(line) => { |
77 | rl.add_history_entry(line.as_str()); | 80 | rl.add_history_entry(line.as_str()); |
78 | let evaled = eval_math_expression(&line[..]); | 81 | let evaled = eval_math_expression(&line[..], &mut prev_ans); |
79 | match evaled { | 82 | match evaled { |
80 | Ok(ans) => pprint(ans), | 83 | Ok(ans) => pprint(ans), |
81 | Err(e) => println!("{}", handler(e)), | 84 | Err(e) => println!("{}", handler(e)), |
@@ -142,16 +145,17 @@ fn parse_arguments() -> Configuration { | |||
142 | } | 145 | } |
143 | } | 146 | } |
144 | 147 | ||
145 | pub fn eval_math_expression(input: &str) -> Result<f64, CalcError> { | 148 | pub fn eval_math_expression(input: &str, prev_ans: &mut f64) -> Result<f64, CalcError> { |
146 | let input = input.trim(); | 149 | let input = input.trim(); |
147 | let input = input.replace(" ", ""); | 150 | let input = input.replace(" ", ""); |
148 | if input.len() == 0 { | 151 | if input.len() == 0 { |
149 | return Ok(0.) | 152 | return Ok(0.) |
150 | } | 153 | } |
151 | let input = format::autobalance_parens(&input[..])?; | 154 | let input = format::autobalance_parens(&input[..])?; |
152 | let lexed = lexer(&input[..])?; | 155 | let lexed = lexer(&input[..], prev_ans)?; |
153 | let postfixed = to_postfix(lexed)?; | 156 | let postfixed = to_postfix(lexed)?; |
154 | let evaled = eval_postfix(postfixed)?; | 157 | let evaled = eval_postfix(postfixed)?; |
158 | *prev_ans = evaled; | ||
155 | let evaled_fixed = format!("{:.*}", CONFIGURATION.fix, evaled).parse::<f64>().unwrap(); | 159 | let evaled_fixed = format!("{:.*}", CONFIGURATION.fix, evaled).parse::<f64>().unwrap(); |
156 | Ok(evaled_fixed) | 160 | Ok(evaled_fixed) |
157 | } | 161 | } |
@@ -162,27 +166,32 @@ mod tests { | |||
162 | 166 | ||
163 | #[test] | 167 | #[test] |
164 | fn basic_ops() { | 168 | fn basic_ops() { |
165 | let evaled = eval_math_expression("6*2 + 3 + 12 -3").unwrap(); | 169 | let evaled = eval_math_expression("6*2 + 3 + 12 -3", &0f64).unwrap(); |
166 | assert_eq!(24., evaled); | 170 | assert_eq!(24., evaled); |
167 | } | 171 | } |
168 | #[test] | 172 | #[test] |
169 | fn trignometric_fns() { | 173 | fn trignometric_fns() { |
170 | let evaled = eval_math_expression("sin(30) + tan(45").unwrap(); | 174 | let evaled = eval_math_expression("sin(30) + tan(45", &0f64).unwrap(); |
171 | assert_eq!(1.5, evaled); | 175 | assert_eq!(1.5, evaled); |
172 | } | 176 | } |
173 | #[test] | 177 | #[test] |
174 | fn brackets() { | 178 | fn brackets() { |
175 | let evaled = eval_math_expression("(((1 + 2 + 3) ^ 2 ) - 4)").unwrap(); | 179 | let evaled = eval_math_expression("(((1 + 2 + 3) ^ 2 ) - 4)", &0f64).unwrap(); |
176 | assert_eq!(32., evaled); | 180 | assert_eq!(32., evaled); |
177 | } | 181 | } |
178 | #[test] | 182 | #[test] |
179 | fn floating_ops() { | 183 | fn floating_ops() { |
180 | let evaled = eval_math_expression("1.2816 + 1 + 1.2816/1.2").unwrap(); | 184 | let evaled = eval_math_expression("1.2816 + 1 + 1.2816/1.2", &0f64).unwrap(); |
181 | assert_eq!(3.3496, evaled); | 185 | assert_eq!(3.3496, evaled); |
182 | } | 186 | } |
183 | #[test] | 187 | #[test] |
184 | fn inverse_trignometric_fns() { | 188 | fn inverse_trignometric_fns() { |
185 | let evaled = eval_math_expression("deg(asin(1) + acos(1))").unwrap(); | 189 | let evaled = eval_math_expression("deg(asin(1) + acos(1))", &0f64).unwrap(); |
186 | assert_eq!(90., evaled); | 190 | assert_eq!(90., evaled); |
187 | } | 191 | } |
192 | #[test] | ||
193 | fn prev_ans() { | ||
194 | let evaled = eval_math_expression("_ + 9", &9f64).unwrap(); | ||
195 | assert_eq!(18.0, evaled); | ||
196 | } | ||
188 | } | 197 | } |
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index b74df4c..5c85172 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs | |||
@@ -95,7 +95,7 @@ pub fn eval_postfix(postfixed: Vec<Token>) -> Result<f64, CalcError> { | |||
95 | } | 95 | } |
96 | } | 96 | } |
97 | _ => { | 97 | _ => { |
98 | unreachable!("nah nigga") | 98 | unreachable!("wut") |
99 | } | 99 | } |
100 | } | 100 | } |
101 | } | 101 | } |
diff --git a/src/readline/mod.rs b/src/readline/mod.rs index 34bce56..9ae14ba 100644 --- a/src/readline/mod.rs +++ b/src/readline/mod.rs | |||
@@ -3,7 +3,7 @@ use std::borrow::Cow::{self,Owned}; | |||
3 | use rustyline::error::ReadlineError; | 3 | use rustyline::error::ReadlineError; |
4 | use rustyline::{ Editor, Context, Helper }; | 4 | use rustyline::{ Editor, Context, Helper }; |
5 | use rustyline::config::{ Builder, ColorMode, EditMode, CompletionType }; | 5 | use rustyline::config::{ Builder, ColorMode, EditMode, CompletionType }; |
6 | use rustyline::hint::Hinter; | 6 | use rustyline::hint::{ Hinter, HistoryHinter }; |
7 | use rustyline::completion::{ FilenameCompleter, Completer, Pair }; | 7 | use rustyline::completion::{ FilenameCompleter, Completer, Pair }; |
8 | use rustyline::highlight::Highlighter; | 8 | use rustyline::highlight::Highlighter; |
9 | 9 | ||
@@ -14,33 +14,16 @@ use crate::eval_math_expression; | |||
14 | pub struct RLHelper { | 14 | pub struct RLHelper { |
15 | completer: FilenameCompleter, | 15 | completer: FilenameCompleter, |
16 | highlighter: LineHighlighter, | 16 | highlighter: LineHighlighter, |
17 | hinter: AnswerHinter, | 17 | hinter: HistoryHinter, |
18 | } | 18 | } |
19 | 19 | ||
20 | struct AnswerHinter { } | ||
21 | impl Hinter for AnswerHinter { | ||
22 | fn hint(&self, line: &str, _: usize, _: &Context) -> Option<String> { | ||
23 | let input = line.trim(); | ||
24 | let input = input.replace(" ", ""); | ||
25 | if input.len() == 0 { | ||
26 | return Some("".into()) | ||
27 | } | ||
28 | let dry_run = eval_math_expression(&input); | ||
29 | match dry_run { | ||
30 | Ok(ans) => return Some(format!(" = {}", ans)), | ||
31 | Err(_) => return Some(format!("")) | ||
32 | }; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | |||
37 | struct LineHighlighter { } | 20 | struct LineHighlighter { } |
38 | impl Highlighter for LineHighlighter { | 21 | impl Highlighter for LineHighlighter { |
39 | fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { | 22 | fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { |
40 | Owned(format!("\x1b[90m{}\x1b[0m", hint)) | 23 | Owned(format!("\x1b[90m{}\x1b[0m", hint)) |
41 | } | 24 | } |
42 | fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> { | 25 | fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> { |
43 | let op = eval_math_expression(line); | 26 | let op = eval_math_expression(line, &mut 0f64); |
44 | match op { | 27 | match op { |
45 | Ok(_) => { | 28 | Ok(_) => { |
46 | let functions = [ | 29 | let functions = [ |
@@ -108,7 +91,7 @@ pub fn create_readline() -> Editor<RLHelper> { | |||
108 | let h = RLHelper { | 91 | let h = RLHelper { |
109 | completer: FilenameCompleter::new(), | 92 | completer: FilenameCompleter::new(), |
110 | highlighter: LineHighlighter {}, | 93 | highlighter: LineHighlighter {}, |
111 | hinter: AnswerHinter {} | 94 | hinter: HistoryHinter {} |
112 | }; | 95 | }; |
113 | rl.set_helper(Some(h)); | 96 | rl.set_helper(Some(h)); |
114 | return rl; | 97 | return rl; |