summaryrefslogtreecommitdiff
path: root/src/main/java/org
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-08-08 23:06:06 +0100
committerMichael Williamson <mike@zwobble.org>2026-08-08 23:06:06 +0100
commit765357e0d65c3f869344d8e86321fbed72edbcd6 (patch)
tree5d278dfa4c29a069ae3edccacad74b9f3c094276 /src/main/java/org
parent39e34d4f524f5492065ba47b6cd33d5f272cd515 (diff)
Support nested constructed native types in java-transient-0
Diffstat (limited to 'src/main/java/org')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java205
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructedType.java2
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java2
3 files changed, 158 insertions, 51 deletions
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 b0f63e7..c9c4ea0 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
@@ -60,12 +60,11 @@ public class JavaTransient0Generator implements Generator {
List<TypedNamespaceNode> namespaces,
TypesInfo typesInfo
) throws IOException {
- var context = new Context(typesInfo);
-
write(generateSupportTypes());
- write(generateBuiltins(context));
+ write(generateBuiltins(new Context(NamespaceName.of(), typesInfo)));
for (var namespace : namespaces) {
+ var context = new Context(namespace.namespaceName(), typesInfo);
var javaCompilationUnits = generateNamespace(namespace, context);
write(javaCompilationUnits);
@@ -268,7 +267,7 @@ public class JavaTransient0Generator implements Generator {
generateEncodeInt64Method(),
generateDecodeInt64Method(),
generateEncodeStringMethod(context),
- generateDecodeStringMethod()
+ generateDecodeStringMethod(context)
),
DocComment.EMPTY
)
@@ -446,7 +445,7 @@ public class JavaTransient0Generator implements Generator {
);
}
- private JavaMethodDeclaration generateDecodeStringMethod() {
+ private JavaMethodDeclaration generateDecodeStringMethod(Context context) {
var bytesLengthVariableName = JavaIdentifier.of("bytesLength");
var bytesVariableName = JavaIdentifier.of("bytes");
@@ -454,7 +453,8 @@ public class JavaTransient0Generator implements Generator {
statements.addAll(generateDecode(
bytesLengthVariableName,
- NativeTypes.INT_64
+ NativeTypes.INT_64,
+ context
));
statements.add(generateAssertLessThanIntMax(
@@ -506,14 +506,36 @@ public class JavaTransient0Generator implements Generator {
transient0JavaName
);
+ var body = new ArrayList<JavaClassBodyDeclaration>();
+
+ for (var statement : namespace.body()) {
+ body.addAll(generateNamespaceStatement(statement, context));
+ }
+
+ for (
+ var constructedTypeIndex = 0;
+ constructedTypeIndex < context.constructedTypes.size();
+ constructedTypeIndex++
+ ) {
+ var constructedType = context.constructedTypes.get(constructedTypeIndex);
+ body.add(generateEncodeConstructedTypeMethod(
+ constructedType,
+ constructedTypeIndex,
+ context
+ ));
+ body.add(generateDecodeConstructedTypeMethod(
+ constructedType,
+ constructedTypeIndex,
+ context
+ ));
+ }
+
return List.of(
new JavaCompilationUnit(
new JavaClassDeclaration(
transient0JavaTypeRef,
List.of(),
- namespace.body().stream()
- .flatMap(statement -> generateNamespaceStatement(statement, context))
- .toList(),
+ body,
DocComment.EMPTY
)
)
@@ -537,33 +559,33 @@ public class JavaTransient0Generator implements Generator {
);
}
- private Stream<JavaClassBodyDeclaration> generateNamespaceStatement(
+ private List<JavaClassBodyDeclaration> generateNamespaceStatement(
TypedNamespaceStatementNode statement,
Context context
) {
return switch (statement) {
case TypedEnumDefinitionNode enumDefinition -> {
- yield Stream.concat(
- Stream.of(generateEncodeEnumMethod(enumDefinition, context)),
- generateDecodeEnumMethod(enumDefinition)
- );
+ yield Lists.concat(List.of(
+ List.of(generateEncodeEnumMethod(enumDefinition, context)),
+ generateDecodeEnumMethod(enumDefinition, context)
+ ));
}
case TypedNativeTypeDefinitionNode _ -> {
- yield Stream.of();
+ yield List.of();
}
case TypedStructDefinitionNode structDefinition -> {
- yield Stream.of(
+ yield List.of(
generateEncodeStructMethod(structDefinition, context),
- generateDecodeStructMethod(structDefinition)
+ generateDecodeStructMethod(structDefinition, context)
);
}
case TypedSumDefinitionNode sumDefinition -> {
- yield Stream.of(
+ yield List.of(
generateEncodeSumMethod(sumDefinition, context),
- generateDecodeSumMethod(sumDefinition, context.typesInfo)
+ generateDecodeSumMethod(sumDefinition, context)
);
}
};
@@ -587,12 +609,15 @@ public class JavaTransient0Generator implements Generator {
);
}
- private Stream<JavaClassBodyDeclaration> generateDecodeEnumMethod(TypedEnumDefinitionNode enumDefinition) {
+ private List<JavaClassBodyDeclaration> generateDecodeEnumMethod(
+ TypedEnumDefinitionNode enumDefinition,
+ Context context
+ ) {
var enumJavaTypeRef = this.javaGenerator.generateTypeRef(enumDefinition.type());
var ordinal = JavaIdentifier.of("ordinal");
var enumValues = JavaIdentifier.of(this.javaGenerator.generateTypeName(enumDefinition.type().name()).value() + "$values");
- return Stream.of(
+ return List.of(
new JavaFieldDeclaration(
JavaVisibility.PRIVATE,
JavaMemberKind.STATIC,
@@ -608,7 +633,7 @@ public class JavaTransient0Generator implements Generator {
generateDecodeMethod(
enumDefinition.type(),
new JavaBlock(Stream.concat(
- generateDecode(ordinal, NativeTypes.INT_32).stream(),
+ generateDecode(ordinal, NativeTypes.INT_32, context).stream(),
Stream.of(new JavaReturn(new JavaArrayAccess(
new JavaRef(enumValues),
new JavaRef(ordinal)
@@ -640,7 +665,10 @@ public class JavaTransient0Generator implements Generator {
);
}
- private JavaMethodDeclaration generateDecodeStructMethod(TypedStructDefinitionNode structDefinition) {
+ private JavaMethodDeclaration generateDecodeStructMethod(
+ TypedStructDefinitionNode structDefinition,
+ Context context
+ ) {
var structJavaTypeRef = this.javaGenerator.generateTypeRef(structDefinition.type());
return generateDecodeMethod(
@@ -654,7 +682,8 @@ public class JavaTransient0Generator implements Generator {
structDefinition.fields().get().stream()
.flatMap(field -> generateDecode(
this.javaGenerator.generateFieldName(field.name()),
- field.type().value()
+ field.type().value(),
+ context
).stream()),
Stream.of(new JavaReturn(new JavaNewExpression(
structJavaTypeRef,
@@ -710,22 +739,22 @@ public class JavaTransient0Generator implements Generator {
private JavaMethodDeclaration generateDecodeSumMethod(
TypedSumDefinitionNode sumDefinition,
- TypesInfo typesInfo
+ Context context
) {
var decodeStatements = new ArrayList<JavaBlockStatement>();
var variantTag = JavaIdentifier.of("variantTag");
- decodeStatements.addAll(generateDecode(variantTag, NativeTypes.INT_32));
+ decodeStatements.addAll(generateDecode(variantTag, NativeTypes.INT_32, context));
var cases = new ArrayList<JavaSwitchRule>();
- for (var variant : typesInfo.sumVariants(sumDefinition.type())) {
+ for (var variant : context.typesInfo.sumVariants(sumDefinition.type())) {
var variantVariable = JavaIdentifier.of(VALUE_NAME.value() + "$" + variant.tag());
var statements = new ArrayList<JavaBlockStatement>();
- statements.addAll(generateDecode(variantVariable, variant.containerType()));
+ statements.addAll(generateDecode(variantVariable, variant.containerType(), context));
statements.add(new JavaReturn(new JavaRef(variantVariable)));
@@ -850,8 +879,13 @@ public class JavaTransient0Generator implements Generator {
private JavaMethodRef generateEncodeMethodRef(Type type, Context context) {
return switch (type) {
- case ConstructedNativeType _ -> {
- throw new UnsupportedOperationException("TODO");
+ case ConstructedType constructedType -> {
+ var constructedTypeIndex = context.constructedTypeIndex(constructedType);
+ var methodName = generateEncodeConstructedTypeMethodName(constructedTypeIndex);
+ yield new JavaMethodRef(
+ generateTransient0TypeRef(context.namespaceName),
+ methodName
+ );
}
case SimpleType simpleType -> {
@@ -871,6 +905,28 @@ public class JavaTransient0Generator implements Generator {
};
}
+ private static JavaIdentifier generateEncodeConstructedTypeMethodName(int constructedTypeIndex) {
+ return JavaIdentifier.of("encode$constructedType$" + constructedTypeIndex);
+ }
+
+ private JavaMethodDeclaration generateEncodeConstructedTypeMethod(
+ ConstructedType constructedType,
+ int constructedTypeIndex,
+ Context context
+ ) {
+ return new JavaMethodDeclaration(
+ generateEncodeConstructedTypeMethodName(constructedTypeIndex),
+ JavaVisibility.PRIVATE,
+ JavaMemberKind.STATIC,
+ JavaTypeRef.VOID,
+ generateEncodeParams(this.javaGenerator.generateTypeRef(constructedType)),
+ List.of(JavaTypeRef.IO_EXCEPTION),
+ Optional.of(new JavaBlock(
+ generateEncode(new JavaRef(VALUE_NAME), constructedType, context)
+ ))
+ );
+ }
+
private JavaBlockStatement generateEncode(
JavaExpression value,
NamespaceName typeNamespaceName,
@@ -893,17 +949,21 @@ public class JavaTransient0Generator implements Generator {
);
}
- private List<JavaBlockStatement> generateDecode(JavaIdentifier target, Type type) {
+ private List<JavaBlockStatement> generateDecode(
+ JavaIdentifier target,
+ Type type,
+ Context context
+ ) {
return switch (type) {
case ConstructedNativeType constructedNativeType -> {
if (constructedNativeType.constructor().equals(NativeTypes.BOX)) {
- yield generateDecode(target, constructedNativeType.args().getFirst());
+ yield generateDecode(target, constructedNativeType.args().getFirst(), context);
} else if (constructedNativeType.constructor().equals(NativeTypes.LIST)) {
- yield generateDecodeList(target, constructedNativeType.args().getFirst());
+ yield generateDecodeList(target, constructedNativeType.args().getFirst(), context);
} else if (constructedNativeType.constructor().equals(NativeTypes.OPTION)) {
- yield generateDecodeOption(target, constructedNativeType.args().getFirst());
+ yield generateDecodeOption(target, constructedNativeType.args().getFirst(), context);
} else if (constructedNativeType.constructor().equals(NativeTypes.SHARED)) {
- yield generateDecodeShared(target, constructedNativeType.args().getFirst());
+ yield generateDecodeShared(target, constructedNativeType.args().getFirst(), context);
} else {
yield List.of(
generateDecode(
@@ -911,7 +971,7 @@ public class JavaTransient0Generator implements Generator {
constructedNativeType.namespaceName(),
constructedNativeType,
constructedNativeType.args().stream()
- .<JavaExpression>map(typeArg -> generateDecodeMethodRef(typeArg))
+ .<JavaExpression>map(typeArg -> generateDecodeMethodRef(typeArg, context))
.toList()
)
);
@@ -938,10 +998,15 @@ public class JavaTransient0Generator implements Generator {
};
}
- private JavaMethodRef generateDecodeMethodRef(Type type) {
+ private JavaMethodRef generateDecodeMethodRef(Type type, Context context) {
return switch (type) {
- case ConstructedNativeType _ -> {
- throw new UnsupportedOperationException("TODO");
+ case ConstructedType constructedType -> {
+ var constructedTypeIndex = context.constructedTypeIndex(constructedType);
+ var methodName = generateDecodeConstructedTypeMethodName(constructedTypeIndex);
+ yield new JavaMethodRef(
+ generateTransient0TypeRef(context.namespaceName),
+ methodName
+ );
}
case SimpleType simpleType -> {
@@ -961,6 +1026,29 @@ public class JavaTransient0Generator implements Generator {
};
}
+ private static JavaIdentifier generateDecodeConstructedTypeMethodName(int constructedTypeIndex) {
+ return JavaIdentifier.of("decode$constructedType$" + constructedTypeIndex);
+ }
+
+ private JavaMethodDeclaration generateDecodeConstructedTypeMethod(
+ ConstructedType constructedType,
+ int constructedTypeIndex,
+ Context context
+ ) {
+ return new JavaMethodDeclaration(
+ generateDecodeConstructedTypeMethodName(constructedTypeIndex),
+ JavaVisibility.PRIVATE,
+ JavaMemberKind.STATIC,
+ this.javaGenerator.generateTypeRef(constructedType),
+ generateDecodeParams(),
+ List.of(JavaTypeRef.IO_EXCEPTION),
+ Optional.of(new JavaBlock(Lists.concat(List.of(
+ generateDecode(VALUE_NAME, constructedType, context),
+ List.of(new JavaReturn(new JavaRef(VALUE_NAME)))
+ ))))
+ );
+ }
+
private JavaBlockStatement generateDecode(
JavaIdentifier target,
NamespaceName typeNamespaceName,
@@ -1019,7 +1107,8 @@ public class JavaTransient0Generator implements Generator {
private List<JavaBlockStatement> generateDecodeList(
JavaIdentifier target,
- Type elementType
+ Type elementType,
+ Context context
) {
var size = JavaIdentifier.of(target.value() + "$size");
var index = JavaIdentifier.of(target.value() + "$index");
@@ -1027,7 +1116,7 @@ public class JavaTransient0Generator implements Generator {
var statements = new ArrayList<JavaBlockStatement>();
- statements.addAll(generateDecode(size, NativeTypes.INT_64));
+ statements.addAll(generateDecode(size, NativeTypes.INT_64, context));
statements.add(generateAssertLessThanIntMax(
size,
@@ -1049,7 +1138,7 @@ public class JavaTransient0Generator implements Generator {
var forBodyStatements = new ArrayList<JavaBlockStatement>();
- forBodyStatements.addAll(generateDecode(element, elementType));
+ forBodyStatements.addAll(generateDecode(element, elementType, context));
forBodyStatements.add(new JavaExpressionStatement(new JavaMethodCall(
new JavaRef(target),
@@ -1115,14 +1204,15 @@ public class JavaTransient0Generator implements Generator {
private List<JavaBlockStatement> generateDecodeOption(
JavaIdentifier target,
- Type elementType
+ Type elementType,
+ Context context
) {
var isPresent = JavaIdentifier.of(target.value() + "$isPresent");
var element = JavaIdentifier.of(target.value() + "$element");
var statements = new ArrayList<JavaBlockStatement>();
- statements.addAll(generateDecode(isPresent, NativeTypes.BOOL));
+ statements.addAll(generateDecode(isPresent, NativeTypes.BOOL, context));
statements.add(new JavaLocalVariableDeclaration(
Optional.of(JavaTypeRef.optional(this.javaGenerator.generateReferenceTypeRef(elementType))),
@@ -1132,7 +1222,7 @@ public class JavaTransient0Generator implements Generator {
var ifTrue = new ArrayList<JavaBlockStatement>();
- ifTrue.addAll(generateDecode(element, elementType));
+ ifTrue.addAll(generateDecode(element, elementType, context));
ifTrue.add(new JavaExpressionStatement(new JavaBinaryOperation(
JavaBinaryOperator.ASSIGN,
@@ -1229,13 +1319,14 @@ public class JavaTransient0Generator implements Generator {
private List<JavaBlockStatement> generateDecodeShared(
JavaIdentifier target,
- Type type
+ Type type,
+ Context context
) {
var id = JavaIdentifier.of(target.value() + "$id");
var decodedValue = JavaIdentifier.of(target.value() + "$decodedValue");
return Lists.concat(List.of(
- generateDecode(id, NativeTypes.INT_64),
+ generateDecode(id, NativeTypes.INT_64, context),
List.of(
generateAssertLessThanIntMax(
id,
@@ -1291,7 +1382,7 @@ public class JavaTransient0Generator implements Generator {
))
)),
new JavaBlock(Lists.concat(List.of(
- generateDecode(decodedValue, type),
+ generateDecode(decodedValue, type, context),
List.of(
new JavaExpressionStatement(new JavaMethodCall(
new JavaRef(SHARED_VALUES_NAME),
@@ -1398,10 +1489,26 @@ public class JavaTransient0Generator implements Generator {
}
private static class Context {
+ private final NamespaceName namespaceName;
private final TypesInfo typesInfo;
+ private final Map<ConstructedType, Integer> constructedTypeIndexes = new HashMap<>();
+ private final List<ConstructedType> constructedTypes = new ArrayList<>();
- public Context(TypesInfo typesInfo) {
+ public Context(NamespaceName namespaceName, TypesInfo typesInfo) {
+ this.namespaceName = namespaceName;
this.typesInfo = typesInfo;
}
+
+ public int constructedTypeIndex(ConstructedType type) {
+ var existingIndex = constructedTypeIndexes.get(type);
+ if (existingIndex != null) {
+ return existingIndex;
+ }
+
+ var index = constructedTypes.size();
+ constructedTypeIndexes.put(type, index);
+ constructedTypes.add(type);
+ return index;
+ }
}
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructedType.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructedType.java
index 03d4718..6224331 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructedType.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructedType.java
@@ -1,4 +1,4 @@
package org.zwobble.hobgoblin.compiler.types;
-public sealed interface ConstructedType permits ConstructedNativeType {
+public sealed interface ConstructedType extends Type permits ConstructedNativeType {
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java
index b483209..90dcc9b 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java
@@ -1,5 +1,5 @@
package org.zwobble.hobgoblin.compiler.types;
-public sealed interface Type extends TypeLevelValue permits ConstructedNativeType, ConstructibleType, EnumType, SimpleNativeType, SimpleType, StructType, SumType, TypeLevelValueType, TypeParam {
+public sealed interface Type extends TypeLevelValue permits ConstructedNativeType, ConstructedType, ConstructibleType, EnumType, SimpleNativeType, SimpleType, StructType, SumType, TypeLevelValueType, TypeParam {
String name();
}