zirium 0.3.0

Lossless textual MLIR syntax parsing and semantic processing
Documentation
use super::{
    EvaluationError, EvaluationState, json_size, output_size, output_value, parser::JsonLiteral,
    render,
};
use crate::semantic::Document;

pub(super) fn evaluate(
    literal: &JsonLiteral,
    document: &Document,
    state: &mut EvaluationState,
    items: &mut usize,
) -> Result<serde_json::Value, EvaluationError> {
    state.charge(1)?;
    *items = items.saturating_add(1);
    state.check_items(*items)?;
    Ok(match literal {
        JsonLiteral::Scalar(value) => value.clone(),
        JsonLiteral::String(parts) => serde_json::Value::String(render::interpolate(parts, state)?),
        JsonLiteral::Binding(name) => {
            let binding = state.bindings.get(name).cloned().ok_or_else(|| {
                EvaluationError::new(format!(
                    "binding `{name}` is unavailable in this evaluation context"
                ))
            })?;
            state.charge(output_size(&binding))?;
            let value = output_value(document, &binding);
            *items = items.saturating_add(json_size(&value).saturating_sub(1));
            state.check_items(*items)?;
            value
        }
        JsonLiteral::Array(elements) => {
            let mut values = Vec::new();
            for element in elements {
                values.push(evaluate(element, document, state, items)?);
            }
            serde_json::Value::Array(values)
        }
        JsonLiteral::Object(entries) => {
            let mut values = serde_json::Map::new();
            for (key, value) in entries {
                let key = render::interpolate(key, state)?;
                if values.contains_key(&key) {
                    return Err(EvaluationError::new(format!(
                        "duplicate JSON object key `{key}` after interpolation"
                    )));
                }
                *items = items.saturating_add(1);
                state.check_items(*items)?;
                values.insert(key, evaluate(value, document, state, items)?);
            }
            serde_json::Value::Object(values)
        }
    })
}