///|
pub using @plan {type Mode, type EvalError}
///|
pub using @ops {type ZoneOffset, type Clock}
///|
/// The global bindings of an evaluation: names to values.
pub struct Bindings {
priv entries : Array[(String, @value.Value)]
}
///|
/// An environment with no global names.
pub fn Bindings::empty() -> Bindings {
{ entries: [], }
}
///|
/// Bind each retained tuple field, preserving order and duplicate names.
/// Tuple construction has already removed MISSING fields. Ambiguous names
/// are reported when evaluation resolves them.
pub fn Bindings::of_tuple(tuple : @value.Tuple) -> Bindings {
{ entries: Array::from_iter(tuple.fields().iter()), }
}
///|
/// The bindings `entries`, in order. Unlike `of_tuple`, a global whose value
/// is MISSING stays bound.
pub fn Bindings::of_pairs(entries : Array[(String, @value.Value)]) -> Bindings {
{ entries: entries.copy(), }
}
///|
/// The bindings of an Ion struct, read as PartiQL-encoded Ion. A value that is
/// not a struct is a `DataError`.
pub fn Bindings::of_ion(value : @ion_core.IonValue) -> Bindings raise EvalError {
let span = @syntax.Span::{ start: 0, end: 0, }
let decoded = try @partiql_ion.from_ion(value) catch {
err => raise DataError(message=@debug.to_string(err), span~)
} noraise {
v => v
}
match decoded {
Tuple(t) => Bindings::of_tuple(t)
_ => raise DataError(message="bindings must be a struct", span~)
}
}
///|
/// Evaluates a statement. A form that this version does not evaluate raises
/// `Unsupported`. `zone` is the session time zone of CAST (default UTC); `clock` gives the
/// statement time of the clock functions (default none: they fail).
pub fn evaluate(
statement : @syntax.Statement,
env~ : Bindings,
mode~ : Mode = Permissive,
zone~ : ZoneOffset = ZoneOffset::utc(),
clock? : Clock,
) -> @value.Value raise EvalError {
match statement {
Query(q) =>
@interp.run(
@lower.lower_query(q),
@interp.Ctx(env.entries, mode~, zone~, clock?),
)
Error(span) =>
raise Unsupported(message="a statement that could not be read", span~)
}
}
///|
/// Parses and evaluates a statement. A syntax error raises `Syntax`.
///
/// ```mbt check
/// test {
/// let env = @eval.Bindings::of_pairs([("x", @value.Value(7))])
/// @expect.expect(@eval.evaluate_text("x + 1", env~)).to_equal(@value.Value(8))
/// }
/// ```
pub fn evaluate_text(
source : String,
env~ : Bindings,
mode~ : Mode = Permissive,
zone~ : ZoneOffset = ZoneOffset::utc(),
clock? : Clock,
) -> @value.Value raise EvalError {
let statement = try @syntax.parse(source) catch {
err => raise Syntax(err)
} noraise {
s => s
}
evaluate(statement, env~, mode~, zone~, clock?)
}