difftreelog
feat obj comp support
in: master
5 files changed
crates/jsonnet-evaluator/src/error.rsdiffbeforeafterboth141415 UndefinedExternalVariable(String),15 UndefinedExternalVariable(String),1617 FieldMustBeStringGot(ValType),161817 RuntimeError(String),19 RuntimeError(String),18 StackOverflow,20 StackOverflow,crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth1use crate::{1use crate::{2 context_creator, create_error, future_wrapper, lazy_val, push, with_state, Context,2 context_creator, create_error, future_wrapper, lazy_val, push, with_state, Context,3 ContextCreator, FuncDesc, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val,3 ContextCreator, Error, FuncDesc, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val,4};4};5use closure::closure;5use closure::closure;6use jsonnet_parser::{6use jsonnet_parser::{167future_wrapper!(HashMap<String, LazyBinding>, FutureNewBindings);167future_wrapper!(HashMap<String, LazyBinding>, FutureNewBindings);168future_wrapper!(ObjValue, FutureObjValue);168future_wrapper!(ObjValue, FutureObjValue);169169170#[inline(always)]170pub fn evaluate_comp(171pub fn evaluate_comp<T>(171 context: Context,172 context: Context,172 value: &LocExpr,173 value: &impl Fn(Context) -> Result<T>,173 specs: &[CompSpec],174 specs: &[CompSpec],174) -> Result<Option<Vec<Val>>> {175) -> Result<Option<Vec<T>>> {175 Ok(match specs.get(0) {176 Ok(match specs.get(0) {176 None => Some(vec![evaluate(context, &value)?]),177 None => Some(vec![value(context)?]),177 Some(CompSpec::IfSpec(IfSpecData(cond))) => {178 Some(CompSpec::IfSpec(IfSpecData(cond))) => {178 if evaluate(context.clone(), &cond)?.try_cast_bool("if spec")? {179 if evaluate(context.clone(), &cond)?.try_cast_bool("if spec")? {179 evaluate_comp(context, value, &specs[1..])?180 evaluate_comp(context, value, &specs[1..])?193 &specs[1..],194 &specs[1..],194 )?);195 )?);195 }196 }196 Some(out.iter().flatten().flatten().cloned().collect())197 Some(out.into_iter().flatten().flatten().collect())197 }198 }198 _ => panic!("for expression evaluated to non-iterable value"),199 _ => panic!("for expression evaluated to non-iterable value"),199 }200 }208 let new_bindings = FutureNewBindings::new();209 let new_bindings = FutureNewBindings::new();209 let future_this = FutureObjValue::new();210 let future_this = FutureObjValue::new();210 let context_creator = context_creator!(211 let context_creator = context_creator!(211 closure!(clone context, clone new_bindings, clone future_this, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {212 closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {212 Ok(context.clone().extend_unbound(213 Ok(context.clone().extend_unbound(213 new_bindings.clone().unwrap(),214 new_bindings.clone().unwrap(),214 context.clone().dollar().clone().or_else(||this.clone()),215 context.clone().dollar().clone().or_else(||this.clone()),301 }302 }302 future_this.fill(ObjValue::new(None, Rc::new(new_members)))303 future_this.fill(ObjValue::new(None, Rc::new(new_members)))303 }304 }305 ObjBody::ObjComp {306 pre_locals,307 key,308 value,309 post_locals,310 compspecs,304 _ => todo!(),311 } => {312 let future_this = FutureObjValue::new();313 let mut new_members = BTreeMap::new();314 for (k, v) in evaluate_comp(315 context.clone(),316 &|ctx| {317 let new_bindings = FutureNewBindings::new();318 let context_creator = context_creator!(319 closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {320 Ok(context.clone().extend_unbound(321 new_bindings.clone().unwrap(),322 context.clone().dollar().clone().or_else(||this.clone()),323 None,324 super_obj325 )?)326 })327 );328 let mut bindings: HashMap<String, LazyBinding> = HashMap::new();329 for (n, b) in pre_locals330 .iter()331 .chain(post_locals.iter())332 .map(|b| evaluate_binding(b, context_creator.clone()))333 {334 bindings.insert(n, b);335 }336 let bindings = new_bindings.fill(bindings);337 let ctx = ctx.extend_unbound(bindings, None, None, None)?;338 let key = evaluate(ctx.clone(), &key)?;339 let value = LazyBinding::Bindable(Rc::new(340 closure!(clone ctx, clone value, |this, _super_obj| {341 Ok(LazyVal::new_resolved(evaluate(ctx.extend(HashMap::new(), None, this, None)?, &value)?))342 }),343 ));344345 Ok((key, value))346 },347 &compspecs,348 )?349 .unwrap()350 {351 match k {352 Val::Null => {}353 Val::Str(n) => {354 new_members.insert(355 n,356 ObjMember {357 add: false,358 visibility: Visibility::Normal,359 invoke: v,360 },361 );362 }363 v => create_error(Error::FieldMustBeStringGot(v.value_type()?))?,364 }365 }366367 future_this.fill(ObjValue::new(None, Rc::new(new_members)))368 }305 })369 })306}370}307371405 }469 }406 ArrComp(expr, compspecs) => Val::Arr(470 ArrComp(expr, compspecs) => Val::Arr(407 // First compspec should be forspec, so no "None" possible here471 // First compspec should be forspec, so no "None" possible here408 evaluate_comp(context, expr, compspecs)?.unwrap(),472 evaluate_comp(context, &|ctx| evaluate(ctx, expr), compspecs)?.unwrap(),409 ),473 ),410 Obj(body) => Val::Obj(evaluate_object(context, body.clone())?),474 Obj(body) => Val::Obj(evaluate_object(context, body.clone())?),411 ObjExtend(s, t) => evaluate_add_op(475 ObjExtend(s, t) => evaluate_add_op(crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth492 );492 );493 }493 }494495 #[test]496 fn object_comp() {497 assert_json!(498 r#"{local t = "a", ["h"+i+"_"+z]: if "h"+(i-1)+"_"+z in self then t+1 else 0+t for i in [1,2,3] for z in [2,3,4] if z != i}"#,499 "{\"h1_2\": \"0a\",\"h1_3\": \"0a\",\"h1_4\": \"0a\",\"h2_3\": \"a1\",\"h2_4\": \"a1\",\"h3_2\": \"0a\",\"h3_4\": \"a1\"}"500 )501 }494502495 #[test]503 #[test]496 fn direct_self() {504 fn direct_self() {crates/jsonnet-parser/src/expr.rsdiffbeforeafterboth120 key: LocExpr,120 key: LocExpr,121 value: LocExpr,121 value: LocExpr,122 post_locals: Vec<BindSpec>,122 post_locals: Vec<BindSpec>,123 rest: Vec<CompSpec>,123 compspecs: Vec<CompSpec>,124 },124 },125}125}126126crates/jsonnet-parser/src/lib.rsdiffbeforeafterboth138 key,138 key,139 value,139 value,140 post_locals,140 post_locals,141 rest: [vec![CompSpec::ForSpec(forspec)], others.unwrap_or_default()].concat(),141 compspecs: [vec![CompSpec::ForSpec(forspec)], others.unwrap_or_default()].concat(),142 }142 }143 }143 }144 / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)}144 / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)}