thin_shunting/
rpnprint.rs1use crate::parser::{precedence, Assoc, RPNExpr};
2use crate::tokenizer::MathToken;
3use std::fmt;
4
5#[derive(Debug, Clone)]
6enum AST<'a> {
7 Leaf(&'a MathToken),
8 Node(&'a MathToken, Vec<AST<'a>>),
9}
10
11impl RPNExpr {
12 fn build_ast(&self) -> AST {
13 let mut ops = Vec::new();
14 for token in self.0.iter() {
15 match *token {
16 MathToken::Number(_) | MathToken::Variable(_) => ops.push(AST::Leaf(token)),
17 MathToken::Function(_, arity) => {
18 let n = ops.len() - arity;
19 let operands = ops.split_off(n);
20 ops.push(AST::Node(token, operands));
21 }
22 MathToken::BOp(_) => {
23 let n = ops.len() - 2;
24 let operands = ops.split_off(n);
25 ops.push(AST::Node(token, operands));
26 }
27 MathToken::UOp(_) => {
28 let n = ops.len() - 1;
29 let operands = ops.split_off(n);
30 ops.push(AST::Node(token, operands));
31 }
32 _ => unreachable!(),
33 }
34 }
35 ops.pop().unwrap()
36 }
37}
38
39impl fmt::Display for RPNExpr {
40 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41 fn printer(root: &AST) -> (String, (usize, Assoc)) {
42 match root {
43 AST::Leaf(ref token) => match *token {
44 MathToken::Number(ref x) => (x.to_string(), precedence(token)),
45 MathToken::Variable(ref x) => (x.to_string(), precedence(token)),
46 _ => unreachable!(),
47 },
48 AST::Node(ref token, ref args) => {
49 match *token {
50 MathToken::UOp(ref op) => {
51 let subtree = printer(&args[0]);
52 let (prec, assoc) = precedence(token);
53 if prec > (subtree.1).0 {
55 (format!("{}({})", op, subtree.0), (prec, assoc))
56 } else {
57 (format!("{}{}", op, subtree.0), (prec, assoc))
58 }
59 }
60 MathToken::BOp(ref op) => {
61 let (lhs, rhs) = (printer(&args[0]), printer(&args[1]));
62 let (prec, assoc) = precedence(token);
63
64 let lh = if prec > (lhs.1).0
65 || (prec == (lhs.1).0 && assoc != Assoc::Left)
66 {
67 format!("({})", lhs.0)
68 } else {
69 lhs.0
70 };
71 let rh = if prec > (rhs.1).0
72 || (prec == (rhs.1).0 && assoc != Assoc::Right)
73 {
74 format!("({})", rhs.0)
75 } else {
76 rhs.0
77 };
78 (format!("{} {} {}", lh, op, rh), (prec, assoc))
81 }
82 MathToken::Function(ref func, _) => {
83 let expr = args
84 .iter()
85 .map(|leaf| printer(&leaf).0)
86 .collect::<Vec<String>>()
87 .join(", ");
88 (format!("{}({})", func, expr), precedence(token))
89 }
90 _ => unreachable!(),
91 }
92 }
93 }
94 }
95
96 write!(f, "{}", printer(&self.build_ast()).0)
97 }
98}