use super::prepared::ReadSlot;
use super::{
Budget, ConstructedValue, DeclaredType, Frame, KeyAxis, KeyedEntry, Located, Location,
PreparedArgument, PreparedArguments, PreparedGenerator, PreparedKind, PreparedValue,
QueryError, RuntimeValue, SetElementType, ValueBinaryOperator, ValueConstructor, ValueKey,
ValueQueryHost, admit_container, admit_diagnostic, allocation, annotate, binary, boolean,
constructed_value_type, copy_axes, copy_constructed_value, copy_declaration, entries,
equal_keys, error, expose, extremum_position, finish_keyed, group_by, insert_set, integer,
integer_range, key_positions, key_set_type, key_value, metadata_vec, optional_access,
push_metadata, record_declaration, reduce_ref, scalar, sort_value, source_axis,
string_match_ref, sum, take_one, take_position, tally_value, unary, underlying, unique_value,
value_keys, zip_exact,
};
use crate::construction::EntryAccounting;
use std::rc::Rc;
pub(crate) struct Body<'a, Q, K> {
pub declaration: crate::functions::DeclarationRef<'a, Q, K>,
pub bindings: Vec<(&'a str, PreparedValue<'a, Q>)>,
pub value: PreparedValue<'a, Q>,
}
#[derive(Clone)]
pub(crate) enum NativeStep {
Record(usize),
Tuple(usize),
List(usize),
Constructed(usize),
Declaration(std::sync::Arc<DeclaredType<()>>),
}
impl NativeStep {
pub fn index(&self) -> usize {
match self {
Self::Record(i) | Self::Tuple(i) | Self::List(i) | Self::Constructed(i) => *i,
Self::Declaration(_) => unreachable!("declaration is not a child selector"),
}
}
}
pub(crate) struct NativeView<N> {
pub owner: std::sync::Arc<N>,
pub path: Vec<NativeStep>,
}
impl<N> NativeView<N> {
pub fn new(owner: std::sync::Arc<N>) -> Self {
Self {
owner,
path: Vec::new(),
}
}
pub fn child(
&self,
step: NativeStep,
budget: &mut Budget,
location: &Location,
) -> Result<Self, QueryError> {
let len = self.path.len()
- usize::from(matches!(self.path.last(), Some(NativeStep::Declaration(_))));
let mut path = metadata_vec(len + 1, budget, location)?;
path.extend_from_slice(&self.path[..len]);
path.push(step);
Ok(Self {
owner: std::sync::Arc::clone(&self.owner),
path,
})
}
pub fn share(&self, budget: &mut Budget, location: &Location) -> Result<Self, QueryError> {
let mut path = metadata_vec(self.path.len(), budget, location)?;
path.extend_from_slice(&self.path);
budget.charge(1, location.clone())?;
Ok(Self {
owner: std::sync::Arc::clone(&self.owner),
path,
})
}
pub fn retain_declaration(
&mut self,
declaration: std::sync::Arc<DeclaredType<()>>,
budget: &mut Budget,
location: &Location,
) -> Result<(), QueryError> {
budget.charge(1, location.clone())?;
if let Some(NativeStep::Declaration(old)) = self.path.last_mut() {
*old = declaration;
} else {
push_metadata(
&mut self.path,
NativeStep::Declaration(declaration),
budget,
location,
)?;
}
Ok(())
}
pub fn native<'v>(
&'v self,
record: impl Fn(&'v N) -> Option<&'v crate::NativeCapture<N>>,
tuple: impl Fn(&'v N) -> Option<&'v [N]>,
list: impl Fn(&'v N) -> Option<&'v [N]>,
) -> &'v N {
let mut native = self.owner.as_ref();
for step in &self.path {
native = match step {
NativeStep::Record(i) => {
&record(native).expect("retained record view").fields[*i].1
}
NativeStep::Tuple(i) => &tuple(native).expect("retained tuple view")[*i],
NativeStep::List(i) => &list(native).expect("retained list view")[*i],
_ => break,
};
}
native
}
pub fn constructed<'v>(
&'v self,
constructed: impl Fn(&'v N) -> Option<&'v ConstructedValue>,
record: impl Fn(&'v N) -> Option<&'v crate::NativeCapture<N>>,
tuple: impl Fn(&'v N) -> Option<&'v [N]>,
list: impl Fn(&'v N) -> Option<&'v [N]>,
budget: &mut Budget,
location: &Location,
) -> Result<Option<ConstructedRef<'v>>, QueryError> {
budget.charge(self.path.len(), location.clone())?;
let native = self.native(record, tuple, list);
let Some(value) = constructed(native) else {
return Ok(None);
};
let mut data = ConstructedRef {
value,
declaration: super::declaration(value),
};
budget.charge(self.path.len(), location.clone())?;
for step in &self.path {
match step {
NativeStep::Constructed(i) => data = data.child(*i, budget, location)?,
NativeStep::Declaration(d) => data.declaration = Some(d),
_ => {}
}
}
Ok(Some(data))
}
}
pub(crate) enum Data<N> {
Constructed(RuntimeValue),
Native(NativeView<N>),
}
pub(crate) struct Value<'a, N, K> {
pub data: Data<N>,
pub contract: Option<&'a DeclaredType<K>>,
}
impl<'a, N, K> Value<'a, N, K> {
pub fn constructed(value: RuntimeValue) -> Self {
Self {
data: Data::Constructed(value),
contract: None,
}
}
pub fn share(&mut self, budget: &mut Budget, location: &Location) -> Result<Self, QueryError> {
let data = match &mut self.data {
Data::Constructed(value) => Data::Constructed(value.share(budget, location)?),
Data::Native(value) => Data::Native(value.share(budget, location)?),
};
Ok(Self {
data,
contract: self.contract,
})
}
fn scalar(&self, location: &Location) -> Result<&ConstructedValue, QueryError> {
match &self.data {
Data::Constructed(value) => Ok(value.as_ref()),
Data::Native(_) => Err(error(
location,
"native handles require an explicit scalar projection; computational values cannot be rendered as data",
)),
}
}
pub fn materialize(
self,
budget: &mut Budget,
location: &Location,
) -> Result<ConstructedValue, QueryError> {
match self.data {
Data::Constructed(value) => {
let value = value.materialize(budget, location)?;
if let Some(contract) = self.contract {
if crate::runtime_types::contains_native(contract, budget, location)? {
Ok(value)
} else {
annotate(
value,
crate::runtime_types::constructed_declaration(
contract, budget, location,
)?,
budget,
location,
)
}
} else {
Ok(value)
}
}
Data::Native(_) => Err(error(
location,
"native handles require an explicit scalar projection; computational values cannot be rendered as data",
)),
}
}
pub fn materialize_with<Q, H: Host<'a, Q, Native = N, Kind = K> + ?Sized>(
self,
host: &H,
budget: &mut Budget,
location: &Location,
) -> Result<ConstructedValue, QueryError> {
host.materialize(self, budget, location)
}
}
type Slots<'a, N, K> = [(&'a str, Value<'a, N, K>)];
pub(crate) struct ConstructedRef<'v> {
pub value: &'v ConstructedValue,
pub declaration: Option<&'v DeclaredType<()>>,
}
impl<'v> ConstructedRef<'v> {
pub fn child(
&self,
index: usize,
budget: &mut Budget,
location: &Location,
) -> Result<Self, QueryError> {
let data = self.value.data();
let declaration = match (self.declaration.map(underlying), data) {
(Some(DeclaredType::Tuple(children)), _) => children.get(index),
(Some(DeclaredType::Record(fields)), ConstructedValue::Record(values)) => Some(
record_declaration(fields, &values[index].0, budget, location)?,
),
(
Some(
DeclaredType::Array(child)
| DeclaredType::Sequence(child)
| DeclaredType::Keyed(child),
),
_,
) => Some(child.as_ref()),
_ => None,
};
let value = match data {
ConstructedValue::Record(fields) => &fields[index].1,
ConstructedValue::Array(values)
| ConstructedValue::Tuple(values)
| ConstructedValue::Set {
elements: values, ..
} => &values[index],
ConstructedValue::KeyedArray { entries, .. } => &entries[index].value,
_ => unreachable!("selected constructed child"),
};
Ok(Self {
value,
declaration: super::declaration(value).or(declaration),
})
}
pub fn materialize(
&self,
budget: &mut Budget,
location: &Location,
) -> Result<ConstructedValue, QueryError> {
let value = copy_constructed_value(self.value, budget, location.clone())?;
match self.declaration {
Some(d) => annotate(
value,
copy_declaration(d, budget, location)?,
budget,
location,
),
None => Ok(value),
}
}
}
pub(crate) trait Host<'a, Q> {
type Native;
type Kind: PartialEq;
type Error: From<QueryError>;
fn native_constructed<'v>(&self, _value: &'v Self::Native) -> Option<&'v ConstructedValue> {
None
}
fn constructed<'v>(
&self,
value: &'v Value<'a, Self::Native, Self::Kind>,
budget: &mut Budget,
location: &Location,
) -> Result<Option<ConstructedRef<'v>>, QueryError> {
match &value.data {
Data::Constructed(data) => Ok(Some(ConstructedRef {
value: data.as_ref(),
declaration: data.declaration(),
})),
Data::Native(view) => view.constructed(
|v| self.native_constructed(v),
|v| self.native_record(v),
|v| self.native_tuple(v),
|v| self.native_list(v),
budget,
location,
),
}
}
fn scalar<'v>(
&self,
value: &'v Value<'a, Self::Native, Self::Kind>,
budget: &mut Budget,
location: &Location,
) -> Result<&'v ConstructedValue, QueryError> {
self.constructed(value, budget, location)?
.map(|v| v.value)
.ok_or_else(|| error(location, "native handles require an explicit scalar projection; computational values cannot be rendered as data"))
}
fn occurs(
&self,
value: &Value<'a, Self::Native, Self::Kind>,
budget: &mut Budget,
location: &Location,
) -> Result<bool, QueryError> {
Ok(self
.constructed(value, budget, location)?
.is_none_or(|v| v.value.occurs()))
}
fn normalize_in_place(
&self,
value: &mut Value<'a, Self::Native, Self::Kind>,
budget: &mut Budget,
location: &Location,
) -> Result<(), QueryError> {
if matches!(value.data, Data::Native(_))
&& let Some(data) = self.constructed(value, budget, location)?
{
value.data =
Data::Constructed(RuntimeValue::Owned(data.materialize(budget, location)?));
}
Ok(())
}
fn normalize(
&self,
mut value: Value<'a, Self::Native, Self::Kind>,
budget: &mut Budget,
location: &Location,
) -> Result<Value<'a, Self::Native, Self::Kind>, QueryError> {
self.normalize_in_place(&mut value, budget, location)?;
Ok(value)
}
fn materialize(
&self,
value: Value<'a, Self::Native, Self::Kind>,
budget: &mut Budget,
location: &Location,
) -> Result<ConstructedValue, QueryError> {
self.normalize(value, budget, location)?
.materialize(budget, location)
}
fn native_record<'v>(
&self,
_value: &'v Self::Native,
) -> Option<&'v crate::NativeCapture<Self::Native>> {
None
}
fn native_tuple<'v>(&self, _value: &'v Self::Native) -> Option<&'v [Self::Native]> {
None
}
fn native_list<'v>(&self, _value: &'v Self::Native) -> Option<&'v [Self::Native]> {
None
}
fn native_data<'v>(
&self,
value: &'v NativeView<Self::Native>,
budget: &mut Budget,
location: &Location,
) -> Result<&'v Self::Native, QueryError> {
budget.charge(value.path.len(), location.clone())?;
let data = value.native(
|v| self.native_record(v),
|v| self.native_tuple(v),
|v| self.native_list(v),
);
Ok(data)
}
fn inspect_pattern(
&mut self,
_value: &Value<'a, Self::Native, Self::Kind>,
_budget: &mut Budget,
_location: &Location,
) -> Result<(), Self::Error> {
Ok(())
}
fn check_native_context(
&mut self,
_value: &Self::Native,
_expected: &DeclaredType<Self::Kind>,
_budget: &mut Budget,
_location: &Location,
) -> Result<(), Self::Error> {
Ok(())
}
fn apply(
&mut self,
expression: &'a PreparedValue<'a, Q>,
values: Vec<Value<'a, Self::Native, Self::Kind>>,
budget: &mut Budget,
) -> Result<Value<'a, Self::Native, Self::Kind>, Self::Error> {
apply(expression, values, self, budget)
}
fn retains_native_admission(&self) -> bool {
false
}
fn current_input(
&mut self,
_budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, Self::Kind>, Self::Error> {
Err(QueryError::query(range.clone(), "constructed current input is unavailable").into())
}
fn predicate_subject(
&mut self,
_budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, Self::Kind>, Self::Error> {
Err(QueryError::query(
range.clone(),
"unnamed argument is only available in a predicate",
)
.into())
}
fn outer(
&mut self,
slot: usize,
name: &str,
budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, Self::Kind>, Self::Error>;
#[expect(
clippy::too_many_arguments,
reason = "A native callback borrows the active request, explicit scope and argument continuations"
)]
fn native(
&mut self,
query: &'a Q,
arguments: &'a [PreparedArgument<'a, Q>],
locals: &mut Slots<'a, Self::Native, Self::Kind>,
bodies: &'a [Body<'a, Q, Self::Kind>],
depth: usize,
function: Option<usize>,
projected: bool,
budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, Self::Kind>, Self::Error>;
fn admit_native(
&mut self,
value: &Self::Native,
expected: &DeclaredType<Self::Kind>,
budget: &mut Budget,
location: Location,
) -> Result<(), Self::Error>;
fn sequence_items(
&mut self,
_value: NativeView<Self::Native>,
_element: &DeclaredType<Self::Kind>,
_budget: &mut Budget,
location: &Location,
) -> Result<Vec<ResultValue<'a, Self, Q>>, Self::Error> {
Err(error(location, "native positional sequences are unsupported").into())
}
fn finish_sequence(
&mut self,
values: Vec<Value<'a, Self::Native, Self::Kind>>,
element: &'a DeclaredType<Self::Kind>,
budget: &mut Budget,
location: &Location,
) -> Result<Value<'a, Self::Native, Self::Kind>, Self::Error> {
Ok(constructed_sequence(
values, element, self, budget, location,
)?)
}
fn native_contract(
&mut self,
_value: &Self::Native,
_budget: &mut Budget,
location: &Location,
) -> Result<DeclaredType<Self::Kind>, Self::Error> {
Err(error(location, "loop state needs an established native contract").into())
}
fn subjects(
&mut self,
_value: NativeView<Self::Native>,
_budget: &mut Budget,
location: &Location,
) -> Result<Vec<Self::Native>, Self::Error> {
Err(error(location, "in source needs an array or supported set").into())
}
fn check(
&mut self,
value: &ConstructedValue,
budget: &mut Budget,
location: &Location,
) -> Result<(), QueryError>;
fn failure(&mut self, _calls: &[(usize, std::ops::Range<usize>)], _omitted: usize) {}
}
struct Activation<'a, N, K> {
function: Option<usize>,
range: std::ops::Range<usize>,
base: usize,
locals: Vec<(&'a str, Value<'a, N, K>)>,
names: &'a [&'a str],
return_contract: Option<&'a DeclaredType<K>>,
}
type ResultValue<'a, H, Q> = Value<'a, <H as Host<'a, Q>>::Native, <H as Host<'a, Q>>::Kind>;
type ResultSource<'a, H, Q> =
GeneratorSource<'a, <H as Host<'a, Q>>::Native, <H as Host<'a, Q>>::Kind>;
enum Pending<'a, Q, N, K> {
Eval(&'a PreparedValue<'a, Q>, usize, bool),
Check(&'a PreparedValue<'a, Q>, usize),
Apply(
&'a PreparedValue<'a, Q>,
usize,
Vec<&'a PreparedValue<'a, Q>>,
Vec<Value<'a, N, K>>,
),
Initialize(
&'a PreparedValue<'a, Q>,
usize,
usize,
bool,
Vec<Value<'a, N, K>>,
),
Loop(Loop<'a, Q, K>),
Break(&'a PreparedValue<'a, Q>, usize),
Next(&'a PreparedValue<'a, Q>, usize, Vec<Value<'a, N, K>>),
Branch(&'a PreparedValue<'a, Q>, usize, usize, bool),
Block(&'a PreparedValue<'a, Q>, usize, usize, bool),
Match(
&'a PreparedValue<'a, Q>,
usize,
usize,
bool,
Option<Value<'a, N, K>>,
),
Guard(
&'a PreparedValue<'a, Q>,
usize,
usize,
bool,
usize,
Value<'a, N, K>,
),
Require(&'a PreparedValue<'a, Q>, usize, bool),
Default(&'a PreparedValue<'a, Q>, usize, bool),
Fallback(&'a PreparedValue<'a, Q>, usize, Value<'a, N, K>),
Call(
&'a PreparedValue<'a, Q>,
usize,
usize,
bool,
Vec<Value<'a, N, K>>,
),
Invoke {
expression: &'a PreparedValue<'a, Q>,
function: usize,
arguments: Vec<Value<'a, N, K>>,
ranges: Vec<&'a std::ops::Range<usize>>,
tail: bool,
return_contract: Option<&'a DeclaredType<K>>,
},
AccumulatorItems(&'a PreparedValue<'a, Q>, usize),
AccumulatorInitial(&'a PreparedValue<'a, Q>, usize, Value<'a, N, K>),
AccumulatorStep(&'a PreparedValue<'a, Q>, usize, Accumulator<'a, N, K>),
Set(
&'a PreparedValue<'a, Q>,
usize,
usize,
Vec<ConstructedValue>,
Option<SetElementType>,
),
DictionaryKey(
&'a PreparedValue<'a, Q>,
usize,
usize,
Vec<(String, ConstructedValue)>,
),
DictionaryValue(
&'a PreparedValue<'a, Q>,
usize,
usize,
Vec<(String, ConstructedValue)>,
String,
),
DeclaredAxes(&'a PreparedValue<'a, Q>, usize, usize, Vec<KeyAxis>),
KeyedKey(
&'a PreparedValue<'a, Q>,
usize,
usize,
Option<Vec<KeyAxis>>,
Vec<Located<KeyedEntry>>,
),
KeyedValue(
&'a PreparedValue<'a, Q>,
usize,
usize,
Option<Vec<KeyAxis>>,
Vec<Located<KeyedEntry>>,
Vec<ValueKey>,
),
Let(usize, usize),
Return(usize),
Predicate(&'a PreparedValue<'a, Q>, usize, usize),
PredicateResult(&'a PreparedValue<'a, Q>, usize),
Clauses(Rc<Comprehension<'a, Q>>, usize, usize),
Source(Rc<Comprehension<'a, Q>>, usize, usize),
Candidate(
Rc<Comprehension<'a, Q>>,
usize,
usize,
GeneratorSource<'a, N, K>,
Vec<usize>,
usize,
),
Filter(Rc<Comprehension<'a, Q>>, usize, usize),
Restore(usize),
Head(Rc<Comprehension<'a, Q>>),
KeyHead(Rc<Comprehension<'a, Q>>, Vec<ValueKey>),
DictionaryHead(Rc<Comprehension<'a, Q>>, String),
FinishComprehension(Rc<Comprehension<'a, Q>>),
EmptyAxes(Rc<Comprehension<'a, Q>>, usize, Vec<KeyAxis>),
}
struct Accumulator<'a, N, K> {
source: GeneratorSource<'a, N, K>,
index: usize,
snapshots: Vec<Value<'a, N, K>>,
}
struct Loop<'a, Q, K> {
expression: &'a PreparedValue<'a, Q>,
depth: usize,
tail: bool,
saved: usize,
contracts: Vec<StateContract<'a, K>>,
}
enum StateContract<'a, K> {
Borrowed(&'a DeclaredType<K>),
Constructed(std::sync::Arc<DeclaredType<()>>),
Native(DeclaredType<K>),
}
enum GeneratorSource<'a, N, K> {
Constructed(RuntimeValue),
Native(Vec<Value<'a, N, K>>),
}
impl<'a, N, K> GeneratorSource<'a, N, K> {
fn len(&self) -> usize {
match self {
Self::Constructed(value) => match value.as_ref() {
ConstructedValue::Array(values)
| ConstructedValue::Set {
elements: values, ..
} => values.len(),
ConstructedValue::KeyedArray { entries, .. } => entries.len(),
_ => unreachable!("admitted generator source"),
},
Self::Native(values) => values.len(),
}
}
fn child(
&mut self,
position: usize,
budget: &mut Budget,
location: &Location,
) -> Result<Value<'a, N, K>, QueryError> {
match self {
Self::Constructed(value) => Ok(Value::constructed(
value
.share(budget, location)?
.child(position, budget, location)?,
)),
Self::Native(values) => values[position].share(budget, location),
}
}
}
struct Comprehension<'a, Q> {
expression: &'a PreparedValue<'a, Q>,
clauses: &'a [Located<PreparedGenerator<'a, Q>>],
key: Option<&'a PreparedValue<'a, Q>>,
head: &'a PreparedValue<'a, Q>,
empty: Option<&'a [PreparedValue<'a, Q>]>,
depth: usize,
output: std::cell::RefCell<Output>,
declaration: std::cell::RefCell<Option<DeclaredType<()>>>,
}
enum Output {
Array(Vec<ConstructedValue>),
Set(Vec<ConstructedValue>, Option<SetElementType>),
Keyed(Option<Vec<KeyAxis>>, Vec<Located<KeyedEntry>>),
Dictionary(Vec<(String, ConstructedValue)>),
}
pub(crate) fn execute<'a, Q, H: Host<'a, Q>>(
entry: &'a PreparedValue<'a, Q>,
names: &'a [&'a str],
bodies: &'a [Body<'a, Q, H::Kind>],
host: &mut H,
budget: &mut Budget,
limit: usize,
offset: usize,
) -> Result<ResultValue<'a, H, Q>, H::Error> {
let location = Location::Query(entry.range.clone());
budget.within_evaluation(0, location.clone(), |budget| {
let mut pending = metadata_vec(1, budget, &location)?;
pending.push(Pending::Eval(entry, 1, false));
let mut frames = metadata_vec(1, budget, &location)?;
frames.push(Activation {
function: None,
range: entry.range.clone(),
base: 0,
locals: Vec::new(),
names,
return_contract: None,
});
let mut result: Option<ResultValue<'a, H, Q>> = None;
let outcome = (|| {
while let Some(next) = pending.pop() {
let frame_depth = frames.len();
let frame = frames.last().expect("active expression scope");
let location = match &next {
Pending::Eval(e, ..)
| Pending::Check(e, ..)
| Pending::Apply(e, ..)
| Pending::Initialize(e, ..)
| Pending::Break(e, ..)
| Pending::Next(e, ..)
| Pending::Block(e, ..)
| Pending::Match(e, ..)
| Pending::Guard(e, ..)
| Pending::Branch(e, ..)
| Pending::Require(e, ..)
| Pending::Default(e, ..)
| Pending::Fallback(e, ..)
| Pending::Call(e, ..)
| Pending::AccumulatorItems(e, ..)
| Pending::AccumulatorInitial(e, ..)
| Pending::AccumulatorStep(e, ..)
| Pending::Invoke { expression: e, .. }
| Pending::Set(e, ..)
| Pending::DictionaryKey(e, ..)
| Pending::DictionaryValue(e, ..)
| Pending::DeclaredAxes(e, ..)
| Pending::KeyedKey(e, ..)
| Pending::KeyedValue(e, ..) => Location::Query(e.range.clone()),
Pending::Loop(state) => Location::Query(state.expression.range.clone()),
_ => Location::Query(frame.range.clone()),
};
let depth = match &next {
Pending::Eval(_, depth, _)
| Pending::Check(_, depth)
| Pending::Apply(_, depth, ..)
| Pending::Initialize(_, depth, ..)
| Pending::Break(_, depth)
| Pending::Next(_, depth, ..)
| Pending::Predicate(_, depth, ..)
| Pending::Block(_, depth, ..)
| Pending::Match(_, depth, ..)
| Pending::Guard(_, depth, ..)
| Pending::Branch(_, depth, ..)
| Pending::Require(_, depth, _)
| Pending::Default(_, depth, _)
| Pending::Fallback(_, depth, _)
| Pending::Call(_, depth, ..)
| Pending::AccumulatorItems(_, depth)
| Pending::AccumulatorInitial(_, depth, ..)
| Pending::AccumulatorStep(_, depth, ..)
| Pending::Set(_, depth, ..)
| Pending::DictionaryKey(_, depth, ..)
| Pending::DictionaryValue(_, depth, ..)
| Pending::DeclaredAxes(_, depth, ..)
| Pending::KeyedKey(_, depth, ..)
| Pending::KeyedValue(_, depth, ..) => *depth,
Pending::Clauses(c, index, _)
| Pending::Source(c, index, _)
| Pending::Candidate(c, index, ..)
| Pending::Filter(c, index, _) => c.depth + index + 1,
Pending::Head(c) | Pending::KeyHead(c, _) | Pending::DictionaryHead(c, _) => {
c.depth + c.clauses.len()
}
Pending::FinishComprehension(c) | Pending::EmptyAxes(c, ..) => c.depth,
Pending::Loop(state) => state.depth,
Pending::Let(..)
| Pending::Return(_)
| Pending::Restore(_)
| Pending::PredicateResult(_, _)
| Pending::Invoke { .. } => 0,
};
budget.within_evaluation(
depth,
location.clone(),
|budget| -> Result<(), H::Error> {
let frame = frames.last_mut().expect("active expression scope");
macro_rules! push {
($v:expr) => {
push_metadata(&mut pending, $v, budget, &location)?
};
}
macro_rules! owned {
($v:expr) => {
Some(Value::constructed(RuntimeValue::Owned($v)))
};
}
match next {
Pending::Eval(expression, depth, tail) => {
budget.charge(1, location.clone())?;
push!(Pending::Check(expression, depth));
match &expression.value {
PreparedKind::Literal(value) => {
result =
owned!(copy_constructed_value(value, budget, location)?)
}
PreparedKind::PredicateSubject => {
result = Some(
host.predicate_subject(budget, &expression.range)?,
);
}
PreparedKind::CurrentInput => {
result =
Some(host.current_input(budget, &expression.range)?);
}
PreparedKind::Name(ReadSlot::Local(index)) => {
result =
Some(frame.locals[*index].1.share(budget, &location)?)
}
PreparedKind::Name(ReadSlot::Outer(index)) => {
result = Some(host.outer(
*index,
frame.names[*index],
budget,
&expression.range,
)?)
}
PreparedKind::NativeQuery { query, arguments }
| PreparedKind::NativeValue { query, arguments } => {
result = Some(host.native(
query,
arguments,
&mut frame.locals,
bodies,
offset + frame_depth - 1,
frame.function,
matches!(
expression.value,
PreparedKind::NativeQuery { .. }
),
budget,
&expression.range,
)?);
}
PreparedKind::SubjectScope { subject, .. } => {
push!(Pending::Predicate(
expression,
depth,
frame.locals.len()
));
push!(Pending::Eval(subject, depth + 1, false));
}
PreparedKind::IdentitySet { .. } => {
result =
Some(host.apply(expression, Vec::new(), budget)?);
}
PreparedKind::Call { arguments, .. } => {
let values =
metadata_vec(arguments.len(), budget, &location)?;
push!(Pending::Call(expression, depth, 0, tail, values));
if let Some(first) = arguments.first() {
push!(Pending::Eval(first, depth + 1, false));
}
}
PreparedKind::Accumulate { items, .. } => {
push!(Pending::AccumulatorItems(expression, depth));
push!(Pending::Eval(items, depth + 1, false));
}
PreparedKind::Loop { .. }
| PreparedKind::Break(_)
| PreparedKind::Continue(_) => {
enter_loop(
expression,
depth,
tail,
frame.base,
&mut pending,
budget,
&location,
)?;
}
PreparedKind::Block { .. } => {
push!(Pending::Restore(frame.locals.len()));
push!(Pending::Block(expression, depth, 0, tail));
}
PreparedKind::ValueMatch { subject, .. } => {
push!(Pending::Match(expression, depth, 0, tail, None));
push!(Pending::Eval(subject, depth + 1, false));
}
PreparedKind::Conditional {
branches,
otherwise,
} => {
if let Some((condition, _)) = branches.first() {
push!(Pending::Branch(expression, depth, 0, tail));
push!(Pending::Eval(condition, depth + 1, false));
} else {
push!(Pending::Eval(otherwise, depth + 1, tail));
}
}
PreparedKind::Require { condition, .. } => {
push!(Pending::Require(expression, depth, tail));
push!(Pending::Eval(condition, depth + 1, false));
}
PreparedKind::Default { value, .. } => {
push!(Pending::Default(expression, depth, tail));
push!(Pending::Eval(value, depth + 1, false));
}
PreparedKind::Set(children) => {
let values =
admit_container(children.len(), budget, &location)?;
if let Some(child) = children.first() {
push!(Pending::Set(expression, depth, 0, values, None));
push!(Pending::Eval(child, depth + 1, false));
} else {
result = owned!(ConstructedValue::Set {
element_type: None,
elements: values
});
}
}
PreparedKind::Dictionary(_)
| PreparedKind::DictionaryComprehension { .. } => {
start_dictionary(
expression,
depth,
frame.locals.len(),
&mut pending,
&mut result,
budget,
)?;
}
PreparedKind::KeyedArray { .. }
| PreparedKind::KeyedComprehension { .. } => {
if let Some(sources) = declared_axis_sources(expression) {
let axes =
admit_container(sources.len(), budget, &location)?;
let source = sources.first().ok_or_else(|| {
error(&location, "axis sources need nonzero rank")
})?;
push!(Pending::DeclaredAxes(
expression, depth, 0, axes
));
push!(Pending::Eval(source, depth + 1, false));
} else {
let axes = match &expression.value {
PreparedKind::KeyedArray { axes, .. } => axes
.map(|axes| copy_axes(axes, budget, &location))
.transpose()?,
_ => None,
};
start_keyed(
expression,
depth,
frame.locals.len(),
axes,
&mut pending,
&mut result,
budget,
)?;
}
}
PreparedKind::Comprehension {
constructor,
clauses,
head,
..
} => {
let output = match constructor {
ValueConstructor::Array => Output::Array(
admit_container(0, budget, &location)?,
),
ValueConstructor::Set => Output::Set(
admit_container(0, budget, &location)?,
None,
),
};
let c = Rc::new(Comprehension {
expression,
clauses,
key: None,
head,
empty: None,
depth,
output: std::cell::RefCell::new(output),
declaration: std::cell::RefCell::new(None),
});
push!(Pending::FinishComprehension(Rc::clone(&c)));
push!(Pending::Clauses(c, 0, frame.locals.len()));
}
_ => {
let children = operands(expression, budget, &location)?;
let values =
metadata_vec(children.len(), budget, &location)?;
let first = children.first().copied();
push!(Pending::Apply(expression, depth, children, values));
if let Some(first) = first {
push!(Pending::Eval(first, depth + 1, false));
}
}
}
}
Pending::Check(expression, _) => {
if let Some(Value {
data: Data::Constructed(value),
..
}) = &result
{
host.check(
value.as_ref(),
budget,
&Location::Query(expression.range.clone()),
)?;
}
}
Pending::Apply(expression, depth, children, mut values) => {
if !children.is_empty() {
let value = result.take().expect("operand result");
let shared = matches!(
expression.value,
PreparedKind::Queue { .. }
| PreparedKind::PopFront(_)
| PreparedKind::PushBackAll { .. }
| PreparedKind::Insert { .. }
| PreparedKind::Array(_)
| PreparedKind::Tuple(_)
| PreparedKind::TupleAccess { .. }
| PreparedKind::Binary {
operator: ValueBinaryOperator::In,
..
}
| PreparedKind::Field { .. }
| PreparedKind::ArrayAccess { .. }
| PreparedKind::Occurs(_)
| PreparedKind::Absent(_)
| PreparedKind::Reduce { .. }
| PreparedKind::Binary {
operator: ValueBinaryOperator::Contains
| ValueBinaryOperator::StartsWith
| ValueBinaryOperator::EndsWith,
..
}
| PreparedKind::Extremum { .. }
);
let value = if values.is_empty()
&& matches!(expression.value, PreparedKind::Range { .. })
{
Value::constructed(RuntimeValue::Owned(
ConstructedValue::Integer(integer(
value.materialize_with(host, budget, &location)?,
&location,
)?),
))
} else {
value
};
values.push(if shared {
value
} else {
Value::constructed(RuntimeValue::Owned(
value.materialize_with(host, budget, &location)?,
))
});
}
if values.len() == 1
&& let PreparedKind::Binary {
operator:
operator @ (ValueBinaryOperator::And
| ValueBinaryOperator::Or),
..
} = expression.value
{
let a = match values[0].scalar(&location)?.data() {
ConstructedValue::Boolean(a) => *a,
_ => {
return Err(error(
&location,
"condition needs a fixed Boolean",
)
.into());
}
};
if (operator == ValueBinaryOperator::And && !a)
|| (operator == ValueBinaryOperator::Or && a)
{
result = owned!(scalar(
ConstructedValue::Boolean(a),
budget,
&location
)?);
return Ok(());
}
}
if values.len() < children.len() {
let next = children[values.len()];
push!(Pending::Apply(expression, depth, children, values));
push!(Pending::Eval(next, depth + 1, false));
} else {
result = Some(host.apply(expression, values, budget)?);
}
}
next @ (Pending::Initialize(..)
| Pending::Loop(_)
| Pending::Break(..)
| Pending::Next(..)) => {
loop_step(
next,
&mut pending,
frame,
&mut result,
host,
budget,
&location,
)?;
}
Pending::Branch(expression, depth, index, tail) => {
let PreparedKind::Conditional {
branches,
otherwise,
} = &expression.value
else {
unreachable!()
};
if boolean(
result
.take()
.expect("condition")
.materialize_with(host, budget, &location)?,
&Location::Query(branches[index].0.range.clone()),
)? {
push!(Pending::Eval(&branches[index].1, depth + 1, tail));
} else if let Some((condition, _)) = branches.get(index + 1) {
push!(Pending::Branch(expression, depth, index + 1, tail));
push!(Pending::Eval(condition, depth + 1, false));
} else {
push!(Pending::Eval(otherwise, depth + 1, tail));
}
}
Pending::Require(expression, depth, tail) => {
let PreparedKind::Require {
condition,
value,
message,
} = &expression.value
else {
unreachable!()
};
if !boolean(
result
.take()
.expect("require condition")
.materialize_with(host, budget, &location)?,
&Location::Query(condition.range.clone()),
)? {
admit_diagnostic("", &message.value, budget, &location)?;
return Err(error(&location, message.value.clone()).into());
}
push!(Pending::Eval(value, depth + 1, tail));
}
next @ (Pending::Default(..) | Pending::Fallback(..)) => {
default_step(
next,
&mut pending,
&mut result,
host,
budget,
&location,
)?;
}
Pending::Block(expression, depth, index, tail) => {
let PreparedKind::Block { bindings, value } = &expression.value
else {
unreachable!()
};
if index > 0 {
let pattern = bindings[index - 1].0;
let value = result.take().expect("block let result");
host.inspect_pattern(
&value,
budget,
&Location::Query(pattern.range.clone()),
)?;
let bound = super::pattern::bind(
super::pattern::PatternRef::Pattern(pattern),
value,
host,
budget,
)?
.ok_or_else(|| {
error(
&Location::Query(pattern.range.clone()),
"binding pattern did not match",
)
})?;
for binding in bound {
push_metadata(
&mut frame.locals,
binding,
budget,
&location,
)?;
}
}
if let Some((_, value)) = bindings.get(index) {
push!(Pending::Block(expression, depth, index + 1, tail));
push!(Pending::Eval(value, depth + 1, false));
} else {
push!(Pending::Eval(value, depth + 1, tail));
}
}
Pending::Match(expression, depth, mut index, tail, subject) => {
let PreparedKind::ValueMatch { arms, .. } = &expression.value
else {
unreachable!()
};
let mut subject = match subject {
Some(subject) => subject,
None => {
let subject = result.take().expect("match subject");
host.inspect_pattern(&subject, budget, &location)?;
subject
}
};
loop {
let arm = &arms[index];
let candidate = subject.share(
budget,
&Location::Query(arm.pattern.range.clone()),
)?;
if let Some(bound) = super::pattern::bind(
super::pattern::PatternRef::Pattern(arm.pattern),
candidate,
host,
budget,
)? {
let saved = frame.locals.len();
for binding in bound {
push_metadata(
&mut frame.locals,
binding,
budget,
&location,
)?;
}
if let Some(guard) = &arm.guard {
push!(Pending::Guard(
expression, depth, index, tail, saved, subject
));
push!(Pending::Eval(guard, depth + 1, false));
} else {
drop(subject);
push!(Pending::Restore(saved));
push!(Pending::Eval(&arm.value, depth + 1, tail));
}
break;
}
index += 1;
}
}
Pending::Guard(expression, depth, index, tail, saved, subject) => {
let PreparedKind::ValueMatch { arms, .. } = &expression.value
else {
unreachable!()
};
let arm = &arms[index];
let guard = arm.guard.as_ref().expect("guard");
budget.charge(1, Location::Query(guard.range.clone()))?;
if boolean(
result
.take()
.expect("guard result")
.materialize_with(host, budget, &location)?,
&Location::Query(guard.range.clone()),
)? {
drop(subject);
push!(Pending::Restore(saved));
push!(Pending::Eval(&arm.value, depth + 1, tail));
} else {
frame.locals.truncate(saved);
push!(Pending::Match(
expression,
depth,
index + 1,
tail,
Some(subject)
));
}
}
Pending::Call(expression, depth, index, tail, mut arguments) => {
let PreparedKind::Call {
function,
arguments: sources,
} = &expression.value
else {
unreachable!()
};
if !sources.is_empty() {
arguments.push(result.take().expect("call argument"));
}
if let Some(next) = sources.get(index + 1) {
push!(Pending::Call(
expression,
depth,
index + 1,
tail,
arguments
));
push!(Pending::Eval(next, depth + 1, false));
return Ok(());
}
let mut ranges = metadata_vec(sources.len(), budget, &location)?;
ranges.extend(sources.iter().map(|source| &source.range));
push!(Pending::Invoke {
expression,
function: *function,
arguments,
ranges,
tail,
return_contract: None
});
}
Pending::Invoke {
expression,
function,
mut arguments,
ranges,
tail,
return_contract,
} => {
budget.charge(1, location.clone())?;
let call_range = match &expression.value {
PreparedKind::Accumulate { step, .. } => &step.range,
_ => &expression.range,
};
let body = bodies.get(function).ok_or_else(|| {
error(&location, "function was not prepared in this request")
})?;
for ((argument, parameter), source) in arguments
.iter_mut()
.zip(body.declaration.parameters.iter())
.zip(ranges)
{
admit(
argument,
parameter.declaration,
host,
budget,
&Location::Query(source.clone()),
)?;
}
let mut locals = Vec::new();
for (parameter, value) in
body.declaration.parameters.iter().zip(arguments)
{
let bound = super::pattern::bind(
parameter.pattern,
value,
host,
budget,
)?
.ok_or_else(|| {
error(
&Location::Query(parameter.pattern.range().clone()),
"parameter pattern did not match",
)
})?;
for binding in bound {
push_metadata(&mut locals, binding, budget, &location)?;
}
}
let reuse = if tail {
match frame.function {
Some(caller) => crate::runtime_types::same_declaration(
&bodies[caller].declaration.result.value,
&body.declaration.result.value,
budget,
&location,
)?,
None => false,
}
} else {
false
};
if reuse {
pending.truncate(frame.base);
frame.locals = locals;
frame.function = Some(function);
frame.range = call_range.clone();
} else {
if offset + frames.len() > limit {
return Err(error(
&location,
"active function depth limit exceeded",
)
.into());
}
let base = pending.len();
push_metadata(
&mut frames,
Activation {
function: Some(function),
range: call_range.clone(),
base,
locals,
names: &[],
return_contract,
},
budget,
&location,
)?;
}
push!(Pending::Return(function));
push!(Pending::Let(function, 0));
}
Pending::AccumulatorItems(expression, depth) => {
let PreparedKind::Accumulate { initial, .. } = &expression.value
else {
unreachable!()
};
let items = result.take().expect("accumulator items");
push!(Pending::AccumulatorInitial(expression, depth, items));
push!(Pending::Eval(initial, depth + 1, false));
}
Pending::AccumulatorInitial(expression, depth, items_value) => {
let PreparedKind::Accumulate {
items,
initial,
function,
..
} = &expression.value
else {
unreachable!()
};
let declaration = &bodies[*function].declaration;
let mut parameters = declaration.parameters.iter();
let state = parameters.next().expect("step state").declaration;
let element = parameters.next().expect("step item").declaration;
let mut initial_value = result.take().expect("accumulator initial");
admit(
&mut initial_value,
state,
host,
budget,
&Location::Query(initial.range.clone()),
)?;
let source_location = Location::Query(items.range.clone());
let source = accumulator_source(
items_value,
element,
host,
budget,
&source_location,
)?;
result = Some(initial_value);
push!(Pending::AccumulatorStep(
expression,
depth,
Accumulator {
source,
index: 0,
snapshots: Vec::new()
}
));
}
Pending::AccumulatorStep(expression, depth, mut accumulator) => {
let PreparedKind::Accumulate {
items,
function,
step,
scan,
..
} = &expression.value
else {
unreachable!()
};
budget.charge(1, location.clone())?;
let state_contract = bodies[*function]
.declaration
.parameters
.iter()
.next()
.expect("step state")
.declaration;
let mut state = result.take().expect("accumulator state");
if *scan && accumulator.index > 0 {
budget.charge_results(1, location.clone())?;
let snapshot = state.share(budget, &location)?;
push_metadata(
&mut accumulator.snapshots,
snapshot,
budget,
&location,
)?;
}
if accumulator.index == accumulator.source.len() {
result = Some(if *scan {
host.finish_sequence(
accumulator.snapshots,
state_contract,
budget,
&location,
)?
} else {
state
});
} else {
let item = accumulator.source.child(
accumulator.index,
budget,
&Location::Query(items.range.clone()),
)?;
accumulator.index += 1;
let mut arguments = metadata_vec(2, budget, &location)?;
arguments.push(state);
arguments.push(item);
let mut ranges = metadata_vec(2, budget, &location)?;
ranges.push(&step.range);
ranges.push(&items.range);
push!(Pending::AccumulatorStep(expression, depth, accumulator));
push!(Pending::Invoke {
expression,
function: *function,
arguments,
ranges,
tail: false,
return_contract: Some(state_contract)
});
}
}
Pending::Set(expression, depth, index, mut values, mut ty) => {
let value = result
.take()
.expect("set child")
.materialize_with(host, budget, &location)?;
insert_set(&mut values, &mut ty, value, false, budget, &location)?;
let PreparedKind::Set(children) = &expression.value else {
unreachable!()
};
if let Some(child) = children.get(index + 1) {
push!(Pending::Set(expression, depth, index + 1, values, ty));
push!(Pending::Eval(child, depth + 1, false));
} else {
result = owned!(ConstructedValue::Set {
element_type: ty,
elements: values
});
}
}
next @ (Pending::DictionaryKey(..) | Pending::DictionaryValue(..)) => {
dictionary_step(next, &mut pending, &mut result, host, budget)?;
}
Pending::DeclaredAxes(expression, depth, index, mut axes) => {
let sources =
declared_axis_sources(expression).expect("declared sources");
let source_location = Location::Query(sources[index].range.clone());
axes.push(source_axis(
result.take().expect("axis source").materialize_with(
host,
budget,
&source_location,
)?,
budget,
&source_location,
)?);
if let Some(source) = sources.get(index + 1) {
push!(Pending::DeclaredAxes(
expression,
depth,
index + 1,
axes
));
push!(Pending::Eval(source, depth + 1, false));
} else {
start_keyed(
expression,
depth,
frame.locals.len(),
Some(axes),
&mut pending,
&mut result,
budget,
)?;
}
}
Pending::KeyedKey(expression, depth, index, axes, values) => {
let PreparedKind::KeyedArray { entries, .. } = &expression.value
else {
unreachable!()
};
let key = result
.take()
.expect("literal key")
.materialize_with(host, budget, &location)?;
let keys = value_keys(
key,
budget,
&Location::Query(entries[index].0.range.clone()),
)?;
push!(Pending::KeyedValue(
expression, depth, index, axes, values, keys
));
push!(Pending::Eval(&entries[index].1, depth + 1, false));
}
Pending::KeyedValue(
expression,
depth,
index,
axes,
mut values,
keys,
) => {
let PreparedKind::KeyedArray { entries, .. } = &expression.value
else {
unreachable!()
};
let value = result
.take()
.expect("literal cell")
.materialize_with(host, budget, &location)?;
values.push(Located::new(
KeyedEntry { key: keys, value },
entries[index].0.range.clone(),
));
if let Some((key, _)) = entries.get(index + 1) {
push!(Pending::KeyedKey(
expression,
depth,
index + 1,
axes,
values
));
push!(Pending::Eval(key, depth + 1, false));
} else {
result = owned!(finish_keyed(axes, values, budget, &location)?);
}
}
Pending::Let(function, index) => {
let body = &bodies[function];
if index > 0 {
push_metadata(
&mut frame.locals,
(
body.bindings[index - 1].0,
result.take().expect("local let"),
),
budget,
&location,
)?;
}
if let Some((_, expression)) = body.bindings.get(index) {
push!(Pending::Let(function, index + 1));
push!(Pending::Eval(expression, 1, false));
} else {
push!(Pending::Eval(&body.value, 1, true));
}
}
Pending::Return(function) => {
let mut value = result.take().expect("function result");
admit(
&mut value,
&bodies[function].declaration.result.value,
host,
budget,
&Location::Query(bodies[function].value.range.clone()),
)?;
if let Some(expected) = frame.return_contract {
admit(
&mut value,
expected,
host,
budget,
&Location::Query(bodies[function].value.range.clone()),
)?;
}
frames.pop();
result = Some(value);
}
Pending::Clauses(c, index, saved) => {
if let Some(clause) = c.clauses.get(index) {
budget.charge(1, Location::Query(clause.range.clone()))?;
push!(Pending::Source(Rc::clone(&c), index, saved));
let source = match &clause.value {
PreparedGenerator::Bind { value, .. } => value,
PreparedGenerator::In { source, .. } => source,
};
push!(Pending::Eval(source, c.depth + index + 2, false));
} else {
push!(Pending::Head(Rc::clone(&c)));
push!(Pending::Eval(
c.key.unwrap_or(c.head),
c.depth + index + 1,
false
));
}
}
Pending::Source(c, index, saved) => {
let value = result.take().expect("generator source");
let clause = &c.clauses[index];
let cl = Location::Query(clause.range.clone());
if matches!(
c.expression.value,
PreparedKind::Comprehension {
retain_declaration: true,
..
}
) && let Some(data) = host.constructed(&value, budget, &cl)?
{
*c.declaration.borrow_mut() = data
.declaration
.map(|d| copy_declaration(d, budget, &cl))
.transpose()?;
}
match &clause.value {
PreparedGenerator::Bind { binder, filter, .. } => {
budget.charge(1, cl.clone())?;
install_pattern(
&mut frame.locals,
binder,
value,
host,
budget,
)?;
push!(Pending::Restore(saved));
if let Some(filter) = filter {
push!(Pending::Filter(
Rc::clone(&c),
index,
frame.locals.len()
));
push!(Pending::Eval(
filter,
c.depth + index + 2,
false
));
} else {
push!(Pending::Clauses(
c,
index + 1,
frame.locals.len()
));
}
}
PreparedGenerator::In { binders, .. } => {
let value = generator_source(value, host, budget, &cl)?;
let len = value.len();
let mut count = 1usize;
for _ in binders {
budget.charge(1, cl.clone())?;
count = count.checked_mul(len).ok_or_else(|| {
error(&cl, "grouped generator cardinality overflow")
})?;
}
budget.charge(count, cl.clone())?;
let mut positions =
metadata_vec(binders.len(), budget, &cl)?;
positions.resize(binders.len(), 0);
push!(Pending::Candidate(
c, index, saved, value, positions, count
));
}
}
}
Pending::Candidate(
c,
index,
saved,
mut source,
mut positions,
count,
) => {
frame.locals.truncate(saved);
if count == 0 {
return Ok(());
}
let clause = &c.clauses[index];
let PreparedGenerator::In {
binders, filter, ..
} = &clause.value
else {
unreachable!()
};
let cl = Location::Query(clause.range.clone());
let len = source.len();
install_candidate(
&mut frame.locals,
binders,
&mut source,
&positions,
host,
budget,
&cl,
)?;
for position in positions.iter_mut().rev() {
budget.charge(1, cl.clone())?;
*position += 1;
if *position < len {
break;
}
*position = 0;
}
push!(Pending::Candidate(
Rc::clone(&c),
index,
saved,
source,
positions,
count - 1
));
if let Some(filter) = filter {
push!(Pending::Filter(
Rc::clone(&c),
index,
frame.locals.len()
));
push!(Pending::Eval(filter, c.depth + index + 2, false));
} else {
push!(Pending::Clauses(c, index + 1, frame.locals.len()));
}
}
Pending::Filter(c, index, saved) => {
let filter = match &c.clauses[index].value {
PreparedGenerator::Bind { filter, .. }
| PreparedGenerator::In { filter, .. } => {
filter.as_ref().expect("generator filter")
}
};
if boolean(
result
.take()
.expect("filter")
.materialize_with(host, budget, &location)?,
&Location::Query(filter.range.clone()),
)? {
push!(Pending::Clauses(c, index + 1, saved));
}
}
Pending::Predicate(expression, depth, saved) => {
let PreparedKind::SubjectScope { argument, body, .. } =
&expression.value
else {
unreachable!()
};
install_predicate(
&mut frame.locals,
result.take().expect("predicate subject"),
*argument,
host,
budget,
&location,
)?;
push!(Pending::PredicateResult(expression, saved));
push!(Pending::Eval(body, depth + 1, false));
}
Pending::PredicateResult(expression, saved) => {
frame.locals.truncate(saved);
if matches!(
expression.value,
PreparedKind::SubjectScope {
predicate: true,
..
}
) {
result = Some(predicate_result(
result.take().expect("predicate result"),
host,
budget,
&Location::Query(expression.range.clone()),
)?);
}
}
Pending::Restore(saved) => frame.locals.truncate(saved),
Pending::Head(c) => {
let value = result
.take()
.expect("head or key")
.materialize_with(host, budget, &location)?;
if let Some(key) = c.key {
if let Output::Dictionary(entries) = &*c.output.borrow() {
let location = Location::Query(key.range.clone());
budget.charge(1, location.clone())?;
let key =
dictionary_key(value, entries, budget, &location)?;
push!(Pending::DictionaryHead(Rc::clone(&c), key));
push!(Pending::Eval(
c.head,
c.depth + c.clauses.len() + 1,
false
));
return Ok(());
}
let keys = value_keys(
value,
budget,
&Location::Query(key.range.clone()),
)?;
push!(Pending::KeyHead(Rc::clone(&c), keys));
push!(Pending::Eval(
c.head,
c.depth + c.clauses.len() + 1,
false
));
} else {
append(&c, value, None, budget)?;
}
}
Pending::KeyHead(c, key) => {
let value = result
.take()
.expect("keyed head")
.materialize_with(host, budget, &location)?;
append(&c, value, Some(key), budget)?;
}
Pending::DictionaryHead(c, key) => {
let value = result
.take()
.expect("dictionary head")
.materialize_with(host, budget, &location)?;
let Output::Dictionary(entries) = &mut *c.output.borrow_mut()
else {
unreachable!("dictionary output")
};
EntryAccounting::Computed.append(
entries,
key,
value,
budget,
&Location::Query(c.expression.range.clone()),
)?;
}
Pending::FinishComprehension(c) => {
let output = std::mem::replace(
&mut *c.output.borrow_mut(),
Output::Array(Vec::new()),
);
let value = match output {
Output::Array(values) => ConstructedValue::Array(values),
Output::Dictionary(entries) => {
ConstructedValue::Record(entries)
}
Output::Set(elements, element_type) => ConstructedValue::Set {
elements,
element_type,
},
Output::Keyed(None, entries) if entries.is_empty() => {
*c.output.borrow_mut() = Output::Keyed(None, entries);
let sources = c.empty.ok_or_else(|| {
error(&location, "unestablished empty keyed axes")
})?;
let axes =
admit_container(sources.len(), budget, &location)?;
if let Some(source) = sources.first() {
push!(Pending::EmptyAxes(Rc::clone(&c), 0, axes));
push!(Pending::Eval(source, c.depth + 1, false));
return Ok(());
}
finish_keyed(Some(axes), Vec::new(), budget, &location)?
}
Output::Keyed(axes, entries) => {
finish_keyed(axes, entries, budget, &location)?
}
};
result = owned!(match c.declaration.borrow_mut().take() {
Some(declaration) =>
annotate(value, declaration, budget, &location)?,
None => value,
});
}
Pending::EmptyAxes(c, index, mut axes) => {
let sources = c.empty.expect("empty sources");
axes.push(source_axis(
result
.take()
.expect("axis source")
.materialize_with(host, budget, &location)?,
budget,
&Location::Query(sources[index].range.clone()),
)?);
if let Some(source) = sources.get(index + 1) {
push!(Pending::EmptyAxes(Rc::clone(&c), index + 1, axes));
push!(Pending::Eval(source, c.depth + 1, false));
} else {
result = owned!(finish_keyed(
Some(axes),
Vec::new(),
budget,
&location
)?);
}
}
}
Ok(())
},
)?;
}
Ok(result.expect("entry result"))
})();
if outcome.is_err() {
let calls = frames
.iter()
.filter_map(|frame| frame.function.map(|id| (id, frame.range.clone())))
.rev()
.take(16)
.collect::<Vec<_>>();
host.failure(&calls, frames.len().saturating_sub(1 + calls.len()));
}
outcome
})
}
fn default_step<'a, Q, H: Host<'a, Q>>(
next: Pending<'a, Q, H::Native, H::Kind>,
pending: &mut Vec<Pending<'a, Q, H::Native, H::Kind>>,
result: &mut Option<ResultValue<'a, H, Q>>,
host: &mut H,
budget: &mut Budget,
location: &Location,
) -> Result<(), H::Error> {
macro_rules! push {
($value:expr) => {
push_metadata(pending, $value, budget, location)?
};
}
match next {
Pending::Default(expression, depth, tail) => {
let left = result.take().expect("default left");
if host.occurs(&left, budget, location)? {
*result = Some(left);
} else {
let left = host.normalize(left, budget, location)?;
let PreparedKind::Default { fallback, .. } = &expression.value else {
unreachable!()
};
let typed = left.contract.is_some()
|| match &left.data {
Data::Constructed(data) => data.declaration().is_some(),
Data::Native(_) => false,
};
if typed {
push!(Pending::Fallback(expression, depth, left));
}
push!(Pending::Eval(fallback, depth + 1, tail && !typed));
}
}
Pending::Fallback(_, _, left) => {
let right = result.take().expect("default fallback");
if let Some(mut expected) = left.contract {
if host.occurs(&right, budget, location)? {
while let DeclaredType::Optional(child) = expected {
expected = child;
}
}
let mut right = right;
admit(&mut right, expected, host, budget, location)?;
*result = Some(right);
return Ok(());
}
let right = host.normalize(right, budget, location)?;
let expected = match left.contract {
Some(c) => crate::runtime_types::constructed_declaration(c, budget, location)?,
None => copy_declaration(
match &left.data {
Data::Constructed(data) => data.declaration().expect("typed absent"),
Data::Native(_) => unreachable!(),
},
budget,
location,
)?,
};
let expected = if right.scalar(location)?.occurs() {
underlying(&expected)
} else {
&expected
};
crate::admit_constructed(right.scalar(location)?, expected, budget, location.clone())?;
*result = Some(Value::constructed(RuntimeValue::Owned(annotate(
right.materialize_with(host, budget, location)?,
copy_declaration(expected, budget, location)?,
budget,
location,
)?)));
}
_ => unreachable!("default continuation dispatch"),
}
Ok(())
}
fn accumulator_source<'a, Q, H: Host<'a, Q>>(
items_value: ResultValue<'a, H, Q>,
element: &DeclaredType<H::Kind>,
host: &mut H,
budget: &mut Budget,
location: &Location,
) -> Result<ResultSource<'a, H, Q>, H::Error> {
let items_value = host.normalize(items_value, budget, location)?;
if let Some(previous) = items_value.contract
&& let Some(previous) = sequence_element(previous, budget, location)?
&& !crate::runtime_types::compatible_state(previous, element, budget, location)?
{
return Err(error(location, "incompatible declared underlying types").into());
}
Ok(match items_value.data {
Data::Constructed(mut value) => {
if let Some(previous) = value.declaration()
&& let Some(previous) = sequence_element(previous, budget, location)?
&& !crate::runtime_types::compatible_declarations(
previous, element, budget, location,
)?
{
return Err(error(location, "incompatible declared underlying types").into());
}
let value = value
.share(budget, location)?
.into_present(budget, location)?;
let ConstructedValue::Array(values) = value.as_ref() else {
return Err(
error(location, "named accumulator needs a positional sequence").into(),
);
};
budget.check_items(values.len(), location.clone())?;
GeneratorSource::Constructed(value)
}
Data::Native(value) => {
let values = host.sequence_items(value, element, budget, location)?;
budget.check_items(values.len(), location.clone())?;
GeneratorSource::Native(values)
}
})
}
fn sequence_element<'t, K>(
mut declaration: &'t DeclaredType<K>,
budget: &mut Budget,
location: &Location,
) -> Result<Option<&'t DeclaredType<K>>, QueryError> {
loop {
budget.charge(1, location.clone())?;
match declaration {
DeclaredType::Optional(child) => declaration = child,
DeclaredType::Array(child) | DeclaredType::Sequence(child) => return Ok(Some(child)),
_ => return Ok(None),
}
}
}
pub(crate) fn constructed_sequence<'a, Q, H: Host<'a, Q> + ?Sized>(
values: Vec<ResultValue<'a, H, Q>>,
element: &DeclaredType<H::Kind>,
host: &H,
budget: &mut Budget,
location: &Location,
) -> Result<ResultValue<'a, H, Q>, QueryError> {
let element = crate::runtime_types::constructed_declaration(element, budget, location)?;
let mut output = admit_container::<ConstructedValue>(values.len(), budget, location)?;
for value in values {
output.push(value.materialize_with(host, budget, location)?);
}
let value = annotate(
ConstructedValue::Array(output),
DeclaredType::Sequence(Box::new(element)),
budget,
location,
)?;
Ok(Value::constructed(RuntimeValue::Owned(value)))
}
fn enter_loop<'a, Q, N, K>(
expression: &'a PreparedValue<'a, Q>,
depth: usize,
tail: bool,
base: usize,
pending: &mut Vec<Pending<'a, Q, N, K>>,
budget: &mut Budget,
location: &Location,
) -> Result<(), QueryError> {
macro_rules! push {
($value:expr) => {
push_metadata(pending, $value, budget, location)?
};
}
match &expression.value {
PreparedKind::Loop { states, .. } => {
let values = metadata_vec(states.len(), budget, location)?;
push!(Pending::Initialize(expression, depth, 0, tail, values));
if let Some((_, first)) = states.first() {
push!(Pending::Eval(first, depth + 1, false));
}
}
PreparedKind::Break(value) => {
let index = loop_target(pending, base, budget, location)?;
let Pending::Loop(state) = &pending[index] else {
unreachable!()
};
let tail = state.tail;
push!(Pending::Break(expression, depth));
push!(Pending::Eval(value, depth + 1, tail));
}
PreparedKind::Continue(values) => {
let staged = metadata_vec(values.len(), budget, location)?;
push!(Pending::Next(expression, depth, staged));
if let Some(first) = values.first() {
push!(Pending::Eval(first, depth + 1, false));
}
}
_ => unreachable!("loop expression dispatch"),
}
Ok(())
}
fn loop_step<'a, Q, H: Host<'a, Q>>(
next: Pending<'a, Q, H::Native, H::Kind>,
pending: &mut Vec<Pending<'a, Q, H::Native, H::Kind>>,
frame: &mut Activation<'a, H::Native, H::Kind>,
result: &mut Option<ResultValue<'a, H, Q>>,
host: &mut H,
budget: &mut Budget,
location: &Location,
) -> Result<(), H::Error> {
macro_rules! push {
($value:expr) => {
push_metadata(pending, $value, budget, location)?
};
}
match next {
Pending::Initialize(expression, depth, index, tail, mut values) => {
let PreparedKind::Loop { states, body } = &expression.value else {
unreachable!()
};
if !states.is_empty() {
values.push(result.take().expect("loop initializer"));
}
if let Some((_, next)) = states.get(index + 1) {
push!(Pending::Initialize(
expression,
depth,
index + 1,
tail,
values
));
push!(Pending::Eval(next, depth + 1, false));
return Ok(());
}
let mut contracts = metadata_vec(values.len(), budget, location)?;
for ((_, source), value) in states.iter().zip(&mut values) {
let at = Location::Query(source.range.clone());
let contract = match value.contract {
Some(contract) => StateContract::Borrowed(contract),
None => match host.constructed(value, budget, &at)? {
Some(data) => StateContract::Constructed(std::sync::Arc::new(
match data.declaration {
Some(contract) => copy_declaration(contract, budget, &at)?,
None => infer_state(data.value, budget, &at)?,
},
)),
None => {
let Data::Native(view) = &value.data else {
unreachable!()
};
StateContract::Native(host.native_contract(
host.native_data(view, budget, &at)?,
budget,
&at,
)?)
}
},
};
admit_state(value, &contract, host, budget, &at)?;
contracts.push(contract);
}
let saved = frame.locals.len();
for ((name, _), value) in states.iter().zip(values) {
push_metadata(
&mut frame.locals,
(name.value.as_str(), value),
budget,
location,
)?;
}
push!(Pending::Loop(Loop {
expression,
depth,
tail,
saved,
contracts
}));
push!(Pending::Eval(body, depth + 1, false));
}
Pending::Loop(_) => {
return Err(error(location, "loop body fell through").into());
}
Pending::Break(_, _) => {
let index = loop_target(pending, frame.base, budget, location)?;
pending.truncate(index + 1);
let Pending::Loop(state) = pending.pop().expect("loop boundary") else {
unreachable!()
};
frame.locals.truncate(state.saved);
}
Pending::Next(expression, depth, mut values) => {
let PreparedKind::Continue(sources) = &expression.value else {
unreachable!()
};
if !sources.is_empty() {
values.push(result.take().expect("next state operand"));
}
if let Some(next) = sources.get(values.len()) {
push!(Pending::Next(expression, depth, values));
push!(Pending::Eval(next, depth + 1, false));
return Ok(());
}
let index = loop_target(pending, frame.base, budget, location)?;
let Pending::Loop(state) = &pending[index] else {
unreachable!()
};
for ((value, contract), source) in values.iter_mut().zip(&state.contracts).zip(sources)
{
admit_state(
value,
contract,
host,
budget,
&Location::Query(source.range.clone()),
)?;
}
pending.truncate(index + 1);
let Pending::Loop(state) = pending.pop().expect("loop boundary") else {
unreachable!()
};
frame.locals.truncate(state.saved + values.len());
for (slot, value) in frame.locals[state.saved..].iter_mut().zip(values) {
slot.1 = value;
}
let PreparedKind::Loop { body, .. } = &state.expression.value else {
unreachable!()
};
let body_depth = state.depth + 1;
push!(Pending::Loop(state));
push!(Pending::Eval(body, body_depth, false));
}
_ => unreachable!("loop continuation dispatch"),
}
Ok(())
}
fn loop_target<Q, N, K>(
pending: &[Pending<'_, Q, N, K>],
base: usize,
budget: &mut Budget,
location: &Location,
) -> Result<usize, QueryError> {
for index in (base..pending.len()).rev() {
budget.charge(1, location.clone())?;
if matches!(pending[index], Pending::Loop(_)) {
return Ok(index);
}
}
unreachable!("prepared terminal transfer has a loop in this activation")
}
fn admit_state<'a, Q, H: Host<'a, Q>>(
value: &mut ResultValue<'a, H, Q>,
contract: &StateContract<'a, H::Kind>,
host: &mut H,
budget: &mut Budget,
location: &Location,
) -> Result<(), H::Error> {
let expected = match contract {
StateContract::Borrowed(expected) => return admit(value, expected, host, budget, location),
StateContract::Constructed(expected) => {
if let Some(previous) = value.contract
&& !crate::runtime_types::compatible_declarations(
expected, previous, budget, location,
)?
{
return Err(error(location, "incompatible declared loop state types").into());
}
let data = host
.constructed(value, budget, location)?
.ok_or_else(|| error(location, "loop state needs a constructed value"))?;
if let Some(previous) = data.declaration
&& !crate::runtime_types::compatible_declarations(
previous,
expected.as_ref(),
budget,
location,
)?
{
return Err(error(location, "incompatible declared loop state types").into());
}
crate::admit_constructed(data.value, expected.as_ref(), budget, location.clone())?;
match &mut value.data {
Data::Constructed(data) => data.retain_declaration(expected, budget, location)?,
Data::Native(view) => {
view.retain_declaration(std::sync::Arc::clone(expected), budget, location)?;
}
}
return Ok(());
}
StateContract::Native(expected) => expected,
};
if let Data::Native(view) = &value.data {
host.check_native_context(
host.native_data(view, budget, location)?,
expected,
budget,
location,
)?;
}
check_state_contract(value, expected, host, budget, location)?;
match host.constructed(value, budget, location)? {
Some(data) => Ok(crate::admit_constructed(
data.value,
expected,
budget,
location.clone(),
)?),
None => {
let Data::Native(view) = &value.data else {
unreachable!()
};
host.admit_native(
host.native_data(view, budget, location)?,
expected,
budget,
location.clone(),
)
}
}
}
fn check_state_contract<'a, Q, H: Host<'a, Q>>(
value: &ResultValue<'a, H, Q>,
expected: &DeclaredType<H::Kind>,
host: &H,
budget: &mut Budget,
location: &Location,
) -> Result<(), H::Error> {
let borrowed = match value.contract {
Some(previous) => {
crate::runtime_types::compatible_state(previous, expected, budget, location)?
}
None => true,
};
let constructed = match host.constructed(value, budget, location)? {
Some(data) => match data.declaration {
Some(previous) => {
crate::runtime_types::compatible_declarations(previous, expected, budget, location)?
}
None => true,
},
None => true,
};
if !borrowed || !constructed {
return Err(error(location, "incompatible declared loop state types").into());
}
Ok(())
}
fn infer_state(
value: &ConstructedValue,
budget: &mut Budget,
location: &Location,
) -> Result<DeclaredType<()>, QueryError> {
let facts = constructed_value_type(value, budget, location.clone())?;
infer_state_type(facts, budget, location)
}
fn infer_state_type(
facts: super::ValueType,
budget: &mut Budget,
location: &Location,
) -> Result<DeclaredType<()>, QueryError> {
use super::{ArrayType, ValueType as T};
budget.within_evaluation(1, location.clone(), |budget| {
budget.charge(1, location.clone())?;
Ok(match facts {
T::Declared { declaration, .. } => declaration,
T::Boolean => DeclaredType::Boolean,
T::Integer => DeclaredType::Integer,
T::Float => DeclaredType::Float,
T::String => DeclaredType::String,
T::Member(id) => DeclaredType::Member(id),
T::Set(Some(kind)) => DeclaredType::Set(kind),
T::Tuple(fields) => {
let mut types = metadata_vec(fields.len(), budget, location)?;
for field in fields {
types.push(infer_state_type(field, budget, location)?);
}
DeclaredType::Tuple(types)
}
T::Record(fields) => {
let mut types = metadata_vec(fields.len(), budget, location)?;
for (name, field) in fields {
types.push((name, infer_state_type(field, budget, location)?));
}
DeclaredType::Record(types)
}
T::Array(ArrayType::Positions(elements) | ArrayType::Elements(elements)) => {
DeclaredType::Sequence(Box::new(infer_state_element(elements, budget, location)?))
}
T::KeyedArray(array) => {
DeclaredType::Keyed(Box::new(infer_state_element(array.elements, budget, location)?))
}
T::Absent | T::Unestablished | T::ScalarKind | T::ArrayKind(_) | T::TupleKind | T::RecordKind | T::Set(None) => {
return Err(error(location,
"loop state needs an established type; use an explicit contract for absent or empty values"));
}
})
})
}
fn infer_state_element(
elements: Vec<super::ValueType>,
budget: &mut Budget,
location: &Location,
) -> Result<DeclaredType<()>, QueryError> {
let mut types = elements.into_iter();
let first = types.next().ok_or_else(|| {
error(
location,
"empty loop state needs an explicit element contract",
)
})?;
let expected = infer_state_type(first, budget, location)?;
for element in types {
let actual = infer_state_type(element, budget, location)?;
if !crate::runtime_types::same_declaration(&actual, &expected, budget, location)? {
return Err(error(
location,
"loop state needs homogeneous collection elements",
));
}
}
Ok(expected)
}
fn admit<'a, Q, H: Host<'a, Q>>(
value: &mut ResultValue<'a, H, Q>,
expected: &'a DeclaredType<H::Kind>,
host: &mut H,
budget: &mut Budget,
location: &Location,
) -> Result<(), H::Error> {
if let Data::Native(view) = &value.data {
host.check_native_context(
host.native_data(view, budget, location)?,
expected,
budget,
location,
)?;
}
if let Some(previous) = value.contract
&& !std::ptr::eq(previous, expected)
&& !crate::runtime_types::compatible_state(previous, expected, budget, location)?
{
return Err(error(location, "incompatible declared underlying types").into());
}
let constructed = host.constructed(value, budget, location)?;
if let Some(data) = &constructed
&& let Some(previous) = data.declaration
&& !crate::runtime_types::compatible_declarations(previous, expected, budget, location)?
{
return Err(error(location, "incompatible declared underlying types").into());
}
let reusable = constructed.is_some() || host.retains_native_admission();
if reusable
&& let Some(previous) = value.contract
&& (std::ptr::eq(previous, expected)
|| crate::runtime_types::same_declaration(previous, expected, budget, location)?)
{
value.contract = Some(expected);
return Ok(());
}
match constructed {
None => {
let Data::Native(view) = &value.data else {
unreachable!()
};
host.admit_native(
host.native_data(view, budget, location)?,
expected,
budget,
location.clone(),
)?
}
Some(data) => {
crate::admit_constructed(data.value, expected, budget, location.clone())?;
}
}
value.contract = Some(expected);
Ok(())
}
fn start_dictionary<'a, Q, N, K>(
expression: &'a PreparedValue<'a, Q>,
depth: usize,
saved: usize,
pending: &mut Vec<Pending<'a, Q, N, K>>,
result: &mut Option<Value<'a, N, K>>,
budget: &mut Budget,
) -> Result<(), QueryError> {
let location = Location::Query(expression.range.clone());
macro_rules! push {
($v:expr) => {
push_metadata(pending, $v, budget, &location)?
};
}
match &expression.value {
PreparedKind::Dictionary(entries) => {
let values = EntryAccounting::Computed.entries(budget, &location)?;
if let Some((key, _)) = entries.first() {
budget.charge(1, Location::Query(key.range.clone()))?;
push!(Pending::DictionaryKey(expression, depth, 0, values));
push!(Pending::Eval(key, depth + 1, false));
} else {
*result = Some(Value::constructed(RuntimeValue::Owned(
ConstructedValue::Record(values),
)));
}
}
PreparedKind::DictionaryComprehension { clauses, key, head } => {
let c = Rc::new(Comprehension {
expression,
clauses,
key: Some(key),
head,
empty: None,
depth,
declaration: std::cell::RefCell::new(None),
output: std::cell::RefCell::new(Output::Dictionary(
EntryAccounting::Computed.entries(budget, &location)?,
)),
});
push!(Pending::FinishComprehension(Rc::clone(&c)));
push!(Pending::Clauses(c, 0, saved));
}
_ => unreachable!("dictionary construction"),
}
Ok(())
}
fn dictionary_step<'a, Q, H: Host<'a, Q>>(
next: Pending<'a, Q, H::Native, H::Kind>,
pending: &mut Vec<Pending<'a, Q, H::Native, H::Kind>>,
result: &mut Option<ResultValue<'a, H, Q>>,
host: &H,
budget: &mut Budget,
) -> Result<(), QueryError> {
let location = match &next {
Pending::DictionaryKey(expression, ..) | Pending::DictionaryValue(expression, ..) => {
Location::Query(expression.range.clone())
}
_ => unreachable!("dictionary continuation"),
};
macro_rules! push {
($v:expr) => {
push_metadata(pending, $v, budget, &location)?
};
}
match next {
Pending::DictionaryKey(expression, depth, index, values) => {
let PreparedKind::Dictionary(entries) = &expression.value else {
unreachable!("dictionary entries")
};
let key_location = Location::Query(entries[index].0.range.clone());
let key = dictionary_key(
result.take().expect("dictionary key").materialize_with(
host,
budget,
&key_location,
)?,
&values,
budget,
&key_location,
)?;
push!(Pending::DictionaryValue(
expression, depth, index, values, key
));
push!(Pending::Eval(&entries[index].1, depth + 1, false));
}
Pending::DictionaryValue(expression, depth, index, mut values, key) => {
let PreparedKind::Dictionary(entries) = &expression.value else {
unreachable!("dictionary entries")
};
let value = result
.take()
.expect("dictionary value")
.materialize_with(host, budget, &location)?;
EntryAccounting::Computed.append(&mut values, key, value, budget, &location)?;
if let Some((key, _)) = entries.get(index + 1) {
budget.charge(1, Location::Query(key.range.clone()))?;
push!(Pending::DictionaryKey(expression, depth, index + 1, values));
push!(Pending::Eval(key, depth + 1, false));
} else {
*result = Some(Value::constructed(RuntimeValue::Owned(
ConstructedValue::Record(values),
)));
}
}
_ => unreachable!("dictionary continuation"),
}
Ok(())
}
fn dictionary_key(
value: ConstructedValue,
entries: &[(String, ConstructedValue)],
budget: &mut Budget,
location: &Location,
) -> Result<String, QueryError> {
let ConstructedValue::String(key) = expose(value, budget, location)? else {
return Err(error(location, "dictionary key needs a present string"));
};
if EntryAccounting::Computed.contains(entries, &key, budget, location)? {
admit_diagnostic("duplicate dictionary key: ", &key, budget, location)?;
return Err(error(location, format!("duplicate dictionary key: {key}")));
}
Ok(key)
}
fn declared_axis_sources<'a, Q>(
expression: &'a PreparedValue<'a, Q>,
) -> Option<&'a [PreparedValue<'a, Q>]> {
match &expression.value {
PreparedKind::KeyedArray {
declared_axis_sources,
..
}
| PreparedKind::KeyedComprehension {
declared_axis_sources,
..
} => declared_axis_sources.as_deref(),
_ => unreachable!("keyed construction"),
}
}
fn start_keyed<'a, Q, N, K>(
expression: &'a PreparedValue<'a, Q>,
depth: usize,
saved: usize,
axes: Option<Vec<KeyAxis>>,
pending: &mut Vec<Pending<'a, Q, N, K>>,
result: &mut Option<Value<'a, N, K>>,
budget: &mut Budget,
) -> Result<(), QueryError> {
let location = Location::Query(expression.range.clone());
macro_rules! push {
($v:expr) => {
push_metadata(pending, $v, budget, &location)?
};
}
match &expression.value {
PreparedKind::KeyedArray { entries, .. } => {
let values = admit_container(entries.len(), budget, &location)?;
if let Some((key, _)) = entries.first() {
push!(Pending::KeyedKey(expression, depth, 0, axes, values));
push!(Pending::Eval(key, depth + 1, false));
} else {
*result = Some(Value::constructed(RuntimeValue::Owned(finish_keyed(
axes, values, budget, &location,
)?)));
}
}
PreparedKind::KeyedComprehension {
clauses,
key,
head,
empty_axis_sources,
..
} => {
let c = Rc::new(Comprehension {
expression,
clauses,
key: Some(key),
head,
empty: empty_axis_sources.as_deref(),
depth,
declaration: std::cell::RefCell::new(None),
output: std::cell::RefCell::new(Output::Keyed(
axes,
admit_container(0, budget, &location)?,
)),
});
push!(Pending::FinishComprehension(Rc::clone(&c)));
push!(Pending::Clauses(c, 0, saved));
}
_ => unreachable!("keyed construction"),
}
Ok(())
}
fn append<Q>(
c: &Comprehension<'_, Q>,
value: ConstructedValue,
key: Option<Vec<ValueKey>>,
budget: &mut Budget,
) -> Result<(), QueryError> {
let location = Location::Query(c.expression.range.clone());
match &mut *c.output.borrow_mut() {
Output::Array(values) => {
allocation::<ConstructedValue>(sum(values.len(), 1, &location)?, &location)?;
budget.charge_results(1, location)?;
values.push(value);
}
Output::Set(elements, ty) => insert_set(elements, ty, value, true, budget, &location)?,
Output::Dictionary(_) => unreachable!("dictionary head has a string key"),
Output::Keyed(_, entries) => {
let expression = c.key.expect("key expression");
let location = Location::Query(expression.range.clone());
let keys = key.expect("keyed value");
allocation::<Located<KeyedEntry>>(sum(entries.len(), 1, &location)?, &location)?;
budget.charge(1, location.clone())?;
budget.charge_results(1, location)?;
entries.push(Located::new(
KeyedEntry { key: keys, value },
expression.range.clone(),
));
}
}
Ok(())
}
fn generator_source<'a, Q, H: Host<'a, Q> + ?Sized>(
mut value: ResultValue<'a, H, Q>,
host: &mut H,
budget: &mut Budget,
cl: &Location,
) -> Result<GeneratorSource<'a, H::Native, H::Kind>, H::Error> {
host.normalize_in_place(&mut value, budget, cl)?;
let contract = value.contract;
Ok(match value.data {
Data::Native(owner) => {
let values = host.subjects(owner, budget, cl)?;
budget.check_items(values.len(), cl.clone())?;
let mut items = metadata_vec(values.len(), budget, cl)?;
let element = contract.and_then(|contract| match contract {
DeclaredType::Sequence(element) | DeclaredType::Array(element) => {
Some(element.as_ref())
}
_ => None,
});
for value in values {
budget.charge(1, cl.clone())?;
budget.charge_results(1, cl.clone())?;
items.push(Value {
data: Data::Native(NativeView::new(std::sync::Arc::new(value))),
contract: element,
});
}
GeneratorSource::Native(items)
}
Data::Constructed(data) => {
let value = Value {
data: Data::<H::Native>::Constructed(data),
contract,
};
let value = if contract.is_some() {
RuntimeValue::Owned(value.materialize(budget, cl)?)
} else {
let Data::Constructed(value) = value.data else {
unreachable!()
};
value
};
let value = if matches!(value.as_ref(), ConstructedValue::Declared { .. }) {
RuntimeValue::Owned(expose(value.materialize(budget, cl)?, budget, cl)?)
} else {
value
};
if !matches!(
value.as_ref(),
ConstructedValue::Array(_)
| ConstructedValue::Set { .. }
| ConstructedValue::KeyedArray { .. }
) {
return Err(error(cl, "in source needs an array or supported set").into());
}
GeneratorSource::Constructed(value)
}
})
}
fn install_pattern<'a, Q, H: Host<'a, Q> + ?Sized>(
locals: &mut Vec<(&'a str, ResultValue<'a, H, Q>)>,
pattern: &'a super::Pattern,
value: Value<'a, H::Native, H::Kind>,
host: &mut H,
budget: &mut Budget,
) -> Result<(), H::Error> {
let location = Location::Query(pattern.range.clone());
if !matches!(
pattern.value,
super::PatternKind::Name(_) | super::PatternKind::Wildcard
) {
host.inspect_pattern(&value, budget, &location)?;
}
let bindings = super::pattern::bind(
super::pattern::PatternRef::Pattern(pattern),
value,
host,
budget,
)?
.ok_or_else(|| error(&location, "generator pattern does not match its value"))?;
for binding in bindings {
push_metadata(locals, binding, budget, &location)?;
}
Ok(())
}
fn install_candidate<'a, Q, H: Host<'a, Q> + ?Sized>(
locals: &mut Vec<(&'a str, ResultValue<'a, H, Q>)>,
binders: &[Option<&'a super::Pattern>],
source: &mut GeneratorSource<'a, H::Native, H::Kind>,
positions: &[usize],
host: &mut H,
budget: &mut Budget,
location: &Location,
) -> Result<(), H::Error> {
for (binder, position) in binders.iter().zip(positions) {
let value = source.child(*position, budget, location)?;
if let Some(pattern) = binder {
install_pattern(locals, pattern, value, host, budget)?;
} else {
push_metadata(locals, (super::PREDICATE_SUBJECT, value), budget, location)?;
}
}
Ok(())
}
fn install_predicate<'a, Q, H: Host<'a, Q> + ?Sized>(
locals: &mut Vec<(&'a str, ResultValue<'a, H, Q>)>,
mut subject: Value<'a, H::Native, H::Kind>,
argument: Option<&'a super::Pattern>,
host: &mut H,
budget: &mut Budget,
location: &Location,
) -> Result<(), H::Error> {
if argument.is_some_and(|p| {
!matches!(
p.value,
super::PatternKind::Name(_) | super::PatternKind::Wildcard
)
}) {
host.inspect_pattern(&subject, budget, location)?;
}
let bindings = match argument {
Some(pattern) => {
let shared = subject.share(budget, location)?;
super::pattern::bind(
super::pattern::PatternRef::Pattern(pattern),
shared,
host,
budget,
)?
.ok_or_else(|| {
error(
&Location::Query(pattern.range.clone()),
"predicate pattern does not match its subject",
)
})?
}
None => Vec::new(),
};
push_metadata(
locals,
(super::PREDICATE_SUBJECT, subject),
budget,
location,
)?;
for binding in bindings {
push_metadata(locals, binding, budget, location)?;
}
Ok(())
}
fn predicate_result<'a, Q, H: Host<'a, Q> + ?Sized>(
value: ResultValue<'a, H, Q>,
host: &H,
budget: &mut Budget,
location: &Location,
) -> Result<ResultValue<'a, H, Q>, H::Error> {
let value = boolean(value.materialize_with(host, budget, location)?, location)?;
Ok(Value::constructed(RuntimeValue::Owned(scalar(
ConstructedValue::Boolean(value),
budget,
location,
)?)))
}
fn operands<'a, Q>(
expression: &'a PreparedValue<'a, Q>,
budget: &mut Budget,
location: &Location,
) -> Result<Vec<&'a PreparedValue<'a, Q>>, QueryError> {
let count = match &expression.value {
PreparedKind::Array(v) | PreparedKind::Tuple(v) | PreparedKind::Set(v) => v.len(),
PreparedKind::Record(v) => v.len(),
PreparedKind::PushBackAll { .. }
| PreparedKind::Insert { .. }
| PreparedKind::Binary { .. }
| PreparedKind::Lookup { .. }
| PreparedKind::HasKey { .. }
| PreparedKind::ArrayAccess { .. }
| PreparedKind::Range { .. }
| PreparedKind::ZipExact { .. } => 2,
_ => 1,
};
let mut result = metadata_vec(count, budget, location)?;
match &expression.value {
PreparedKind::Array(v) | PreparedKind::Tuple(v) | PreparedKind::Set(v) => result.extend(v),
PreparedKind::Record(v) => result.extend(v.iter().map(|(_, value)| value)),
PreparedKind::PushBackAll {
queue: left,
items: right,
}
| PreparedKind::Insert {
set: left,
item: right,
}
| PreparedKind::Binary { left, right, .. }
| PreparedKind::ZipExact { left, right } => result.extend([left.as_ref(), right.as_ref()]),
PreparedKind::Lookup { value, key } | PreparedKind::HasKey { value, key } => {
result.extend([value.as_ref(), key.as_ref()])
}
PreparedKind::ArrayAccess { array, index } => {
result.extend([array.as_ref(), index.as_ref()])
}
PreparedKind::Range { lower, upper } => result.extend([lower.as_ref(), upper.as_ref()]),
PreparedKind::Queue { items: value, .. }
| PreparedKind::PopFront(value)
| PreparedKind::One(value)
| PreparedKind::Occurs(value)
| PreparedKind::Absent(value)
| PreparedKind::IndexSet(value)
| PreparedKind::Entries(value)
| PreparedKind::Unique(value)
| PreparedKind::Tally(value)
| PreparedKind::Unary { operand: value, .. }
| PreparedKind::Field { value, .. }
| PreparedKind::TupleAccess { value, .. }
| PreparedKind::Reduce { array: value, .. }
| PreparedKind::Sort { array: value, .. }
| PreparedKind::Extremum { array: value, .. }
| PreparedKind::GroupBy { rows: value, .. } => result.push(value),
_ => unreachable!("special control has no ordinary operands"),
}
Ok(result)
}
fn select_record_field<'a, Q, H: Host<'a, Q> + ?Sized>(
value: &mut ResultValue<'a, H, Q>,
label: &str,
host: &H,
budget: &mut Budget,
location: &Location,
) -> Result<ResultValue<'a, H, Q>, H::Error> {
let data = host.constructed(value, budget, location)?.ok_or_else(|| {
error(
location,
"native handles require an explicit scalar projection",
)
})?;
let ConstructedValue::Record(fields) = data.value.data() else {
return Err(error(location, "field access needs a record").into());
};
if let Some(DeclaredType::Record(fields)) = data.declaration.map(underlying) {
record_declaration(fields, label, budget, location)?;
}
if let Some(mut contract) = value.contract {
while let DeclaredType::Optional(child) = contract {
contract = child;
}
if let DeclaredType::Record(fields) = contract {
record_declaration(fields, label, budget, location)?;
}
}
for (index, (candidate, _)) in fields.iter().enumerate() {
budget.charge(
sum(1, candidate.len().min(label.len()), location)?,
location.clone(),
)?;
if candidate == label {
return super::pattern::select(
value,
NativeStep::Record(index),
host,
budget,
location,
);
}
}
admit_diagnostic("missing record field: ", label, budget, location)?;
Err(error(location, format!("missing record field: {label}")).into())
}
pub(crate) fn apply<'a, Q, H: Host<'a, Q> + ?Sized>(
expression: &'a PreparedValue<'a, Q>,
mut values: Vec<ResultValue<'a, H, Q>>,
host: &H,
budget: &mut Budget,
) -> Result<ResultValue<'a, H, Q>, H::Error> {
let location = Location::Query(expression.range.clone());
if let PreparedKind::Field { field, .. } = &expression.value {
return select_record_field(
&mut values.pop().expect("field operand"),
&field.value,
host,
budget,
&location,
);
}
if matches!(expression.value, PreparedKind::ArrayAccess { .. })
&& host
.constructed(&values[0], budget, &location)?
.is_some_and(|data| matches!(data.value.data(), ConstructedValue::Record(_)))
{
let key = host.materialize(values.pop().expect("record key"), budget, &location)?;
let ConstructedValue::String(key) = expose(key, budget, &location)? else {
return Err(error(&location, "record access needs a string label").into());
};
return select_record_field(
&mut values.pop().expect("record operand"),
&key,
host,
budget,
&location,
);
}
if let PreparedKind::Occurs(_) | PreparedKind::Absent(_) = &expression.value {
let present = host.occurs(&values[0], budget, &location)?;
return Ok(Value::constructed(RuntimeValue::Owned(scalar(
ConstructedValue::Boolean(if matches!(expression.value, PreparedKind::Occurs(_)) {
present
} else {
!present
}),
budget,
&location,
)?)));
}
if let PreparedKind::Reduce { operator, .. } = &expression.value {
return Ok(Value::constructed(RuntimeValue::Owned(reduce_ref(
*operator,
host.scalar(&values[0], budget, &location)?,
budget,
&location,
)?)));
}
if let PreparedKind::Binary {
operator:
operator @ (ValueBinaryOperator::Contains
| ValueBinaryOperator::StartsWith
| ValueBinaryOperator::EndsWith),
..
} = &expression.value
{
return Ok(Value::constructed(RuntimeValue::Owned(string_match_ref(
*operator,
host.scalar(&values[0], budget, &location)?,
host.scalar(&values[1], budget, &location)?,
budget,
&location,
)?)));
}
if let PreparedKind::Extremum {
operator, field, ..
} = &expression.value
{
let mut value = values.pop().expect("extremum operand");
let position = extremum_position(
*operator,
host.scalar(&value, budget, &location)?,
*field,
budget,
&location,
)?;
let contract = value.contract.and_then(|mut contract| {
while let DeclaredType::Optional(child) = contract {
contract = child;
}
match contract {
DeclaredType::Array(child) | DeclaredType::Sequence(child) => Some(child.as_ref()),
_ => None,
}
});
let child_declaration = match host
.constructed(&value, budget, &location)?
.and_then(|v| v.declaration)
.map(underlying)
{
Some(DeclaredType::Array(child) | DeclaredType::Sequence(child)) => {
Some(copy_declaration(child, budget, &location)?)
}
_ => None,
};
let Some(position) = position else {
let mut absent = scalar(ConstructedValue::Absent, budget, &location)?;
let declaration = match child_declaration {
Some(child) => Some(child),
None => contract
.map(|child| {
crate::runtime_types::constructed_declaration(child, budget, &location)
})
.transpose()?,
};
if let Some(declaration) = declaration {
absent = annotate(
absent,
DeclaredType::Optional(Box::new(declaration)),
budget,
&location,
)?;
}
return Ok(Value::constructed(RuntimeValue::Owned(absent)));
};
if matches!(value.data, Data::Native(_)) {
let mut selected = super::pattern::select(
&mut value,
NativeStep::Tuple(position),
host,
budget,
&location,
)?;
selected.contract = contract;
return Ok(selected);
}
let Data::Constructed(data) = value.data else {
unreachable!("constructed extremum")
};
let selected = data
.into_data(budget, &location)?
.child(position, budget, &location)?;
let selected = if let Some(declaration) = child_declaration {
RuntimeValue::Owned(annotate(
selected.materialize(budget, &location)?,
declaration,
budget,
&location,
)?)
} else {
selected
};
return Ok(Value {
data: Data::Constructed(selected),
contract,
});
}
let mut arguments = metadata_vec(values.len(), budget, &location)?;
for value in values {
arguments.push(host.materialize(value, budget, &location)?);
}
let mut arguments = arguments.into_iter();
let mut next = || arguments.next().expect("prepared operand");
let value = match &expression.value {
PreparedKind::One(_) => {
let ConstructedValue::Array(values) = expose(next(), budget, &location)? else {
return Err(error(&location, "one needs a positional array").into());
};
take_one(values, expression.range.clone())?
}
PreparedKind::Lookup { .. } | PreparedKind::HasKey { .. } => {
let (present, value) = optional_access(next(), next(), budget, &location)?;
if matches!(expression.value, PreparedKind::HasKey { .. }) {
scalar(ConstructedValue::Boolean(present), budget, &location)?
} else {
value
}
}
PreparedKind::Array(_) | PreparedKind::Tuple(_) | PreparedKind::Set(_) => {
let mut values = admit_container(arguments.len(), budget, &location)?;
let mut element_type = None;
for value in arguments {
if matches!(expression.value, PreparedKind::Set(_)) {
insert_set(
&mut values,
&mut element_type,
value,
false,
budget,
&location,
)?;
} else {
values.push(value);
}
}
match expression.value {
PreparedKind::Array(_) => ConstructedValue::Array(values),
PreparedKind::Tuple(_) => ConstructedValue::Tuple(values),
_ => ConstructedValue::Set {
elements: values,
element_type,
},
}
}
PreparedKind::Record(fields) => {
let mut result = admit_container(fields.len(), budget, &location)?;
for ((label, _), value) in fields.iter().zip(arguments) {
budget.charge(label.value.len(), Location::Query(label.range.clone()))?;
result.push((label.value.clone(), value));
}
ConstructedValue::Record(result)
}
PreparedKind::Unary { operator, .. } => unary(*operator, next(), budget, &location)?,
PreparedKind::Binary { operator, .. } => {
binary(*operator, next(), next(), budget, &location)?
}
PreparedKind::TupleAccess { position, .. } => {
let ConstructedValue::Tuple(values) = expose(next(), budget, &location)? else {
return Err(error(&location, "tuple access needs a tuple").into());
};
take_position(values, position.value, budget, &location)?
}
PreparedKind::ArrayAccess { .. } => {
let array = expose(next(), budget, &location)?;
let index = next();
match array {
ConstructedValue::Array(values) => {
let position = usize::try_from(integer(index, &location)?)
.map_err(|_| error(&location, "missing array position"))?;
take_position(values, position, budget, &location)?
}
ConstructedValue::KeyedArray { axes, entries } => {
let key = value_keys(index, budget, &location)?;
key_positions(&key, &axes, budget, &location)?;
let mut selected = None;
for entry in entries {
budget.charge(1, location.clone())?;
if equal_keys(&key, &entry.key, budget, &location)? {
selected = Some(entry.value);
break;
}
}
selected.ok_or_else(|| error(&location, "missing keyed array cell"))?
}
_ => return Err(error(&location, "array access needs an array").into()),
}
}
PreparedKind::IndexSet(_) => match expose(next(), budget, &location)? {
ConstructedValue::Array(values) => {
let len =
i64::try_from(values.len()).map_err(|_| error(&location, "index overflow"))?;
integer_range(1, len, budget, &location)?
}
ConstructedValue::KeyedArray { mut axes, .. } if axes.len() == 1 => {
let axis = axes.pop().expect("rank one");
let mut values = admit_container(axis.keys.len(), budget, &location)?;
let mut element_type = Some(key_set_type(axis.key_type));
for key in axis.keys {
budget.charge(1, location.clone())?;
insert_set(
&mut values,
&mut element_type,
key_value(key),
false,
budget,
&location,
)?;
}
ConstructedValue::Set {
element_type,
elements: values,
}
}
ConstructedValue::KeyedArray { .. } => {
return Err(error(&location, "index_set needs rank one").into());
}
_ => return Err(error(&location, "index_set needs an array").into()),
},
PreparedKind::Entries(_) => entries(next(), budget, &location)?,
PreparedKind::Unique(_) => unique_value(next(), budget, &location)?,
PreparedKind::Tally(_) => tally_value(next(), budget, &location)?,
PreparedKind::ZipExact { .. } => zip_exact(next(), next(), budget, &location)?,
PreparedKind::GroupBy { field, .. } => group_by(next(), field, budget, &location)?,
PreparedKind::Sort {
selector,
descending,
..
} => sort_value(next(), *selector, *descending, budget, &location)?,
PreparedKind::Range { .. } => integer_range(
integer(next(), &location)?,
integer(next(), &location)?,
budget,
&location,
)?,
_ => unreachable!("control handled by continuations"),
};
Ok(Value::constructed(RuntimeValue::Owned(value)))
}
pub(super) struct ScalarHost<'f, 'a, Q, H: ?Sized, F> {
pub(super) queries: &'f mut H,
pub(super) frame: &'f mut Frame<'a>,
pub(super) check: &'f mut F,
pub(super) query: std::marker::PhantomData<Q>,
pub(super) calls: &'f mut crate::functions::CallTrace,
}
impl<'a, 's, Q, H, F> Host<'a, Q> for ScalarHost<'_, 's, Q, H, F>
where
H: ValueQueryHost<Q> + ?Sized,
F: FnMut(&ConstructedValue, &mut Budget, &Location) -> Result<(), QueryError>,
{
type Native = std::convert::Infallible;
type Kind = ();
type Error = H::Error;
fn current_input(
&mut self,
budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, ()>, Self::Error> {
Ok(Value::constructed(self.frame.current_input(
self.queries,
budget,
range,
)?))
}
fn predicate_subject(
&mut self,
budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, ()>, Self::Error> {
Ok(Value::constructed(RuntimeValue::Owned(
self.queries.read_predicate_subject(range, budget)?,
)))
}
fn outer(
&mut self,
slot: usize,
_: &str,
budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, ()>, Self::Error> {
Ok(Value::constructed(self.frame.read(
&ReadSlot::Outer(slot),
self.queries,
budget,
range,
)?))
}
fn native(
&mut self,
query: &'a Q,
arguments: &'a [PreparedArgument<'a, Q>],
locals: &mut [(&'a str, Value<'a, Self::Native, ()>)],
_: &'a [Body<'a, Q, ()>],
_: usize,
_: Option<usize>,
projected: bool,
budget: &mut Budget,
range: &std::ops::Range<usize>,
) -> Result<Value<'a, Self::Native, ()>, Self::Error> {
if !projected {
return Err(QueryError::query(
range.clone(),
"native values require a function request",
)
.into());
}
let location = Location::Query(range.clone());
let mut values = metadata_vec(locals.len(), budget, &location)?;
for (name, value) in locals {
let Data::Constructed(value) = &mut value.data else {
unreachable!()
};
values.push((
*name,
value
.share(budget, &location)?
.into_shared(budget, &location)?,
));
}
let mut frames = metadata_vec(arguments.len(), budget, &location)?;
for argument in arguments {
let mut names = metadata_vec(argument.names.len(), budget, &location)?;
names.extend_from_slice(&argument.names);
frames.push(Frame::new(names, budget, &location)?);
}
let mut arguments = PreparedArguments {
arguments,
frames,
check_value: self.check,
};
let value = self.queries.evaluate_query_with_arguments(
query,
&values,
&mut arguments,
budget,
range,
)?;
constructed_value_type(&value, budget, location)?;
Ok(Value::constructed(RuntimeValue::Owned(value)))
}
fn admit_native(
&mut self,
value: &Self::Native,
_: &DeclaredType<()>,
_: &mut Budget,
_: Location,
) -> Result<(), Self::Error> {
match *value {}
}
fn check(
&mut self,
value: &ConstructedValue,
budget: &mut Budget,
location: &Location,
) -> Result<(), QueryError> {
(self.check)(value, budget, location)
}
fn failure(&mut self, calls: &[(usize, std::ops::Range<usize>)], omitted: usize) {
self.calls.append(calls, omitted);
}
}
pub(super) fn run_scalar<'a, Q, H: ValueQueryHost<Q> + ?Sized>(
expression: &'a PreparedValue<'a, Q>,
queries: &mut H,
frame: &mut Frame<'a>,
budget: &mut Budget,
check: &mut impl FnMut(&ConstructedValue, &mut Budget, &Location) -> Result<(), QueryError>,
) -> Result<RuntimeValue, H::Error> {
let mut names = metadata_vec(
frame.names.len(),
budget,
&Location::Query(expression.range.clone()),
)?;
names.extend_from_slice(&frame.names);
let mut calls = crate::functions::CallTrace::default();
let mut host = ScalarHost {
queries,
frame,
check,
query: std::marker::PhantomData,
calls: &mut calls,
};
let value = execute(expression, &names, &[], &mut host, budget, 0, 0)?;
let Data::Constructed(value) = value.data else {
unreachable!()
};
Ok(value)
}