diff options
Diffstat (limited to 'src/lex/mod.rs')
-rw-r--r-- | src/lex/mod.rs | 115 |
1 files changed, 57 insertions, 58 deletions
diff --git a/src/lex/mod.rs b/src/lex/mod.rs index 2793699..c82c17e 100644 --- a/src/lex/mod.rs +++ b/src/lex/mod.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | * Refer to LICENCE for more information. | 2 | * Refer to LICENCE for more information. |
3 | * */ | 3 | * */ |
4 | 4 | ||
5 | use lazy_static::lazy_static; | ||
5 | use std::collections::HashMap; | 6 | use std::collections::HashMap; |
6 | 7 | ||
7 | use crate::CONFIGURATION; | 8 | use crate::CONFIGURATION; |
@@ -77,52 +78,54 @@ pub enum Token { | |||
77 | RParen | 78 | RParen |
78 | } | 79 | } |
79 | 80 | ||
80 | fn get_constants() -> HashMap<&'static str, Token> { | 81 | lazy_static! { |
81 | return [ | 82 | static ref CONSTANTS: HashMap<&'static str, Token> = { |
82 | ("e", Token::Num(std::f64::consts::E)), | 83 | let mut m = HashMap::new(); |
83 | ("pi", Token::Num(std::f64::consts::PI)), | 84 | m.insert("e", Token::Num(std::f64::consts::E)); |
84 | ].iter().cloned().collect(); | 85 | m.insert("pi", Token::Num(std::f64::consts::PI)); |
85 | } | 86 | m |
87 | }; | ||
86 | 88 | ||
87 | fn get_functions() -> HashMap<&'static str, Token> { | 89 | static ref FUNCTIONS: HashMap<&'static str, Token> = { |
88 | return [ | 90 | let mut m = HashMap::new(); |
89 | ("sin", Function::token_from_fn("sin".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).sin())), | 91 | m.insert("sin", Function::token_from_fn("sin".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).sin())); |
90 | ("cos", Function::token_from_fn("cos".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).cos())), | 92 | m.insert("cos", Function::token_from_fn("cos".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).cos())); |
91 | ("tan", Function::token_from_fn("tan".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).tan())), | 93 | m.insert("tan", Function::token_from_fn("tan".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).tan())); |
92 | ("csc", Function::token_from_fn("csc".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).sin().recip())), | 94 | m.insert("csc", Function::token_from_fn("csc".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).sin().recip())); |
93 | ("sec", Function::token_from_fn("sec".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).cos().recip())), | 95 | m.insert("sec", Function::token_from_fn("sec".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).cos().recip())); |
94 | ("cot", Function::token_from_fn("cot".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).tan().recip())), | 96 | m.insert("cot", Function::token_from_fn("cot".into(), |x| is_radian_mode(x, CONFIGURATION.radian_mode).tan().recip())); |
95 | ("sinh", Function::token_from_fn("sinh".into(), |x| x.sinh())), | 97 | m.insert("sinh", Function::token_from_fn("sinh".into(), |x| x.sinh())); |
96 | ("cosh", Function::token_from_fn("cosh".into(), |x| x.cosh())), | 98 | m.insert("cosh", Function::token_from_fn("cosh".into(), |x| x.cosh())); |
97 | ("tanh", Function::token_from_fn("tanh".into(), |x| x.tanh())), | 99 | m.insert("tanh", Function::token_from_fn("tanh".into(), |x| x.tanh())); |
98 | ("ln", Function::token_from_fn("ln".into(), |x| x.ln())), | 100 | m.insert("ln", Function::token_from_fn("ln".into(), |x| x.ln())); |
99 | ("log", Function::token_from_fn("log".into(), |x| x.log10())), | 101 | m.insert("log", Function::token_from_fn("log".into(), |x| x.log10())); |
100 | ("sqrt", Function::token_from_fn("sqrt".into(), |x| x.sqrt())), | 102 | m.insert("sqrt", Function::token_from_fn("sqrt".into(), |x| x.sqrt())); |
101 | ("ceil", Function::token_from_fn("ceil".into(), |x| x.ceil())), | 103 | m.insert("ceil", Function::token_from_fn("ceil".into(), |x| x.ceil())); |
102 | ("floor", Function::token_from_fn("floor".into(), |x| x.floor())), | 104 | m.insert("floor", Function::token_from_fn("floor".into(), |x| x.floor())); |
103 | ("rad", Function::token_from_fn("rad".into(), |x| x.to_radians())), | 105 | m.insert("rad", Function::token_from_fn("rad".into(), |x| x.to_radians())); |
104 | ("deg", Function::token_from_fn("deg".into(), |x| x.to_degrees())), | 106 | m.insert("deg", Function::token_from_fn("deg".into(), |x| x.to_degrees())); |
105 | ("abs", Function::token_from_fn("abs".into(), |x| x.abs())), | 107 | m.insert("abs", Function::token_from_fn("abs".into(), |x| x.abs())); |
106 | ("asin", Function::token_from_fn("asin".into(), |x| x.asin())), | 108 | m.insert("asin", Function::token_from_fn("asin".into(), |x| x.asin())); |
107 | ("acos", Function::token_from_fn("acos".into(), |x| x.acos())), | 109 | m.insert("acos", Function::token_from_fn("acos".into(), |x| x.acos())); |
108 | ("atan", Function::token_from_fn("atan".into(), |x| x.atan())), | 110 | m.insert("atan", Function::token_from_fn("atan".into(), |x| x.atan())); |
109 | ("acsc", Function::token_from_fn("acsc".into(), |x| (1./x).asin())), | 111 | m.insert("acsc", Function::token_from_fn("acsc".into(), |x| (1./x).asin())); |
110 | ("asec", Function::token_from_fn("asec".into(), |x| (1./x).acos())), | 112 | m.insert("asec", Function::token_from_fn("asec".into(), |x| (1./x).acos())); |
111 | ("acot", Function::token_from_fn("acot".into(), |x| (1./x).atan())), | 113 | m.insert("acot", Function::token_from_fn("acot".into(), |x| (1./x).atan())); |
112 | // single arg function s can be added here | 114 | // single arg function s can be added here |
113 | ].iter().cloned().collect(); | 115 | m |
114 | } | 116 | }; |
115 | 117 | ||
116 | pub fn get_operators() -> HashMap<char, Token> { | 118 | static ref OPERATORS: HashMap<char, Token> = { |
117 | return [ | 119 | let mut m = HashMap::new(); |
118 | ('+', Operator::token_from_op('+', |x, y| x + y, 2, true)), | 120 | m.insert('+', Operator::token_from_op('+', |x, y| x + y, 2, true)); |
119 | ('-', Operator::token_from_op('-', |x, y| x - y, 2, true)), | 121 | m.insert('-', Operator::token_from_op('-', |x, y| x - y, 2, true)); |
120 | ('*', Operator::token_from_op('*', |x, y| x * y, 3, true)), | 122 | m.insert('*', Operator::token_from_op('*', |x, y| x * y, 3, true)); |
121 | ('/', Operator::token_from_op('/', |x, y| x / y, 3, true)), | 123 | m.insert('/', Operator::token_from_op('/', |x, y| x / y, 3, true)); |
122 | ('%', Operator::token_from_op('%', |x, y| x % y, 3, true)), | 124 | m.insert('%', Operator::token_from_op('%', |x, y| x % y, 3, true)); |
123 | ('^', Operator::token_from_op('^', |x, y| x.powf(y) , 4, false)), | 125 | m.insert('^', Operator::token_from_op('^', |x, y| x.powf(y) , 4, false)); |
124 | ('!', Operator::token_from_op('!', |x, _| factorial(x) , 4, true)), | 126 | m.insert('!', Operator::token_from_op('!', |x, _| factorial(x) , 4, true)); |
125 | ].iter().cloned().collect(); | 127 | m |
128 | }; | ||
126 | } | 129 | } |
127 | 130 | ||
128 | fn factorial (n: f64) -> f64 { | 131 | fn factorial (n: f64) -> f64 { |
@@ -130,10 +133,6 @@ fn factorial (n: f64) -> f64 { | |||
130 | } | 133 | } |
131 | 134 | ||
132 | pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | 135 | pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { |
133 | let constants: HashMap<&str, Token> = get_constants(); | ||
134 | let functions: HashMap<&str, Token> = get_functions(); | ||
135 | let operators: HashMap<char, Token> = get_operators(); | ||
136 | |||
137 | let mut num_vec: String = String::new(); | 136 | let mut num_vec: String = String::new(); |
138 | let mut char_vec: String = String::new(); | 137 | let mut char_vec: String = String::new(); |
139 | let mut result: Vec<Token> = vec![]; | 138 | let mut result: Vec<Token> = vec![]; |
@@ -143,7 +142,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
143 | match letter { | 142 | match letter { |
144 | '0'...'9' | '.' => { | 143 | '0'...'9' | '.' => { |
145 | if char_vec.len() > 0 { | 144 | if char_vec.len() > 0 { |
146 | if let Some(_) = functions.get(&char_vec[..]) { | 145 | if let Some(_) = FUNCTIONS.get(&char_vec[..]) { |
147 | return Err(CalcError::Syntax(format!("Function '{}' expected parentheses", char_vec))) | 146 | return Err(CalcError::Syntax(format!("Function '{}' expected parentheses", char_vec))) |
148 | } else { | 147 | } else { |
149 | return Err(CalcError::Syntax(format!("Unexpected character '{}'", char_vec))) | 148 | return Err(CalcError::Syntax(format!("Unexpected character '{}'", char_vec))) |
@@ -154,7 +153,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
154 | }, | 153 | }, |
155 | '_' => { | 154 | '_' => { |
156 | if char_vec.len() > 0 { | 155 | if char_vec.len() > 0 { |
157 | if let Some(_) = functions.get(&char_vec[..]) { | 156 | if let Some(_) = FUNCTIONS.get(&char_vec[..]) { |
158 | return Err(CalcError::Syntax(format!("Function '{}' expected parentheses", char_vec))) | 157 | return Err(CalcError::Syntax(format!("Function '{}' expected parentheses", char_vec))) |
159 | } else { | 158 | } else { |
160 | return Err(CalcError::Syntax(format!("Unexpected character '{}'", char_vec))) | 159 | return Err(CalcError::Syntax(format!("Unexpected character '{}'", char_vec))) |
@@ -163,7 +162,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
163 | let parse_num = num_vec.parse::<f64>().ok(); | 162 | let parse_num = num_vec.parse::<f64>().ok(); |
164 | if let Some(x) = parse_num { | 163 | if let Some(x) = parse_num { |
165 | result.push(Token::Num(x)); | 164 | result.push(Token::Num(x)); |
166 | result.push(operators.get(&'*').unwrap().clone()); | 165 | result.push(OPERATORS.get(&'*').unwrap().clone()); |
167 | num_vec.clear(); | 166 | num_vec.clear(); |
168 | } | 167 | } |
169 | last_char_is_op = false; | 168 | last_char_is_op = false; |
@@ -173,21 +172,21 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
173 | let parse_num = num_vec.parse::<f64>().ok(); | 172 | let parse_num = num_vec.parse::<f64>().ok(); |
174 | if let Some(x) = parse_num { | 173 | if let Some(x) = parse_num { |
175 | result.push(Token::Num(x)); | 174 | result.push(Token::Num(x)); |
176 | result.push(operators.get(&'*').unwrap().clone()); | 175 | result.push(OPERATORS.get(&'*').unwrap().clone()); |
177 | num_vec.clear(); | 176 | num_vec.clear(); |
178 | } | 177 | } |
179 | char_vec.push(letter); | 178 | char_vec.push(letter); |
180 | last_char_is_op = false; | 179 | last_char_is_op = false; |
181 | }, | 180 | }, |
182 | '+' | '-' => { | 181 | '+' | '-' => { |
183 | let op_token = operators.get(&letter).unwrap().clone(); | 182 | let op_token = OPERATORS.get(&letter).unwrap().clone(); |
184 | let parse_num = num_vec.parse::<f64>().ok(); | 183 | let parse_num = num_vec.parse::<f64>().ok(); |
185 | if !last_char_is_op { | 184 | if !last_char_is_op { |
186 | if let Some(x) = parse_num { | 185 | if let Some(x) = parse_num { |
187 | result.push(Token::Num(x)); | 186 | result.push(Token::Num(x)); |
188 | num_vec.clear(); | 187 | num_vec.clear(); |
189 | last_char_is_op = true; | 188 | last_char_is_op = true; |
190 | } else if let Some(token) = constants.get(&char_vec[..]) { | 189 | } else if let Some(token) = CONSTANTS.get(&char_vec[..]) { |
191 | result.push(token.clone()); | 190 | result.push(token.clone()); |
192 | char_vec.clear(); | 191 | char_vec.clear(); |
193 | last_char_is_op = true; | 192 | last_char_is_op = true; |
@@ -202,7 +201,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
202 | }, | 201 | }, |
203 | '/' | '*' | '%' | '^' | '!' => { | 202 | '/' | '*' | '%' | '^' | '!' => { |
204 | drain_stack(&mut num_vec, &mut char_vec, &mut result); | 203 | drain_stack(&mut num_vec, &mut char_vec, &mut result); |
205 | let operator_token: Token = operators.get(&letter).unwrap().clone(); | 204 | let operator_token: Token = OPERATORS.get(&letter).unwrap().clone(); |
206 | result.push(operator_token); | 205 | result.push(operator_token); |
207 | last_char_is_op = true; | 206 | last_char_is_op = true; |
208 | if letter == '!' { | 207 | if letter == '!' { |
@@ -212,7 +211,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
212 | }, | 211 | }, |
213 | '(' => { | 212 | '(' => { |
214 | if char_vec.len() > 0 { | 213 | if char_vec.len() > 0 { |
215 | if let Some(res) = functions.get(&char_vec[..]) { | 214 | if let Some(res) = FUNCTIONS.get(&char_vec[..]) { |
216 | result.push(res.clone()); | 215 | result.push(res.clone()); |
217 | } else { | 216 | } else { |
218 | return Err(CalcError::Syntax(format!("Unknown function '{}'", char_vec))) | 217 | return Err(CalcError::Syntax(format!("Unknown function '{}'", char_vec))) |
@@ -222,7 +221,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
222 | let parse_num = num_vec.parse::<f64>().ok(); | 221 | let parse_num = num_vec.parse::<f64>().ok(); |
223 | if let Some(x) = parse_num { | 222 | if let Some(x) = parse_num { |
224 | result.push(Token::Num(x)); | 223 | result.push(Token::Num(x)); |
225 | result.push(operators.get(&'*').unwrap().clone()); | 224 | result.push(OPERATORS.get(&'*').unwrap().clone()); |
226 | num_vec.clear(); | 225 | num_vec.clear(); |
227 | } | 226 | } |
228 | } | 227 | } |
@@ -230,7 +229,7 @@ pub fn lexer(input: &str, prev_ans: f64) -> Result<Vec<Token>, CalcError> { | |||
230 | if let Some(x) = result.last() { | 229 | if let Some(x) = result.last() { |
231 | match x { | 230 | match x { |
232 | Token::RParen => { | 231 | Token::RParen => { |
233 | result.push(operators.get(&'*').unwrap().clone()); | 232 | result.push(OPERATORS.get(&'*').unwrap().clone()); |
234 | }, | 233 | }, |
235 | _ => {} | 234 | _ => {} |
236 | }; | 235 | }; |
@@ -259,7 +258,7 @@ fn drain_stack(num_vec: &mut String, char_vec: &mut String, result: &mut Vec<Tok | |||
259 | if let Some(x) = parse_num { | 258 | if let Some(x) = parse_num { |
260 | result.push(Token::Num(x)); | 259 | result.push(Token::Num(x)); |
261 | num_vec.clear(); | 260 | num_vec.clear(); |
262 | } else if let Some(token) = get_constants().get(&char_vec[..]) { | 261 | } else if let Some(token) = CONSTANTS.get(&char_vec[..]) { |
263 | result.push(token.clone()); | 262 | result.push(token.clone()); |
264 | char_vec.clear(); | 263 | char_vec.clear(); |
265 | } | 264 | } |