use serde_json::Value;
use std::collections::HashMap;
use super::helpers::{check_invalid_args_marker, is_truthy};
use crate::trace::TraceCollector;
use crate::{CompiledNode, ContextStack, DataLogic, Result};
#[inline]
pub fn evaluate_if(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
) -> Result<Value> {
if args.is_empty() {
return Ok(Value::Null);
}
check_invalid_args_marker(args)?;
let mut i = 0;
while i < args.len() {
if i == args.len() - 1 {
return engine.evaluate_node(&args[i], context);
}
let condition = engine.evaluate_node_cow(&args[i], context)?;
if is_truthy(&condition, engine) {
if i + 1 < args.len() {
return engine.evaluate_node(&args[i + 1], context);
} else {
return Ok(condition.into_owned());
}
}
i += 2;
}
Ok(Value::Null)
}
#[inline(always)]
pub fn evaluate_ternary(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
) -> Result<Value> {
if args.len() < 3 {
return Ok(Value::Null);
}
let condition = engine.evaluate_node_cow(&args[0], context)?;
if is_truthy(&condition, engine) {
engine.evaluate_node(&args[1], context)
} else {
engine.evaluate_node(&args[2], context)
}
}
#[inline]
pub fn evaluate_coalesce(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
) -> Result<Value> {
if args.is_empty() {
return Ok(Value::Null);
}
for arg in args {
let value = engine.evaluate_node_cow(arg, context)?;
if *value != Value::Null {
return Ok(value.into_owned());
}
}
Ok(Value::Null)
}
#[inline]
pub fn evaluate_switch(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
) -> Result<Value> {
if args.len() < 2 {
return Ok(Value::Null);
}
let discriminant = engine.evaluate_node(&args[0], context)?;
match &args[1] {
CompiledNode::Array { nodes } => {
for case_node in nodes.iter() {
match case_node {
CompiledNode::Array { nodes: pair } if pair.len() >= 2 => {
let case_value = engine.evaluate_node(&pair[0], context)?;
if discriminant == case_value {
return engine.evaluate_node(&pair[1], context);
}
}
CompiledNode::Value {
value: Value::Array(pair),
} if pair.len() >= 2 => {
if discriminant == pair[0] {
return Ok(pair[1].clone());
}
}
_ => {}
}
}
}
CompiledNode::Value {
value: Value::Array(cases),
} => {
for case in cases {
if let Value::Array(pair) = case
&& pair.len() >= 2
&& discriminant == pair[0]
{
return Ok(pair[1].clone());
}
}
}
_ => {}
}
if args.len() > 2 {
return engine.evaluate_node(&args[2], context);
}
Ok(Value::Null)
}
#[inline(never)]
pub fn evaluate_if_traced(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
collector: &mut TraceCollector,
node_id_map: &HashMap<usize, u32>,
) -> Result<Value> {
if args.is_empty() {
return Ok(Value::Null);
}
check_invalid_args_marker(args)?;
let mut i = 0;
while i < args.len() {
if i == args.len() - 1 {
return engine.evaluate_node_traced(&args[i], context, collector, node_id_map);
}
let condition = engine.evaluate_node_traced(&args[i], context, collector, node_id_map)?;
if is_truthy(&condition, engine) {
if i + 1 < args.len() {
return engine.evaluate_node_traced(&args[i + 1], context, collector, node_id_map);
} else {
return Ok(condition);
}
}
i += 2;
}
Ok(Value::Null)
}
#[inline(never)]
pub fn evaluate_ternary_traced(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
collector: &mut TraceCollector,
node_id_map: &HashMap<usize, u32>,
) -> Result<Value> {
if args.len() < 3 {
return Ok(Value::Null);
}
let condition = engine.evaluate_node_traced(&args[0], context, collector, node_id_map)?;
if is_truthy(&condition, engine) {
engine.evaluate_node_traced(&args[1], context, collector, node_id_map)
} else {
engine.evaluate_node_traced(&args[2], context, collector, node_id_map)
}
}
#[inline(never)]
pub fn evaluate_coalesce_traced(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
collector: &mut TraceCollector,
node_id_map: &HashMap<usize, u32>,
) -> Result<Value> {
if args.is_empty() {
return Ok(Value::Null);
}
for arg in args {
let value = engine.evaluate_node_traced(arg, context, collector, node_id_map)?;
if value != Value::Null {
return Ok(value);
}
}
Ok(Value::Null)
}
#[inline(never)]
pub fn evaluate_switch_traced(
args: &[CompiledNode],
context: &mut ContextStack,
engine: &DataLogic,
collector: &mut TraceCollector,
node_id_map: &HashMap<usize, u32>,
) -> Result<Value> {
if args.len() < 2 {
return Ok(Value::Null);
}
let discriminant = engine.evaluate_node_traced(&args[0], context, collector, node_id_map)?;
match &args[1] {
CompiledNode::Array { nodes } => {
for case_node in nodes.iter() {
match case_node {
CompiledNode::Array { nodes: pair } if pair.len() >= 2 => {
let case_value = engine.evaluate_node_traced(
&pair[0],
context,
collector,
node_id_map,
)?;
if discriminant == case_value {
return engine.evaluate_node_traced(
&pair[1],
context,
collector,
node_id_map,
);
}
}
CompiledNode::Value {
value: Value::Array(pair),
} if pair.len() >= 2 => {
if discriminant == pair[0] {
return Ok(pair[1].clone());
}
}
_ => {}
}
}
}
CompiledNode::Value {
value: Value::Array(cases),
} => {
for case in cases {
if let Value::Array(pair) = case
&& pair.len() >= 2
&& discriminant == pair[0]
{
return Ok(pair[1].clone());
}
}
}
_ => {}
}
if args.len() > 2 {
return engine.evaluate_node_traced(&args[2], context, collector, node_id_map);
}
Ok(Value::Null)
}