summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-07-18 19:10:38 +0100
committerMichael Williamson <mike@zwobble.org>2026-07-18 19:10:38 +0100
commitb94fc2c22021dc50381856f170fe9dca4b879468 (patch)
tree1471883697d60ad8c120b56d92d286525347a638
parentf222af6b5e38fcbf876c3213016e298bf590b60a (diff)
Add iterator loop expressions to Rust AST
-rw-r--r--hobgoblin/src/output/lang/rust/ast.hob7
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java16
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustExpression.java2
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpression.java48
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriterTests.java23
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpressionMatcher.java51
6 files changed, 146 insertions, 1 deletions
diff --git a/hobgoblin/src/output/lang/rust/ast.hob b/hobgoblin/src/output/lang/rust/ast.hob
index a5641d1..d362291 100644
--- a/hobgoblin/src/output/lang/rust/ast.hob
+++ b/hobgoblin/src/output/lang/rust/ast.hob
@@ -130,6 +130,7 @@ sum RustExpression {
variant RustFieldExpression;
variant RustIfExpression;
variant RustIntegerLiteral;
+ variant RustIteratorLoopExpression;
variant RustPath;
variant RustPrefixExpression;
variant RustStructExpression;
@@ -185,6 +186,12 @@ struct RustIntegerLiteral {
field type: Option[RustIdentifier];
}
+struct RustIteratorLoopExpression {
+ field elementName: RustIdentifier;
+ field elements: RustExpression;
+ field body: RustBlockExpression;
+}
+
struct RustPrefixExpression {
field operator: RustPrefixOperator;
field operand: RustExpression;
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java
index d4228b0..d916311 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java
@@ -347,6 +347,10 @@ public class RustWriter implements AutoCloseable {
this.writeIntegerLiteral(integerLiteral);
}
+ case RustIteratorLoopExpression iteratorLoopExpression -> {
+ this.writeIteratorLoopExpression(iteratorLoopExpression);
+ }
+
case RustPath path -> {
this.writePath(path);
}
@@ -405,6 +409,7 @@ public class RustWriter implements AutoCloseable {
case RustFieldExpression _ -> RustPrecedence.FIELD_EXPRESSIONS;
case RustIfExpression _ -> RustPrecedence.PRIMARY;
case RustIntegerLiteral _ -> RustPrecedence.PRIMARY;
+ case RustIteratorLoopExpression _ -> RustPrecedence.PRIMARY;
case RustPath _ -> RustPrecedence.PATHS;
case RustPrefixExpression _ -> RustPrecedence.PREFIX;
case RustStructExpression _ -> RustPrecedence.PRIMARY;
@@ -517,6 +522,17 @@ public class RustWriter implements AutoCloseable {
}
}
+ private void writeIteratorLoopExpression(
+ RustIteratorLoopExpression iteratorLoopExpression
+ ) throws IOException {
+ this.writer.write("for ");
+ this.writeIdentifier(iteratorLoopExpression.elementName());
+ this.writer.write(" in ");
+ this.writeTopLevelExpression(iteratorLoopExpression.elements());
+ this.writer.write(" ");
+ this.writeBlockExpression(iteratorLoopExpression.body());
+ }
+
private void writePrefixExpression(RustPrefixExpression prefixExpression) throws IOException {
this.writer.write(switch (prefixExpression.operator()) {
case BORROW -> "&";
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustExpression.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustExpression.java
index 95ca9f8..239f972 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustExpression.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustExpression.java
@@ -5,7 +5,7 @@ package org.zwobble.hobgoblin.compiler.output.lang.rust.ast;
// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression imports
// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression imports
-public sealed interface RustExpression permits org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustArrayRepeatExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBinaryExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBoolLiteral, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustCallExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustFieldExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIfExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIntegerLiteral, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustPath, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustPrefixExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustTryPropagationExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustTupleExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustVecRepeatExpression {
+public sealed interface RustExpression permits org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustArrayRepeatExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBinaryExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBoolLiteral, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustCallExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustFieldExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIfExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIntegerLiteral, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustPath, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustPrefixExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustTryPropagationExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustTupleExpression, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustVecRepeatExpression {
public interface Builder {
public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression build();
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpression.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpression.java
new file mode 100644
index 0000000..0cd1ceb
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpression.java
@@ -0,0 +1,48 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.output.lang.rust.ast;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression imports
+// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression imports
+
+public record RustIteratorLoopExpression(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier elementName, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression elements, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression body) implements org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression {
+ public static org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier.arbitrary().build(), org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression.arbitrary().build(), org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression.arbitrary().build());
+ }
+
+ public record Builder(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier elementName, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression elements, org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression body) implements org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression.Builder {
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression build() {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression(elementName, elements, body);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder withElementName(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier elementName) {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder(elementName, elements, body);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder withElementName(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier.Builder elementName) {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder(elementName.build(), elements, body);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder withElements(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression elements) {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder(elementName, elements, body);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder withElements(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression.Builder elements) {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder(elementName, elements.build(), body);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder withBody(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression body) {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder(elementName, elements, body);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder withBody(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression.Builder body) {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder(elementName, elements, body.build());
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression body
+ // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriterTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriterTests.java
index bf93c1d..e947db9 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriterTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriterTests.java
@@ -621,6 +621,29 @@ public class RustWriterTests {
assertThat(string, equalTo("123i32"));
}
+ // === Iterator expressions ===
+
+ @Test
+ public void iteratorExpression() throws IOException {
+ var rust = RustIteratorLoopExpression.arbitrary()
+ .withElementName(RustIdentifier.of("x"))
+ .withElements(RustPath.of("xs"))
+ .withBody(RustBlockExpression.arbitrary()
+ .withFinalOperand(RustCallExpression.arbitrary()
+ .withFunction(RustPath.of("print"))
+ .addArg(RustPath.of("x"))
+ )
+ )
+ .build();
+
+ var string = write(writer -> writer.writeTopLevelExpression(rust));
+
+ assertThat(string, equalTo("""
+ for x in xs {
+ print(x)
+ }"""));
+ }
+
// === Prefix expressions ===
@Test
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpressionMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpressionMatcher.java
new file mode 100644
index 0000000..6bd153a
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustIteratorLoopExpressionMatcher.java
@@ -0,0 +1,51 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.output.lang.rust.ast;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher imports
+
+public class RustIteratorLoopExpressionMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher isRustIteratorLoopExpression() {
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression>> submatchers;
+
+ private RustIteratorLoopExpressionMatcher(java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression>> submatchers) {
+ this.submatchers = submatchers;
+ }
+
+ public org.zwobble.precisely.MatchResult match(java.lang.Object actual) {
+ return this.toMatcher().match(actual);
+ }
+
+ public org.zwobble.precisely.TextTree describe() {
+ return this.toMatcher().describe();
+ }
+
+ private org.zwobble.precisely.Matcher<java.lang.Object> toMatcher() {
+ return org.zwobble.precisely.Matchers.instanceOf(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher withElementName(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier> elementName) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("elementName", org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression::elementName, elementName));
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher withElements(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustExpression> elements) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("elements", org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression::elements, elements));
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher withBody(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustBlockExpression> body) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("body", org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpression::body, body));
+ return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIteratorLoopExpressionMatcher body
+}