From 1b7795b5f1ce80071182096e3834a84780e5f889 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Wed, 09 Nov 2022 19:12:20 +0000 Subject: [PATCH] feat: destructure in comprehensions --- --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -8,6 +8,7 @@ }; use jrsonnet_types::ValType; +use self::destructure::destruct; use crate::{ destructure::evaluate_dest, error::Error::*, @@ -63,12 +64,16 @@ } Some(CompSpec::ForSpec(ForSpecData(var, expr))) => match evaluate(ctx.clone(), expr)? { Val::Arr(list) => { - for item in list.iter() { - evaluate_comp( - ctx.clone().with_var(var.clone(), item?.clone()), - &specs[1..], - callback, - )?; + for item in list.iter_lazy() { + let fctx = Pending::new(); + let mut new_bindings = GcHashMap::new(); + destruct(var, item, fctx.clone(), &mut new_bindings)?; + let ctx = ctx + .clone() + .extend(new_bindings, None, None, None) + .into_future(fctx); + + evaluate_comp(ctx, &specs[1..], callback)?; } } _ => throw!(InComprehensionCanOnlyIterateOverArray), @@ -78,6 +83,7 @@ } trait CloneableUnbound: Unbound + Clone {} +impl CloneableUnbound for V where V: Unbound + Clone {} fn evaluate_object_locals( fctx: Pending, @@ -88,7 +94,6 @@ fctx: Pending, locals: Rc>, } - impl CloneableUnbound for UnboundLocals {} impl Unbound for UnboundLocals { type Bound = Context; @@ -117,15 +122,20 @@ builder: &mut ObjValueBuilder, ctx: Context, uctx: B, - member: &FieldMember, + field: &FieldMember, ) -> Result<()> { - match member { + let name = evaluate_field_name(ctx.clone(), &field.name)?; + let Some(name) = name else { + return Ok(()); + }; + + match field { FieldMember { - name, plus, params: None, visibility, value, + .. } => { #[derive(Trace)] struct UnboundValue { @@ -143,11 +153,6 @@ )?) } } - - let name = evaluate_field_name(ctx.clone(), name)?; - let Some(name) = name else { - return Ok(()); - }; builder .member(name.clone()) @@ -161,7 +166,6 @@ }))?; } FieldMember { - name, params: Some(params), value, .. @@ -184,10 +188,6 @@ )) } } - - let Some(name) = evaluate_field_name(ctx.clone(), name)? else { - return Ok(()); - }; builder .member(name.clone()) @@ -227,9 +227,6 @@ Member::Field(field) => { evaluate_field_member(&mut builder, ctx.clone(), uctx.clone(), &field)? } - Member::BindStmt(_) => { - // Already handled - } Member::AssertStmt(stmt) => { #[derive(Trace)] struct ObjectAssert { @@ -247,6 +244,9 @@ assert: stmt.clone(), })); } + Member::BindStmt(_) => { + // Already handled + } } } let this = builder.build(); --- a/crates/jrsonnet-parser/src/expr.rs +++ b/crates/jrsonnet-parser/src/expr.rs @@ -253,7 +253,7 @@ #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq, Trace)] -pub struct ForSpecData(pub IStr, pub LocExpr); +pub struct ForSpecData(pub Destruct, pub LocExpr); #[cfg_attr(feature = "structdump", derive(Codegen))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] --- a/crates/jrsonnet-parser/src/lib.rs +++ b/crates/jrsonnet-parser/src/lib.rs @@ -208,7 +208,7 @@ pub rule ifspec(s: &ParserSettings) -> IfSpecData = keyword("if") _ expr:expr(s) {IfSpecData(expr)} pub rule forspec(s: &ParserSettings) -> ForSpecData - = keyword("for") _ id:id() _ keyword("in") _ cond:expr(s) {ForSpecData(id, cond)} + = keyword("for") _ id:destruct(s) _ keyword("in") _ cond:expr(s) {ForSpecData(id, cond)} pub rule compspec(s: &ParserSettings) -> Vec = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s} pub rule local_expr(s: &ParserSettings) -> Expr @@ -620,7 +620,7 @@ 16 ), vec![CompSpec::ForSpec(ForSpecData( - "x".into(), + Destruct::Full("x".into()), el!(Var("arr".into()), 26, 29) ))] ), -- gitstuff