From a8b25fbfa77b7adfe3998d87dec371c871a43290 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Thu, 19 Mar 2026 03:50:37 +0000 Subject: [PATCH] refactor(ir): flatten obj member --- --- a/crates/jrsonnet-evaluator/src/async_import.rs +++ b/crates/jrsonnet-evaluator/src/async_import.rs @@ -4,7 +4,7 @@ use jrsonnet_gcmodule::Acyclic; use jrsonnet_parser::{ ArgsDesc, AssertExpr, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName, - ForSpecData, IfElse, IfSpecData, ImportKind, Member, ObjBody, Param, ParamsDesc, + ForSpecData, IfElse, IfSpecData, ImportKind, ObjBody, Param, ParamsDesc, ParserSettings, Slice, SliceDesc, Source, SourcePath, Spanned, }; use rustc_hash::FxHashMap; @@ -102,31 +102,30 @@ } fn in_obj(obj: &ObjBody, out: &mut FoundImports) { match obj { - ObjBody::MemberList(v) => { - for member in v { - match member { - Member::Field(FieldMember { - name, - params, - value, - .. - }) => { - match name { - FieldName::Fixed(_) => {} - FieldName::Dyn(expr) => find_imports(expr, out), - } - if let Some(params) = params { - in_params(params, out); - } - find_imports(value, out); - } - Member::BindStmt(_) => todo!(), - Member::AssertStmt(assert) => { - find_imports(&assert.0, out); - if let Some(expr) = &assert.1 { - find_imports(expr, out); - } - } + ObjBody::MemberList(obj) => { + for FieldMember { + name, + params, + value, + .. + } in &obj.fields + { + match name { + FieldName::Fixed(_) => {} + FieldName::Dyn(expr) => find_imports(expr, out), + } + if let Some(params) = params { + in_params(params, out); + } + find_imports(value, out); + } + for _ in &*obj.locals { + todo!() + } + for assert in &*obj.asserts { + find_imports(&assert.0, out); + if let Some(expr) = &assert.1 { + find_imports(expr, out); } } } --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -4,7 +4,7 @@ use jrsonnet_interner::IStr; use jrsonnet_parser::{ ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, FieldName, - ForSpecData, IfSpecData, ImportKind, LiteralType, Member, ObjBody, ParamsDesc, Spanned, + ForSpecData, IfSpecData, ImportKind, LiteralType, ObjBody, ObjMembers, ParamsDesc, Spanned, }; use jrsonnet_types::ValType; use rustc_hash::FxHashMap; @@ -282,48 +282,38 @@ } #[allow(clippy::too_many_lines)] -pub fn evaluate_member_list_object(ctx: Context, members: &[Member]) -> Result { +pub fn evaluate_member_list_object(ctx: Context, members: &ObjMembers) -> Result { let mut builder = ObjValueBuilder::new(); - let locals = Rc::new( - members - .iter() - .filter_map(|m| match m { - Member::BindStmt(bind) => Some(bind.clone()), - _ => None, - }) - .collect::>(), - ); + let locals = members.locals.clone(); // We have single context for all fields, so we can cache binds let uctx = CachedUnbound::new(evaluate_object_locals(ctx.clone(), locals)); - for member in members { - match member { - Member::Field(field) => { - evaluate_field_member(&mut builder, ctx.clone(), uctx.clone(), field)?; - } - Member::AssertStmt(stmt) => { - #[derive(Trace)] - struct ObjectAssert { - uctx: B, - assert: Rc, + for field in &members.fields { + evaluate_field_member(&mut builder, ctx.clone(), uctx.clone(), &field)?; + } + + if !members.asserts.is_empty() { + #[derive(Trace)] + struct ObjectAssert { + uctx: B, + asserts: Rc>, + } + impl> ObjectAssertion for ObjectAssert { + fn run(&self, sup_this: SupThis) -> Result<()> { + let ctx = self.uctx.bind(sup_this)?; + for assert in &*self.asserts { + evaluate_assert(ctx.clone(), &assert)?; } - impl> ObjectAssertion for ObjectAssert { - fn run(&self, sup_this: SupThis) -> Result<()> { - let ctx = self.uctx.bind(sup_this)?; - evaluate_assert(ctx, &self.assert) - } - } - builder.assert(ObjectAssert { - uctx: uctx.clone(), - assert: stmt.clone(), - }); - } - Member::BindStmt(_) => { - // Already handled + Ok(()) } } + builder.assert(ObjectAssert { + uctx: uctx.clone(), + asserts: members.asserts.clone(), + }); } + Ok(builder.build()) } @@ -332,13 +322,7 @@ ObjBody::MemberList(members) => evaluate_member_list_object(ctx, members)?, ObjBody::ObjComp(obj) => { let mut builder = ObjValueBuilder::new(); - let locals = Rc::new( - obj.pre_locals - .iter() - .chain(obj.post_locals.iter()) - .cloned() - .collect::>(), - ); + let locals = obj.locals.clone(); evaluate_comp(ctx, &obj.compspecs, &mut |ctx| { let uctx = evaluate_object_locals(ctx.clone(), locals.clone()); --- a/crates/jrsonnet-parser/src/expr.rs +++ b/crates/jrsonnet-parser/src/expr.rs @@ -47,10 +47,10 @@ } #[derive(Debug, PartialEq, Acyclic)] -pub enum Member { +pub(crate) enum Member { Field(FieldMember), BindStmt(BindSpec), - AssertStmt(Rc), + AssertStmt(AssertStmt), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)] @@ -240,7 +240,7 @@ } } -#[derive(Debug, Clone, PartialEq, Acyclic)] +#[derive(Debug, PartialEq, Acyclic)] pub enum BindSpec { Field { into: Destruct, @@ -275,15 +275,21 @@ #[derive(Debug, PartialEq, Acyclic)] pub struct ObjComp { - pub pre_locals: Vec, + pub locals: Rc>, pub field: Rc, - pub post_locals: Vec, pub compspecs: Vec, } #[derive(Debug, PartialEq, Acyclic)] +pub struct ObjMembers { + pub locals: Rc>, + pub asserts: Rc>, + pub fields: Vec, +} + +#[derive(Debug, PartialEq, Acyclic)] pub enum ObjBody { - MemberList(Vec), + MemberList(ObjMembers), ObjComp(ObjComp), } --- a/crates/jrsonnet-parser/src/lib.rs +++ b/crates/jrsonnet-parser/src/lib.rs @@ -139,8 +139,8 @@ / obj:destruct_object(s) {obj} pub rule bind(s: &ParserSettings) -> expr::BindSpec - = into:destruct(s) _ "=" _ expr:expr(s) {expr::BindSpec::Field{into, value: Rc::new(expr)}} - / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec::Function{name, params, value: Rc::new(expr)}} + = into:destruct(s) _ "=" _ value:expr(s) {expr::BindSpec::Field{into, value: Rc::new(value)}} + / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {expr::BindSpec::Function{name, params, value: Rc::new(value)}} pub rule assertion(s: &ParserSettings) -> expr::AssertStmt = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) } @@ -207,20 +207,35 @@ = keyword("local") _ bind:bind(s) {bind} pub rule member(s: &ParserSettings) -> expr::Member = bind:obj_local(s) {expr::Member::BindStmt(bind)} - / assertion:assertion(s) {expr::Member::AssertStmt(Rc::new(assertion))} + / assertion:assertion(s) {expr::Member::AssertStmt(assertion)} / field:field(s) {expr::Member::Field(field)} pub rule objinside(s: &ParserSettings) -> expr::ObjBody = pre_locals:(b: obj_local(s) comma() {b})* &"[" field:field(s) post_locals:(comma() b:obj_local(s) {b})* _ ("," _)? forspec:forspec(s) others:(_ rest:compspec(s) {rest})? { let mut compspecs = vec![CompSpec::ForSpec(forspec)]; compspecs.extend(others.unwrap_or_default()); + let mut locals = pre_locals; + locals.extend(post_locals); expr::ObjBody::ObjComp(expr::ObjComp{ - pre_locals, + locals: Rc::new(locals), field: Rc::new(field), - post_locals, compspecs, }) } - / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)} + / members:(member(s) ** comma()) comma()? { + let mut locals = Vec::new(); + let mut asserts = Vec::new(); + let mut fields = Vec::new(); + for member in members { + match member { + Member::Field(field_member) => fields.push(field_member), + Member::BindStmt(bind_spec) => locals.push(bind_spec), + Member::AssertStmt(assert_stmt) => asserts.push(assert_stmt), + } + } + expr::ObjBody::MemberList(ObjMembers { + locals: Rc::new(locals), asserts: Rc::new(asserts), fields + }) + } pub rule ifspec(s: &ParserSettings) -> IfSpecData = keyword("if") _ expr:expr(s) {IfSpecData(expr)} pub rule forspec(s: &ParserSettings) -> ForSpecData --- a/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__add_location_info_to_all_sub_expressions.snap +++ b/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__add_location_info_to_all_sub_expressions.snap @@ -7,12 +7,16 @@ lhs: ObjExtend( Obj( MemberList( - [], + ObjMembers { + locals: [], + asserts: [], + fields: [], + }, ), ) from virtual::0-2, MemberList( - [ - BindStmt( + ObjMembers { + locals: [ Field { into: Full( "x", @@ -21,8 +25,9 @@ 1.0, ) from virtual::15-16, }, - ), - Field( + ], + asserts: [], + fields: [ FieldMember { name: Fixed( "x", @@ -34,14 +39,18 @@ "x", ) from virtual::21-22, }, - ), - ], + ], + }, ), ) from virtual::0-24, op: Add, rhs: Obj( MemberList( - [], + ObjMembers { + locals: [], + asserts: [], + fields: [], + }, ), ) from virtual::27-29, }, --- a/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__empty_object.snap +++ b/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__empty_object.snap @@ -4,6 +4,10 @@ --- Obj( MemberList( - [], + ObjMembers { + locals: [], + asserts: [], + fields: [], + }, ), ) from virtual::0-2 --- a/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__missing_newline_between_comment_and_eof.snap +++ b/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__missing_newline_between_comment_and_eof.snap @@ -4,8 +4,10 @@ --- Obj( MemberList( - [ - Field( + ObjMembers { + locals: [], + asserts: [], + fields: [ FieldMember { name: Fixed( "a", @@ -17,7 +19,7 @@ 1.0, ) from virtual::3-4, }, - ), - ], + ], + }, ), ) from virtual::0-5 -- gitstuff