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

difftreelog

feat parse new object iteration syntax

tvmprlwuYaroslav Bolyukin2026-05-06parent: #0f5424f.patch.diff
in: master

10 files changed

modifiedcmds/jrsonnet/Cargo.tomldiffbeforeafterboth
--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -31,7 +31,7 @@
 ]
 # Destructuring of locals
 exp-destruct = ["jrsonnet-evaluator/exp-destruct"]
-# Iteration over objects yields [key, value] elements
+# Iteration over objects using [key]: value syntax
 exp-object-iteration = ["jrsonnet-evaluator/exp-object-iteration"]
 # Bigint type
 exp-bigint = ["jrsonnet-evaluator/exp-bigint", "jrsonnet-cli/exp-bigint"]
modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -40,8 +40,12 @@
   "jrsonnet-peg-parser?/exp-destruct",
   "jrsonnet-ir-parser?/exp-destruct",
 ]
-# Iteration over objects yields [key, value] elements
-exp-object-iteration = []
+# Iteration over objects using [key]: value syntax
+exp-object-iteration = [
+  "jrsonnet-ir/exp-object-iteration",
+  "jrsonnet-peg-parser?/exp-object-iteration",
+  "jrsonnet-ir-parser?/exp-object-iteration",
+]
 # Bigint type
 exp-bigint = ["num-bigint", "jrsonnet-types/exp-bigint"]
 # obj?.field, obj?.['field']
modifiedcrates/jrsonnet-evaluator/src/analyze.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/analyze.rs
+++ b/crates/jrsonnet-evaluator/src/analyze.rs
@@ -1862,6 +1862,8 @@
 				);
 				(r, rest)
 			}
+			#[cfg(feature = "exp-object-iteration")]
+			CompSpec::ForObjSpec(_) => todo!(),
 		}
 	}
 	let outer_depth = stack.depth;
modifiedcrates/jrsonnet-ir-parser/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/Cargo.toml
+++ b/crates/jrsonnet-ir-parser/Cargo.toml
@@ -11,9 +11,10 @@
 
 [features]
 default = []
-experimental = ["exp-null-coaelse", "exp-destruct"]
+experimental = ["exp-null-coaelse", "exp-destruct", "exp-object-iteration"]
 exp-null-coaelse = ["jrsonnet-ir/exp-null-coaelse"]
 exp-destruct = ["jrsonnet-ir/exp-destruct"]
+exp-object-iteration = ["jrsonnet-ir/exp-object-iteration"]
 
 [dependencies]
 insta.workspace = true
modifiedcrates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth
66 !self.at_eof() && self.peek() == kind66 !self.at_eof() && self.peek() == kind
67 }67 }
6868
69 #[allow(dead_code)]
70 fn nth(&self, n: usize) -> SyntaxKind {
71 self.lexemes
72 .get(self.offset + n)
73 .map_or(SyntaxKind::EOF, |l| l.kind)
74 }
75
69 fn eat_any(&mut self) {76 fn eat_any(&mut self) {
70 self.offset += 1;77 self.offset += 1;
71 }78 }
561 }568 }
562}569}
563570
564fn for_spec(p: &mut Parser<'_>) -> Result<ForSpecData> {571fn for_spec(p: &mut Parser<'_>) -> Result<CompSpec> {
565 p.eat(T![for])?;572 p.eat(T![for])?;
573 #[cfg(feature = "exp-object-iteration")]
574 if p.at(T!['[']) && p.nth(1) == SyntaxKind::IDENT && p.nth(2) == T![']'] && p.nth(3) == T![:] {
575 p.eat(T!['['])?;
576 let key = ident(p)?;
577 p.eat(T![']'])?;
578 let visibility = visibility(p)?;
579 let value = destruct(p)?;
580 p.eat(T![in])?;
581 let over = expr(p)?;
582 return Ok(CompSpec::ForObjSpec(jrsonnet_ir::ForObjSpecData {
583 key,
584 visibility,
585 value,
586 over,
587 }));
588 }
566 let d = destruct(p)?;589 let d = destruct(p)?;
567 p.eat(T![in])?;590 p.eat(T![in])?;
568 let over = expr(p)?;591 let over = expr(p)?;
569 Ok(ForSpecData { destruct: d, over })592 Ok(CompSpec::ForSpec(ForSpecData { destruct: d, over }))
570}593}
571594
572fn compspecs(p: &mut Parser<'_>) -> Result<Vec<CompSpec>> {595fn compspecs(p: &mut Parser<'_>) -> Result<Vec<CompSpec>> {
573 let mut specs = Vec::new();596 let mut specs = Vec::new();
574 specs.push(CompSpec::ForSpec(for_spec(p)?));597 specs.push(for_spec(p)?);
575 loop {598 loop {
576 if p.at(T![for]) {599 if p.at(T![for]) {
577 specs.push(CompSpec::ForSpec(for_spec(p)?));600 specs.push(for_spec(p)?);
578 } else if p.at(T![if]) {601 } else if p.at(T![if]) {
579 let isd = if_spec_data(p)?;602 let isd = if_spec_data(p)?;
580 specs.push(CompSpec::IfSpec(isd));603 specs.push(CompSpec::IfSpec(isd));
modifiedcrates/jrsonnet-ir/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-ir/Cargo.toml
+++ b/crates/jrsonnet-ir/Cargo.toml
@@ -12,9 +12,10 @@
 
 [features]
 default = []
-experimental = ["exp-destruct", "exp-null-coaelse"]
+experimental = ["exp-destruct", "exp-null-coaelse", "exp-object-iteration"]
 exp-destruct = []
 exp-null-coaelse = []
+exp-object-iteration = []
 
 [dependencies]
 jrsonnet-interner.workspace = true
modifiedcrates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth
--- a/crates/jrsonnet-ir/src/expr.rs
+++ b/crates/jrsonnet-ir/src/expr.rs
@@ -314,10 +314,21 @@
 	pub over: Expr,
 }
 
+#[cfg(feature = "exp-object-iteration")]
 #[derive(Debug, PartialEq, Acyclic)]
+pub struct ForObjSpecData {
+	pub key: IStr,
+	pub visibility: Visibility,
+	pub value: Destruct,
+	pub over: Expr,
+}
+
+#[derive(Debug, PartialEq, Acyclic)]
 pub enum CompSpec {
 	IfSpec(IfSpecData),
 	ForSpec(ForSpecData),
+	#[cfg(feature = "exp-object-iteration")]
+	ForObjSpec(ForObjSpecData),
 }
 
 #[derive(Debug, PartialEq, Acyclic)]
modifiedcrates/jrsonnet-ir/src/visit.rsdiffbeforeafterboth
--- a/crates/jrsonnet-ir/src/visit.rs
+++ b/crates/jrsonnet-ir/src/visit.rs
@@ -1,5 +1,7 @@
 use jrsonnet_interner::IStr;
 
+#[cfg(feature = "exp-object-iteration")]
+use crate::ForObjSpecData;
 use crate::{
 	ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, Expr, ExprParam,
 	ExprParams, FieldMember, FieldName, ForSpecData, IfElse, IfSpecData, ImportKind, IndexPart,
@@ -69,6 +71,17 @@
 			visit_destruct(v, destruct);
 			v.visit_expr(over);
 		}
+		#[cfg(feature = "exp-object-iteration")]
+		CompSpec::ForObjSpec(for_obj_spec_data) => {
+			let ForObjSpecData {
+				key: _,
+				visibility: _,
+				value,
+				over,
+			} = for_obj_spec_data;
+			visit_destruct(v, value);
+			v.visit_expr(over);
+		}
 	}
 }
 pub fn visit_params<V: Visitor>(v: &mut V, par: &ExprParams) {
modifiedcrates/jrsonnet-peg-parser/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/Cargo.toml
+++ b/crates/jrsonnet-peg-parser/Cargo.toml
@@ -22,6 +22,7 @@
 
 [features]
 default = []
-experimental = ["exp-destruct", "exp-null-coaelse"]
+experimental = ["exp-destruct", "exp-null-coaelse", "exp-object-iteration"]
 exp-destruct = ["jrsonnet-ir/exp-destruct"]
 exp-null-coaelse = ["jrsonnet-ir/exp-null-coaelse"]
+exp-object-iteration = ["jrsonnet-ir/exp-object-iteration"]
modifiedcrates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/src/lib.rs
+++ b/crates/jrsonnet-peg-parser/src/lib.rs
@@ -241,11 +241,21 @@
 			= i:spanned(<keyword("if")>, s) _ cond:expr(s) {IfSpecData { span: i.span, cond }}
 		pub rule forspec(s: &ParserSettings) -> ForSpecData
 			= keyword("for") _ destruct:destruct(s) _ keyword("in") _ over:expr(s) { ForSpecData { destruct, over } }
+		rule ensure_object_iteration()
+			= "" {?
+				#[cfg(not(feature = "exp-object-iteration"))] return Err("!!!experimental object iteration was not enabled");
+				#[cfg(feature = "exp-object-iteration")] Ok(())
+			}
+		pub rule forobjspec(s: &ParserSettings) -> CompSpec
+			= ensure_object_iteration() keyword("for") _ "[" _ key:id() _ "]" _ vis:visibility() _ value:destruct(s) _ keyword("in") _ over:expr(s) {
+				#[cfg(feature = "exp-object-iteration")] return CompSpec::ForObjSpec(jrsonnet_ir::ForObjSpecData { key, visibility: vis, value, over });
+				#[cfg(not(feature = "exp-object-iteration"))] unreachable!("ensure_object_iteration will fail if feature is not enabled")
+			}
 		rule compspec(s: &ParserSettings) -> CompSpec
-			= i:ifspec(s) { CompSpec::IfSpec(i) } / f:forspec(s) {CompSpec::ForSpec(f)}
+			= i:ifspec(s) { CompSpec::IfSpec(i) } / f:forobjspec(s) { f } / f:forspec(s) {CompSpec::ForSpec(f)}
 		pub rule compspecs(s: &ParserSettings) -> Vec<CompSpec>
 			= specs:compspec(s) ++ _ {?
-				if !matches!(specs[0], CompSpec::ForSpec(_)) {
+				if matches!(specs[0], CompSpec::IfSpec(_)) {
 					return Err("<first compspec should be for>")
 				}
 				Ok(specs)