1use std::str::FromStr;
42
43#[repr(u8)]
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum OpCode {
47 Var = 0,
49 Val = 1,
50 Exists = 57,
51
52 Equals = 2,
54 StrictEquals = 3,
55 NotEquals = 4,
56 StrictNotEquals = 5,
57 GreaterThan = 6,
58 GreaterThanEqual = 7,
59 LessThan = 8,
60 LessThanEqual = 9,
61
62 Not = 10,
64 DoubleNot = 11,
65 And = 12,
66 Or = 13,
67
68 If = 14,
70 Ternary = 15,
71 Coalesce = 56,
72 Switch = 59,
73
74 Add = 16,
76 Subtract = 17,
77 Multiply = 18,
78 Divide = 19,
79 Modulo = 20,
80 Max = 21,
81 Min = 22,
82 Abs = 49,
83 Ceil = 50,
84 Floor = 51,
85
86 Cat = 23,
88 Substr = 24,
89 In = 25,
90 Length = 53,
91 StartsWith = 38,
92 EndsWith = 39,
93 Upper = 40,
94 Lower = 41,
95 Trim = 42,
96 Split = 43,
97
98 Merge = 26,
100 Filter = 27,
101 Map = 28,
102 Reduce = 29,
103 All = 30,
104 Some = 31,
105 None = 32,
106 Sort = 54,
107 Slice = 55,
108
109 Datetime = 44,
111 Timestamp = 45,
112 ParseDate = 46,
113 FormatDate = 47,
114 DateDiff = 48,
115 Now = 58,
116
117 Try = 35,
119 Throw = 36,
120
121 Type = 37,
123
124 Missing = 33,
126 MissingSome = 34,
127
128 Preserve = 52,
130}
131
132impl FromStr for OpCode {
133 type Err = ();
134
135 fn from_str(s: &str) -> Result<Self, Self::Err> {
136 match s {
137 "var" => Ok(OpCode::Var),
138 "val" => Ok(OpCode::Val),
139 "==" => Ok(OpCode::Equals),
140 "===" => Ok(OpCode::StrictEquals),
141 "!=" => Ok(OpCode::NotEquals),
142 "!==" => Ok(OpCode::StrictNotEquals),
143 ">" => Ok(OpCode::GreaterThan),
144 ">=" => Ok(OpCode::GreaterThanEqual),
145 "<" => Ok(OpCode::LessThan),
146 "<=" => Ok(OpCode::LessThanEqual),
147 "!" => Ok(OpCode::Not),
148 "!!" => Ok(OpCode::DoubleNot),
149 "and" => Ok(OpCode::And),
150 "or" => Ok(OpCode::Or),
151 "if" => Ok(OpCode::If),
152 "?:" => Ok(OpCode::Ternary),
153 "+" => Ok(OpCode::Add),
154 "-" => Ok(OpCode::Subtract),
155 "*" => Ok(OpCode::Multiply),
156 "/" => Ok(OpCode::Divide),
157 "%" => Ok(OpCode::Modulo),
158 "max" => Ok(OpCode::Max),
159 "min" => Ok(OpCode::Min),
160 "cat" => Ok(OpCode::Cat),
161 "substr" => Ok(OpCode::Substr),
162 "in" => Ok(OpCode::In),
163 "merge" => Ok(OpCode::Merge),
164 "filter" => Ok(OpCode::Filter),
165 "map" => Ok(OpCode::Map),
166 "reduce" => Ok(OpCode::Reduce),
167 "all" => Ok(OpCode::All),
168 "some" => Ok(OpCode::Some),
169 "none" => Ok(OpCode::None),
170 "missing" => Ok(OpCode::Missing),
171 "missing_some" => Ok(OpCode::MissingSome),
172 "try" => Ok(OpCode::Try),
173 "throw" => Ok(OpCode::Throw),
174 "type" => Ok(OpCode::Type),
175 "starts_with" => Ok(OpCode::StartsWith),
176 "ends_with" => Ok(OpCode::EndsWith),
177 "upper" => Ok(OpCode::Upper),
178 "lower" => Ok(OpCode::Lower),
179 "trim" => Ok(OpCode::Trim),
180 "split" => Ok(OpCode::Split),
181 "datetime" => Ok(OpCode::Datetime),
182 "timestamp" => Ok(OpCode::Timestamp),
183 "parse_date" => Ok(OpCode::ParseDate),
184 "format_date" => Ok(OpCode::FormatDate),
185 "date_diff" => Ok(OpCode::DateDiff),
186 "now" => Ok(OpCode::Now),
187 "abs" => Ok(OpCode::Abs),
188 "ceil" => Ok(OpCode::Ceil),
189 "floor" => Ok(OpCode::Floor),
190 "preserve" => Ok(OpCode::Preserve),
191 "length" => Ok(OpCode::Length),
192 "sort" => Ok(OpCode::Sort),
193 "slice" => Ok(OpCode::Slice),
194 "??" => Ok(OpCode::Coalesce),
195 "exists" => Ok(OpCode::Exists),
196 "switch" | "match" => Ok(OpCode::Switch),
197 _ => Err(()),
198 }
199 }
200}
201
202impl OpCode {
203 pub const COUNT: usize = 60;
205
206 pub fn as_str(&self) -> &'static str {
208 match self {
209 OpCode::Var => "var",
210 OpCode::Val => "val",
211 OpCode::Equals => "==",
212 OpCode::StrictEquals => "===",
213 OpCode::NotEquals => "!=",
214 OpCode::StrictNotEquals => "!==",
215 OpCode::GreaterThan => ">",
216 OpCode::GreaterThanEqual => ">=",
217 OpCode::LessThan => "<",
218 OpCode::LessThanEqual => "<=",
219 OpCode::Not => "!",
220 OpCode::DoubleNot => "!!",
221 OpCode::And => "and",
222 OpCode::Or => "or",
223 OpCode::If => "if",
224 OpCode::Ternary => "?:",
225 OpCode::Add => "+",
226 OpCode::Subtract => "-",
227 OpCode::Multiply => "*",
228 OpCode::Divide => "/",
229 OpCode::Modulo => "%",
230 OpCode::Max => "max",
231 OpCode::Min => "min",
232 OpCode::Cat => "cat",
233 OpCode::Substr => "substr",
234 OpCode::In => "in",
235 OpCode::Merge => "merge",
236 OpCode::Filter => "filter",
237 OpCode::Map => "map",
238 OpCode::Reduce => "reduce",
239 OpCode::All => "all",
240 OpCode::Some => "some",
241 OpCode::None => "none",
242 OpCode::Missing => "missing",
243 OpCode::MissingSome => "missing_some",
244 OpCode::Try => "try",
245 OpCode::Throw => "throw",
246 OpCode::Type => "type",
247 OpCode::StartsWith => "starts_with",
248 OpCode::EndsWith => "ends_with",
249 OpCode::Upper => "upper",
250 OpCode::Lower => "lower",
251 OpCode::Trim => "trim",
252 OpCode::Split => "split",
253 OpCode::Datetime => "datetime",
254 OpCode::Timestamp => "timestamp",
255 OpCode::ParseDate => "parse_date",
256 OpCode::FormatDate => "format_date",
257 OpCode::DateDiff => "date_diff",
258 OpCode::Now => "now",
259 OpCode::Abs => "abs",
260 OpCode::Ceil => "ceil",
261 OpCode::Floor => "floor",
262 OpCode::Preserve => "preserve",
263 OpCode::Length => "length",
264 OpCode::Sort => "sort",
265 OpCode::Slice => "slice",
266 OpCode::Coalesce => "??",
267 OpCode::Exists => "exists",
268 OpCode::Switch => "switch",
269 }
270 }
271
272 pub fn evaluate_direct(
274 &self,
275 args: &[crate::CompiledNode],
276 context: &mut crate::ContextStack,
277 engine: &crate::DataLogic,
278 ) -> crate::Result<serde_json::Value> {
279 use crate::operators::{
280 arithmetic, array, comparison, control, datetime, logical, math, missing, preserve,
281 string, throw, try_op, type_op, variable,
282 };
283
284 match self {
285 OpCode::Var => variable::evaluate_var(args, context, engine),
287 OpCode::Val => variable::evaluate_val(args, context, engine),
288 OpCode::Exists => variable::evaluate_exists(args, context, engine),
289
290 OpCode::Equals => comparison::evaluate_equals(args, context, engine),
292 OpCode::StrictEquals => comparison::evaluate_strict_equals(args, context, engine),
293 OpCode::NotEquals => comparison::evaluate_not_equals(args, context, engine),
294 OpCode::StrictNotEquals => {
295 comparison::evaluate_strict_not_equals(args, context, engine)
296 }
297 OpCode::GreaterThan => comparison::evaluate_greater_than(args, context, engine),
298 OpCode::GreaterThanEqual => {
299 comparison::evaluate_greater_than_equal(args, context, engine)
300 }
301 OpCode::LessThan => comparison::evaluate_less_than(args, context, engine),
302 OpCode::LessThanEqual => comparison::evaluate_less_than_equal(args, context, engine),
303
304 OpCode::Not => logical::evaluate_not(args, context, engine),
306 OpCode::DoubleNot => logical::evaluate_double_not(args, context, engine),
307 OpCode::And => logical::evaluate_and(args, context, engine),
308 OpCode::Or => logical::evaluate_or(args, context, engine),
309
310 OpCode::If => control::evaluate_if(args, context, engine),
312 OpCode::Ternary => control::evaluate_ternary(args, context, engine),
313 OpCode::Coalesce => control::evaluate_coalesce(args, context, engine),
314 OpCode::Switch => control::evaluate_switch(args, context, engine),
315
316 OpCode::Add => arithmetic::evaluate_add(args, context, engine),
318 OpCode::Subtract => arithmetic::evaluate_subtract(args, context, engine),
319 OpCode::Multiply => arithmetic::evaluate_multiply(args, context, engine),
320 OpCode::Divide => arithmetic::evaluate_divide(args, context, engine),
321 OpCode::Modulo => arithmetic::evaluate_modulo(args, context, engine),
322 OpCode::Max => arithmetic::evaluate_max(args, context, engine),
323 OpCode::Min => arithmetic::evaluate_min(args, context, engine),
324 OpCode::Abs => math::evaluate_abs(args, context, engine),
325 OpCode::Ceil => math::evaluate_ceil(args, context, engine),
326 OpCode::Floor => math::evaluate_floor(args, context, engine),
327
328 OpCode::Cat => string::evaluate_cat(args, context, engine),
330 OpCode::Substr => string::evaluate_substr(args, context, engine),
331 OpCode::In => string::evaluate_in(args, context, engine),
332 OpCode::Length => string::evaluate_length(args, context, engine),
333 OpCode::StartsWith => string::evaluate_starts_with(args, context, engine),
334 OpCode::EndsWith => string::evaluate_ends_with(args, context, engine),
335 OpCode::Upper => string::evaluate_upper(args, context, engine),
336 OpCode::Lower => string::evaluate_lower(args, context, engine),
337 OpCode::Trim => string::evaluate_trim(args, context, engine),
338 OpCode::Split => string::evaluate_split(args, context, engine),
339
340 OpCode::Merge => array::evaluate_merge(args, context, engine),
342 OpCode::Filter => array::evaluate_filter(args, context, engine),
343 OpCode::Map => array::evaluate_map(args, context, engine),
344 OpCode::Reduce => array::evaluate_reduce(args, context, engine),
345 OpCode::All => array::evaluate_all(args, context, engine),
346 OpCode::Some => array::evaluate_some(args, context, engine),
347 OpCode::None => array::evaluate_none(args, context, engine),
348 OpCode::Sort => array::evaluate_sort(args, context, engine),
349 OpCode::Slice => array::evaluate_slice(args, context, engine),
350
351 OpCode::Missing => missing::evaluate_missing(args, context, engine),
353 OpCode::MissingSome => missing::evaluate_missing_some(args, context, engine),
354 OpCode::Try => try_op::evaluate_try(args, context, engine),
355 OpCode::Throw => throw::evaluate_throw(args, context, engine),
356 OpCode::Type => type_op::evaluate_type(args, context, engine),
357 OpCode::Preserve => preserve::evaluate_preserve(args, context, engine),
358
359 OpCode::Datetime => datetime::evaluate_datetime(args, context, engine),
361 OpCode::Timestamp => datetime::evaluate_timestamp(args, context, engine),
362 OpCode::ParseDate => datetime::evaluate_parse_date(args, context, engine),
363 OpCode::FormatDate => datetime::evaluate_format_date(args, context, engine),
364 OpCode::DateDiff => datetime::evaluate_date_diff(args, context, engine),
365 OpCode::Now => datetime::evaluate_now(args, context, engine),
366 }
367 }
368
369 pub fn evaluate_traced(
375 &self,
376 args: &[crate::CompiledNode],
377 context: &mut crate::ContextStack,
378 engine: &crate::DataLogic,
379 collector: &mut crate::trace::TraceCollector,
380 node_id_map: &std::collections::HashMap<usize, u32>,
381 ) -> crate::Result<serde_json::Value> {
382 use crate::operators::{array, control, logical, throw, try_op};
383
384 match self {
385 OpCode::Map => {
387 array::evaluate_map_traced(args, context, engine, collector, node_id_map)
388 }
389 OpCode::Filter => {
390 array::evaluate_filter_traced(args, context, engine, collector, node_id_map)
391 }
392 OpCode::Reduce => {
393 array::evaluate_reduce_traced(args, context, engine, collector, node_id_map)
394 }
395 OpCode::All => {
396 array::evaluate_all_traced(args, context, engine, collector, node_id_map)
397 }
398 OpCode::Some => {
399 array::evaluate_some_traced(args, context, engine, collector, node_id_map)
400 }
401 OpCode::None => {
402 array::evaluate_none_traced(args, context, engine, collector, node_id_map)
403 }
404
405 OpCode::And => {
407 logical::evaluate_and_traced(args, context, engine, collector, node_id_map)
408 }
409 OpCode::Or => {
410 logical::evaluate_or_traced(args, context, engine, collector, node_id_map)
411 }
412
413 OpCode::If => {
415 control::evaluate_if_traced(args, context, engine, collector, node_id_map)
416 }
417 OpCode::Ternary => {
418 control::evaluate_ternary_traced(args, context, engine, collector, node_id_map)
419 }
420 OpCode::Coalesce => {
421 control::evaluate_coalesce_traced(args, context, engine, collector, node_id_map)
422 }
423 OpCode::Switch => {
424 control::evaluate_switch_traced(args, context, engine, collector, node_id_map)
425 }
426
427 OpCode::Try => {
429 try_op::evaluate_try_traced(args, context, engine, collector, node_id_map)
430 }
431 OpCode::Throw => {
432 throw::evaluate_throw_traced(args, context, engine, collector, node_id_map)
433 }
434
435 _ => {
437 let mut evaluated_args: Vec<serde_json::Value> = Vec::with_capacity(args.len());
439 for arg in args {
440 let value =
441 engine.evaluate_node_traced(arg, context, collector, node_id_map)?;
442 evaluated_args.push(value);
443 }
444
445 let value_nodes: Vec<crate::CompiledNode> = evaluated_args
447 .into_iter()
448 .map(|v| crate::CompiledNode::Value { value: v })
449 .collect();
450
451 self.evaluate_direct(&value_nodes, context, engine)
453 }
454 }
455 }
456}