litcheck_filecheck/expr/
mod.rs

1mod cli;
2mod error;
3pub mod num;
4mod parser;
5mod value;
6
7pub use self::cli::CliVariable;
8pub use self::error::*;
9pub use self::num::{FormatSpecifier, Number, NumberFormat, ParseNumberError};
10pub use self::value::{Value, ValueType};
11
12use litcheck::variables;
13
14use crate::common::*;
15
16pub type VariableName = variables::VariableName<Symbol>;
17pub type Variable<'a> = variables::Variable<Symbol, Value<'a>>;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub(crate) struct Var<'a> {
21    pub name: VariableName,
22    pub value: Value<'a>,
23}
24
25#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
26pub struct TypedVariable {
27    pub name: VariableName,
28    pub ty: ValueType,
29}
30
31#[derive(Debug, Clone)]
32pub enum Expr {
33    Num(Number),
34    Var(VariableName),
35    Binary {
36        span: SourceSpan,
37        op: BinaryOp,
38        lhs: Box<Expr>,
39        rhs: Box<Expr>,
40    },
41}
42impl Spanned for Expr {
43    fn span(&self) -> SourceSpan {
44        match self {
45            Self::Num(spanned) => spanned.span(),
46            Self::Var(spanned) => spanned.span(),
47            Self::Binary { span, .. } => *span,
48        }
49    }
50}
51impl Expr {
52    pub fn from_call(
53        interner: &mut StringInterner,
54        span: SourceSpan,
55        callee: Span<Symbol>,
56        mut args: Vec<Expr>,
57    ) -> Result<Self, InvalidCallExprError> {
58        match args.len() {
59            2 => {
60                let op = match interner.resolve(callee.into_inner()) {
61                    "add" => BinaryOp::Add,
62                    "sub" => BinaryOp::Sub,
63                    "mul" => BinaryOp::Mul,
64                    "div" => BinaryOp::Div,
65                    "min" => BinaryOp::Min,
66                    "max" => BinaryOp::Max,
67                    callee => {
68                        return Err(InvalidCallExprError::Undefined {
69                            span,
70                            callee: callee.to_string(),
71                        })
72                    }
73                };
74                let rhs = Box::new(args.pop().unwrap());
75                let lhs = Box::new(args.pop().unwrap());
76                Ok(Self::Binary { span, op, lhs, rhs })
77            }
78            arity => match interner.resolve(*callee) {
79                callee @ ("add" | "sub" | "mul" | "div" | "min" | "max") => {
80                    Err(InvalidCallExprError::InvalidArity {
81                        span,
82                        callee: callee.to_string(),
83                        expected: 2,
84                        given: arity as u8,
85                    })
86                }
87                callee => Err(InvalidCallExprError::Undefined {
88                    span,
89                    callee: callee.to_string(),
90                }),
91            },
92        }
93    }
94}
95impl Eq for Expr {}
96impl PartialEq for Expr {
97    fn eq(&self, other: &Self) -> bool {
98        match (self, other) {
99            (Self::Num(a), Self::Num(b)) => a == b,
100            (Self::Var(a), Self::Var(b)) => a == b,
101            (
102                Self::Binary {
103                    op: aop,
104                    lhs: al,
105                    rhs: ar,
106                    ..
107                },
108                Self::Binary {
109                    op: bop,
110                    lhs: bl,
111                    rhs: br,
112                    ..
113                },
114            ) => aop == bop && al == bl && ar == br,
115            _ => false,
116        }
117    }
118}
119impl PartialOrd for Expr {
120    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
121        Some(self.cmp(other))
122    }
123}
124impl Ord for Expr {
125    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
126        use core::cmp::Ordering;
127        match (self, other) {
128            (Self::Num(l), Self::Num(r)) => l.cmp(r),
129            (Self::Num(_), _) => Ordering::Less,
130            (_, Self::Num(_)) => Ordering::Greater,
131            (Self::Var(l), Self::Var(r)) => l.cmp(r),
132            (Self::Var(_), _) => Ordering::Less,
133            (_, Self::Var(_)) => Ordering::Greater,
134            (
135                Self::Binary {
136                    op: lop,
137                    lhs: ll,
138                    rhs: lr,
139                    ..
140                },
141                Self::Binary {
142                    op: rop,
143                    lhs: rl,
144                    rhs: rr,
145                    ..
146                },
147            ) => lop
148                .cmp(rop)
149                .then_with(|| ll.cmp(rl))
150                .then_with(|| lr.cmp(rr)),
151        }
152    }
153}
154
155#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
156pub enum BinaryOp {
157    Eq,
158    Add,
159    Sub,
160    Mul,
161    Div,
162    Min,
163    Max,
164}