use bumpalo::Bump;
use crate::arena::{ContextStack, DataValue};
use crate::node::{MetadataHint, PathSegment, ReduceHint};
use crate::{CompiledNode, Result};
#[cfg(feature = "ext-control")]
mod exists;
mod val;
#[cfg(feature = "ext-control")]
pub(crate) use exists::{evaluate_exists, evaluate_exists_compiled};
pub(crate) use val::{evaluate_val, evaluate_val_compiled};
#[inline]
fn metadata_hint_lookup<'a>(
ctx: &ContextStack<'a>,
path: &str,
arena: &'a Bump,
) -> Option<&'a DataValue<'a>> {
if path == "index" {
let idx = ctx.current().get_index()?;
let i = idx as i64;
return Some(
crate::arena::singletons::singleton_small_int(i).unwrap_or_else(|| {
arena.alloc(DataValue::Number(datavalue::NumberValue::Integer(i)))
}),
);
}
if path == "key" {
let key = ctx.current().get_key()?;
return Some(arena.alloc(DataValue::String(key)));
}
None
}
#[inline(always)]
fn current_data<'a>(ctx: &ContextStack<'a>, _arena: &'a Bump) -> &'a DataValue<'a> {
use crate::arena::context::ContextRef;
match ctx.current() {
ContextRef::Frame(f) => f.data(),
ContextRef::Root(av) => av,
}
}
#[inline]
fn frame_data_at_level<'a>(
ctx: &ContextStack<'a>,
level: isize,
_arena: &'a Bump,
) -> Option<&'a DataValue<'a>> {
use crate::arena::context::ContextRef;
let aref = ctx.get_at_level(level)?;
Some(match aref {
ContextRef::Frame(f) => f.data(),
ContextRef::Root(av) => av,
})
}
#[rustfmt::skip]
static SMALL_INT_STRS: [&str; 100] = [
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
];
#[inline]
pub(super) fn small_int_str(i: i64) -> Option<&'static str> {
if (0..100).contains(&i) {
Some(SMALL_INT_STRS[i as usize])
} else {
None
}
}
#[inline]
fn path_str_from_data<'a>(av: &'a DataValue<'a>, arena: &'a Bump) -> &'a str {
if let Some(s) = av.as_str() {
return s;
}
if let DataValue::Number(n) = av {
if let Some(i) = n.as_i64() {
if let Some(s) = small_int_str(i) {
return s;
}
}
return arena.alloc_str(&n.to_string());
}
""
}
pub(crate) struct CompiledVarSpec<'n> {
pub scope_level: u32,
pub segments: &'n [PathSegment],
pub reduce_hint: ReduceHint,
pub metadata_hint: MetadataHint,
pub default_value: Option<&'n CompiledNode>,
}
#[inline]
fn level_marker_from_array(av: &DataValue<'_>) -> Option<i64> {
match av {
DataValue::Array(items) if !items.is_empty() => items[0].as_i64(),
_ => None,
}
}
#[inline]
fn array_len(av: &DataValue<'_>) -> Option<usize> {
match av {
DataValue::Array(items) => Some(items.len()),
_ => None,
}
}
#[inline]
fn array_get<'a>(av: &'a DataValue<'a>, i: usize) -> Option<&'a DataValue<'a>> {
let DataValue::Array(items) = av else {
return None;
};
items.get(i)
}
#[inline]
fn default_or_null<'a>(
default_value: Option<&'a CompiledNode>,
ctx: &mut ContextStack<'a>,
engine: &crate::Engine,
arena: &'a Bump,
) -> Result<&'a DataValue<'a>> {
match default_value {
Some(node) => engine.dispatch_node(node, ctx, arena),
None => Ok(crate::arena::singletons::singleton_null()),
}
}