use crate::context::ExecutionContext;
use crate::marshal::register_typed_fn_3_full;
use crate::module_exports::{ModuleExports, ModuleParam};
use crate::typed_module_exports::{ConcreteReturn, ConcreteType, TypedReturn};
use shape_ast::error::{Result, ShapeError};
use shape_value::KindedSlot;
use std::sync::Arc;
pub fn create_recurrence_intrinsics_module() -> ModuleExports {
let mut module = ModuleExports::new("std::core::intrinsics::recurrence");
module.description =
"Recurrence intrinsics (typed entry; legacy body retained for shape-vm dispatcher consumer per cross-crate-dual-consumer pattern)"
.to_string();
register_typed_fn_3_full::<_, Arc<Vec<f64>>, f64, Option<f64>>(
&mut module,
"__intrinsic_linear_recurrence",
"Linear recurrence: y[t] = y[t-1] * decay + input[t]",
[
ModuleParam {
name: "input".to_string(),
type_name: "Array<number>".to_string(),
required: true,
description: "Input series".to_string(),
..Default::default()
},
ModuleParam {
name: "decay".to_string(),
type_name: "number".to_string(),
required: true,
description: "Decay factor applied to previous output".to_string(),
..Default::default()
},
ModuleParam {
name: "initial_value".to_string(),
type_name: "number?".to_string(),
required: false,
description: "Optional seed for y[0]; when omitted, y[0] = input[0]"
.to_string(),
default_snippet: Some("null".to_string()),
..Default::default()
},
],
ConcreteType::ArrayNumber,
|input, decay, initial_value, _ctx| {
let data = input.as_slice();
if data.is_empty() {
return Ok(TypedReturn::Concrete(ConcreteReturn::ArrayF64(vec![])));
}
let mut result = Vec::with_capacity(data.len());
if let Some(init) = initial_value {
let mut prev = init;
for &val in data {
let curr = prev * decay + val;
result.push(curr);
prev = curr;
}
} else {
let first = data[0];
result.push(first);
let mut prev = first;
for &val in &data[1..] {
let curr = prev * decay + val;
result.push(curr);
prev = curr;
}
}
Ok(TypedReturn::Concrete(ConcreteReturn::ArrayF64(result)))
},
);
module
}
pub fn intrinsic_linear_recurrence(
_args: &[KindedSlot],
_ctx: &mut ExecutionContext,
) -> Result<KindedSlot> {
Err(ShapeError::RuntimeError {
message: "intrinsic_linear_recurrence: pending Phase 2c intrinsic kind threading — see ADR-006 §2.7.4".to_string(),
location: None,
})
}