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