git.delta.rocks / jrsonnet / refs/commits / e9c741d736e9

difftreelog

refactor AssertStmt to struct

zksvlxnsYaroslav Bolyukin2026-04-25parent: #6fbff53.patch.diff
in: master

6 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -454,19 +454,18 @@
 }
 
 pub fn evaluate_assert(ctx: Context, assertion: &AssertStmt) -> Result<()> {
-	let value = &assertion.0;
-	let msg = &assertion.1;
+	let AssertStmt { assertion, message } = assertion;
 	let assertion_result = in_frame(
-		CallLocation::new(&value.span),
+		CallLocation::new(&assertion.span),
 		|| "assertion condition".to_owned(),
-		|| bool::from_untyped(evaluate(ctx.clone(), value)?),
+		|| bool::from_untyped(evaluate(ctx.clone(), assertion)?),
 	)?;
 	if !assertion_result {
 		in_frame(
-			CallLocation::new(&value.span),
+			CallLocation::new(&assertion.span),
 			|| "assertion failure".to_owned(),
 			|| {
-				if let Some(msg) = msg {
+				if let Some(msg) = message {
 					bail!(AssertionFailed(evaluate(ctx, msg)?.to_string()?));
 				}
 				bail!(AssertionFailed(Val::Null.to_string()?));
modifiedcrates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/lib.rs
+++ b/crates/jrsonnet-ir-parser/src/lib.rs
@@ -237,13 +237,13 @@
 
 fn assert_stmt(p: &mut Parser<'_>) -> Result<AssertStmt> {
 	p.eat(T![assert])?;
-	let cond = spanned(p, expr)?;
-	let msg = if p.try_eat(T![:]) {
-		Some(spanned(p, expr)?)
+	let assertion = spanned(p, expr)?;
+	let message = if p.try_eat(T![:]) {
+		Some(expr(p)?)
 	} else {
 		None
 	};
-	Ok(AssertStmt(cond, msg))
+	Ok(AssertStmt { assertion, message })
 }
 
 fn if_spec_data(p: &mut Parser<'_>) -> Result<IfSpecData> {
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_test.snapdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_test.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_test.snap
@@ -4,8 +4,8 @@
 ---
 AssertExpr(
     AssertExpr {
-        assert: AssertStmt(
-            Index {
+        assert: AssertStmt {
+            assertion: Index {
                 indexable: Literal(
                     True,
                 ),
@@ -18,12 +18,12 @@
                     },
                 ],
             } from virtual:<test>:7-18,
-            Some(
+            message: Some(
                 Literal(
                     False,
-                ) from virtual:<test>:21-26,
+                ),
             ),
-        ),
+        },
         rest: Literal(
             True,
         ),
modifiedcrates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth
before · crates/jrsonnet-ir/src/expr.rs
1use std::{2	fmt::{self, Debug, Display},3	ops::Deref,4	rc::Rc,5};67use jrsonnet_gcmodule::Acyclic;8use jrsonnet_interner::IStr;910use crate::{11	function::{FunctionSignature, ParamDefault, ParamName, ParamParse},12	source::Source,13};1415#[derive(Debug, PartialEq, Acyclic)]16pub enum FieldName {17	/// {fixed: 2}18	Fixed(IStr),19	/// {["dyn"+"amic"]: 3}20	Dyn(Expr),21}2223#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]24#[repr(u8)]25pub enum Visibility {26	/// :27	Normal,28	/// ::29	Hidden,30	/// :::31	Unhide,32}3334impl Visibility {35	pub fn is_visible(&self) -> bool {36		matches!(self, Self::Normal | Self::Unhide)37	}38}3940#[derive(Debug, PartialEq, Acyclic)]41pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);4243#[derive(Debug, PartialEq, Acyclic)]44pub struct FieldMember {45	pub name: Spanned<FieldName>,46	pub plus: bool,47	pub params: Option<ExprParams>,48	pub visibility: Visibility,49	pub value: Rc<Expr>,50}5152#[derive(Debug, PartialEq, Acyclic)]53pub enum Member {54	Field(FieldMember),55	BindStmt(BindSpec),56	AssertStmt(AssertStmt),57}5859#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]60pub enum UnaryOpType {61	Plus,62	Minus,63	BitNot,64	Not,65}6667impl Display for UnaryOpType {68	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {69		use UnaryOpType::*;70		write!(71			f,72			"{}",73			match self {74				Plus => "+",75				Minus => "-",76				BitNot => "~",77				Not => "!",78			}79		)80	}81}8283#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]84pub enum BinaryOpType {85	Mul,86	Div,8788	/// Implemented as intrinsic, put here for completeness89	Mod,9091	Add,92	Sub,9394	Lhs,95	Rhs,9697	Lt,98	Gt,99	Lte,100	Gte,101102	BitAnd,103	BitOr,104	BitXor,105106	Eq,107	Neq,108109	And,110	Or,111	#[cfg(feature = "exp-null-coaelse")]112	NullCoaelse,113114	// Equialent to std.objectHasEx(a, b, true)115	In,116}117118impl Display for BinaryOpType {119	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {120		use BinaryOpType::*;121		write!(122			f,123			"{}",124			match self {125				Mul => "*",126				Div => "/",127				Mod => "%",128				Add => "+",129				Sub => "-",130				Lhs => "<<",131				Rhs => ">>",132				Lt => "<",133				Gt => ">",134				Lte => "<=",135				Gte => ">=",136				BitAnd => "&",137				BitOr => "|",138				BitXor => "^",139				Eq => "==",140				Neq => "!=",141				And => "&&",142				Or => "||",143				In => "in",144				#[cfg(feature = "exp-null-coaelse")]145				NullCoaelse => "??",146			}147		)148	}149}150151/// name, default value152#[derive(Debug, PartialEq, Acyclic)]153pub struct ExprParam {154	pub destruct: Destruct,155	pub default: Option<Rc<Expr>>,156}157158/// Defined function parameters159#[derive(Debug, Clone, PartialEq, Acyclic)]160pub struct ExprParams {161	pub exprs: Rc<Vec<ExprParam>>,162	pub signature: FunctionSignature,163	pub(crate) binds_len: usize,164}165impl ExprParams {166	pub fn len(&self) -> usize {167		self.exprs.len()168	}169	pub fn is_empty(&self) -> bool {170		self.exprs.is_empty()171	}172173	pub fn binds_len(&self) -> usize {174		self.binds_len175	}176	pub fn new(exprs: Vec<ExprParam>) -> Self {177		Self {178			signature: FunctionSignature::new(179				exprs180					.iter()181					.map(|p| {182						ParamParse::new(183							p.destruct.name(),184							ParamDefault::exists(p.default.is_some()),185						)186					})187					.collect(),188			),189			binds_len: exprs.iter().map(|v| v.destruct.binds_len()).sum(),190			exprs: Rc::new(exprs),191		}192	}193}194195#[derive(Debug, PartialEq, Acyclic)]196pub struct ArgsDesc {197	pub unnamed: Vec<Rc<Expr>>,198	pub names: Vec<IStr>,199	pub values: Vec<Rc<Expr>>,200}201impl ArgsDesc {202	pub fn new(unnamed: Vec<Rc<Expr>>, names: Vec<IStr>, values: Vec<Rc<Expr>>) -> Self {203		Self {204			unnamed,205			names,206			values,207		}208	}209}210211#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]212pub enum DestructRest {213	/// ...rest214	Keep(IStr),215	/// ...216	Drop,217}218219#[derive(Debug, Clone, PartialEq, Acyclic)]220pub enum Destruct {221	Full(IStr),222	#[cfg(feature = "exp-destruct")]223	Skip,224	#[cfg(feature = "exp-destruct")]225	Array {226		start: Vec<Destruct>,227		rest: Option<DestructRest>,228		end: Vec<Destruct>,229	},230	#[cfg(feature = "exp-destruct")]231	Object {232		#[allow(clippy::type_complexity)]233		fields: Vec<(IStr, Option<Destruct>, Option<Rc<Spanned<Expr>>>)>,234		rest: Option<DestructRest>,235	},236}237impl Destruct {238	/// Name of destructure, used for function parameter names239	pub fn name(&self) -> ParamName {240		match self {241			Self::Full(name) => ParamName::Named(name.clone()),242			#[cfg(feature = "exp-destruct")]243			_ => ParamName::Unnamed,244		}245	}246	pub fn binds_len(&self) -> usize {247		#[cfg(feature = "exp-destruct")]248		fn cap_rest(rest: &Option<DestructRest>) -> usize {249			match rest {250				Some(DestructRest::Keep(_)) => 1,251				Some(DestructRest::Drop) => 0,252				None => 0,253			}254		}255		match self {256			Self::Full(_) => 1,257			#[cfg(feature = "exp-destruct")]258			Self::Skip => 0,259			#[cfg(feature = "exp-destruct")]260			Self::Array { start, rest, end } => {261				start.iter().map(Destruct::binds_len).sum::<usize>()262					+ end.iter().map(Destruct::binds_len).sum::<usize>()263					+ cap_rest(rest)264			}265			#[cfg(feature = "exp-destruct")]266			Self::Object { fields, rest } => {267				let mut out = 0;268				for (_, into, _) in fields {269					match into {270						Some(v) => out += v.binds_len(),271						// Field is destructured to default name272						None => out += 1,273					}274				}275				out + cap_rest(rest)276			}277		}278	}279}280281#[derive(Debug, PartialEq, Acyclic)]282pub enum BindSpec {283	Field {284		into: Destruct,285		value: Rc<Expr>,286	},287	Function {288		name: IStr,289		params: ExprParams,290		value: Rc<Expr>,291	},292}293impl BindSpec {294	pub fn binds_len(&self) -> usize {295		match self {296			BindSpec::Field { into, .. } => into.binds_len(),297			BindSpec::Function { .. } => 1,298		}299	}300}301302#[derive(Debug, PartialEq, Acyclic)]303pub struct IfSpecData {304	pub span: Span,305	pub cond: Expr,306}307308#[derive(Debug, PartialEq, Acyclic)]309pub struct ForSpecData {310	pub destruct: Destruct,311	pub over: Expr,312}313314#[derive(Debug, PartialEq, Acyclic)]315pub enum CompSpec {316	IfSpec(IfSpecData),317	ForSpec(ForSpecData),318}319320#[derive(Debug, PartialEq, Acyclic)]321pub struct ObjComp {322	pub locals: Rc<Vec<BindSpec>>,323	pub field: Rc<FieldMember>,324	pub compspecs: Vec<CompSpec>,325}326327#[derive(Debug, PartialEq, Acyclic)]328pub struct ObjMembers {329	pub locals: Rc<Vec<BindSpec>>,330	pub asserts: Rc<Vec<AssertStmt>>,331	pub fields: Vec<FieldMember>,332}333334#[derive(Debug, PartialEq, Acyclic)]335pub enum ObjBody {336	MemberList(ObjMembers),337	ObjComp(ObjComp),338}339340#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]341pub enum LiteralType {342	This,343	Super,344	Dollar,345	Null,346	True,347	False,348}349350#[derive(Debug, PartialEq, Acyclic)]351pub struct SliceDesc {352	pub start: Option<Spanned<Expr>>,353	pub end: Option<Spanned<Expr>>,354	pub step: Option<Spanned<Expr>>,355}356357#[derive(Debug, PartialEq, Acyclic)]358pub struct AssertExpr {359	pub assert: AssertStmt,360	pub rest: Expr,361}362363#[derive(Debug, PartialEq, Acyclic)]364pub struct BinaryOp {365	pub lhs: Expr,366	pub op: BinaryOpType,367	pub rhs: Expr,368}369370#[derive(Debug, PartialEq, Acyclic)]371pub enum ImportKind {372	Normal,373	Str,374	Bin,375}376377#[derive(Debug, PartialEq, Acyclic)]378pub struct IfElse {379	pub cond: IfSpecData,380	pub cond_then: Expr,381	pub cond_else: Option<Expr>,382}383384#[derive(Debug, PartialEq, Acyclic)]385pub struct Slice {386	pub value: Expr,387	pub slice: SliceDesc,388}389390/// Syntax base391#[derive(Debug, PartialEq, Acyclic)]392pub enum Expr {393	Literal(LiteralType),394395	/// String value: "hello"396	Str(IStr),397	/// Number: 1, 2.0, 2e+20398	Num(f64),399	/// Variable name: test400	Var(Spanned<IStr>),401402	/// Array of expressions: [1, 2, "Hello"]403	Arr(Rc<Vec<Expr>>),404	/// Array comprehension:405	/// ```jsonnet406	///  ingredients: [407	///    { kind: kind, qty: 4 / 3 }408	///    for kind in [409	///      'Honey Syrup',410	///      'Lemon Juice',411	///      'Farmers Gin',412	///    ]413	///  ],414	/// ```415	ArrComp(Rc<Expr>, Vec<CompSpec>),416417	/// Object: {a: 2}418	Obj(ObjBody),419	/// Object extension: var1 {b: 2}420	ObjExtend(Rc<Expr>, ObjBody),421422	/// -2423	UnaryOp(UnaryOpType, Box<Expr>),424	/// 2 - 2425	BinaryOp(Box<BinaryOp>),426	/// assert 2 == 2 : "Math is broken"427	AssertExpr(Rc<AssertExpr>),428	/// local a = 2; { b: a }429	LocalExpr(Vec<BindSpec>, Box<Expr>),430431	/// import* "hello"432	Import(Spanned<ImportKind>, Box<Expr>),433	/// error "I'm broken"434	ErrorStmt(Span, Box<Expr>),435	/// a(b, c)436	Apply(Box<Expr>, Spanned<ArgsDesc>, bool),437	/// a[b], a.b, a?.b438	Index {439		indexable: Box<Expr>,440		parts: Vec<IndexPart>,441	},442	/// function(x) x443	Function(ExprParams, Rc<Expr>),444	/// if true == false then 1 else 2445	IfElse(Box<IfElse>),446	Slice(Box<Slice>),447}448449#[derive(Debug, PartialEq, Acyclic)]450pub struct IndexPart {451	pub span: Span,452	pub value: Expr,453	#[cfg(feature = "exp-null-coaelse")]454	pub null_coaelse: bool,455}456457/// file, begin offset, end offset458#[derive(Clone, PartialEq, Eq, Acyclic)]459#[repr(C)]460pub struct Span(pub Source, pub u32, pub u32);461impl Span {462	pub fn belongs_to(&self, other: &Span) -> bool {463		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2464	}465}466467#[cfg(target_pointer_width = "64")]468static_assertions::assert_eq_size!(Span, (usize, usize));469470impl Debug for Span {471	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {472		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)473	}474}475476#[derive(Clone, PartialEq, Acyclic)]477pub struct Spanned<T: Acyclic> {478	pub value: T,479	pub span: Span,480}481impl<T: Acyclic> Deref for Spanned<T> {482	type Target = T;483	fn deref(&self) -> &Self::Target {484		&self.value485	}486}487impl<T: Acyclic> Spanned<T> {488	#[inline]489	pub fn new(value: T, span: Span) -> Self {490		Self { value, span }491	}492}493494impl<T: Debug + Acyclic> Debug for Spanned<T> {495	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {496		let expr = &**self;497		if f.alternate() {498			write!(f, "{:#?}", expr)?;499		} else {500			write!(f, "{:?}", expr)?;501		}502		write!(f, " from {:?}", self.span)?;503		Ok(())504	}505}
modifiedcrates/jrsonnet-ir/src/visit.rsdiffbeforeafterboth
--- a/crates/jrsonnet-ir/src/visit.rs
+++ b/crates/jrsonnet-ir/src/visit.rs
@@ -157,10 +157,10 @@
 }
 
 pub fn visit_assert_stmt<V: Visitor>(v: &mut V, ass: &AssertStmt) {
-	let AssertStmt(cond, msg) = ass;
-	v.visit_expr(cond);
-	if let Some(msg) = msg {
-		v.visit_expr(msg);
+	let AssertStmt { assertion, message } = ass;
+	v.visit_expr(assertion);
+	if let Some(message) = message {
+		v.visit_expr(message);
 	}
 }
 pub fn visit_expr<V: Visitor>(v: &mut V, e: &Expr) {
modifiedcrates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/src/lib.rs
+++ b/crates/jrsonnet-peg-parser/src/lib.rs
@@ -138,7 +138,7 @@
 			/ name:id() _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {BindSpec::Function{name, params, value: Rc::new(value)}}
 
 		pub rule assertion(s: &ParserSettings) -> AssertStmt
-			= keyword("assert") _ cond:spanned(<expr(s)>, s) msg:(_ ":" _ e:spanned(<expr(s)>, s) {e})? { AssertStmt(cond, msg) }
+			= keyword("assert") _ assertion:spanned(<expr(s)>, s) message:(_ ":" _ e:expr(s) {e})? { AssertStmt{assertion, message} }
 
 		pub rule whole_line() -> &'input str
 			= str:$((!['\n'][_])* "\n") {str}