pub(crate) mod recursion;
use reblessive::tree::Stk;
use crate::ctx::FrozenContext;
use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::exe::FlowResultExt;
use crate::expr::idiom::Idiom;
use crate::expr::part::{Next, NextMethod};
use crate::expr::{Expr, FlowResult, Literal, Part};
use crate::val::{Number, Value};
pub(crate) async fn idiom_substitute_indices(
this: Idiom,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> anyhow::Result<Idiom> {
let mut out = Vec::with_capacity(this.0.len());
for part in this.0 {
let part = match part {
Part::Value(Expr::Literal(Literal::String(s))) => Part::Field(s),
Part::Value(Expr::Literal(lit)) => Part::Value(Expr::Literal(lit)),
Part::Value(expr) => {
let value = stk
.run(|stk| crate::legacy::expr_compute(&expr, stk, ctx, opt, doc))
.await
.catch_return()?;
match value {
Value::Number(Number::Int(i)) => {
Part::Value(Expr::Literal(Literal::Integer(i)))
}
Value::String(s) => Part::Field(s),
other => {
return Err(anyhow::anyhow!(
"Field path index must evaluate to an integer or string, found {}",
other.kind_of()
));
}
}
}
other => other,
};
out.push(part);
}
Ok(Idiom(out))
}
pub(crate) async fn idiom_compute(
this: &Idiom,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> FlowResult<Value> {
match this.first() {
Some(Part::Start(v)) => {
crate::legacy::value_get(
&stk.run(|stk| crate::legacy::expr_compute(v, stk, ctx, opt, doc)).await?,
stk,
ctx,
opt,
doc,
this.as_ref().next(),
)
.await
}
_ => match doc {
Some(v) => crate::legacy::value_get(v.doc.as_ref(), stk, ctx, opt, doc, this).await,
None => {
crate::legacy::value_get(&Value::None, stk, ctx, opt, doc, this.next_method()).await
}
},
}
}