///|
/// 默认最大递归深度。
/// 设为 8000:覆盖 case007 的 6555 层互递归;同时较低以保证在 8MB native 栈耗尽前
/// 触发 U1001 拦截无限递归(case005/case006)。
pub let default_max_depth : Int = 8000
///|
/// 默认最大求值步数。
/// 设为 1000000:覆盖复杂表达式求值(如 performance/case001 的 256 项嵌套路径)。
/// 无限尾递归(TCO trampoline)通过 per-trampoline 迭代计数器拦截,
/// 不依赖全局 max_steps。
pub let default_max_steps : Int = 1_000_000
///|
/// 默认最大序列长度。-1 表示不限制。
///
/// 对应 JSONata `guardrails` 文档 `sequence` 选项(默认不开启)。
/// 通过 `EvalOptions::sequence` 显式启用,超限抛 `D2015`。
pub let default_max_sequence : Int = -1
///|
/// 求值上下文:持有根数据、绑定表与递归/步数/序列护栏。
///
/// - `root`:`$` 根数据(不可变,JSONata 中 `$` 始终指原始根)。
/// - `bindings`:变量绑定表(含内建函数),Map 本身可变,字段无需 `mut`。
/// - `depth`/`max_depth`:递归深度护栏。
/// - `steps`/`max_steps`:求值步数护栏。
/// - `max_sequence`:序列长度护栏(-1 不限制),对齐 JSONata `guardrails` `sequence` 选项。
/// - `depth_exceeded_code`/`steps_exceeded_code`/`sequence_exceeded_code`:
/// 护栏超限时抛出的错误码。默认 `U1001`/`U1001`/`D2015`,
/// 通过 `EvalOptions::stack`/`timeout`/`sequence` 启用时改用 `D1011`/`D1012`/`D2015`
/// 对齐 JSONata 官方文档(U1001 仅用于 jsonata-js test runner 的 `timeboxExpression` 兼容路径)。
/// - `current`:`@` 当前项(谓词过滤/路径迭代时绑定)。
/// - `parent`:`$$` 父级上下文。
/// - `ancestors`:当前项的父级链,首项为 `%`,后续项支持 `%.%`。
pub struct EvalContext {
root : JsonataValue
mut bindings : Map[String, JsonataValue]
mut depth : Int
max_depth : Int
mut steps : Int
max_steps : Int
max_sequence : Int
depth_exceeded_code : String
steps_exceeded_code : String
sequence_exceeded_code : String
mut current : JsonataValue
mut parent : JsonataValue
mut ancestors : Array[JsonataValue]
}
///|
/// 构造上下文(使用默认护栏阈值)。
pub fn EvalContext::new(root : JsonataValue) -> EvalContext {
{
root,
bindings: Map([]),
depth: 0,
max_depth: default_max_depth,
steps: 0,
max_steps: default_max_steps,
max_sequence: default_max_sequence,
depth_exceeded_code: "U1001",
steps_exceeded_code: "U1001",
sequence_exceeded_code: "D2015",
current: root,
parent: root,
ancestors: [root],
}
}
///|
/// 构造上下文并指定护栏阈值。
pub fn EvalContext::new_with_limits(
root : JsonataValue,
max_depth? : Int = default_max_depth,
max_steps? : Int = default_max_steps,
) -> EvalContext {
{
root,
bindings: Map([]),
depth: 0,
max_depth,
steps: 0,
max_steps,
max_sequence: default_max_sequence,
depth_exceeded_code: "U1001",
steps_exceeded_code: "U1001",
sequence_exceeded_code: "D2015",
current: root,
parent: root,
ancestors: [root],
}
}
///|
/// 构造上下文并指定完整护栏配置(含序列长度与错误码)。
///
/// 用于 `EvalOptions` 启用 JSONata 官方 `guardrails` 语义:
/// - `stack` 对应 `max_depth`,超限抛 `D1011`
/// - `timeout`(毫秒)映射为 `max_steps` 的近似上限(MoonBit 当前无原生 wall-clock
/// 超时支持,使用步数上限近似),超限抛 `D1012`
/// - `sequence` 对应 `max_sequence`,超限抛 `D2015`
pub fn EvalContext::new_with_guardrails(
root : JsonataValue,
max_depth? : Int = default_max_depth,
max_steps? : Int = default_max_steps,
max_sequence? : Int = default_max_sequence,
depth_exceeded_code? : String = "U1001",
steps_exceeded_code? : String = "U1001",
sequence_exceeded_code? : String = "D2015",
) -> EvalContext {
{
root,
bindings: Map([]),
depth: 0,
max_depth,
steps: 0,
max_steps,
max_sequence,
depth_exceeded_code,
steps_exceeded_code,
sequence_exceeded_code,
current: root,
parent: root,
ancestors: [root],
}
}
///|
/// 复制求值上下文,保留当前项、父级、护栏计数与已有绑定。
pub fn EvalContext::capture(self : EvalContext) -> EvalContext {
let bindings : Map[String, JsonataValue] = Map([])
for name, value in self.bindings {
bindings[name] = value
}
{
root: self.root,
bindings,
depth: self.depth,
max_depth: self.max_depth,
steps: self.steps,
max_steps: self.max_steps,
max_sequence: self.max_sequence,
depth_exceeded_code: self.depth_exceeded_code,
steps_exceeded_code: self.steps_exceeded_code,
sequence_exceeded_code: self.sequence_exceeded_code,
current: self.current,
parent: self.parent,
ancestors: self.ancestors.copy(),
}
}
///|
/// 从另一个上下文补齐当前尚未捕获的绑定。
pub fn EvalContext::inherit_missing_bindings_from(
self : EvalContext,
other : EvalContext,
) -> Unit {
for name, value in other.bindings {
if self.bindings.get(name) is None {
self.bindings[name] = value
}
}
}
///|
/// 获取根数据(`$`)。
pub fn EvalContext::root(self : EvalContext) -> JsonataValue {
self.root
}
///|
/// 获取当前项(`@`)。
pub fn EvalContext::current(self : EvalContext) -> JsonataValue {
self.current
}
///|
/// 获取父级上下文(`$$`)。
pub fn EvalContext::parent(self : EvalContext) -> JsonataValue {
match self.ancestors {
[first, ..] => first
[] => self.parent
}
}
///|
/// 获取父级链副本。
pub fn EvalContext::ancestors(self : EvalContext) -> Array[JsonataValue] {
self.ancestors.copy()
}
///|
/// 设置当前项(`@`),返回旧值以便恢复。
pub fn EvalContext::set_current(
self : EvalContext,
v : JsonataValue,
) -> JsonataValue {
let old = self.current
self.current = v
old
}
///|
/// 设置父级上下文(`$$`),返回旧值以便恢复。
pub fn EvalContext::set_parent(
self : EvalContext,
v : JsonataValue,
) -> JsonataValue {
let old = self.parent
self.parent = v
self.ancestors = [v]
old
}
///|
/// 在指定当前项与父级下执行函数,自动恢复(含异常路径)。
pub fn[T] EvalContext::with_context(
self : EvalContext,
current~ : JsonataValue,
parent~ : JsonataValue,
f : () -> T raise @error.JsonataError,
) -> T raise @error.JsonataError {
let old_current = self.current
let old_parent = self.parent
let old_ancestors = self.ancestors
self.current = current
self.parent = parent
let next_ancestors : Array[JsonataValue] = [parent]
for ancestor in old_ancestors {
next_ancestors.push(ancestor)
}
self.ancestors = next_ancestors
try {
let r = f()
self.current = old_current
self.parent = old_parent
self.ancestors = old_ancestors
r
} catch {
e => {
self.current = old_current
self.parent = old_parent
self.ancestors = old_ancestors
raise e
}
}
}
///|
/// 在指定当前项与完整父级链下执行函数,自动恢复。
pub fn[T] EvalContext::with_lineage(
self : EvalContext,
current~ : JsonataValue,
ancestors~ : Array[JsonataValue],
f : () -> T raise @error.JsonataError,
) -> T raise @error.JsonataError {
let old_current = self.current
let old_parent = self.parent
let old_ancestors = self.ancestors
self.current = current
self.ancestors = ancestors.copy()
self.parent = match self.ancestors {
[first, ..] => first
[] => JsonataValue::Undefined
}
try {
let r = f()
self.current = old_current
self.parent = old_parent
self.ancestors = old_ancestors
r
} catch {
e => {
self.current = old_current
self.parent = old_parent
self.ancestors = old_ancestors
raise e
}
}
}
///|
/// 绑定变量。
pub fn EvalContext::bind(
self : EvalContext,
name : String,
value : JsonataValue,
) -> Unit {
self.bindings[name] = value
}
///|
/// 在局部变量绑定下执行函数,结束后恢复旧绑定。
pub fn[T] EvalContext::with_binding(
self : EvalContext,
name : String,
value : JsonataValue,
f : () -> T raise @error.JsonataError,
) -> T raise @error.JsonataError {
let old = self.bindings.get(name)
self.bindings[name] = value
try {
let r = f()
restore_binding(self.bindings, name, old)
r
} catch {
e => {
restore_binding(self.bindings, name, old)
raise e
}
}
}
///|
fn restore_binding(
bindings : Map[String, JsonataValue],
name : String,
old : JsonataValue?,
) -> Unit {
match old {
Some(v) => bindings[name] = v
None => ignore(bindings.remove(name))
}
}
///|
/// 查找绑定,未找到返回 None。
pub fn EvalContext::lookup(self : EvalContext, name : String) -> JsonataValue? {
self.bindings.get(name)
}
///|
/// 获取绑定的不可变快照(用于块级作用域保存/恢复)。
pub fn EvalContext::bindings_snapshot(
self : EvalContext,
) -> Map[String, JsonataValue] {
let copy : Map[String, JsonataValue] = Map([])
for name, value in self.bindings {
copy[name] = value
}
copy
}
///|
/// 恢复绑定的快照(用于块级作用域退出时)。
pub fn EvalContext::restore_bindings(
self : EvalContext,
snapshot : Map[String, JsonataValue],
) -> Unit {
let new_map : Map[String, JsonataValue] = Map([])
for name, value in snapshot {
new_map[name] = value
}
self.bindings = new_map
}
///|
/// 进入递归层(护栏:超限抛 GuardrailError)。
///
/// 错误码:
/// - 默认 `U1001`(对齐 jsonata-js test runner `timeboxExpression` 语义,
/// 用于 `evaluate_with_max_depth` 等 legacy 路径)
/// - 通过 `EvalOptions::stack` 启用时改用 `D1011`(对齐 JSONata `guardrails` 文档)
pub fn EvalContext::enter(self : EvalContext) -> Unit raise @error.JsonataError {
self.depth = self.depth + 1
if self.depth > self.max_depth {
raise @error.guardrail_error(
"\{self.depth_exceeded_code}: Stack overflow error: Check for non-terminating recursive function. Consider rewriting as tail-recursive. (depth=\{self.depth}, max_depth=\{self.max_depth})",
limit=Some("max_depth=\{self.max_depth}"),
code=Some(self.depth_exceeded_code),
)
}
}
///|
/// 同步 caller 的递归深度到当前上下文(用于 Lambda invoke 跨上下文传播深度计数)。
/// Lambda 闭包捕获定义时的 depth,invoke 时若不与 caller 同步会导致护栏失效。
pub fn EvalContext::sync_depth_from(
self : EvalContext,
other : EvalContext,
) -> Unit {
self.depth = other.depth
}
///|
/// 退出递归层。
pub fn EvalContext::exit(self : EvalContext) -> Unit {
self.depth = self.depth - 1
}
///|
/// 记录一步求值(护栏:超限抛 GuardrailError)。
///
/// 错误码:
/// - 默认 `U1001`(对齐 jsonata-js test runner 的 `timeboxExpression` 超时语义,
/// 使无限尾递归(如 `tail-recursion/case006`)在 TCO trampoline 下也能被拦截)
/// - 通过 `EvalOptions::timeout` 启用时改用 `D1012`(对齐 JSONata `guardrails` 文档)
pub fn EvalContext::tick(self : EvalContext) -> Unit raise @error.JsonataError {
self.steps = self.steps + 1
if self.steps > self.max_steps {
raise @error.guardrail_error(
"\{self.steps_exceeded_code}: Stack overflow error: Check for non-terminating recursive function. Consider rewriting as tail-recursive. (steps=\{self.steps}, max_steps=\{self.max_steps})",
limit=Some("max_steps=\{self.max_steps}"),
code=Some(self.steps_exceeded_code),
)
}
}
///|
/// 检查序列长度是否超限(护栏:超限抛 GuardrailError,错误码 `D2015`)。
///
/// 对齐 JSONata `guardrails` 文档 `sequence` 选项:
/// > The `sequence` option can be set to specify the maximum sequence length
/// > that can be created by an expression, including any intermediate sequences
/// > created by sub-expressions. Error `D2015` will be thrown if, during the
/// > evaluation of an expression, the evaluator attempts to generate a sequence
/// > exceeding this upper limit.
///
/// 当 `max_sequence <= 0` 时不限制(默认行为)。
pub fn EvalContext::check_sequence_length(
self : EvalContext,
length : Int,
) -> Unit raise @error.JsonataError {
if self.max_sequence > 0 && length > self.max_sequence {
raise @error.guardrail_error(
"\{self.sequence_exceeded_code}: The maximum sequence length of \{self.max_sequence} has been exceeded: \{length}",
limit=Some("max_sequence=\{self.max_sequence}"),
code=Some(self.sequence_exceeded_code),
)
}
}
///|
/// 在递归层内执行函数,自动 enter/exit(含异常路径)。
pub fn[T] EvalContext::with_depth(
self : EvalContext,
f : () -> T raise @error.JsonataError,
) -> T raise @error.JsonataError {
self.enter()
try {
let r = f()
self.exit()
r
} catch {
e => {
self.exit()
raise e
}
}
}