1use std::env;
2use std::error;
3use std::io::{self, Read, Write};
4
5use text_scanner::Scanner;
6
7#[derive(PartialEq, Clone, Debug)]
8enum Token<'text> {
9 Ident(&'text str),
10 Int(i32),
11 Float(f32),
12 Sym(Sym),
13}
14
15#[derive(PartialEq, Clone, Copy, Debug)]
16enum Sym {
17 Plus,
18 Minus,
19 Star,
20 Slash,
21 LParen,
22 RParen,
23}
24
25impl<'text> Token<'text> {
26 fn parse_token(scanner: &mut Scanner<'text>) -> Result<Option<Self>, Box<dyn error::Error>> {
27 scanner.skip_whitespace();
28
29 if let Ok((first, _c)) = scanner.accept_if(|c| c.is_alphabetic() || (c == '_')) {
30 let (last, _s) = scanner.skip_while(|c| c.is_alphanumeric() || (c == '_'));
31 return Ok(Some(Self::Ident(&scanner.text()[first.start..last.end])));
32 }
33
34 if let Ok((first, _c)) = scanner.accept_if(|c| c.is_ascii_digit()) {
35 let (last, _s) = scanner.skip_while(|c| c.is_ascii_digit());
36
37 if scanner.accept_char('.').is_ok() {
38 let (last, _s) = scanner.skip_while(|c| c.is_ascii_digit());
39 let text = &scanner.text()[first.start..last.end];
40 let f = text.parse()?;
41 return Ok(Some(Self::Float(f)));
42 } else {
43 let text = &scanner.text()[first.start..last.end];
44 let f = text.parse()?;
45 return Ok(Some(Self::Int(f)));
46 }
47 }
48
49 if let Some(sym) = Sym::parse_token(scanner) {
50 return Ok(Some(Self::Sym(sym)));
51 }
52
53 Ok(None)
54 }
55}
56
57impl<'text> Sym {
58 fn parse_token(scanner: &mut Scanner<'text>) -> Option<Self> {
59 let (_r, c) = scanner
60 .accept_char_any(&['+', '-', '*', '/', '(', ')'])
61 .ok()?;
62 match c {
63 '+' => Some(Self::Plus),
64 '-' => Some(Self::Minus),
65 '*' => Some(Self::Star),
66 '/' => Some(Self::Slash),
67 '(' => Some(Self::LParen),
68 ')' => Some(Self::RParen),
69 _ => unreachable!(),
70 }
71 }
72}
73
74#[derive(Debug)]
75enum Expr<'text> {
76 Ident(&'text str),
77 Int(i32),
78 Float(f32),
79 Add(Box<Self>, Box<Self>),
80 Sub(Box<Self>, Box<Self>),
81 Mul(Box<Self>, Box<Self>),
82 Div(Box<Self>, Box<Self>),
83 Pos(Box<Self>),
84 Neg(Box<Self>),
85}
86
87impl<'text> Expr<'text> {
88 fn parse(text: &'text str) -> Result<Self, Box<dyn error::Error>> {
89 ExprParser::new(text).parse()
90 }
91}
92
93struct ExprParser<'text> {
94 scanner: Scanner<'text>,
95 next: Option<Token<'text>>,
96}
97
98impl<'text> ExprParser<'text> {
99 fn new(text: &'text str) -> Self {
100 Self {
101 scanner: Scanner::new(text),
102 next: None,
103 }
104 }
105
106 fn next_token(&mut self) -> Result<Option<Token<'text>>, Box<dyn error::Error>> {
107 if let Some(tok) = self.next.take() {
108 return Ok(Some(tok));
109 }
110 Token::parse_token(&mut self.scanner)
111 }
112
113 fn peek_token(&mut self) -> Result<Option<&Token<'text>>, Box<dyn error::Error>> {
114 if self.next.is_none() {
115 self.next = self.next_token()?;
116 }
117 Ok(self.next.as_ref())
118 }
119
120 fn parse(&mut self) -> Result<Expr<'text>, Box<dyn error::Error>> {
121 let expr = self.parse_expr()?;
122
123 if let Some(tok) = self.next_token()? {
124 return Err(format!("expected end of input, received {:?}", tok).into());
125 }
126
127 Ok(expr)
128 }
129
130 fn parse_expr(&mut self) -> Result<Expr<'text>, Box<dyn error::Error>> {
131 self.parse_expr_additive()
132 }
133
134 fn parse_expr_additive(&mut self) -> Result<Expr<'text>, Box<dyn error::Error>> {
135 let mut expr = self.parse_expr_multiplicative()?;
136
137 while let Some(&Token::Sym(op @ (Sym::Plus | Sym::Minus))) = self.peek_token()? {
138 _ = self.next_token(); let rhs = self.parse_expr_multiplicative()?;
141
142 expr = match op {
143 Sym::Plus => Expr::Add(Box::new(expr), Box::new(rhs)),
144 Sym::Minus => Expr::Sub(Box::new(expr), Box::new(rhs)),
145 _ => unreachable!(),
146 };
147 }
148
149 Ok(expr)
150 }
151
152 fn parse_expr_multiplicative(&mut self) -> Result<Expr<'text>, Box<dyn error::Error>> {
153 let mut expr = self.parse_expr_unary()?;
154
155 while let Some(&Token::Sym(op @ (Sym::Star | Sym::Slash))) = self.peek_token()? {
156 _ = self.next_token(); let rhs = self.parse_expr_multiplicative()?;
159
160 expr = match op {
161 Sym::Star => Expr::Mul(Box::new(expr), Box::new(rhs)),
162 Sym::Slash => Expr::Div(Box::new(expr), Box::new(rhs)),
163 _ => unreachable!(),
164 };
165 }
166
167 Ok(expr)
168 }
169
170 fn parse_expr_unary(&mut self) -> Result<Expr<'text>, Box<dyn error::Error>> {
171 if let Some(&Token::Sym(op @ (Sym::Plus | Sym::Minus))) = self.peek_token()? {
172 _ = self.next_token(); let expr = self.parse_expr_unary()?;
175
176 match op {
177 Sym::Plus => Ok(Expr::Pos(Box::new(expr))),
178 Sym::Minus => Ok(Expr::Neg(Box::new(expr))),
179 _ => unreachable!(),
180 }
181 } else {
182 self.parse_expr_value()
183 }
184 }
185
186 fn parse_expr_value(&mut self) -> Result<Expr<'text>, Box<dyn error::Error>> {
187 let tok = self
188 .next_token()?
189 .ok_or_else(|| "unexpected end of input")?;
190 match tok {
191 Token::Ident(ident) => Ok(Expr::Ident(ident)),
192 Token::Int(i) => Ok(Expr::Int(i)),
193 Token::Float(f) => Ok(Expr::Float(f)),
194 Token::Sym(Sym::LParen) => {
195 let expr = self.parse_expr()?;
196
197 let tok = self
198 .next_token()?
199 .ok_or_else(|| "unexpected end of input")?;
200 if tok != Token::Sym(Sym::RParen) {
201 return Err(format!("expected `)` found {:?}", tok).into());
202 }
203
204 Ok(expr)
205 }
206 _ => Err(format!("unexpected token {:?}", tok).into()),
207 }
208 }
209}
210
211impl<'text> Expr<'text> {
212 fn eval(&self) -> Result<f32, Box<dyn error::Error>> {
213 match self {
214 &Self::Ident(ident) => match ident {
215 "pi" | "PI" => Ok(std::f32::consts::PI),
216 "tau" | "TAU" => Ok(std::f32::consts::TAU),
217 _ => Err(format!("unknown ident `{}`, expected `pi` or `tau`", ident).into()),
218 },
219 &Self::Int(i) => Ok(i as f32),
220 &Self::Float(f) => Ok(f),
221 Self::Add(lhs, rhs) => Ok(lhs.eval()? + rhs.eval()?),
222 Self::Sub(lhs, rhs) => Ok(lhs.eval()? - rhs.eval()?),
223 Self::Mul(lhs, rhs) => Ok(lhs.eval()? * rhs.eval()?),
224 Self::Div(lhs, rhs) => Ok(lhs.eval()? / rhs.eval()?),
225 Self::Pos(operand) => Ok(operand.eval()?),
226 Self::Neg(operand) => Ok(-operand.eval()?),
227 }
228 }
229}
230
231fn main() {
232 eval_print_input("2 + 3");
233 eval_print_input("-(2 + 3)");
234 eval_print_input("-(2 + 3) * -5");
235 eval_print_input("3 * pi - tau");
236
237 let mut read_stdin = false;
238 let mut repl = false;
239
240 for arg in env::args().skip(1) {
241 if arg == "-i" {
242 repl = true;
243 } else if arg == "-" {
244 read_stdin = true;
245 } else {
246 eval_print_input(&arg);
247 }
248 }
249
250 if read_stdin {
251 println!();
252
253 let mut buf = String::new();
254 io::stdin().read_to_string(&mut buf).unwrap();
255 eval_print_input(&buf);
256 } else if repl {
257 println!();
258 println!("Enter `exit` or press Ctrl+C to exit repl");
259
260 let mut input = String::new();
261
262 loop {
263 print!("> ");
264 _ = io::stdout().flush();
265 input.clear();
266 io::stdin().read_line(&mut input).unwrap();
267 let input = input.trim();
268
269 if input.is_empty() {
270 continue;
271 } else if input == "exit" {
272 break;
273 }
274
275 eval(&input);
276 }
277 }
278}
279
280fn eval_print_input(expr: &str) {
281 println!("{}", expr);
282 eval(expr);
283}
284
285fn eval(expr: &str) {
286 match Expr::parse(expr) {
287 Ok(expr) => match expr.eval() {
288 Ok(val) => println!("= {}", val),
289 Err(err) => eprintln!("eval error: {}", err),
290 },
291 Err(err) => eprintln!("parse error: {}", err),
292 }
293}