summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-07-06 21:47:09 +0100
committerMichael Williamson <mike@zwobble.org>2026-07-06 21:47:09 +0100
commit870371abf7ec001d612f08f275f52d4a4c952db9 (patch)
tree8059c643e53951fa773955a5815be3c902093259
parent115fdcf79d0e7fa2bd69f5b5dd330c7863c03d5a (diff)
Support strings in Java transient-0
-rw-r--r--examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java15
-rw-r--r--examples/10-transient-0/src/data.hob5
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java113
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java3
4 files changed, 113 insertions, 23 deletions
diff --git a/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java b/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java
index c75f454..8466647 100644
--- a/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java
+++ b/examples/10-transient-0/output/java-junit/src/test/java/org/zwobble/example/Transient0Tests.java
@@ -11,6 +11,7 @@ import org.zwobble.example.types.data.OuterStruct;
import org.zwobble.example.types.data.StructWithBool;
import org.zwobble.example.types.data.StructWithInt32;
import org.zwobble.example.types.data.StructWithInt64;
+import org.zwobble.example.types.data.StructWithString;
public class Transient0Tests {
@Test
@@ -56,6 +57,20 @@ public class Transient0Tests {
}
@Test
+ public void structWithString() throws IOException {
+ var value = new StructWithString("abc", "def");
+
+ var outputStream = new ByteArrayOutputStream();
+ HobgoblinTransient0Data.encodeStructWithString(value, outputStream);
+ var bytes = outputStream.toByteArray();
+
+ var inputStream = new ByteArrayInputStream(bytes);
+ var decodedValue = HobgoblinTransient0Data.decodeStructWithString(inputStream);
+
+ Assertions.assertEquals(value, decodedValue);
+ }
+
+ @Test
public void nestedStruct() throws IOException {
var value = new OuterStruct(new InnerStruct(10, 25), 42);
diff --git a/examples/10-transient-0/src/data.hob b/examples/10-transient-0/src/data.hob
index d2ad016..c750cdd 100644
--- a/examples/10-transient-0/src/data.hob
+++ b/examples/10-transient-0/src/data.hob
@@ -13,6 +13,11 @@ struct StructWithInt64 {
field b: Int64;
}
+struct StructWithString {
+ field a: String;
+ field b: String;
+}
+
struct OuterStruct {
field inner: InnerStruct;
field c: Int32;
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java
index 346bde0..e61146a 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java
@@ -90,7 +90,9 @@ public class JavaTransient0Generator implements Generator {
generateEncodeInt32Method(),
generateDecodeInt32Method(),
generateEncodeInt64Method(),
- generateDecodeInt64Method()
+ generateDecodeInt64Method(),
+ generateEncodeStringMethod(),
+ generateDecodeStringMethod()
),
new JavaCustomArea(transient0JavaTypeRef, "body"),
DocComment.EMPTY
@@ -206,6 +208,75 @@ public class JavaTransient0Generator implements Generator {
return generateDecodeMethod(type, new JavaBlock(statements));
}
+ private JavaMethodDeclaration generateEncodeStringMethod() {
+ var bytesVariableName = JavaIdentifier.of("bytes");
+
+ return generateEncodeMethod(
+ NativeTypes.STRING,
+ new JavaBlock(List.of(
+ new JavaLocalVariableDeclaration(
+ Optional.empty(),
+ bytesVariableName,
+ new JavaMethodCall(
+ new JavaRef(VALUE_NAME),
+ JavaIdentifier.of("getBytes"),
+ List.of(new JavaStaticFieldAccess(
+ JavaTypeRef.STANDARD_CHARSETS,
+ JavaIdentifier.of("UTF_8")
+ ))
+ )
+ ),
+ generateEncode(
+ new JavaCast(JavaTypeRef.LONG, new JavaFieldAccess(
+ new JavaRef(bytesVariableName),
+ JavaIdentifier.of("length")
+ )),
+ NativeTypes.INT_64
+ ),
+ new JavaExpressionStatement(generateOutputStreamWrite(
+ new JavaRef(bytesVariableName)
+ ))
+ ))
+ );
+ }
+
+ private JavaMethodDeclaration generateDecodeStringMethod() {
+ var bytesLengthVariableName = JavaIdentifier.of("bytesLength");
+ var bytesVariableName = JavaIdentifier.of("bytes");
+
+ return generateDecodeMethod(
+ NativeTypes.STRING,
+ new JavaBlock(List.of(
+ generateDecode(
+ bytesLengthVariableName,
+ NativeTypes.INT_64
+ ),
+ new JavaLocalVariableDeclaration(
+ Optional.empty(),
+ bytesVariableName,
+ new JavaMethodCall(
+ new JavaRef(INPUT_STREAM_NAME),
+ JavaIdentifier.of("readNBytes"),
+ // TODO: handle very long strings
+ List.of(new JavaCast(JavaTypeRef.INT, new JavaRef(bytesLengthVariableName)))
+ )
+ ),
+ new JavaReturn(
+ new JavaNewExpression(
+ JavaTypeRef.STRING,
+ List.of(
+ new JavaRef(bytesVariableName),
+ new JavaStaticFieldAccess(
+ JavaTypeRef.STANDARD_CHARSETS,
+ JavaIdentifier.of("UTF_8")
+ )
+ )
+ )
+ )
+ ))
+ );
+ }
+
private List<JavaCompilationUnit> generateNamespace(
TypedNamespaceNode namespace,
Context context
@@ -272,7 +343,7 @@ public class JavaTransient0Generator implements Generator {
structDefinition.type(),
new JavaBlock(
structDefinition.fields().stream()
- .flatMap(field -> generateEncode(
+ .map(field -> generateEncode(
new JavaMethodCall(
new JavaRef(VALUE_NAME),
this.javaGenerator.generateFieldName(field.name()),
@@ -288,7 +359,7 @@ public class JavaTransient0Generator implements Generator {
new JavaBlock(
Stream.concat(
structDefinition.fields().stream()
- .flatMap(field -> generateDecode(
+ .map(field -> generateDecode(
this.javaGenerator.generateFieldName(field.name()),
field.type().value()
)),
@@ -355,7 +426,7 @@ public class JavaTransient0Generator implements Generator {
);
}
- private Stream<JavaBlockStatement> generateEncode(JavaExpression value, Type type) {
+ private JavaBlockStatement generateEncode(JavaExpression value, Type type) {
return switch (type) {
case ConstructedNativeType constructedNativeType -> {
throw new UnsupportedOperationException("TODO");
@@ -395,23 +466,21 @@ public class JavaTransient0Generator implements Generator {
};
}
- private Stream<JavaBlockStatement> generateEncode(
+ private JavaBlockStatement generateEncode(
JavaExpression value,
NamespaceName typeNamespaceName,
Type type
) {
- return Stream.of(
- new JavaExpressionStatement(
- new JavaStaticMethodCall(
- generateTransient0TypeRef(typeNamespaceName),
- encodeMethodName(type),
- List.of(value, new JavaRef(OUTPUT_STREAM_NAME))
- )
+ return new JavaExpressionStatement(
+ new JavaStaticMethodCall(
+ generateTransient0TypeRef(typeNamespaceName),
+ encodeMethodName(type),
+ List.of(value, new JavaRef(OUTPUT_STREAM_NAME))
)
);
}
- private Stream<JavaBlockStatement> generateDecode(JavaIdentifier target, Type type) {
+ private JavaBlockStatement generateDecode(JavaIdentifier target, Type type) {
return switch (type) {
case ConstructedNativeType constructedNativeType -> {
throw new UnsupportedOperationException("TODO");
@@ -451,20 +520,18 @@ public class JavaTransient0Generator implements Generator {
};
}
- private Stream<JavaBlockStatement> generateDecode(
+ private JavaBlockStatement generateDecode(
JavaIdentifier target,
NamespaceName typeNamespaceName,
Type type
) {
- return Stream.of(
- new JavaLocalVariableDeclaration(
- Optional.empty(),
- target,
- new JavaStaticMethodCall(
- generateTransient0TypeRef(typeNamespaceName),
- decodeMethodName(type),
- List.of(new JavaRef(INPUT_STREAM_NAME))
- )
+ return new JavaLocalVariableDeclaration(
+ Optional.empty(),
+ target,
+ new JavaStaticMethodCall(
+ generateTransient0TypeRef(typeNamespaceName),
+ decodeMethodName(type),
+ List.of(new JavaRef(INPUT_STREAM_NAME))
)
);
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java
index 1d1274e..0975e4e 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/ast/JavaTypeRef.java
@@ -35,6 +35,7 @@ public record JavaTypeRef(JavaPackageName packageName, List<JavaIdentifier> type
private static class JavaPackages {
private static final JavaPackageName JAVA_IO = JavaPackageName.of("java", "io");
private static final JavaPackageName JAVA_LANG = JavaPackageName.of("java", "lang");
+ private static final JavaPackageName JAVA_NIO_CHARSET = JavaPackageName.of("java", "nio", "charset");
private static final JavaPackageName JAVA_UTIL = JavaPackageName.of("java", "util");
private static final JavaPackageName JAVA_UTIL_STREAM = JavaPackageName.of("java", "util", "stream");
}
@@ -76,5 +77,7 @@ public record JavaTypeRef(JavaPackageName packageName, List<JavaIdentifier> type
public static final JavaTypeRef OUTPUT_STREAM = topLevel(JavaPackages.JAVA_IO, JavaIdentifier.of("OutputStream"));
+ public static final JavaTypeRef STANDARD_CHARSETS = topLevel(JavaPackages.JAVA_NIO_CHARSET, JavaIdentifier.of("StandardCharsets"));
+
public static final JavaTypeRef STREAM = topLevel(JavaPackages.JAVA_UTIL_STREAM, JavaIdentifier.of("Stream"));
}