1use crate::Real;
7use crate::error::ExprError;
8use crate::types::{AstExpr, FunctionName, HString};
9use alloc::format;
10
11#[derive(Clone)]
13pub enum EvalOp<'arena> {
14 Eval {
16 expr: &'arena AstExpr<'arena>,
17 ctx_id: usize,
18 },
19
20 ApplyUnary { op: UnaryOp },
22
23 CompleteBinary { op: BinaryOp },
25
26 ShortCircuitAnd {
28 right_expr: &'arena AstExpr<'arena>,
29 ctx_id: usize,
30 },
31
32 ShortCircuitOr {
34 right_expr: &'arena AstExpr<'arena>,
35 ctx_id: usize,
36 },
37
38 CompleteAnd,
40
41 CompleteOr,
43
44 ApplyFunction {
46 name: FunctionName,
47 arg_count: usize,
48 ctx_id: usize,
49 },
50
51 TernaryCondition {
53 true_branch: &'arena AstExpr<'arena>,
54 false_branch: &'arena AstExpr<'arena>,
55 ctx_id: usize,
56 },
57
58 LookupVariable { name: HString, ctx_id: usize },
60
61 AccessArray { array_name: HString, ctx_id: usize },
63
64 AccessAttribute {
66 object_name: HString,
67 attr_name: HString,
68 ctx_id: usize,
69 },
70
71 RestoreFunctionParams {
73 params: Option<&'arena [(crate::types::HString, crate::Real)]>,
75 },
76}
77
78#[derive(Debug, Clone, Copy, PartialEq)]
80pub enum UnaryOp {
81 Negate,
82 Not,
83}
84
85#[derive(Debug, Clone, Copy, PartialEq)]
87pub enum BinaryOp {
88 Add,
89 Subtract,
90 Multiply,
91 Divide,
92 Modulo,
93 Power,
94 Less,
95 Greater,
96 LessEqual,
97 GreaterEqual,
98 Equal,
99 NotEqual,
100 }
102
103impl UnaryOp {
104 pub fn apply(self, operand: Real) -> Real {
106 match self {
107 UnaryOp::Negate => -operand,
108 UnaryOp::Not => {
109 if operand == 0.0 {
110 1.0
111 } else {
112 0.0
113 }
114 }
115 }
116 }
117}
118
119impl BinaryOp {
120 pub fn apply(self, left: Real, right: Real) -> Real {
122 match self {
123 BinaryOp::Add => left + right,
124 BinaryOp::Subtract => left - right,
125 BinaryOp::Multiply => left * right,
126 BinaryOp::Divide => left / right,
127 BinaryOp::Modulo => left % right,
128 BinaryOp::Power => {
129 #[cfg(feature = "libm")]
130 {
131 crate::functions::pow(left, right)
132 }
133 #[cfg(not(feature = "libm"))]
134 {
135 panic!("Power operation requires libm feature or registered pow function")
138 }
139 }
140 BinaryOp::Less => {
141 if left < right {
142 1.0
143 } else {
144 0.0
145 }
146 }
147 BinaryOp::Greater => {
148 if left > right {
149 1.0
150 } else {
151 0.0
152 }
153 }
154 BinaryOp::LessEqual => {
155 if left <= right {
156 1.0
157 } else {
158 0.0
159 }
160 }
161 BinaryOp::GreaterEqual => {
162 if left >= right {
163 1.0
164 } else {
165 0.0
166 }
167 }
168 BinaryOp::Equal => {
169 if left == right {
170 1.0
171 } else {
172 0.0
173 }
174 }
175 BinaryOp::NotEqual => {
176 if left != right {
177 1.0
178 } else {
179 0.0
180 }
181 }
182 }
183 }
184}
185
186pub fn ast_to_stack_op(op: &str) -> Result<BinaryOp, ExprError> {
188 match op {
189 "+" => Ok(BinaryOp::Add),
190 "-" => Ok(BinaryOp::Subtract),
191 "*" => Ok(BinaryOp::Multiply),
192 "/" => Ok(BinaryOp::Divide),
193 "%" => Ok(BinaryOp::Modulo),
194 "^" | "**" => Ok(BinaryOp::Power),
195 "<" => Ok(BinaryOp::Less),
196 ">" => Ok(BinaryOp::Greater),
197 "<=" => Ok(BinaryOp::LessEqual),
198 ">=" => Ok(BinaryOp::GreaterEqual),
199 "==" => Ok(BinaryOp::Equal),
200 "!=" => Ok(BinaryOp::NotEqual),
201 _ => Err(ExprError::Syntax(format!("Unknown operator: {}", op))),
202 }
203}
204
205pub fn is_binary_operator(op: &str) -> bool {
207 matches!(
208 op,
209 "+" | "-" | "*" | "/" | "%" | "^" | "**" | "<" | ">" | "<=" | ">=" | "==" | "!="
210 )
211}
212
213impl<'arena> core::fmt::Debug for EvalOp<'arena> {
214 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
215 match self {
216 EvalOp::Eval { expr: _, ctx_id } => {
217 write!(f, "Eval {{ expr: <AstExpr>, ctx_id: {} }}", ctx_id)
218 }
219 EvalOp::ApplyUnary { op } => {
220 write!(f, "ApplyUnary {{ op: {:?} }}", op)
221 }
222 EvalOp::CompleteBinary { op } => {
223 write!(f, "CompleteBinary {{ op: {:?} }}", op)
224 }
225 EvalOp::ShortCircuitAnd {
226 right_expr: _,
227 ctx_id,
228 } => {
229 write!(
230 f,
231 "ShortCircuitAnd {{ right_expr: <AstExpr>, ctx_id: {} }}",
232 ctx_id
233 )
234 }
235 EvalOp::ShortCircuitOr {
236 right_expr: _,
237 ctx_id,
238 } => {
239 write!(
240 f,
241 "ShortCircuitOr {{ right_expr: <AstExpr>, ctx_id: {} }}",
242 ctx_id
243 )
244 }
245 EvalOp::CompleteAnd => write!(f, "CompleteAnd"),
246 EvalOp::CompleteOr => write!(f, "CompleteOr"),
247 EvalOp::ApplyFunction {
248 name,
249 arg_count,
250 ctx_id,
251 } => {
252 write!(
253 f,
254 "ApplyFunction {{ name: {:?}, arg_count: {}, ctx_id: {} }}",
255 name, arg_count, ctx_id
256 )
257 }
258 EvalOp::LookupVariable { name, ctx_id } => {
259 write!(
260 f,
261 "LookupVariable {{ name: {:?}, ctx_id: {} }}",
262 name, ctx_id
263 )
264 }
265 EvalOp::TernaryCondition {
266 true_branch: _,
267 false_branch: _,
268 ctx_id,
269 } => {
270 write!(
271 f,
272 "TernaryCondition {{ true_branch: <AstExpr>, false_branch: <AstExpr>, ctx_id: {} }}",
273 ctx_id
274 )
275 }
276 EvalOp::AccessArray { array_name, ctx_id } => {
277 write!(
278 f,
279 "AccessArray {{ array_name: {:?}, ctx_id: {} }}",
280 array_name, ctx_id
281 )
282 }
283 EvalOp::AccessAttribute {
284 object_name,
285 attr_name,
286 ctx_id,
287 } => {
288 write!(
289 f,
290 "AccessAttribute {{ object_name: {:?}, attr_name: {:?}, ctx_id: {} }}",
291 object_name, attr_name, ctx_id
292 )
293 }
294 EvalOp::RestoreFunctionParams { params } => {
295 write!(f, "RestoreFunctionParams {{ params: {} }}", params.is_some())
296 }
297 }
298 }
299}