diff options
Diffstat (limited to 'src/lex')
-rw-r--r-- | src/lex/mod.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/lex/mod.rs b/src/lex/mod.rs new file mode 100644 index 0000000..af5ff06 --- /dev/null +++ b/src/lex/mod.rs | |||
@@ -0,0 +1,145 @@ | |||
1 | use std::f64; | ||
2 | #[derive(Debug, Copy, Clone, PartialEq)] | ||
3 | pub struct Operator { | ||
4 | token: char, | ||
5 | pub operation: fn(f64, f64) -> f64, | ||
6 | pub precedence: u8, | ||
7 | pub is_left_associative: bool, | ||
8 | } | ||
9 | |||
10 | impl Operator { | ||
11 | fn token_from_op(token: char, operation: fn(f64, f64) -> f64, precedence: u8, is_left_associative: bool) -> Token { | ||
12 | Token::Operator( | ||
13 | Operator { | ||
14 | token, | ||
15 | operation, | ||
16 | precedence, | ||
17 | is_left_associative | ||
18 | } | ||
19 | ) | ||
20 | } | ||
21 | pub fn operate(self, x: f64, y: f64) -> f64 { | ||
22 | (self.operation)(x, y) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | #[derive(Debug, Clone, PartialEq)] | ||
27 | pub struct Function { | ||
28 | token: String, | ||
29 | relation: fn(f64) -> f64, | ||
30 | } | ||
31 | |||
32 | impl Function { | ||
33 | fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { | ||
34 | Token::Function( | ||
35 | Function { | ||
36 | token, | ||
37 | relation | ||
38 | } | ||
39 | ) | ||
40 | } | ||
41 | pub fn apply(self, arg: f64) -> f64 { | ||
42 | (self.relation)(arg) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | |||
47 | #[derive(Debug, Clone, PartialEq)] | ||
48 | pub enum Token { | ||
49 | Operator(Operator), | ||
50 | Num(f64), | ||
51 | Function(Function), | ||
52 | LParen, | ||
53 | RParen | ||
54 | } | ||
55 | |||
56 | pub fn lexer(input: &str) -> Result<Vec<Token>, String> { | ||
57 | let mut num_vec: String = String::new(); | ||
58 | let mut char_vec: String = String::new(); | ||
59 | let mut result: Vec<Token> = vec![]; | ||
60 | for letter in input.chars() { | ||
61 | match letter { | ||
62 | '0'...'9' | '.' => { | ||
63 | num_vec.push(letter); | ||
64 | }, | ||
65 | 'a'...'z' | 'A'...'Z' => { | ||
66 | let parse_num = num_vec.parse::<f64>().ok(); | ||
67 | if let Some(x) = parse_num { | ||
68 | result.push(Token::Num(x)); | ||
69 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
70 | num_vec.clear(); | ||
71 | } | ||
72 | char_vec.push(letter); | ||
73 | }, | ||
74 | '+' | '-' | '/' | '*' | '^' => { | ||
75 | let parse_num = num_vec.parse::<f64>().ok(); | ||
76 | if let Some(x) = parse_num { | ||
77 | result.push(Token::Num(x)); | ||
78 | num_vec.clear(); | ||
79 | } | ||
80 | let operator_token: Token = match letter { | ||
81 | '+' => Operator::token_from_op('+', |x, y| x + y, 2, true), | ||
82 | '-' => Operator::token_from_op('-', |x, y| x - y, 2, true), | ||
83 | '/' => Operator::token_from_op('/', |x, y| x / y, 3, true), | ||
84 | '*' => Operator::token_from_op('*', |x, y| x * y, 3, true), | ||
85 | '^' => Operator::token_from_op('^', |x, y| x.powf(y), 4, false), | ||
86 | _ => panic!("unexpected op whuuu"), | ||
87 | }; | ||
88 | result.push(operator_token); | ||
89 | }, | ||
90 | '(' => { | ||
91 | if char_vec.len() > 0 { | ||
92 | let funct = char_vec.clone(); | ||
93 | match &funct[..] { | ||
94 | "sin" | "sine" => result.push(Function::token_from_fn("sin".into(), |x| x.to_radians().sin())), | ||
95 | "cos" | "cosine" => result.push(Function::token_from_fn("cos".into(), |x| x.to_radians().cos())), | ||
96 | "tan" | "tangent" => result.push(Function::token_from_fn("tan".into(), |x| x.to_radians().tan())), | ||
97 | "csc" | "cosec" => result.push(Function::token_from_fn("csc".into(), |x| 1f64 / x.to_radians().sin())), | ||
98 | "sec" | "secant" => result.push(Function::token_from_fn("sec".into(), |x| 1f64 / x.to_radians().cos())), | ||
99 | "cot" | "cotangent" => result.push(Function::token_from_fn("cot".into(), |x| 1f64 / x.to_radians().tan())), | ||
100 | "ln" => result.push(Function::token_from_fn("ln".into(), |x| x.ln())), | ||
101 | "log" => result.push(Function::token_from_fn("log".into(), |x| x.log10())), | ||
102 | "sqrt" => result.push(Function::token_from_fn("sqrt".into(), |x| x.sqrt())), | ||
103 | _ => return Err(format!("Unexpected function {}", funct)) | ||
104 | } | ||
105 | char_vec.clear(); | ||
106 | } else { | ||
107 | let parse_num = num_vec.parse::<f64>().ok(); | ||
108 | if let Some(x) = parse_num { | ||
109 | result.push(Token::Num(x)); | ||
110 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
111 | num_vec.clear(); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if let Some(x) = result.last() { | ||
116 | match x { | ||
117 | Token::RParen => { | ||
118 | result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); | ||
119 | }, | ||
120 | _ => {} | ||
121 | }; | ||
122 | } | ||
123 | result.push(Token::LParen); | ||
124 | }, | ||
125 | ')' => { | ||
126 | let parse_num = num_vec.parse::<f64>().ok(); | ||
127 | if let Some(x) = parse_num { | ||
128 | result.push(Token::Num(x)); | ||
129 | num_vec.clear(); | ||
130 | } | ||
131 | result.push(Token::RParen); | ||
132 | } | ||
133 | ' ' => {} | ||
134 | _ => { | ||
135 | return Err(format!("Unexpected character: {}", letter)) | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | let parse_num = num_vec.parse::<f64>().ok(); | ||
140 | if let Some(x) = parse_num { | ||
141 | result.push(Token::Num(x)); | ||
142 | num_vec.clear(); | ||
143 | } | ||
144 | Ok(result) | ||
145 | } | ||