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

difftreelog

feat object destructuring defaults

Yaroslav Bolyukin2022-06-03parent: #3961a53.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/dynamic.rs
+++ b/crates/jrsonnet-evaluator/src/dynamic.rs
@@ -8,6 +8,9 @@
 	pub fn new() -> Self {
 		Self(Cc::new(RefCell::new(None)))
 	}
+	pub fn new_filled(v: T) -> Self {
+		Self(Cc::new(RefCell::new(Some(v))))
+	}
 	/// # Panics
 	/// If wrapper is filled already
 	pub fn fill(self, value: T) {
modifiedcrates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -12,9 +12,11 @@
 };
 
 #[allow(clippy::too_many_lines)]
+#[allow(unused_variables)]
 pub fn destruct(
 	d: &Destruct,
 	parent: Thunk<Val>,
+	fctx: Pending<Context>,
 	new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,
 ) -> Result<()> {
 	match d {
@@ -89,6 +91,7 @@
 							full: full.clone(),
 							index: i,
 						})),
+						fctx.clone(),
 						new_bindings,
 					)?;
 				}
@@ -119,6 +122,7 @@
 							start: start.len(),
 							end: end.len(),
 						})),
+						fctx.clone(),
 						new_bindings,
 					)?;
 				}
@@ -151,6 +155,7 @@
 							index: i,
 							end: end.len(),
 						})),
+						fctx.clone(),
 						new_bindings,
 					)?;
 				}
@@ -189,36 +194,51 @@
 					Ok(obj)
 				}
 			}
-			let field_names: Vec<_> = fields.iter().map(|f| f.0.clone()).collect();
+			let field_names: Vec<_> = fields
+				.iter()
+				.filter(|f| f.2.is_none())
+				.map(|f| f.0.clone())
+				.collect();
 			let full = Thunk::new(tb!(DataThunk {
 				parent,
 				field_names: field_names.clone(),
 				has_rest: rest.is_some()
 			}));
 
-			for (field, d) in fields {
+			for (field, d, default) in fields {
 				#[derive(Trace)]
 				struct FieldThunk {
 					full: Thunk<ObjValue>,
 					field: IStr,
+					default: Option<(Pending<Context>, LocExpr)>,
 				}
 				impl ThunkValue for FieldThunk {
 					type Output = Val;
 
 					fn get(self: Box<Self>, s: State) -> Result<Self::Output> {
 						let full = self.full.evaluate(s.clone())?;
-						let field = full.get(s, self.field)?.expect("shape is checked");
-						Ok(field)
+						if let Some(field) = full.get(s.clone(), self.field)? {
+							Ok(field)
+						} else {
+							let (fctx, expr) = self.default.as_ref().expect("shape is checked");
+							Ok(evaluate(s, fctx.clone().unwrap(), &expr)?)
+						}
 					}
 				}
 				let value = Thunk::new(tb!(FieldThunk {
 					full: full.clone(),
-					field: field.clone()
+					field: field.clone(),
+					default: default.clone().map(|e| (fctx.clone(), e)),
 				}));
 				if let Some(d) = d {
-					destruct(d, value, new_bindings)?;
+					destruct(d, value, fctx.clone(), new_bindings)?;
 				} else {
-					destruct(&Destruct::Full(field.clone()), value, new_bindings)?;
+					destruct(
+						&Destruct::Full(field.clone()),
+						value,
+						fctx.clone(),
+						new_bindings,
+					)?;
 				}
 			}
 		}
@@ -251,10 +271,10 @@
 			}
 			let data = Thunk::new(tb!(EvaluateThunkValue {
 				name: into.name(),
-				fctx,
+				fctx: fctx.clone(),
 				expr: value.clone(),
 			}));
-			destruct(into, data, new_bindings)?;
+			destruct(into, data, fctx, new_bindings)?;
 		}
 		BindSpec::Function {
 			name,
modifiedcrates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function/parse.rs
+++ b/crates/jrsonnet-evaluator/src/function/parse.rs
@@ -56,7 +56,12 @@
 
 	args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {
 		let name = params[id].0.clone();
-		destruct(&name, arg, &mut passed_args)?;
+		destruct(
+			&name,
+			arg,
+			Pending::new_filled(ctx.clone()),
+			&mut passed_args,
+		)?;
 		filled_positionals += 1;
 		Ok(())
 	})?;
@@ -96,6 +101,7 @@
 					name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
 					value: param.1.clone().expect("default exists"),
 				})),
+				fctx.clone(),
 				&mut defaults,
 			)?;
 			if param.0.name().is_some() {
@@ -230,6 +236,7 @@
 					name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
 					value: v.clone(),
 				})),
+				fctx.clone(),
 				&mut bindings,
 			)?;
 		} else {
@@ -238,6 +245,7 @@
 				Thunk::new(tb!(DependsOnUnbound(
 					param.0.name().unwrap_or_else(|| "<destruct>".into())
 				))),
+				fctx.clone(),
 				&mut bindings,
 			)?;
 		}
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
before · crates/jrsonnet-parser/src/expr.rs
1use std::{2	fmt::{self, Debug, Display},3	ops::Deref,4	rc::Rc,5};67use gcmodule::Trace;8use jrsonnet_interner::IStr;9#[cfg(feature = "serde")]10use serde::{Deserialize, Serialize};1112use crate::source::Source;1314#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]15#[derive(Debug, PartialEq, Trace)]16pub enum FieldName {17	/// {fixed: 2}18	Fixed(IStr),19	/// {["dyn"+"amic"]: 3}20	Dyn(LocExpr),21}2223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]24#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]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#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]41#[derive(Clone, Debug, PartialEq, Trace)]42pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);4344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]45#[derive(Debug, PartialEq, Trace)]46pub struct FieldMember {47	pub name: FieldName,48	pub plus: bool,49	pub params: Option<ParamsDesc>,50	pub visibility: Visibility,51	pub value: LocExpr,52}5354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]55#[derive(Debug, PartialEq, Trace)]56pub enum Member {57	Field(FieldMember),58	BindStmt(BindSpec),59	AssertStmt(AssertStmt),60}6162#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]63#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]64pub enum UnaryOpType {65	Plus,66	Minus,67	BitNot,68	Not,69}7071impl Display for UnaryOpType {72	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {73		use UnaryOpType::*;74		write!(75			f,76			"{}",77			match self {78				Plus => "+",79				Minus => "-",80				BitNot => "~",81				Not => "!",82			}83		)84	}85}8687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]88#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]89pub enum BinaryOpType {90	Mul,91	Div,9293	/// Implemented as intrinsic, put here for completeness94	Mod,9596	Add,97	Sub,9899	Lhs,100	Rhs,101102	Lt,103	Gt,104	Lte,105	Gte,106107	BitAnd,108	BitOr,109	BitXor,110111	Eq,112	Neq,113114	And,115	Or,116117	// Equialent to std.objectHasEx(a, b, true)118	In,119}120121impl Display for BinaryOpType {122	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {123		use BinaryOpType::*;124		write!(125			f,126			"{}",127			match self {128				Mul => "*",129				Div => "/",130				Mod => "%",131				Add => "+",132				Sub => "-",133				Lhs => "<<",134				Rhs => ">>",135				Lt => "<",136				Gt => ">",137				Lte => "<=",138				Gte => ">=",139				BitAnd => "&",140				BitOr => "|",141				BitXor => "^",142				Eq => "==",143				Neq => "!=",144				And => "&&",145				Or => "||",146				In => "in",147			}148		)149	}150}151152/// name, default value153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]154#[derive(Debug, PartialEq, Trace)]155pub struct Param(pub Destruct, pub Option<LocExpr>);156157/// Defined function parameters158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]159#[derive(Debug, Clone, PartialEq, Trace)]160pub struct ParamsDesc(pub Rc<Vec<Param>>);161162impl Deref for ParamsDesc {163	type Target = Vec<Param>;164	fn deref(&self) -> &Self::Target {165		&self.0166	}167}168169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]170#[derive(Debug, PartialEq, Trace)]171pub struct ArgsDesc {172	pub unnamed: Vec<LocExpr>,173	pub named: Vec<(IStr, LocExpr)>,174}175impl ArgsDesc {176	pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {177		Self { unnamed, named }178	}179}180181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]182#[derive(Debug, Clone, PartialEq, Eq, Trace)]183pub enum DestructRest {184	/// ...rest185	Keep(IStr),186	/// ...187	Drop,188}189190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]191#[derive(Debug, Clone, PartialEq, Eq, Trace)]192pub enum Destruct {193	Full(IStr),194	#[cfg(feature = "exp-destruct")]195	Skip,196	#[cfg(feature = "exp-destruct")]197	Array {198		start: Vec<Destruct>,199		rest: Option<DestructRest>,200		end: Vec<Destruct>,201	},202	#[cfg(feature = "exp-destruct")]203	Object {204		fields: Vec<(IStr, Option<Destruct>)>,205		rest: Option<DestructRest>,206	},207}208impl Destruct {209	/// Name of destructure, used for function parameter names210	pub fn name(&self) -> Option<IStr> {211		match self {212			Self::Full(name) => Some(name.clone()),213			#[cfg(feature = "exp-destruct")]214			_ => None,215		}216	}217}218219#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]220#[derive(Debug, Clone, PartialEq, Trace)]221pub enum BindSpec {222	Field {223		into: Destruct,224		value: LocExpr,225	},226	Function {227		name: IStr,228		params: ParamsDesc,229		value: LocExpr,230	},231}232233#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]234#[derive(Debug, PartialEq, Trace)]235pub struct IfSpecData(pub LocExpr);236237#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]238#[derive(Debug, PartialEq, Trace)]239pub struct ForSpecData(pub IStr, pub LocExpr);240241#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]242#[derive(Debug, PartialEq, Trace)]243pub enum CompSpec {244	IfSpec(IfSpecData),245	ForSpec(ForSpecData),246}247248#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]249#[derive(Debug, PartialEq, Trace)]250pub struct ObjComp {251	pub pre_locals: Vec<BindSpec>,252	pub key: LocExpr,253	pub plus: bool,254	pub value: LocExpr,255	pub post_locals: Vec<BindSpec>,256	pub compspecs: Vec<CompSpec>,257}258259#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]260#[derive(Debug, PartialEq, Trace)]261pub enum ObjBody {262	MemberList(Vec<Member>),263	ObjComp(ObjComp),264}265266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]267#[derive(Debug, PartialEq, Eq, Clone, Copy, Trace)]268pub enum LiteralType {269	This,270	Super,271	Dollar,272	Null,273	True,274	False,275}276277#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]278#[derive(Debug, PartialEq, Trace)]279pub struct SliceDesc {280	pub start: Option<LocExpr>,281	pub end: Option<LocExpr>,282	pub step: Option<LocExpr>,283}284285/// Syntax base286#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]287#[derive(Debug, PartialEq, Trace)]288pub enum Expr {289	Literal(LiteralType),290291	/// String value: "hello"292	Str(IStr),293	/// Number: 1, 2.0, 2e+20294	Num(f64),295	/// Variable name: test296	Var(IStr),297298	/// Array of expressions: [1, 2, "Hello"]299	Arr(Vec<LocExpr>),300	/// Array comprehension:301	/// ```jsonnet302	///  ingredients: [303	///    { kind: kind, qty: 4 / 3 }304	///    for kind in [305	///      'Honey Syrup',306	///      'Lemon Juice',307	///      'Farmers Gin',308	///    ]309	///  ],310	/// ```311	ArrComp(LocExpr, Vec<CompSpec>),312313	/// Object: {a: 2}314	Obj(ObjBody),315	/// Object extension: var1 {b: 2}316	ObjExtend(LocExpr, ObjBody),317318	/// (obj)319	Parened(LocExpr),320321	/// -2322	UnaryOp(UnaryOpType, LocExpr),323	/// 2 - 2324	BinaryOp(LocExpr, BinaryOpType, LocExpr),325	/// assert 2 == 2 : "Math is broken"326	AssertExpr(AssertStmt, LocExpr),327	/// local a = 2; { b: a }328	LocalExpr(Vec<BindSpec>, LocExpr),329330	/// import "hello"331	Import(IStr),332	/// importStr "file.txt"333	ImportStr(IStr),334	/// importBin "file.txt"335	ImportBin(IStr),336	/// error "I'm broken"337	ErrorStmt(LocExpr),338	/// a(b, c)339	Apply(LocExpr, ArgsDesc, bool),340	/// a[b]341	Index(LocExpr, LocExpr),342	/// function(x) x343	Function(ParamsDesc, LocExpr),344	/// std.thisFile345	IntrinsicThisFile,346	/// std.id,347	IntrinsicId,348	/// std.primitiveEquals349	Intrinsic(IStr),350	/// if true == false then 1 else 2351	IfElse {352		cond: IfSpecData,353		cond_then: LocExpr,354		cond_else: Option<LocExpr>,355	},356	Slice(LocExpr, SliceDesc),357}358359/// file, begin offset, end offset360#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]361#[derive(Clone, PartialEq, Eq, Trace)]362#[skip_trace]363#[repr(C)]364pub struct ExprLocation(pub Source, pub u32, pub u32);365impl ExprLocation {366	pub fn belongs_to(&self, other: &ExprLocation) -> bool {367		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2368	}369}370371#[cfg(target_pointer_width = "64")]372static_assertions::assert_eq_size!(ExprLocation, [u8; 16]);373374impl Debug for ExprLocation {375	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {376		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)377	}378}379380/// Holds AST expression and its location in source file381#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]382#[derive(Clone, PartialEq, Trace)]383pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);384385#[cfg(target_pointer_width = "64")]386static_assertions::assert_eq_size!(LocExpr, [u8; 24]);387388impl Debug for LocExpr {389	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {390		if f.alternate() {391			write!(f, "{:#?}", self.0)?;392		} else {393			write!(f, "{:?}", self.0)?;394		}395		write!(f, " from {:?}", self.1)?;396		Ok(())397	}398}
after · crates/jrsonnet-parser/src/expr.rs
1use std::{2	fmt::{self, Debug, Display},3	ops::Deref,4	rc::Rc,5};67use gcmodule::Trace;8use jrsonnet_interner::IStr;9#[cfg(feature = "serde")]10use serde::{Deserialize, Serialize};1112use crate::source::Source;1314#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]15#[derive(Debug, PartialEq, Trace)]16pub enum FieldName {17	/// {fixed: 2}18	Fixed(IStr),19	/// {["dyn"+"amic"]: 3}20	Dyn(LocExpr),21}2223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]24#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]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#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]41#[derive(Clone, Debug, PartialEq, Trace)]42pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);4344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]45#[derive(Debug, PartialEq, Trace)]46pub struct FieldMember {47	pub name: FieldName,48	pub plus: bool,49	pub params: Option<ParamsDesc>,50	pub visibility: Visibility,51	pub value: LocExpr,52}5354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]55#[derive(Debug, PartialEq, Trace)]56pub enum Member {57	Field(FieldMember),58	BindStmt(BindSpec),59	AssertStmt(AssertStmt),60}6162#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]63#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]64pub enum UnaryOpType {65	Plus,66	Minus,67	BitNot,68	Not,69}7071impl Display for UnaryOpType {72	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {73		use UnaryOpType::*;74		write!(75			f,76			"{}",77			match self {78				Plus => "+",79				Minus => "-",80				BitNot => "~",81				Not => "!",82			}83		)84	}85}8687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]88#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]89pub enum BinaryOpType {90	Mul,91	Div,9293	/// Implemented as intrinsic, put here for completeness94	Mod,9596	Add,97	Sub,9899	Lhs,100	Rhs,101102	Lt,103	Gt,104	Lte,105	Gte,106107	BitAnd,108	BitOr,109	BitXor,110111	Eq,112	Neq,113114	And,115	Or,116117	// Equialent to std.objectHasEx(a, b, true)118	In,119}120121impl Display for BinaryOpType {122	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {123		use BinaryOpType::*;124		write!(125			f,126			"{}",127			match self {128				Mul => "*",129				Div => "/",130				Mod => "%",131				Add => "+",132				Sub => "-",133				Lhs => "<<",134				Rhs => ">>",135				Lt => "<",136				Gt => ">",137				Lte => "<=",138				Gte => ">=",139				BitAnd => "&",140				BitOr => "|",141				BitXor => "^",142				Eq => "==",143				Neq => "!=",144				And => "&&",145				Or => "||",146				In => "in",147			}148		)149	}150}151152/// name, default value153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]154#[derive(Debug, PartialEq, Trace)]155pub struct Param(pub Destruct, pub Option<LocExpr>);156157/// Defined function parameters158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]159#[derive(Debug, Clone, PartialEq, Trace)]160pub struct ParamsDesc(pub Rc<Vec<Param>>);161162impl Deref for ParamsDesc {163	type Target = Vec<Param>;164	fn deref(&self) -> &Self::Target {165		&self.0166	}167}168169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]170#[derive(Debug, PartialEq, Trace)]171pub struct ArgsDesc {172	pub unnamed: Vec<LocExpr>,173	pub named: Vec<(IStr, LocExpr)>,174}175impl ArgsDesc {176	pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {177		Self { unnamed, named }178	}179}180181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]182#[derive(Debug, Clone, PartialEq, Eq, Trace)]183pub enum DestructRest {184	/// ...rest185	Keep(IStr),186	/// ...187	Drop,188}189190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]191#[derive(Debug, Clone, PartialEq, Trace)]192pub enum Destruct {193	Full(IStr),194	#[cfg(feature = "exp-destruct")]195	Skip,196	#[cfg(feature = "exp-destruct")]197	Array {198		start: Vec<Destruct>,199		rest: Option<DestructRest>,200		end: Vec<Destruct>,201	},202	#[cfg(feature = "exp-destruct")]203	Object {204		fields: Vec<(IStr, Option<Destruct>, Option<LocExpr>)>,205		rest: Option<DestructRest>,206	},207}208impl Destruct {209	/// Name of destructure, used for function parameter names210	pub fn name(&self) -> Option<IStr> {211		match self {212			Self::Full(name) => Some(name.clone()),213			#[cfg(feature = "exp-destruct")]214			_ => None,215		}216	}217}218219#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]220#[derive(Debug, Clone, PartialEq, Trace)]221pub enum BindSpec {222	Field {223		into: Destruct,224		value: LocExpr,225	},226	Function {227		name: IStr,228		params: ParamsDesc,229		value: LocExpr,230	},231}232233#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]234#[derive(Debug, PartialEq, Trace)]235pub struct IfSpecData(pub LocExpr);236237#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]238#[derive(Debug, PartialEq, Trace)]239pub struct ForSpecData(pub IStr, pub LocExpr);240241#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]242#[derive(Debug, PartialEq, Trace)]243pub enum CompSpec {244	IfSpec(IfSpecData),245	ForSpec(ForSpecData),246}247248#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]249#[derive(Debug, PartialEq, Trace)]250pub struct ObjComp {251	pub pre_locals: Vec<BindSpec>,252	pub key: LocExpr,253	pub plus: bool,254	pub value: LocExpr,255	pub post_locals: Vec<BindSpec>,256	pub compspecs: Vec<CompSpec>,257}258259#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]260#[derive(Debug, PartialEq, Trace)]261pub enum ObjBody {262	MemberList(Vec<Member>),263	ObjComp(ObjComp),264}265266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]267#[derive(Debug, PartialEq, Eq, Clone, Copy, Trace)]268pub enum LiteralType {269	This,270	Super,271	Dollar,272	Null,273	True,274	False,275}276277#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]278#[derive(Debug, PartialEq, Trace)]279pub struct SliceDesc {280	pub start: Option<LocExpr>,281	pub end: Option<LocExpr>,282	pub step: Option<LocExpr>,283}284285/// Syntax base286#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]287#[derive(Debug, PartialEq, Trace)]288pub enum Expr {289	Literal(LiteralType),290291	/// String value: "hello"292	Str(IStr),293	/// Number: 1, 2.0, 2e+20294	Num(f64),295	/// Variable name: test296	Var(IStr),297298	/// Array of expressions: [1, 2, "Hello"]299	Arr(Vec<LocExpr>),300	/// Array comprehension:301	/// ```jsonnet302	///  ingredients: [303	///    { kind: kind, qty: 4 / 3 }304	///    for kind in [305	///      'Honey Syrup',306	///      'Lemon Juice',307	///      'Farmers Gin',308	///    ]309	///  ],310	/// ```311	ArrComp(LocExpr, Vec<CompSpec>),312313	/// Object: {a: 2}314	Obj(ObjBody),315	/// Object extension: var1 {b: 2}316	ObjExtend(LocExpr, ObjBody),317318	/// (obj)319	Parened(LocExpr),320321	/// -2322	UnaryOp(UnaryOpType, LocExpr),323	/// 2 - 2324	BinaryOp(LocExpr, BinaryOpType, LocExpr),325	/// assert 2 == 2 : "Math is broken"326	AssertExpr(AssertStmt, LocExpr),327	/// local a = 2; { b: a }328	LocalExpr(Vec<BindSpec>, LocExpr),329330	/// import "hello"331	Import(IStr),332	/// importStr "file.txt"333	ImportStr(IStr),334	/// importBin "file.txt"335	ImportBin(IStr),336	/// error "I'm broken"337	ErrorStmt(LocExpr),338	/// a(b, c)339	Apply(LocExpr, ArgsDesc, bool),340	/// a[b]341	Index(LocExpr, LocExpr),342	/// function(x) x343	Function(ParamsDesc, LocExpr),344	/// std.thisFile345	IntrinsicThisFile,346	/// std.id,347	IntrinsicId,348	/// std.primitiveEquals349	Intrinsic(IStr),350	/// if true == false then 1 else 2351	IfElse {352		cond: IfSpecData,353		cond_then: LocExpr,354		cond_else: Option<LocExpr>,355	},356	Slice(LocExpr, SliceDesc),357}358359/// file, begin offset, end offset360#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]361#[derive(Clone, PartialEq, Eq, Trace)]362#[skip_trace]363#[repr(C)]364pub struct ExprLocation(pub Source, pub u32, pub u32);365impl ExprLocation {366	pub fn belongs_to(&self, other: &ExprLocation) -> bool {367		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2368	}369}370371#[cfg(target_pointer_width = "64")]372static_assertions::assert_eq_size!(ExprLocation, [u8; 16]);373374impl Debug for ExprLocation {375	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {376		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)377	}378}379380/// Holds AST expression and its location in source file381#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]382#[derive(Clone, PartialEq, Trace)]383pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);384385#[cfg(target_pointer_width = "64")]386static_assertions::assert_eq_size!(LocExpr, [u8; 24]);387388impl Debug for LocExpr {389	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {390		if f.alternate() {391			write!(f, "{:#?}", self.0)?;392		} else {393			write!(f, "{:?}", self.0)?;394		}395		write!(f, " from {:?}", self.1)?;396		Ok(())397	}398}
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::redundant_closure_call)]
+#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]
 
 use std::rc::Rc;
 
@@ -109,7 +109,7 @@
 			}
 		pub rule destruct_object(s: &ParserSettings) -> expr::Destruct
 			= "{" _
-				fields:(name:id() _ into:(":" _ into:destruct(s) {into})? {(name, into)})**comma()
+				fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:expr(s) {v})? {(name, into, default)})**comma()
 				rest:(
 					comma() rest:destruct_rest()? {rest}
 					/ comma()? {None}