From f55983f8a5fefe039df83fc601679fc32e04581e Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Tue, 30 Jun 2026 20:44:46 +0100 Subject: Write doc comment for Rust structs --- examples/01-struct/output/rust/src/point.rs | 2 ++ hobgoblin/src/output/lang/rust/ast.hob | 3 +++ .../generators/rusttypes/RustTypesGenerator.java | 5 ++--- .../compiler/output/lang/rust/RustWriter.java | 10 ++++++++++ .../output/lang/rust/ast/RustStructStruct.java | 18 +++++++++++------- .../compiler/output/lang/java/JavaWriterTests.java | 2 -- .../compiler/output/lang/rust/RustWriterTests.java | 16 ++++++++++++++++ .../output/lang/rust/ast/RustStructStructMatcher.java | 4 ++++ 8 files changed, 48 insertions(+), 12 deletions(-) diff --git a/examples/01-struct/output/rust/src/point.rs b/examples/01-struct/output/rust/src/point.rs index aa90e19..063c3f0 100644 --- a/examples/01-struct/output/rust/src/point.rs +++ b/examples/01-struct/output/rust/src/point.rs @@ -1,8 +1,10 @@ +/// A straight line from one point to another. pub struct Line { pub start: Point, pub end: Point, } +/// A 2D point. pub struct Point { pub x: i32, pub y: i32, diff --git a/hobgoblin/src/output/lang/rust/ast.hob b/hobgoblin/src/output/lang/rust/ast.hob index f3ff901..ab64a91 100644 --- a/hobgoblin/src/output/lang/rust/ast.hob +++ b/hobgoblin/src/output/lang/rust/ast.hob @@ -1,3 +1,5 @@ +import {DocComment} from ast; + // == Modules == struct RustModule { @@ -14,6 +16,7 @@ sum RustItem { struct RustStructStruct { field name: RustIdentifier; field fields: List[RustStructField]; + field docComment: DocComment; } struct RustStructField { diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java index b5cf01c..b19f3e5 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java @@ -4,7 +4,6 @@ import org.zwobble.hobgoblin.compiler.ast.typed.*; import org.zwobble.hobgoblin.compiler.config.OutputConfig; import org.zwobble.hobgoblin.compiler.output.generators.Generator; import org.zwobble.hobgoblin.compiler.output.generators.rust.RustGeneratorConfig; -import org.zwobble.hobgoblin.compiler.output.lang.java.JavaWriter; import org.zwobble.hobgoblin.compiler.output.lang.rust.RustWriter; import org.zwobble.hobgoblin.compiler.output.lang.rust.ast.*; import org.zwobble.hobgoblin.compiler.typechecker.TypesInfo; @@ -59,7 +58,7 @@ public class RustTypesGenerator implements Generator { private RustModule generateNamespace(TypedNamespaceNode namespace) { var rustModuleName = generateNamespaceName(namespace.namespaceName()); - + var rustItems = namespace.body().stream() .flatMap(statement -> generateNamespaceStatement(statement).stream()) .toList(); @@ -90,7 +89,7 @@ public class RustTypesGenerator implements Generator { .map(field -> new RustStructField(generateFieldName(field.name()), generateRustTypeExpression(field.type()))) .toList(); - var rustStruct = new RustStructStruct(rustStructName, rustFields); + var rustStruct = new RustStructStruct(rustStructName, rustFields, structDefinition.docComment()); yield List.of(rustStruct); } 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 25335ee..9153d83 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 @@ -1,5 +1,6 @@ package org.zwobble.hobgoblin.compiler.output.lang.rust; +import org.zwobble.hobgoblin.compiler.ast.DocComment; import org.zwobble.hobgoblin.compiler.output.CodeWriter; import org.zwobble.hobgoblin.compiler.output.lang.rust.ast.*; @@ -36,6 +37,14 @@ public class RustWriter implements AutoCloseable { this.writer.close(); } + private void writeDocComment(DocComment docComment) throws IOException { + for (var line : docComment.lines()) { + this.writer.write("/// "); + this.writer.write(line); + this.writer.write("\n"); + } + } + public void writeModule(RustModule module) throws IOException { writeWithSeparator( module.items(), @@ -63,6 +72,7 @@ public class RustWriter implements AutoCloseable { } private void writeStructStruct(RustStructStruct structStruct) throws IOException { + this.writeDocComment(structStruct.docComment()); this.writer.write("pub struct "); this.writeIdentifier(structStruct.name()); this.writer.write(" {"); diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStruct.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStruct.java index 3e9c3ad..5b02a96 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStruct.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStruct.java @@ -5,26 +5,30 @@ package org.zwobble.hobgoblin.compiler.output.lang.rust.ast; // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct imports // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct imports -public record RustStructStruct(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier name, java.util.List fields) implements org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustItem { +public record RustStructStruct(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier name, java.util.List fields, org.zwobble.hobgoblin.compiler.ast.DocComment docComment) implements org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustItem { public static org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder arbitrary() { - return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier.arbitrary().build(), java.util.List.of()); + return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier.arbitrary().build(), java.util.List.of(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment()); } - public record Builder(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier name, java.util.List fields) implements org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustItem.Builder { + public record Builder(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier name, java.util.List fields, org.zwobble.hobgoblin.compiler.ast.DocComment docComment) implements org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustItem.Builder { public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct build() { - return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct(name, fields); + return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct(name, fields, docComment); } public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder withName(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier name) { - return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(name, fields); + return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(name, fields, docComment); } public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder withName(org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustIdentifier.Builder name) { - return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(name.build(), fields); + return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(name.build(), fields, docComment); } public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder withFields(java.util.List fields) { - return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(name, fields); + return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(name, fields, docComment); + } + + public org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder withDocComment(org.zwobble.hobgoblin.compiler.ast.DocComment docComment) { + return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder(name, fields, docComment); } // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct.Builder body diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriterTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriterTests.java index 992d9bd..cd74430 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriterTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriterTests.java @@ -7,8 +7,6 @@ import org.zwobble.hobgoblin.compiler.output.lang.java.ast.*; import java.io.IOException; import java.io.StringWriter; -import java.io.Writer; -import java.nio.file.NoSuchFileException; import java.util.List; import java.util.Optional; 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 c41bb9e..eca8685 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 @@ -1,6 +1,7 @@ package org.zwobble.hobgoblin.compiler.output.lang.rust; import org.junit.jupiter.api.Test; +import org.zwobble.hobgoblin.compiler.ast.DocComment; import org.zwobble.hobgoblin.compiler.output.CodeWriter; import org.zwobble.hobgoblin.compiler.output.lang.rust.ast.*; @@ -70,6 +71,21 @@ public class RustWriterTests { }""")); } + @Test + public void structWithDocComment() throws IOException { + var rust = RustStructStruct.arbitrary() + .withName(new RustIdentifier("Rectangle")) + .withDocComment(new DocComment("A 2D rectangle.")) + .build(); + + var string = write(writer -> writer.writeItem(rust)); + + assertThat(string, equalTo(""" + /// A 2D rectangle. + pub struct Rectangle { + }""")); + } + @Test public void typeSegmentsAreSeparatedByDoubleColons() throws IOException { var rust = RustTypePath.of("std", "string", "String"); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStructMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStructMatcher.java index e8c6c39..1bbacef 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStructMatcher.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/rust/ast/RustStructStructMatcher.java @@ -36,6 +36,10 @@ public class RustStructStructMatcher implements org.zwobble.precisely.Matcher docComment) { + return new org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStructMatcher(java.util.stream.Stream.concat(this.submatchers.stream(), java.util.stream.Stream.of(org.zwobble.precisely.Matchers.has("docComment", org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStruct::docComment, docComment))).toList()); + } + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStructMatcher body // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.rust.ast.RustStructStructMatcher body } -- cgit v1.2.3