use super::*;
mod args;
mod collection;
mod lazy;
use args::{
emit_arg_eval, eval_array_arg_traced, eval_eager_op_traced, eval_expr_at_index_traced,
v1_operator_has_scoped_expr_args,
};
use collection::{eval_array_fold_traced, eval_array_map_traced, eval_array_reduce_traced};
use lazy::{eval_bool_and_or_traced, eval_coalesce_traced};
pub(super) fn eval_expr_traced(
expr: &Expr,
record: &JsonValue,
context: Option<&JsonValue>,
out: &JsonValue,
base_path: &str,
locals: Option<&EvalLocals<'_>>,
collector: &mut TraceCollector,
) -> Result<EvalValue, TransformError> {
collector
.start_span(TraceEventKind::ExprStart, TracePhase::Start)
.rule_path(base_path)
.finish(collector);
let result = match expr {
Expr::Literal(value) => {
let value = EvalValue::Value(value.clone());
collector
.emit(TraceEventKind::LiteralEval, TracePhase::Instant)
.rule_path(base_path)
.finish_with_eval_output(collector, &value, None);
Ok(value)
}
Expr::Ref(expr_ref) => {
let value = eval_ref(expr_ref, record, context, out, base_path, locals);
if let Ok(value) = &value {
collector
.emit(TraceEventKind::RefRead, TracePhase::Instant)
.rule_path(base_path)
.input_path(canonical_ref_path(&expr_ref.ref_path))
.finish_with_eval_output(collector, value, Some(&expr_ref.ref_path));
}
value
}
Expr::Op(expr_op) => {
collector
.start_span(TraceEventKind::OpStart, TracePhase::Start)
.rule_path(base_path)
.operator(&expr_op.op)
.finish(collector);
let op_result = match expr_op.op.as_str() {
"coalesce" => eval_coalesce_traced(
&expr_op.args,
None,
record,
context,
out,
base_path,
locals,
collector,
),
"and" => eval_bool_and_or_traced(
&expr_op.args,
None,
record,
context,
out,
base_path,
true,
locals,
collector,
),
"or" => eval_bool_and_or_traced(
&expr_op.args,
None,
record,
context,
out,
base_path,
false,
locals,
collector,
),
"map" => eval_array_map_traced(
&expr_op.args,
None,
record,
context,
out,
base_path,
locals,
collector,
),
"reduce" => eval_array_reduce_traced(
&expr_op.args,
None,
record,
context,
out,
base_path,
locals,
collector,
),
"fold" => eval_array_fold_traced(
&expr_op.args,
None,
record,
context,
out,
base_path,
locals,
collector,
),
op if v1_operator_has_scoped_expr_args(op) => {
eval_op(expr_op, record, context, out, base_path, None, locals)
}
_ => eval_eager_op_traced(
expr_op, record, context, out, base_path, locals, collector,
),
};
match op_result {
Ok(value) => {
collector
.end_span(TraceEventKind::OpEnd, TracePhase::End)
.rule_path(base_path)
.operator(&expr_op.op)
.finish_with_eval_output(collector, &value, None);
Ok(value)
}
Err(error) => {
collector
.error_span(TraceEventKind::OpError, "OP_ERROR", "operator failed")
.rule_path(base_path)
.operator(&expr_op.op)
.finish(collector);
Err(error)
}
}
}
Expr::Chain(expr_chain) => eval_chain(expr_chain, record, context, out, base_path, locals),
};
match &result {
Ok(value) => {
collector
.end_span(TraceEventKind::ExprEnd, TracePhase::End)
.rule_path(base_path)
.finish_with_eval_output(collector, value, None);
}
Err(_) => {
collector
.error_span(TraceEventKind::Error, "EXPR_ERROR", "expression failed")
.rule_path(base_path)
.finish(collector);
}
}
result
}