difftreelog
feat forObj evaluation
in: master
4 files changed
crates/jrsonnet-evaluator/src/analyze.rsdiffbeforeafterboth410 /// Is `over` does not depend on any variable introduced by an earlier for-spec in this comprehension chain410 /// Is `over` does not depend on any variable introduced by an earlier for-spec in this comprehension chain411 loop_invariant: bool,411 loop_invariant: bool,412 },412 },413 #[cfg(feature = "exp-object-iteration")]414 ForObj {415 frame_shape: ClosureShape,416 key: LocalSlot,417 visibility: jrsonnet_ir::Visibility,418 value: LDestruct,419 over: LExpr,420 loop_invariant: bool,421 },413}422}414423415struct FrameAlloc<'s> {424struct FrameAlloc<'s> {1863 (r, rest)1872 (r, rest)1864 }1873 }1865 #[cfg(feature = "exp-object-iteration")]1874 #[cfg(feature = "exp-object-iteration")]1866 CompSpec::ForObjSpec(_) => todo!(),1875 CompSpec::ForObjSpec(data) => {1876 let mut over_taint = AnalysisResult::default();1877 let over_l = analyze(&data.over, stack, &mut over_taint);1878 let loop_invariant = over_taint.local_dependent_depth > outer_depth;1879 taint.taint_by(over_taint);18801881 let mut alloc = FrameAlloc::new(stack);1882 let closure = alloc.push_locals_closure();1883 let Some((_, key_slot)) = alloc.define_local(data.key.clone(), None) else {1884 stack.pop_closure(closure);1885 return go(idx + 1, specs, outer_depth, stack, taint, inside);1886 };1887 let Some(l_value) = alloc.alloc_destruct(&data.value) else {1888 stack.pop_closure(closure);1889 return go(idx + 1, specs, outer_depth, stack, taint, inside);1890 };1891 let mut pending = alloc.finish();18921893 let var_analysis = AnalysisResult::default();1894 pending.record_spec_init(&LDestruct::Full(key_slot), var_analysis);1895 pending.record_spec_init(&l_value, var_analysis);18961897 let body_frame = pending.finish();1898 let (r, mut rest) =1899 go(idx + 1, specs, outer_depth, body_frame.stack, taint, inside);1900 body_frame.finish();1901 let frame_shape = stack.pop_closure(closure);19021903 rest.insert(1904 0,1905 LCompSpec::ForObj {1906 frame_shape,1907 key: key_slot,1908 visibility: data.visibility,1909 value: l_value,1910 over: over_l,1911 loop_invariant,1912 },1913 );1914 (r, rest)1915 }1867 }1916 }1868 }1917 }1869 let outer_depth = stack.depth;1918 let outer_depth = stack.depth;1970 use super::*;2019 use super::*;197120201972 #[test]2021 #[test]2022 #[cfg(not(feature = "exp-null-coaelse"))]1973 fn snapshots() {2023 fn snapshots() {1974 glob!("analysis_tests/*.jsonnet", |path| {2024 glob!("analysis_tests/*.jsonnet", |path| {1975 let code = fs::read_to_string(path).expect("read test file");2025 let code = fs::read_to_string(path).expect("read test file");crates/jrsonnet-evaluator/src/evaluate/compspec.rsdiffbeforeafterboth6 destructure::{destruct, evaluate_locals_unbound, fill_letrec_binds},6 destructure::{destruct, evaluate_locals_unbound, fill_letrec_binds},7 evaluate_field_member_static, evaluate_field_member_unbound,7 evaluate_field_member_static, evaluate_field_member_unbound,8};8};9#[cfg(feature = "exp-object-iteration")]10use jrsonnet_interner::IStr;119use crate::{12use crate::{10 Context, ObjValue, ObjValueBuilder, Result, Thunk, Val,13 Context, ObjValue, ObjValueBuilder, Result, Thunk, Val,18 evaluate::{evaluate, evaluate_trivial},21 evaluate::{evaluate, evaluate_trivial},19};22};2324enum CachedOver {25 Arr(ArrValue),26 #[cfg(feature = "exp-object-iteration")]27 Obj(ObjValue),28}202921trait CompCollector {30trait CompCollector {22 fn reserve(&mut self, _guaranteed: usize) {}31 fn reserve(&mut self, _guaranteed: usize) {}215 Ok(Val::arr(items))224 Ok(Val::arr(items))216}225}217226218fn cache_overs(ctx: &Context, specs: &[LCompSpec]) -> Result<Vec<Option<ArrValue>>> {227fn cache_overs(ctx: &Context, specs: &[LCompSpec]) -> Result<Vec<Option<CachedOver>>> {219 specs228 specs220 .iter()229 .iter()221 .map(|spec| {230 .map(|spec| {229 let Val::Arr(arr) = val else {238 let Val::Arr(arr) = val else {230 bail!(InComprehensionCanOnlyIterateOverArray)239 bail!(InComprehensionCanOnlyIterateOverArray)231 };240 };232 Some(arr)241 Some(CachedOver::Arr(arr))233 }242 }243 #[cfg(feature = "exp-object-iteration")]244 LCompSpec::ForObj {245 over,246 loop_invariant: true,247 ..248 } => {249 let val = evaluate(ctx.clone(), over)?;250 let Val::Obj(obj) = val else {251 bail!(TypeMismatch(252 "object iteration over",253 vec![jrsonnet_types::ValType::Obj],254 val.value_type(),255 ))256 };257 Some(CachedOver::Obj(obj))258 }234 _ => None,259 _ => None,235 })260 })236 })261 })240fn evaluate_compspecs_eager(265fn evaluate_compspecs_eager(241 ctx: Context,266 ctx: Context,242 specs: &[LCompSpec],267 specs: &[LCompSpec],243 cached_overs: &[Option<ArrValue>],268 cached_overs: &[Option<CachedOver>],244 idx: usize,269 idx: usize,245 guaranteed_reserve: usize,270 guaranteed_reserve: usize,246 collector: &mut dyn CompCollector,271 collector: &mut dyn CompCollector,269 over,294 over,270 ..295 ..271 } => {296 } => {272 let arr = if let Some(cached) = &cached_overs[idx] {297 let arr = if let Some(CachedOver::Arr(cached)) = &cached_overs[idx] {273 cached.clone()298 cached.clone()274 } else {299 } else {275 let arr_val = evaluate(ctx.clone(), over)?;300 let arr_val = evaluate(ctx.clone(), over)?;304 _ => unreachable!("eager compspecs are not possible with non-full patterns"),329 _ => unreachable!("eager compspecs are not possible with non-full patterns"),305 }330 }306 }331 }332 #[cfg(feature = "exp-object-iteration")]333 LCompSpec::ForObj { .. } => {334 unreachable!("eager compspecs filter rejects ForObj");335 }307 }336 }308 Ok(())337 Ok(())309}338}310339311fn evaluate_compspecs(340fn evaluate_compspecs(312 ctx: Context,341 ctx: Context,313 specs: &[LCompSpec],342 specs: &[LCompSpec],314 cached_overs: &[Option<ArrValue>],343 cached_overs: &[Option<CachedOver>],315 idx: usize,344 idx: usize,316 guaranteed_reserve: usize,345 guaranteed_reserve: usize,317 collector: &mut dyn CompCollector,346 collector: &mut dyn CompCollector,340 over,369 over,341 ..370 ..342 } => {371 } => {343 let arr = if let Some(cached) = &cached_overs[idx] {372 let arr = if let Some(CachedOver::Arr(cached)) = &cached_overs[idx] {344 cached.clone()373 cached.clone()345 } else {374 } else {346 let arr_val = evaluate(ctx.clone(), over)?;375 let arr_val = evaluate(ctx.clone(), over)?;365 )?;394 )?;366 }395 }367 }396 }397 #[cfg(feature = "exp-object-iteration")]398 LCompSpec::ForObj {399 frame_shape,400 key,401 visibility,402 value,403 over,404 ..405 } => {406 use jrsonnet_ir::Visibility;407 let obj = if let Some(CachedOver::Obj(cached)) = &cached_overs[idx] {408 cached.clone()409 } else {410 let val = evaluate(ctx.clone(), over)?;411 let Val::Obj(obj) = val else {412 bail!(TypeMismatch(413 "object iteration over",414 vec![ValType::Obj],415 val.value_type(),416 ))417 };418 obj419 };420 let fields = obj.fields_with_visibility(421 #[cfg(feature = "exp-preserve-order")]422 false,423 );424 let pairs: Vec<(IStr, Visibility)> = fields425 .into_iter()426 .filter(|(_, v)| match visibility {427 Visibility::Normal => v.is_visible(),428 Visibility::Hidden => !v.is_visible(),429 Visibility::Unhide => true,430 })431 .collect();432 let inner_reserve = guaranteed_reserve.max(1) * pairs.len();433 for (i, (field_name, _)) in pairs.into_iter().enumerate() {434 let key_val = Val::string(field_name.clone());435 let value_thunk = obj436 .get_lazy(field_name.clone())437 .expect("field exists, just enumerated");438 let inner_ctx = ctx.pack_captures_sup_this(frame_shape).enter(|fill, ctx| {439 fill.set(*key, Thunk::evaluated(key_val));440 destruct(value, fill, value_thunk, &ctx);441 });442 evaluate_compspecs(443 inner_ctx,444 specs,445 cached_overs,446 idx + 1,447 if i == 0 { inner_reserve } else { 0 },448 collector,449 )?;450 }451 }368 }452 }369 Ok(())453 Ok(())370}454}crates/jrsonnet-evaluator/src/obj/mod.rsdiffbeforeafterboth909909910 out910 out911 }911 }912 pub fn fields_with_visibility(913 &self,914 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,915 ) -> Vec<(IStr, Visibility)> {916 #[cfg(feature = "exp-preserve-order")]917 if preserve_order {918 let (mut fields, mut keys): (Vec<_>, Vec<_>) = self919 .fields_visibility()920 .into_iter()921 .enumerate()922 .map(|(idx, (k, d))| {923 (924 (925 k,926 d.exists_visible.expect("non-existing fields filtered out"),927 ),928 (d.sort_key(), idx),929 )930 })931 .unzip();932 keys.sort_unstable_by_key(|v| v.0);933 for i in 0..fields.len() {934 let x = fields[i].clone();935 let mut j = i;936 loop {937 let k = keys[j].1;938 keys[j].1 = j;939 if k == i {940 break;941 }942 fields[j] = fields[k].clone();943 j = k;944 }945 fields[j] = x;946 }947 return fields;948 }949 let mut fields: Vec<_> = self950 .fields_visibility()951 .into_iter()952 .map(|(k, d)| {953 (954 k,955 d.exists_visible.expect("non-existing fields filtered out"),956 )957 })958 .collect();959 fields.sort_unstable_by(|a, b| a.0.cmp(&b.0));960 fields961 }912 pub fn fields_ex(962 pub fn fields_ex(913 &self,963 &self,914 include_hidden: bool,964 include_hidden: bool,crates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth441 use crate::{ParserSettings, parse};441 use crate::{ParserSettings, parse};442442443 #[test]443 #[test]444 #[cfg(not(feature = "exp-null-coaelse"))]444 fn snapshots() {445 fn snapshots() {445 glob!("tests/*.jsonnet", |path| {446 glob!("tests/*.jsonnet", |path| {446 let input = fs::read_to_string(path).expect("read test file");447 let input = fs::read_to_string(path).expect("read test file");