vegafusion_core/expression/ast/
binary.rs

1use crate::expression::ast::expression::ExpressionTrait;
2use crate::proto::gen::expression::{BinaryExpression, BinaryOperator, Expression};
3use std::fmt::{Display, Formatter};
4
5// Binary
6impl Display for BinaryOperator {
7    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
8        match self {
9            BinaryOperator::Plus => write!(f, "+"),
10            BinaryOperator::Minus => write!(f, "-"),
11            BinaryOperator::Mult => write!(f, "*"),
12            BinaryOperator::Div => write!(f, "/"),
13            BinaryOperator::Mod => write!(f, "%"),
14            BinaryOperator::Equals => write!(f, "=="),
15            BinaryOperator::StrictEquals => write!(f, "==="),
16            BinaryOperator::NotEquals => write!(f, "!="),
17            BinaryOperator::NotStrictEquals => write!(f, "!=="),
18            BinaryOperator::GreaterThan => write!(f, ">"),
19            BinaryOperator::LessThan => write!(f, "<"),
20            BinaryOperator::GreaterThanEqual => write!(f, ">="),
21            BinaryOperator::LessThanEqual => write!(f, "<="),
22            BinaryOperator::BitwiseAnd => write!(f, "&"),
23            BinaryOperator::BitwiseOr => write!(f, "|"),
24            BinaryOperator::BitwiseXor => write!(f, "^"),
25            BinaryOperator::BitwiseShiftLeft => write!(f, "<<"),
26            BinaryOperator::BitwiseShiftRight => write!(f, ">>"),
27        }
28    }
29}
30
31impl BinaryOperator {
32    pub fn infix_binding_power(&self) -> (f64, f64) {
33        // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
34        //  - left-to-right operators have larger number to the right
35        //  - right-to-left have larger number to the left
36
37        match self {
38            BinaryOperator::Plus | BinaryOperator::Minus => (14.0, 14.5),
39            BinaryOperator::Mult | BinaryOperator::Div | BinaryOperator::Mod => (15.0, 15.5),
40            BinaryOperator::GreaterThan
41            | BinaryOperator::LessThan
42            | BinaryOperator::GreaterThanEqual
43            | BinaryOperator::LessThanEqual => (12.0, 12.5),
44            BinaryOperator::Equals
45            | BinaryOperator::StrictEquals
46            | BinaryOperator::NotEquals
47            | BinaryOperator::NotStrictEquals => (11.0, 11.5),
48            BinaryOperator::BitwiseShiftLeft | BinaryOperator::BitwiseShiftRight => (10.0, 10.5),
49            BinaryOperator::BitwiseAnd => (7.0, 7.5),
50            BinaryOperator::BitwiseXor => (6.0, 6.5),
51            BinaryOperator::BitwiseOr => (5.0, 5.5),
52        }
53    }
54}
55
56impl BinaryExpression {
57    pub fn new(lhs: Expression, op: &BinaryOperator, rhs: Expression) -> Self {
58        Self {
59            left: Some(Box::new(lhs)),
60            operator: *op as i32,
61            right: Some(Box::new(rhs)),
62        }
63    }
64
65    pub fn to_operator(&self) -> BinaryOperator {
66        BinaryOperator::try_from(self.operator).unwrap()
67    }
68
69    pub fn infix_binding_power(&self) -> (f64, f64) {
70        self.to_operator().infix_binding_power()
71    }
72
73    pub fn left(&self) -> &Expression {
74        self.left.as_ref().unwrap()
75    }
76
77    pub fn right(&self) -> &Expression {
78        self.right.as_ref().unwrap()
79    }
80}
81
82impl ExpressionTrait for BinaryExpression {
83    fn binding_power(&self) -> (f64, f64) {
84        self.infix_binding_power()
85    }
86}
87
88impl Display for BinaryExpression {
89    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
90        // Use binding power to determine whether lhs and/or rhs need parens
91        let lhs_bp = self.left.as_ref().unwrap().binding_power();
92        let rhs_bp = self.right.as_ref().unwrap().binding_power();
93        let self_bp = self.binding_power();
94        let lhs_parens = lhs_bp.1 < self_bp.0;
95        let rhs_parens = rhs_bp.0 < self_bp.1;
96
97        // Write lhs
98        if lhs_parens {
99            write!(f, "({})", self.left.as_ref().unwrap())?;
100        } else {
101            write!(f, "{}", self.left.as_ref().unwrap())?;
102        }
103
104        write!(f, " {} ", self.to_operator())?;
105
106        // Write rhs
107        if rhs_parens {
108            write!(f, "({})", self.right.as_ref().unwrap())
109        } else {
110            write!(f, "{}", self.right.as_ref().unwrap())
111        }
112    }
113}