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