1use crate::filtermodifier::FilterModifier;
2use crate::interpreter::Ast;
3use crate::options::Options;
4use std::iter::Peekable;
5use std::str::Chars;
6
7#[derive(Debug)]
8pub struct Parser<'a> {
9 expr: Peekable<Chars<'a>>,
10 pos: u64,
11 source: String,
12
13 pub advanced: bool,
14}
15
16impl<'a> Parser<'a> {
17 pub fn new(expr: &'a str) -> Self {
18 Self {
19 source: expr.to_string(),
20 expr: expr.chars().peekable(),
21 pos: 0,
22 advanced: false,
23 }
24 }
25
26 pub fn advanced(mut self) -> Self {
27 self.advanced = true;
28 self
29 }
30
31 pub fn backup(&self) -> Self {
32 Self {
33 expr: self.expr.clone(),
34 source: self.source.clone(),
35 pos: self.pos,
36 advanced: self.advanced,
37 }
38 }
39
40 pub fn restore(&mut self, other: Self) {
41 self.expr = other.expr;
42 self.pos = other.pos;
43 self.source = other.source;
44 self.advanced = other.advanced;
45 }
46
47 pub fn accept(&mut self, c: char, options: Options) -> Result<(), Options> {
48 self.expect(c, options)?;
49
50 self.pos += 1;
51 self.expr.next();
52 Ok(())
53 }
54
55 pub fn accept_string(&mut self, text: &str, options: Options) -> Result<(), Options> {
56 let backup = self.backup();
57 for c in text.chars() {
58 if let Err(e) = self.accept(c, options.clone()) {
59 self.restore(backup);
60 return Err(e);
61 }
62 }
63
64 Ok(())
65 }
66
67 pub fn expect(&mut self, c: char, options: Options) -> Result<(), Options> {
68 while let Some(i) = self.expr.peek() {
69 if !i.is_whitespace() {
70 break;
71 }
72 self.pos += 1;
73 self.expr.next();
74 }
75
76 let pk = self.expr.peek();
77 if pk == Some(&c) {
78 Ok(())
79 } else {
80 Err(options.add(c).pos(self.pos))
81 }
82 }
83
84 pub fn accept_any(
85 &mut self,
86 c: &[char],
87 mut options: Options,
88 name: Option<Options>,
89 ) -> Result<char, Options> {
90 for i in c {
91 match self.accept(*i, options.clone()) {
92 Ok(_) => return Ok(*i),
93 Err(o) => {
94 if name.is_none() {
95 options = options.merge(o)
96 }
97 }
98 }
99 }
100
101 if let Some(n) = name {
102 options = options.merge(n)
103 }
104
105 Err(options)
106 }
107
108 pub fn parse(&mut self) -> Result<Ast, Options> {
109 let result = self.parse_expr(Options::new(self.source.clone()))?;
110
111 if self.expr.next().is_some() {
112 return Err(Options::new(self.source.clone())
113 .pos(self.pos)
114 .message("unexpected trailing character(s)"));
115 }
116
117 Ok(result)
118 }
119
120 pub fn parse_expr(&mut self, options: Options) -> Result<Ast, Options> {
121 self.parse_sum(options)
122 }
123
124 pub fn parse_sum(&mut self, options: Options) -> Result<Ast, Options> {
125 let mut res = self.parse_term(options.clone())?;
126
127 while let Ok(op) = self.accept_any(&['+', '-'], options.clone(), None) {
128 let right = self.parse_term(options.clone())?;
129
130 res = match op {
131 '+' => Ast::Add(Box::new(res), Box::new(right)),
132 '-' => Ast::Sub(Box::new(res), Box::new(right)),
133 _ => unreachable!(),
134 }
135 }
136
137 Ok(res)
138 }
139
140 pub fn parse_term(&mut self, mut options: Options) -> Result<Ast, Options> {
141 let mut res = self.parse_factor(options.clone())?;
142
143 loop {
144 let opres = self.accept_any(&['*', '/'], options.clone(), None);
145 let mut op = if let Ok(i) = opres {
146 i
147 } else if self.accept_string("mod", options.clone()).is_ok() {
148 '%'
149 } else {
150 options.add_str("mod").add_str("//");
151 break;
152 };
153
154 if op == '/' && self.accept('/', options.clone()).is_ok() {
155 op = 'i'
156 } else {
157 options = options.add('/');
158 }
159
160 let right = self.parse_factor(options.clone())?;
161
162 res = match op {
163 '*' => Ast::Mul(Box::new(res), Box::new(right)),
164 '/' => Ast::Div(Box::new(res), Box::new(right)),
165 'i' => Ast::IDiv(Box::new(res), Box::new(right)),
166 '%' => Ast::Mod(Box::new(res), Box::new(right)),
167 _ => unreachable!(),
168 }
169 }
170
171 Ok(res)
172 }
173
174 pub fn parse_factor(&mut self, options: Options) -> Result<Ast, Options> {
175 let backup = self.backup();
176
177 Ok(match self.accept('-', options.clone()) {
178 Ok(_) => Ast::Minus(Box::new(self.parse_power(options)?)),
179 Err(o) => {
180 self.restore(backup);
181
182 return self.parse_power(o);
183 }
184 })
185 }
186
187 pub fn parse_power(&mut self, options: Options) -> Result<Ast, Options> {
188 let mut res = self.parse_atom(options.clone())?;
189 if self.accept_string("**", options.clone()).is_ok() {
190 let right = self.parse_factor(options)?;
191 res = Ast::Power(Box::new(res), Box::new(right));
192 }
193
194 Ok(res)
195 }
196
197 pub fn parse_atom(&mut self, options: Options) -> Result<Ast, Options> {
198 let backup = self.backup();
199 Ok(match self.parse_dice(options) {
200 Err(mut o) => {
201 self.restore(backup);
202
203 let backup = self.backup();
204 if self.accept('(', o.clone()).is_ok() {
205 let sm = self.parse_sum(o.clone())?;
206 self.accept(')', o)
207 .map_err(|e| e.message("missing closing parenthesis"))?;
208
209 return Ok(sm);
210 } else {
211 o = o
212 .add('(')
213 .message("tried to parse expression between parenthesis");
214 self.restore(backup);
215 }
216
217 self.parse_number(o.message("tried to parse dice roll"))?
218 }
219 Ok(i) => i,
220 })
221 }
222
223 pub fn parse_dice(&mut self, mut options: Options) -> Result<Ast, Options> {
224 let backup = self.backup();
225
226 let rolls = if self.advanced && self.accept('(', options.clone()).is_ok() {
227 let sm = self.parse_sum(options.clone())?;
228 self.accept(')', options.clone())
229 .map_err(|e| e.message("missing closing parenthesis"))?;
230
231 Some(Box::new(sm))
232 } else {
233 if self.advanced {
234 options = options
235 .add('(')
236 .message("tried to parse expression between parenthesis");
237 }
238 self.restore(backup);
239 self.parse_number(options.clone()).map(Box::new).ok()
240 };
241
242 self.accept('d', options.clone())?;
243 let dpos = self.pos - 1;
244
245 let backup = self.backup();
246 let sides = if self.advanced && self.accept('(', options.clone()).is_ok() {
247 let sm = self.parse_sum(options.clone())?;
248 self.accept(')', options.clone())
249 .map_err(|e| e.message("missing closing parenthesis"))?;
250
251 Some(Box::new(sm))
252 } else {
253 if self.advanced {
254 options = options
255 .add('(')
256 .message("tried to parse expression between parenthesis");
257 }
258 self.restore(backup);
259
260 self.parse_number_or_percent(options.clone())
261 .map(Box::new)
262 .ok()
263 };
264
265 let fm = if self.accept_string("kh", options.clone()).is_ok()
266 || self.accept('h', options.clone()).is_ok()
267 {
268 FilterModifier::KeepHighest(Box::new(
269 self.parse_number(options)
270 .unwrap_or_else(|_| Ast::Const("1".to_string())),
271 ))
272 } else if self.accept_string("dl", options.clone()).is_ok()
273 || self.accept('l', options.clone()).is_ok()
274 {
275 FilterModifier::DropLowest(Box::new(
276 self.parse_number(options)
277 .unwrap_or_else(|_| Ast::Const("1".to_string())),
278 ))
279 } else if self.accept_string("dh", options.clone()).is_ok() {
280 FilterModifier::DropHighest(Box::new(
281 self.parse_number(options)
282 .unwrap_or_else(|_| Ast::Const("1".to_string())),
283 ))
284 } else if self.accept_string("kl", options.clone()).is_ok() {
285 FilterModifier::KeepLowest(Box::new(
286 self.parse_number(options)
287 .unwrap_or_else(|_| Ast::Const("1".to_string())),
288 ))
289 } else {
290 FilterModifier::None
291 };
292
293 Ok(Ast::Dice(rolls, sides, fm, dpos))
294 }
295
296 pub fn parse_number_or_percent(&mut self, options: Options) -> Result<Ast, Options> {
297 if self.accept('%', options.clone()).is_ok() {
298 Ok(Ast::Const("100".to_ascii_lowercase()))
299 } else {
300 self.parse_number(options.add('%'))
301 }
302 }
303
304 pub fn parse_number(&mut self, options: Options) -> Result<Ast, Options> {
305 const DIGITS: &[char] = &['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.'];
306 let digits_name = Options::new("".to_string()).add_str("0-9");
307
308 let mut number = vec![self
309 .accept_any(&DIGITS, options.clone(), Some(digits_name.clone()))
310 .map_err(|e| {
311 options
312 .clone()
313 .merge(e)
314 .add('(')
315 .message("tried to parse a number")
316 })?];
317
318 loop {
319 let backup = self.backup();
320
321 let digit = match self.accept_any(&DIGITS, options.clone(), Some(digits_name.clone())) {
322 Ok(i) => i,
323 Err(_) => {
324 self.restore(backup);
325 break;
326 }
327 };
328
329 number.push(digit)
330 }
331
332 let string: String = number.iter().collect();
333
334 Ok(Ast::Const(string))
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use super::*;
341 use crate::filtermodifier::FilterModifier;
342 use crate::interpreter::{Ast, Value, DEFAULT_SIDES};
343
344 #[test]
345 pub fn add() {
346 let mut p = Parser::new("3 + 5");
347 assert_eq!(
348 p.parse().unwrap().interp(&mut Vec::new()).unwrap(),
349 Value::Int(8)
350 );
351 }
352
353 #[test]
354 pub fn sub() {
355 let mut p = Parser::new("3 - 5");
356 assert_eq!(
357 p.parse().unwrap().interp(&mut Vec::new()).unwrap(),
358 Value::Int(-2)
359 );
360 }
361
362 #[test]
363 pub fn mul() {
364 let mut p = Parser::new("3 * 5");
365 assert_eq!(
366 p.parse().unwrap().interp(&mut Vec::new()).unwrap(),
367 Value::Int(15)
368 );
369 }
370
371 #[test]
372 pub fn div() {
373 let mut p = Parser::new("15/3");
374 let ast = p.parse().unwrap();
375 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Float(5.0));
376 }
377
378 #[test]
379 pub fn pemdas() {
380 let mut p = Parser::new("3 * 5 + -5");
381 let ast = p.parse().unwrap();
382 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Int(10));
383 }
384
385 #[test]
386 pub fn parens() {
387 let mut p = Parser::new("3 * (5 + -5)");
388 let ast = p.parse().unwrap();
389 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Int(0))
390 }
391
392 #[test]
393 pub fn meme() {
394 let mut p = Parser::new("6 / 2 * (1 + 2)");
395 let ast = p.parse().unwrap();
396 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Float(9.0))
397 }
398
399 #[test]
400 pub fn long_sum() {
401 let mut p = Parser::new("3 + 3 + 3");
402 let ast = p.parse().unwrap();
403 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Int(9));
404 }
405
406 #[test]
407 pub fn long_mul() {
408 let mut p = Parser::new("3 * 3 * 3");
409 let ast = p.parse().unwrap();
410 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Int(27));
411 }
412
413 #[test]
414 pub fn idiv() {
415 let mut p = Parser::new("3 // 5");
416 let ast = p.parse().unwrap();
417 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Int(0));
418 }
419
420 #[test]
421 pub fn dice_none() {
422 let mut p = Parser::new("d");
423 let ast = p.parse().unwrap();
424 assert_eq!(ast, Ast::Dice(None, None, FilterModifier::None, 0));
425
426 let mut rolls = Vec::new();
427 let res = ast.interp(&mut rolls).unwrap();
428
429 assert_eq!(rolls.len(), 1);
430
431 let roll = &rolls[0].1;
432 assert_eq!(DEFAULT_SIDES, roll.sides.to_string());
433
434 assert_eq!(res, Value::Int(roll.total));
435 }
436
437 #[test]
438 pub fn dice_6() {
439 let mut p = Parser::new("d6");
440 let ast = p.parse().unwrap();
441 assert_eq!(
442 ast,
443 Ast::Dice(
444 None,
445 Some(Box::new(Ast::Const("6".to_string()))),
446 FilterModifier::None,
447 0
448 )
449 );
450
451 let mut rolls = Vec::new();
452 let res = ast.interp(&mut rolls).unwrap();
453
454 assert_eq!(rolls.len(), 1);
455
456 let roll = &rolls[0].1;
457
458 assert_eq!(res, Value::Int(roll.total as i64));
459 }
460
461 #[test]
462 pub fn dice_3_6() {
463 let mut p = Parser::new("3d6");
464 let ast = p.parse().unwrap();
465 assert_eq!(
466 ast,
467 Ast::Dice(
468 Some(Box::new(Ast::Const("3".to_string()))),
469 Some(Box::new(Ast::Const("6".to_string()))),
470 FilterModifier::None,
471 1
472 )
473 );
474
475 let mut rolls = Vec::new();
476 let res = ast.interp(&mut rolls).unwrap();
477
478 assert_eq!(rolls.len(), 1);
479
480 let roll0 = &rolls[0].1.vals[0];
481 let roll1 = &rolls[0].1.vals[1];
482 let roll2 = &rolls[0].1.vals[2];
483
484 assert_eq!(res, Value::Int((roll0 + roll1 + roll2) as i64));
485 }
486
487 #[test]
488 pub fn dice_0() {
489 let mut p = Parser::new("0d6");
490 let ast = p.parse().unwrap();
491 assert_eq!(
492 ast,
493 Ast::Dice(
494 Some(Box::new(Ast::Const("0".to_string()))),
495 Some(Box::new(Ast::Const("6".to_string()))),
496 FilterModifier::None,
497 1
498 )
499 );
500
501 let mut rolls = Vec::new();
502 let res = ast.interp(&mut rolls).unwrap();
503
504 assert_eq!(rolls.len(), 1);
505
506 assert_eq!(res, Value::Int(0));
507 }
508
509 #[test]
510 pub fn dice_float() {
511 let mut p = Parser::new("3.5d6");
512 let ast = p.parse().unwrap();
513 assert_eq!(
514 ast,
515 Ast::Dice(
516 Some(Box::new(Ast::Const("3.5".to_string()))),
517 Some(Box::new(Ast::Const("6".to_string()))),
518 FilterModifier::None,
519 3
520 )
521 );
522
523 ast.interp(&mut Vec::new()).expect_err("result was okay");
524 }
525
526 #[test]
527 pub fn dice_dfloat() {
528 let mut p = Parser::new("3d3.5");
529 let ast = p.parse().unwrap();
530 assert_eq!(
531 ast,
532 Ast::Dice(
533 Some(Box::new(Ast::Const("3".to_string()))),
534 Some(Box::new(Ast::Const("3.5".to_string()))),
535 FilterModifier::None,
536 1
537 )
538 );
539
540 ast.interp(&mut Vec::new()).expect_err("result was okay");
541 }
542
543 #[test]
544 pub fn dice_d0() {
545 let mut p = Parser::new("3d0");
546 let ast = p.parse().unwrap();
547 assert_eq!(
548 ast,
549 Ast::Dice(
550 Some(Box::new(Ast::Const("3".to_string()))),
551 Some(Box::new(Ast::Const("0".to_string()))),
552 FilterModifier::None,
553 1
554 )
555 );
556
557 ast.interp(&mut Vec::new()).expect_err("result was okay");
558 }
559
560 #[test]
561 pub fn dice_dpercent() {
562 let mut p = Parser::new("d%");
563 let ast = p.parse().unwrap();
564 assert_eq!(
565 ast,
566 Ast::Dice(
567 None,
568 Some(Box::new(Ast::Const("100".to_string()))),
569 FilterModifier::None,
570 0
571 )
572 );
573
574 let mut rolls = Vec::new();
575 let res = ast.interp(&mut rolls).unwrap();
576
577 assert_eq!(rolls.len(), 1);
578
579 let roll = &rolls[0].1;
580
581 assert_eq!(roll.sides.get(), 100);
582 assert_eq!(res, Value::Int(roll.total));
583 }
584
585 #[test]
586 pub fn dice_kl() {
587 let mut p = Parser::new("5d%kl");
588 let ast = p.parse().unwrap();
589
590 let mut rolls = Vec::new();
591 let res = ast.interp(&mut rolls).unwrap();
592
593 assert_eq!(rolls.len(), 1);
594
595 let roll = &rolls[0].1;
596
597 assert_eq!(roll.vals.len(), 1);
598 assert_eq!(res, Value::Int(roll.total));
599 }
600
601 #[test]
602 pub fn pow() {
603 let mut p = Parser::new("5 ** 2");
604 let ast = p.parse().unwrap();
605 assert_eq!(ast.interp(&mut Vec::new()).unwrap(), Value::Int(25));
606 }
607
608 #[test]
609 pub fn compound() {
610 let mut p = Parser::new("(3d5)d(5d3)");
611 p.advanced = true;
612 let _ = p.parse().unwrap();
613 }
614}