difftreelog
fix align object iteration with context refactor
in: master
2 files changed
crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth1use jrsonnet_ir::{BindSpec, Destruct};23use crate::{4 Context, ContextBuilder, Pending, Thunk, Val, error::Result, evaluate_method,5 evaluate_named_param,6};78#[allow(clippy::too_many_lines)]9#[allow(unused_variables)]10pub fn destruct(11 d: &Destruct,12 parent: Thunk<Val>,13 fctx: Pending<Context>,14 new_bindings: &mut ContextBuilder,15) -> Result<()> {16 match d {17 Destruct::Full(v) => {18 new_bindings.try_bind(v.clone(), parent)?;19 }20 #[cfg(feature = "exp-destruct")]21 Destruct::Skip => {}22 #[cfg(feature = "exp-destruct")]23 Destruct::Array { start, rest, end } => {24 use jrsonnet_ir::DestructRest;2526 use crate::bail;2728 let min_len = start.len() + end.len();29 let has_rest = rest.is_some();30 let full = Thunk!(move || {31 let v = parent.evaluate()?;32 let Val::Arr(arr) = v else {33 bail!("expected array");34 };35 if !has_rest {36 if arr.len() != min_len {37 bail!("expected {} elements, got {}", min_len, arr.len())38 }39 } else if arr.len() < min_len {40 bail!(41 "expected at least {} elements, but array was only {}",42 min_len,43 arr.len()44 )45 }46 Ok(arr)47 });4849 {50 for (i, d) in start.iter().enumerate() {51 let full = full.clone();52 destruct(53 d,54 Thunk!(move || Ok(full.evaluate()?.get(i)?.expect("length is checked"))),55 fctx.clone(),56 new_bindings,57 )?;58 }59 }6061 match rest {62 Some(DestructRest::Keep(v)) => {63 let start = start.len();64 let end = end.len();65 let full = full.clone();66 destruct(67 &Destruct::Full(v.clone()),68 Thunk!(move || {69 let full = full.evaluate()?;70 let to = full.len() - end;71 Ok(Val::Arr(full.slice(72 Some(start as i32),73 Some(to as i32),74 None,75 )))76 }),77 fctx.clone(),78 new_bindings,79 )?;80 }81 Some(DestructRest::Drop) | None => {}82 }8384 {85 for (i, d) in end.iter().enumerate() {86 let full = full.clone();87 let end = end.len();88 destruct(89 d,90 Thunk!(move || {91 let full = full.evaluate()?;92 Ok(full.get(full.len() - end + i)?.expect("length is checked"))93 }),94 fctx.clone(),95 new_bindings,96 )?;97 }98 }99 }100 #[cfg(feature = "exp-destruct")]101 Destruct::Object { fields, rest } => {102 use jrsonnet_ir::DestructRest;103 use rustc_hash::FxHashSet;104105 use crate::{ObjValueBuilder, bail};106107 let captured_fields: FxHashSet<_> = fields.iter().map(|f| f.0.clone()).collect();108 let field_names: Vec<_> = fields109 .iter()110 .map(|f| (f.0.clone(), f.2.is_some()))111 .collect();112 let has_rest = rest.is_some();113 let full = Thunk!(move || {114 let v = parent.evaluate()?;115 let Val::Obj(obj) = v else {116 bail!("expected object");117 };118 for (field, has_default) in &field_names {119 if !has_default && !obj.has_field_ex(field.clone(), true) {120 bail!("missing field: {field}");121 }122 }123 if !has_rest {124 let len = obj.len();125 if len > field_names.len() {126 bail!("too many fields, and rest not found");127 }128 }129 Ok(obj)130 });131132 match rest {133 Some(DestructRest::Keep(v)) => {134 let full = full.clone();135 destruct(136 &Destruct::Full(v.clone()),137 Thunk!(move || {138 let full = full.evaluate()?;139 let mut builder = ObjValueBuilder::new();140 builder.extend_with_core(full.as_standalone());141 builder.with_fields_omitted(captured_fields);142 Ok(Val::Obj(builder.build()))143 }),144 fctx.clone(),145 new_bindings,146 )?;147 }148 Some(DestructRest::Drop) | None => {}149 }150151 for (field, d, default) in fields {152 let default = default.clone().map(|e| (fctx.clone(), e));153 let value = {154 let field = field.clone();155 let full = full.clone();156 Thunk!(move || {157 let full = full.evaluate()?;158 if let Some(field) = full.get(field)? {159 Ok(field)160 } else {161 let (fctx, expr) = default.as_ref().expect("shape is checked");162 Ok(crate::evaluate(fctx.clone().unwrap(), expr)?)163 }164 })165 };166167 if let Some(d) = d {168 destruct(d, value, fctx.clone(), new_bindings)?;169 } else {170 destruct(171 &Destruct::Full(field.clone()),172 value,173 fctx.clone(),174 new_bindings,175 )?;176 }177 }178 }179 }180 Ok(())181}182183pub fn evaluate_dest(184 d: &BindSpec,185 fctx: Pending<Context>,186 new_bindings: &mut ContextBuilder,187) -> Result<()> {188 match d {189 BindSpec::Field { into, value } => {190 let name = into.name();191 let value = value.clone();192 let data = {193 let fctx = fctx.clone();194 Thunk!(move || evaluate_named_param(fctx.unwrap(), &value, name))195 };196 destruct(into, data, fctx, new_bindings)?;197 }198 BindSpec::Function {199 name,200 params,201 value,202 } => {203 let params = params.clone();204 let name = name.clone();205 let value = value.clone();206 new_bindings.try_bind(207 name.clone(),208 Thunk!(move || Ok(evaluate_method(fctx.unwrap(), name, params, value))),209 )?;210 }211 }212 Ok(())213}crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -145,28 +145,36 @@
)?;
}
}
- #[cfg(feature = "exp-object-iteration")]
- Val::Obj(obj) => {
+ Val::Obj(obj) if cfg!(feature = "exp-object-iteration") => {
let fields = obj.fields(
// TODO: Should there be ability to preserve iteration order?
#[cfg(feature = "exp-preserve-order")]
false,
);
guaranteed_reserve = guaranteed_reserve.max(1) * fields.len();
- for field in fields {
+ for (i, field) in fields.into_iter().enumerate() {
let fctx = Pending::new();
- let mut new_bindings = FxHashMap::with_capacity(into.binds_len());
+ let mut ctx = ContextBuilder::extend_fast(ctx.clone());
let obj = obj.clone();
let value = Thunk::evaluated(Val::arr(vec![
Thunk::evaluated(Val::string(field.clone())),
- obj.get_lazy(field).transpose().expect(
+ obj.get_lazy(field).expect(
"field exists, as field name was obtained from object.fields()",
),
]));
- destruct(into, value, fctx.clone(), &mut new_bindings)?;
- let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx);
+ destruct(into, value, fctx.clone(), &mut ctx)?;
+ let ctx = ctx.build().into_future(fctx);
- evaluate_comp(ctx, &specs[1..], callback)?;
+ evaluate_comp(
+ ctx,
+ &specs[1..],
+ if i == 0 || !specs.is_empty() {
+ guaranteed_reserve
+ } else {
+ 0
+ },
+ callback,
+ )?;
}
}
_ => bail!(InComprehensionCanOnlyIterateOverArray),