psi_lang/
expr.rs

1use crate::{Error, Identifier, Identifiers, Table};
2use smartstring::alias::String;
3use std::collections::VecDeque;
4use std::fmt;
5use std::ops::{Add, Div, Mul, Rem, Sub};
6
7#[derive(Debug, PartialEq, PartialOrd, Clone)]
8pub enum Expr {
9    Integer(i64),
10    Float(f64),
11    StringFmt(Identifiers),
12    StringRaw(String),
13    Identifier(Identifier),
14    Boolean(bool),
15    Inclusive(Box<Expr>, Box<Expr>),
16    Exclusive(Box<Expr>, Box<Expr>),
17    Array(Identifiers),
18    Table(Table),
19    Not(Box<Expr>),
20    BinOp(Box<Expr>, Op, Box<Expr>),
21    FnCall(Box<Expr>, Identifiers),
22    VarIndex(Box<Expr>, VecDeque<Expr>),
23    Impossible,
24}
25
26#[derive(Debug, PartialEq, PartialOrd, Clone, Copy)]
27pub enum Op {
28    Add,
29    Sub,
30    Mul,
31    Div,
32    Pow,
33    Rem,
34    And,
35    Or,
36    In,
37    Greater,
38    Less,
39    GreaterEq,
40    LessEq,
41    Equals,
42    NotEquals,
43}
44
45impl Add for Expr {
46    type Output = Self;
47    fn add(self, by: Self) -> Self::Output {
48        match (self, by) {
49            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 + f2),
50            (Self::Integer(i), Self::Float(f)) => Self::Float(i as f64 + f),
51            (Self::Float(f), Self::Integer(i)) => Self::Float(f + i as f64),
52            (Self::Integer(i1), Self::Integer(i2)) => Self::Integer(i1 + i2),
53            _ => Self::Impossible,
54        }
55    }
56}
57
58impl Sub for Expr {
59    type Output = Self;
60    fn sub(self, by: Self) -> Self::Output {
61        match (self, by) {
62            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 - f2),
63            (Self::Integer(i), Self::Float(f)) => Self::Float(i as f64 - f),
64            (Self::Float(f), Self::Integer(i)) => Self::Float(f - i as f64),
65            (Self::Integer(i1), Self::Integer(i2)) => Self::Integer(i1 - i2),
66            _ => Self::Impossible,
67        }
68    }
69}
70
71impl Mul for Expr {
72    type Output = Self;
73    fn mul(self, by: Self) -> Self::Output {
74        match (self, by) {
75            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 * f2),
76            (Self::Integer(i), Self::Float(f)) => Self::Float(i as f64 * f),
77            (Self::Float(f), Self::Integer(i)) => Self::Float(f * i as f64),
78            (Self::Integer(i1), Self::Integer(i2)) => Self::Integer(i1 * i2),
79            _ => Self::Impossible,
80        }
81    }
82}
83
84impl Div for Expr {
85    type Output = Self;
86    fn div(self, by: Self) -> Self::Output {
87        match (self, by) {
88            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 / f2),
89            (Self::Integer(i), Self::Float(f)) => Self::Float(i as f64 / f),
90            (Self::Float(f), Self::Integer(i)) => Self::Float(f / i as f64),
91            (Self::Integer(i1), Self::Integer(i2)) => Self::Float(i1 as f64 / i2 as f64),
92            _ => Self::Impossible,
93        }
94    }
95}
96
97impl Rem for Expr {
98    type Output = Self;
99    fn rem(self, by: Self) -> Self::Output {
100        match (self, by) {
101            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 % f2),
102            (Self::Integer(i), Self::Float(f)) => Self::Float(i as f64 % f),
103            (Self::Float(f), Self::Integer(i)) => Self::Float(f % i as f64),
104            (Self::Integer(i1), Self::Integer(i2)) => Self::Integer(i1 % i2),
105            _ => Self::Impossible,
106        }
107    }
108}
109
110impl Expr {
111    pub fn pow(self, by: Expr) -> Expr {
112        match (self, by) {
113            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1.powf(f2)),
114            (Self::Integer(i), Self::Float(f)) => Self::Float((i as f64).powf(f)),
115            (Self::Float(f), Self::Integer(i)) => Self::Float(f.powf(i as f64)),
116            (Self::Integer(i1), Self::Integer(i2)) => Self::Float((i1 as f64).powf(i2 as f64)),
117            _ => Self::Impossible,
118        }
119    }
120
121    pub fn as_bool(&self) -> Result<bool, Error> {
122        if let Expr::Boolean(b) = self {
123            Ok(*b)
124        } else {
125            Err(Error::EvalNotBool)
126        }
127    }
128}
129
130impl fmt::Display for Op {
131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132        match self {
133            Op::Add => write!(f, "+"),
134            Op::Sub => write!(f, "-"),
135            Op::Mul => write!(f, "*"),
136            Op::Div => write!(f, "/"),
137            Op::Pow => write!(f, "^"),
138            Op::Rem => write!(f, "%"),
139            Op::Equals => write!(f, "=="),
140            Op::NotEquals => write!(f, "!="),
141            Op::Greater => write!(f, ">"),
142            Op::Less => write!(f, "<"),
143            Op::GreaterEq => write!(f, ">="),
144            Op::LessEq => write!(f, "<="),
145            Op::Or => write!(f, "or"),
146            Op::And => write!(f, "and"),
147            Op::In => write!(f, "in"),
148        }
149    }
150}
151
152impl fmt::Display for Expr {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        match self {
155            Expr::Integer(i) => write!(f, "{}", i),
156            Expr::Float(fl) => write!(f, "{}", fl),
157            Expr::Boolean(b) => write!(f, "{}", b),
158            Expr::Identifier(i) => write!(f, "{}", i.join(".")),
159            Expr::VarIndex(i, l) => write!(
160                f,
161                "{}{}",
162                i,
163                l.iter()
164                    .map(|x| format!("[{}]", x))
165                    .collect::<Vec<_>>()
166                    .join("")
167            ),
168            Expr::Exclusive(s, e) => write!(f, "{}..{}", s, e),
169            Expr::Inclusive(s, e) => write!(f, "{}...{}", s, e),
170            Expr::StringRaw(s) => write!(f, "{}", s),
171            Expr::StringFmt(p) => write!(f, "{:?}", p),
172            Expr::Array(s) => write!(
173                f,
174                "[{}]",
175                s.iter()
176                    .map(|i| format!("{}", i))
177                    .collect::<Vec<_>>()
178                    .join(", ")
179            ),
180            Expr::Table(s) => write!(f, "{}", s),
181            Expr::FnCall(i, a) => write!(
182                f,
183                "{}({})",
184                i,
185                a.iter()
186                    .map(|i| format!("{}", i))
187                    .collect::<Vec<_>>()
188                    .join(", ")
189            ),
190            Expr::BinOp(l, o, r) => write!(f, "{} {} {}", l, o, r),
191            Expr::Not(e) => write!(f, "not {}", e),
192            _ => unreachable!(),
193        }
194    }
195}