use super::Engine;
use crate::arena::ContextStack;
use crate::{CompiledNode, Error, Result};
macro_rules! dispatch {
(
node: $node:expr,
ctx: $ctx:expr,
engine: $engine:expr,
arena: $arena:expr,
other: { $($others:tt)* },
simple: [ $( $(#[$scfg:meta])* $sop:ident => $sfn:path ),* $(,)? ],
iter: [ $( $(#[$icfg:meta])* $iop:ident => $ifn:path ),* $(,)? ],
with_kind: [ $( $(#[$kcfg:meta])* $kop:ident => ($kfn:path, $kkind:expr) ),* $(,)? ] $(,)?
) => {
match $node {
$($others)*
$(
$(#[$scfg])*
CompiledNode::BuiltinOperator {
opcode: crate::OpCode::$sop,
args,
..
} => $sfn(args, $ctx, $engine, $arena),
)*
$(
$(#[$icfg])*
CompiledNode::BuiltinOperator {
opcode: crate::OpCode::$iop,
args,
iter_arg_kind,
..
} => $ifn(args, *iter_arg_kind, $ctx, $engine, $arena),
)*
$(
$(#[$kcfg])*
CompiledNode::BuiltinOperator {
opcode: crate::OpCode::$kop,
args,
..
} => $kfn(args, $ctx, $engine, $arena, $kkind),
)*
}
};
}
#[inline(always)]
pub(super) fn dispatch_node_inner<'a>(
engine: &Engine,
node: &'a CompiledNode,
ctx: &mut ContextStack<'a>,
arena: &'a bumpalo::Bump,
) -> Result<&'a crate::arena::DataValue<'a>> {
dispatch! {
node: node,
ctx: ctx,
engine: engine,
arena: arena,
other: {
CompiledNode::Var {
scope_level,
segments,
reduce_hint,
metadata_hint,
default_value,
..
} => crate::operators::variable::evaluate_val_compiled(
crate::operators::variable::CompiledVarSpec {
scope_level: *scope_level,
segments,
reduce_hint: *reduce_hint,
metadata_hint: *metadata_hint,
default_value: default_value.as_deref(),
},
ctx,
engine,
arena,
),
#[cfg(feature = "ext-control")]
CompiledNode::Exists(data) => crate::operators::variable::evaluate_exists_compiled(
data.scope_level,
&data.segments,
ctx,
),
CompiledNode::Value { value, .. } => Ok(super::literal_fallback(value, arena)),
CompiledNode::Missing(data) => {
crate::operators::missing::evaluate_compiled_missing(data, ctx, engine, arena)
}
CompiledNode::MissingSome(data) => {
crate::operators::missing::evaluate_compiled_missing_some(data, ctx, engine, arena)
}
CompiledNode::InvalidArgs { op_name, .. } => {
Err(crate::Error::invalid_args().with_operator(*op_name))
}
#[cfg(feature = "error-handling")]
CompiledNode::Throw(data) => Err(Error::thrown(data.error.clone())),
#[cfg(feature = "templating")]
CompiledNode::StructuredObject(data) => {
evaluate_structured_object(data, ctx, engine, arena)
}
CompiledNode::Array { nodes, .. } => evaluate_array_literal(nodes, ctx, engine, arena),
CompiledNode::CustomOperator(data) => evaluate_custom_operator(data, ctx, engine, arena),
},
simple: [
Val => crate::operators::variable::evaluate_val,
#[cfg(feature = "ext-control")]
Exists => crate::operators::variable::evaluate_exists,
Merge => crate::operators::array::evaluate_merge,
Missing => crate::operators::missing::evaluate_missing,
MissingSome => crate::operators::missing::evaluate_missing_some,
#[cfg(feature = "ext-string")]
Length => crate::operators::array::evaluate_length,
#[cfg(feature = "ext-array")]
Slice => crate::operators::array::evaluate_slice,
Add => crate::operators::arithmetic::evaluate_add,
Multiply => crate::operators::arithmetic::evaluate_multiply,
Subtract => crate::operators::arithmetic::evaluate_subtract,
Equals => crate::operators::comparison::evaluate_equals,
StrictEquals => crate::operators::comparison::evaluate_strict_equals,
NotEquals => crate::operators::comparison::evaluate_not_equals,
StrictNotEquals => crate::operators::comparison::evaluate_strict_not_equals,
GreaterThan => crate::operators::comparison::evaluate_greater_than,
GreaterThanEqual => crate::operators::comparison::evaluate_greater_than_equal,
LessThan => crate::operators::comparison::evaluate_less_than,
LessThanEqual => crate::operators::comparison::evaluate_less_than_equal,
Not => crate::operators::logical::evaluate_not,
BoolCast => crate::operators::logical::evaluate_bool_cast,
And => crate::operators::logical::evaluate_and,
Or => crate::operators::logical::evaluate_or,
If => crate::operators::control::evaluate_if,
#[cfg(feature = "ext-control")]
Coalesce => crate::operators::control::evaluate_coalesce,
#[cfg(feature = "ext-control")]
Switch => crate::operators::control::evaluate_switch,
Concat => crate::operators::string::evaluate_concat,
Substr => crate::operators::string::evaluate_substr,
In => crate::operators::string::evaluate_in,
#[cfg(feature = "ext-string")]
StartsWith => crate::operators::string::evaluate_starts_with,
#[cfg(feature = "ext-string")]
EndsWith => crate::operators::string::evaluate_ends_with,
#[cfg(feature = "ext-string")]
Upper => crate::operators::string::evaluate_upper,
#[cfg(feature = "ext-string")]
Lower => crate::operators::string::evaluate_lower,
#[cfg(feature = "ext-string")]
Trim => crate::operators::string::evaluate_trim,
#[cfg(feature = "ext-string")]
Split => crate::operators::string::evaluate_split,
#[cfg(feature = "datetime")]
Datetime => crate::operators::datetime::evaluate_datetime,
#[cfg(feature = "datetime")]
Timestamp => crate::operators::datetime::evaluate_timestamp,
#[cfg(feature = "datetime")]
ParseDate => crate::operators::datetime::evaluate_parse_date,
#[cfg(feature = "datetime")]
FormatDate => crate::operators::datetime::evaluate_format_date,
#[cfg(feature = "datetime")]
DateDiff => crate::operators::datetime::evaluate_date_diff,
#[cfg(feature = "datetime")]
Now => crate::operators::datetime::evaluate_now,
#[cfg(feature = "ext-control")]
Type => crate::operators::inspect::evaluate_type,
#[cfg(feature = "error-handling")]
Throw => crate::operators::error_handling::evaluate_throw,
#[cfg(feature = "error-handling")]
Try => crate::operators::error_handling::evaluate_try,
#[cfg(feature = "flagd")]
Fractional => crate::operators::flagd::evaluate_fractional,
#[cfg(feature = "flagd")]
SemVer => crate::operators::flagd::evaluate_sem_ver,
],
iter: [
Filter => crate::operators::array::evaluate_filter,
Map => crate::operators::array::evaluate_map,
All => crate::operators::array::evaluate_all,
Some => crate::operators::array::evaluate_some,
None => crate::operators::array::evaluate_none,
Reduce => crate::operators::array::evaluate_reduce,
Max => crate::operators::arithmetic::evaluate_max,
Min => crate::operators::arithmetic::evaluate_min,
#[cfg(feature = "ext-array")]
Sort => crate::operators::array::evaluate_sort,
],
with_kind: [
Divide => (crate::operators::arithmetic::div_or_mod, crate::operators::arithmetic::DivOp::Divide),
Modulo => (crate::operators::arithmetic::div_or_mod, crate::operators::arithmetic::DivOp::Modulo),
#[cfg(feature = "ext-math")]
Abs => (crate::operators::arithmetic::unary_math, crate::operators::arithmetic::UnaryMathOp::Abs),
#[cfg(feature = "ext-math")]
Ceil => (crate::operators::arithmetic::unary_math, crate::operators::arithmetic::UnaryMathOp::Ceil),
#[cfg(feature = "ext-math")]
Floor => (crate::operators::arithmetic::unary_math, crate::operators::arithmetic::UnaryMathOp::Floor),
],
}
}
#[cfg(feature = "templating")]
#[inline(never)]
fn evaluate_structured_object<'a>(
data: &'a crate::node::StructuredObjectData,
ctx: &mut crate::arena::ContextStack<'a>,
engine: &super::Engine,
arena: &'a bumpalo::Bump,
) -> crate::Result<&'a crate::arena::DataValue<'a>> {
use crate::arena::DataValue;
if data.fields.is_empty() {
return Ok(crate::arena::singletons::singleton_empty_object());
}
let mut pairs: bumpalo::collections::Vec<'a, (&'a str, DataValue<'a>)> =
bumpalo::collections::Vec::with_capacity_in(data.fields.len(), arena);
for (key, n) in data.fields.iter() {
let val_av = engine.dispatch_node(n, ctx, arena)?;
let val_owned = *val_av;
let k: &'a str = arena.alloc_str(key);
pairs.push((k, val_owned));
}
Ok(arena.alloc(DataValue::Object(pairs.into_bump_slice())))
}
#[inline(never)]
fn evaluate_array_literal<'a>(
nodes: &'a [crate::CompiledNode],
ctx: &mut crate::arena::ContextStack<'a>,
engine: &super::Engine,
arena: &'a bumpalo::Bump,
) -> crate::Result<&'a crate::arena::DataValue<'a>> {
use crate::arena::DataValue;
if nodes.is_empty() {
return Ok(crate::arena::singletons::singleton_empty_array());
}
let mut items: bumpalo::collections::Vec<'a, DataValue<'a>> =
bumpalo::collections::Vec::with_capacity_in(nodes.len(), arena);
for n in nodes.iter() {
let av = engine.dispatch_node(n, ctx, arena)?;
items.push(*av);
}
Ok(arena.alloc(DataValue::Array(items.into_bump_slice())))
}
#[inline(never)]
fn evaluate_custom_operator<'a>(
data: &'a crate::node::CustomOperatorData,
ctx: &mut crate::arena::ContextStack<'a>,
engine: &super::Engine,
arena: &'a bumpalo::Bump,
) -> crate::Result<&'a crate::arena::DataValue<'a>> {
use crate::arena::DataValue;
let op = engine
.custom_operators
.get(&data.name)
.ok_or_else(|| Error::invalid_operator(data.name.clone()))?;
let mut args: bumpalo::collections::Vec<'a, &'a DataValue<'a>> =
bumpalo::collections::Vec::with_capacity_in(data.args.len(), arena);
for arg in data.args.iter() {
args.push(engine.dispatch_node(arg, ctx, arena)?);
}
let mut wrapped = crate::operator::EvalContext::new(ctx);
op.evaluate(&args, &mut wrapped, arena)
}