git.delta.rocks / jrsonnet / refs/commits / 0f5424fc1b4b

difftreelog

feat(rowan) alternative object comp syntax

lmvywrutYaroslav Bolyukin2026-05-06parent: #604f09d.patch.diff
in: master

10 files changed

modifiedcrates/jrsonnet-formatter/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-formatter/src/lib.rs
+++ b/crates/jrsonnet-formatter/src/lib.rs
@@ -13,9 +13,9 @@
 	AstNode, AstToken as _, SyntaxToken,
 	nodes::{
 		Arg, ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart,
-		DestructRest, Expr, ExprArray, ExprBase, FieldName, ForSpec, IfSpec, ImportKind, Literal,
-		Member, Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Stmt, Suffix,
-		Text, TextKind, UnaryOperator, Visibility,
+		DestructRest, Expr, ExprArray, ExprBase, FieldName, ForObjSpec, ForSpec, IfSpec,
+		ImportKind, Literal, Member, Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc,
+		SourceFile, Stmt, Suffix, Text, TextKind, UnaryOperator, Visibility,
 	},
 };
 
@@ -645,6 +645,11 @@
 		p!(out, str("for ") {self.bind()} str(" in ") {self.expr()});
 	}
 }
+impl Printable for ForObjSpec {
+	fn print(&self, out: &mut PrintItems) {
+		p!(out, str("for [") {self.key()} str("]") {self.visibility()} str(" ") {self.value()} str(" in ") {self.expr()});
+	}
+}
 impl Printable for IfSpec {
 	fn print(&self, out: &mut PrintItems) {
 		p!(out, str("if ") {self.expr()});
@@ -654,6 +659,7 @@
 	fn print(&self, out: &mut PrintItems) {
 		match self {
 			Self::ForSpec(f) => f.print(out),
+			Self::ForObjSpec(f) => f.print(out),
 			Self::IfSpec(i) => i.print(out),
 		}
 	}
modifiedcrates/jrsonnet-rowan-parser/jsonnet.ungramdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/jsonnet.ungram
+++ b/crates/jrsonnet-rowan-parser/jsonnet.ungram
@@ -246,11 +246,21 @@
     bind:Destruct
     'in'
     Expr
+ForObjSpec =
+    'for'
+    '['
+    key:Name
+    ']'
+    Visibility
+    value:Destruct
+    'in'
+    Expr
 IfSpec =
     'if'
     Expr
 CompSpec =
     ForSpec
+|   ForObjSpec
 |   IfSpec
 
 BindDestruct =
modifiedcrates/jrsonnet-rowan-parser/src/generated/nodes.rsdiffbeforeafterboth
649 }649 }
650}650}
651
652#[derive(Debug, Clone, PartialEq, Eq, Hash)]
653pub struct ForObjSpec {
654 pub(crate) syntax: SyntaxNode,
655}
656impl ForObjSpec {
657 pub fn for_kw_token(&self) -> Option<SyntaxToken> {
658 support::token(&self.syntax, T![for])
659 }
660 pub fn l_brack_token(&self) -> Option<SyntaxToken> {
661 support::token(&self.syntax, T!['['])
662 }
663 pub fn key(&self) -> Option<Name> {
664 support::children(&self.syntax).next()
665 }
666 pub fn r_brack_token(&self) -> Option<SyntaxToken> {
667 support::token(&self.syntax, T![']'])
668 }
669 pub fn visibility(&self) -> Option<Visibility> {
670 support::children(&self.syntax).next()
671 }
672 pub fn value(&self) -> Option<Destruct> {
673 support::children(&self.syntax).next()
674 }
675 pub fn in_kw_token(&self) -> Option<SyntaxToken> {
676 support::token(&self.syntax, T![in])
677 }
678 pub fn expr(&self) -> Option<Expr> {
679 support::children(&self.syntax).next()
680 }
681}
651682
652#[derive(Debug, Clone, PartialEq, Eq, Hash)]683#[derive(Debug, Clone, PartialEq, Eq, Hash)]
653pub struct IfSpec {684pub struct IfSpec {
845#[derive(Debug, Clone, PartialEq, Eq, Hash)]876#[derive(Debug, Clone, PartialEq, Eq, Hash)]
846pub enum CompSpec {877pub enum CompSpec {
847 ForSpec(ForSpec),878 ForSpec(ForSpec),
879 ForObjSpec(ForObjSpec),
848 IfSpec(IfSpec),880 IfSpec(IfSpec),
849}881}
850882
1702 &self.syntax1734 &self.syntax
1703 }1735 }
1704}1736}
1737impl AstNode for ForObjSpec {
1738 fn can_cast(kind: SyntaxKind) -> bool {
1739 kind == FOR_OBJ_SPEC
1740 }
1741 fn cast(syntax: SyntaxNode) -> Option<Self> {
1742 if Self::can_cast(syntax.kind()) {
1743 Some(Self { syntax })
1744 } else {
1745 None
1746 }
1747 }
1748 fn syntax(&self) -> &SyntaxNode {
1749 &self.syntax
1750 }
1751}
1705impl AstNode for IfSpec {1752impl AstNode for IfSpec {
1706 fn can_cast(kind: SyntaxKind) -> bool {1753 fn can_cast(kind: SyntaxKind) -> bool {
1707 kind == IF_SPEC1754 kind == IF_SPEC
2014 CompSpec::ForSpec(node)2061 CompSpec::ForSpec(node)
2015 }2062 }
2016}2063}
2064impl From<ForObjSpec> for CompSpec {
2065 fn from(node: ForObjSpec) -> CompSpec {
2066 CompSpec::ForObjSpec(node)
2067 }
2068}
2017impl From<IfSpec> for CompSpec {2069impl From<IfSpec> for CompSpec {
2018 fn from(node: IfSpec) -> CompSpec {2070 fn from(node: IfSpec) -> CompSpec {
2019 CompSpec::IfSpec(node)2071 CompSpec::IfSpec(node)
2022impl AstNode for CompSpec {2074impl AstNode for CompSpec {
2023 fn can_cast(kind: SyntaxKind) -> bool {2075 fn can_cast(kind: SyntaxKind) -> bool {
2024 match kind {2076 match kind {
2025 FOR_SPEC | IF_SPEC => true,2077 FOR_SPEC | FOR_OBJ_SPEC | IF_SPEC => true,
2026 _ => false,2078 _ => false,
2027 }2079 }
2028 }2080 }
2029 fn cast(syntax: SyntaxNode) -> Option<Self> {2081 fn cast(syntax: SyntaxNode) -> Option<Self> {
2030 let res = match syntax.kind() {2082 let res = match syntax.kind() {
2031 FOR_SPEC => CompSpec::ForSpec(ForSpec { syntax }),2083 FOR_SPEC => CompSpec::ForSpec(ForSpec { syntax }),
2084 FOR_OBJ_SPEC => CompSpec::ForObjSpec(ForObjSpec { syntax }),
2032 IF_SPEC => CompSpec::IfSpec(IfSpec { syntax }),2085 IF_SPEC => CompSpec::IfSpec(IfSpec { syntax }),
2033 _ => return None,2086 _ => return None,
2034 };2087 };
2037 fn syntax(&self) -> &SyntaxNode {2090 fn syntax(&self) -> &SyntaxNode {
2038 match self {2091 match self {
2039 CompSpec::ForSpec(it) => &it.syntax,2092 CompSpec::ForSpec(it) => &it.syntax,
2093 CompSpec::ForObjSpec(it) => &it.syntax,
2040 CompSpec::IfSpec(it) => &it.syntax,2094 CompSpec::IfSpec(it) => &it.syntax,
2041 }2095 }
2042 }2096 }
3016 std::fmt::Display::fmt(self.syntax(), f)3070 std::fmt::Display::fmt(self.syntax(), f)
3017 }3071 }
3018}3072}
3073impl std::fmt::Display for ForObjSpec {
3074 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3075 std::fmt::Display::fmt(self.syntax(), f)
3076 }
3077}
3019impl std::fmt::Display for IfSpec {3078impl std::fmt::Display for IfSpec {
3020 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {3079 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3021 std::fmt::Display::fmt(self.syntax(), f)3080 std::fmt::Display::fmt(self.syntax(), f)
modifiedcrates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
+++ b/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
@@ -145,6 +145,7 @@
 	FIELD_NAME_FIXED,
 	FIELD_NAME_DYNAMIC,
 	FOR_SPEC,
+	FOR_OBJ_SPEC,
 	IF_SPEC,
 	BIND_DESTRUCT,
 	BIND_FUNCTION,
modifiedcrates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/parser.rs
+++ b/crates/jrsonnet-rowan-parser/src/parser.rs
@@ -364,6 +364,19 @@
 fn compspec(p: &mut Parser) -> CompletedMarker {
 	assert!(p.at_ts(COMPSPEC));
 	if p.at(T![for]) {
+		if p.nth_at(1, T!['[']) && p.nth_at(2, IDENT) && p.nth_at(3, T![']']) && p.nth_at(4, T![:])
+		{
+			let m = p.start();
+			p.bump_assert(T![for]);
+			p.bump_assert(T!['[']);
+			name(p);
+			p.expect(T![']']);
+			visibility(p);
+			destruct(p);
+			p.expect(T![in]);
+			expr(p);
+			return m.complete(p, FOR_OBJ_SPEC);
+		}
 		let m = p.start();
 		p.bump();
 		destruct(p);
addedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_force_visible.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_force_visible.snap
@@ -0,0 +1,51 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{ [k]: v for [k]::: v in obj }\n"
+---
+SOURCE_FILE@0..31
+  EXPR@0..30
+    EXPR_OBJECT@0..30
+      OBJ_BODY_COMP@0..30
+        L_BRACE@0..1 "{"
+        WHITESPACE@1..2 " "
+        MEMBER_FIELD_NORMAL@2..8
+          FIELD_NAME_DYNAMIC@2..5
+            L_BRACK@2..3 "["
+            EXPR@3..4
+              EXPR_VAR@3..4
+                NAME@3..4
+                  IDENT@3..4 "k"
+            R_BRACK@4..5 "]"
+          VISIBILITY@5..6
+            COLON@5..6 ":"
+          WHITESPACE@6..7 " "
+          EXPR@7..8
+            EXPR_VAR@7..8
+              NAME@7..8
+                IDENT@7..8 "v"
+        WHITESPACE@8..9 " "
+        FOR_OBJ_SPEC@9..28
+          FOR_KW@9..12 "for"
+          WHITESPACE@12..13 " "
+          L_BRACK@13..14 "["
+          NAME@14..15
+            IDENT@14..15 "k"
+          R_BRACK@15..16 "]"
+          VISIBILITY@16..19
+            COLON@16..17 ":"
+            COLON@17..18 ":"
+            COLON@18..19 ":"
+          WHITESPACE@19..20 " "
+          DESTRUCT_FULL@20..21
+            NAME@20..21
+              IDENT@20..21 "v"
+          WHITESPACE@21..22 " "
+          IN_KW@22..24 "in"
+          WHITESPACE@24..25 " "
+          EXPR@25..28
+            EXPR_VAR@25..28
+              NAME@25..28
+                IDENT@25..28 "obj"
+        WHITESPACE@28..29 " "
+        R_BRACE@29..30 "}"
+  WHITESPACE@30..31 "\n"
addedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_hidden.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_hidden.snap
@@ -0,0 +1,50 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{ [k]: v for [k]:: v in obj }\n"
+---
+SOURCE_FILE@0..30
+  EXPR@0..29
+    EXPR_OBJECT@0..29
+      OBJ_BODY_COMP@0..29
+        L_BRACE@0..1 "{"
+        WHITESPACE@1..2 " "
+        MEMBER_FIELD_NORMAL@2..8
+          FIELD_NAME_DYNAMIC@2..5
+            L_BRACK@2..3 "["
+            EXPR@3..4
+              EXPR_VAR@3..4
+                NAME@3..4
+                  IDENT@3..4 "k"
+            R_BRACK@4..5 "]"
+          VISIBILITY@5..6
+            COLON@5..6 ":"
+          WHITESPACE@6..7 " "
+          EXPR@7..8
+            EXPR_VAR@7..8
+              NAME@7..8
+                IDENT@7..8 "v"
+        WHITESPACE@8..9 " "
+        FOR_OBJ_SPEC@9..27
+          FOR_KW@9..12 "for"
+          WHITESPACE@12..13 " "
+          L_BRACK@13..14 "["
+          NAME@14..15
+            IDENT@14..15 "k"
+          R_BRACK@15..16 "]"
+          VISIBILITY@16..18
+            COLON@16..17 ":"
+            COLON@17..18 ":"
+          WHITESPACE@18..19 " "
+          DESTRUCT_FULL@19..20
+            NAME@19..20
+              IDENT@19..20 "v"
+          WHITESPACE@20..21 " "
+          IN_KW@21..23 "in"
+          WHITESPACE@23..24 " "
+          EXPR@24..27
+            EXPR_VAR@24..27
+              NAME@24..27
+                IDENT@24..27 "obj"
+        WHITESPACE@27..28 " "
+        R_BRACE@28..29 "}"
+  WHITESPACE@29..30 "\n"
addedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_value_destruct.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_value_destruct.snap
@@ -0,0 +1,66 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{ [k]: a + b for [k]: [a, b] in obj }\n"
+---
+SOURCE_FILE@0..38
+  EXPR@0..37
+    EXPR_OBJECT@0..37
+      OBJ_BODY_COMP@0..37
+        L_BRACE@0..1 "{"
+        WHITESPACE@1..2 " "
+        MEMBER_FIELD_NORMAL@2..12
+          FIELD_NAME_DYNAMIC@2..5
+            L_BRACK@2..3 "["
+            EXPR@3..4
+              EXPR_VAR@3..4
+                NAME@3..4
+                  IDENT@3..4 "k"
+            R_BRACK@4..5 "]"
+          VISIBILITY@5..6
+            COLON@5..6 ":"
+          WHITESPACE@6..7 " "
+          EXPR@7..12
+            EXPR_BINARY@7..12
+              EXPR@7..8
+                EXPR_VAR@7..8
+                  NAME@7..8
+                    IDENT@7..8 "a"
+              WHITESPACE@8..9 " "
+              PLUS@9..10 "+"
+              WHITESPACE@10..11 " "
+              EXPR@11..12
+                EXPR_VAR@11..12
+                  NAME@11..12
+                    IDENT@11..12 "b"
+        WHITESPACE@12..13 " "
+        FOR_OBJ_SPEC@13..35
+          FOR_KW@13..16 "for"
+          WHITESPACE@16..17 " "
+          L_BRACK@17..18 "["
+          NAME@18..19
+            IDENT@18..19 "k"
+          R_BRACK@19..20 "]"
+          VISIBILITY@20..21
+            COLON@20..21 ":"
+          WHITESPACE@21..22 " "
+          DESTRUCT_ARRAY@22..28
+            L_BRACK@22..23 "["
+            DESTRUCT_FULL@23..24
+              NAME@23..24
+                IDENT@23..24 "a"
+            COMMA@24..25 ","
+            WHITESPACE@25..26 " "
+            DESTRUCT_FULL@26..27
+              NAME@26..27
+                IDENT@26..27 "b"
+            R_BRACK@27..28 "]"
+          WHITESPACE@28..29 " "
+          IN_KW@29..31 "in"
+          WHITESPACE@31..32 " "
+          EXPR@32..35
+            EXPR_VAR@32..35
+              NAME@32..35
+                IDENT@32..35 "obj"
+        WHITESPACE@35..36 " "
+        R_BRACE@36..37 "}"
+  WHITESPACE@37..38 "\n"
addedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_visible.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__for_obj_spec_visible.snap
@@ -0,0 +1,49 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{ [k]: v for [k]: v in obj }\n"
+---
+SOURCE_FILE@0..29
+  EXPR@0..28
+    EXPR_OBJECT@0..28
+      OBJ_BODY_COMP@0..28
+        L_BRACE@0..1 "{"
+        WHITESPACE@1..2 " "
+        MEMBER_FIELD_NORMAL@2..8
+          FIELD_NAME_DYNAMIC@2..5
+            L_BRACK@2..3 "["
+            EXPR@3..4
+              EXPR_VAR@3..4
+                NAME@3..4
+                  IDENT@3..4 "k"
+            R_BRACK@4..5 "]"
+          VISIBILITY@5..6
+            COLON@5..6 ":"
+          WHITESPACE@6..7 " "
+          EXPR@7..8
+            EXPR_VAR@7..8
+              NAME@7..8
+                IDENT@7..8 "v"
+        WHITESPACE@8..9 " "
+        FOR_OBJ_SPEC@9..26
+          FOR_KW@9..12 "for"
+          WHITESPACE@12..13 " "
+          L_BRACK@13..14 "["
+          NAME@14..15
+            IDENT@14..15 "k"
+          R_BRACK@15..16 "]"
+          VISIBILITY@16..17
+            COLON@16..17 ":"
+          WHITESPACE@17..18 " "
+          DESTRUCT_FULL@18..19
+            NAME@18..19
+              IDENT@18..19 "v"
+          WHITESPACE@19..20 " "
+          IN_KW@20..22 "in"
+          WHITESPACE@22..23 " "
+          EXPR@23..26
+            EXPR_VAR@23..26
+              NAME@23..26
+                IDENT@23..26 "obj"
+        WHITESPACE@26..27 " "
+        R_BRACE@27..28 "}"
+  WHITESPACE@28..29 "\n"
modifiedcrates/jrsonnet-rowan-parser/src/tests.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/tests.rs
+++ b/crates/jrsonnet-rowan-parser/src/tests.rs
@@ -228,6 +228,19 @@
 	local_in_binop_rhs => r#"
 		a + local x = 1; x
 	"#
+
+	for_obj_spec_visible => r#"
+		{ [k]: v for [k]: v in obj }
+	"#
+	for_obj_spec_hidden => r#"
+		{ [k]: v for [k]:: v in obj }
+	"#
+	for_obj_spec_force_visible => r#"
+		{ [k]: v for [k]::: v in obj }
+	"#
+	for_obj_spec_value_destruct => r#"
+		{ [k]: a + b for [k]: [a, b] in obj }
+	"#
 );
 
 #[test]