diff --git a/crates/jrsonnet-evaluator/src/evaluate/mod.rs b/crates/jrsonnet-evaluator/src/evaluate/mod.rs index df414745..f3e9ac50 100644 --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -655,11 +655,11 @@ pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result { desc: &'static str, ) -> Result> { if let Some(value) = expr { - Ok(Some(in_frame( + Ok(in_frame( loc, || format!("slice {desc}"), - || T::from_untyped(evaluate(ctx.clone(), value)?), - )?)) + || >::from_untyped(evaluate(ctx.clone(), value)?), + )?) } else { Ok(None) } diff --git a/crates/jrsonnet-evaluator/src/typed/conversions.rs b/crates/jrsonnet-evaluator/src/typed/conversions.rs index 998723fe..b5e5df93 100644 --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -655,6 +655,26 @@ impl Typed for Null { } } +impl Typed for Option +where + T: Typed, +{ + const TYPE: &'static ComplexValType = + &ComplexValType::UnionRef(&[&ComplexValType::Simple(ValType::Null), T::TYPE]); + + fn into_untyped(typed: Self) -> Result { + typed.map_or_else(|| Ok(Val::Null), |v| T::into_untyped(v)) + } + + fn from_untyped(untyped: Val) -> Result { + if matches!(untyped, Val::Null) { + Ok(None) + } else { + T::from_untyped(untyped).map(Some) + } + } +} + pub struct NativeFn(D::Value); impl Deref for NativeFn { type Target = D::Value; diff --git a/crates/jrsonnet-stdlib/src/arrays.rs b/crates/jrsonnet-stdlib/src/arrays.rs index effa8dca..11b51c14 100644 --- a/crates/jrsonnet-stdlib/src/arrays.rs +++ b/crates/jrsonnet-stdlib/src/arrays.rs @@ -48,11 +48,13 @@ pub fn builtin_repeat(what: Either![IStr, ArrValue], count: usize) -> Result, - end: Option, - step: Option>, + index: Option>, + end: Option>, + step: Option>>, ) -> Result { - indexable.slice(index, end, step).map(Val::from) + indexable + .slice(index.flatten(), end.flatten(), step.flatten()) + .map(Val::from) } #[builtin]