summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-08-08 22:32:02 +0100
committerMichael Williamson <mike@zwobble.org>2026-08-08 22:33:36 +0100
commit39e34d4f524f5492065ba47b6cd33d5f272cd515 (patch)
treef16782a9292d9da9564e4ce7d5d6efb791ef0498 /src
parent6dd8f8fe274e11348b631abcf67ee7ccf8254997 (diff)
Partially support generic native types in java-transient-0
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java406
1 files changed, 289 insertions, 117 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 ff9b1e9..b0f63e7 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
@@ -63,7 +63,7 @@ public class JavaTransient0Generator implements Generator {
var context = new Context(typesInfo);
write(generateSupportTypes());
- write(generateBuiltins());
+ write(generateBuiltins(context));
for (var namespace : namespaces) {
var javaCompilationUnits = generateNamespace(namespace, context);
@@ -77,66 +77,72 @@ public class JavaTransient0Generator implements Generator {
}
private List<JavaCompilationUnit> generateSupportTypes() {
+ return List.of(
+ generateTaggedSharedValueType(),
+ generateEncoderType(),
+ generateDecoderType()
+ );
+ }
+
+ private JavaCompilationUnit generateTaggedSharedValueType() {
var typeId = JavaIdentifier.of("typeId");
var value = JavaIdentifier.of("value");
var other = JavaIdentifier.of("other");
var otherSharedValue = JavaIdentifier.of("otherSharedValue");
- return List.of(
- new JavaCompilationUnit(new JavaRecordDeclaration(
- this.taggedSharedValueRef(),
- List.of(
- new JavaRecordComponent(JavaTypeRef.LONG, typeId),
- new JavaRecordComponent(JavaTypeRef.OBJECT, value)
- ),
- List.of(),
- List.of(
- new JavaMethodDeclaration(
- JavaIdentifier.of("equals"),
- JavaVisibility.PUBLIC,
- JavaMemberKind.INSTANCE,
- JavaTypeRef.BOOLEAN,
- List.of(new JavaParam(JavaTypeRef.OBJECT, other)),
- List.of(),
- Optional.of(new JavaBlock(List.of(
- new JavaReturn(new JavaBinaryOperation(
+ return new JavaCompilationUnit(new JavaRecordDeclaration(
+ this.taggedSharedValueRef(),
+ List.of(
+ new JavaRecordComponent(JavaTypeRef.LONG, typeId),
+ new JavaRecordComponent(JavaTypeRef.OBJECT, value)
+ ),
+ List.of(),
+ List.of(
+ new JavaMethodDeclaration(
+ JavaIdentifier.of("equals"),
+ JavaVisibility.PUBLIC,
+ JavaMemberKind.INSTANCE,
+ JavaTypeRef.BOOLEAN,
+ List.of(new JavaParam(JavaTypeRef.OBJECT, other)),
+ List.of(),
+ Optional.of(new JavaBlock(List.of(
+ new JavaReturn(new JavaBinaryOperation(
+ JavaBinaryOperator.LOGICAL_AND,
+ new JavaBinaryOperation(
JavaBinaryOperator.LOGICAL_AND,
- new JavaBinaryOperation(
- JavaBinaryOperator.LOGICAL_AND,
- new JavaInstanceofExpression(
- new JavaRef(other),
- new JavaPattern(taggedSharedValueRef(), otherSharedValue)
- ),
- new JavaBinaryOperation(
- JavaBinaryOperator.EQUAL_TO,
- new JavaFieldAccess(JavaRef.THIS, typeId),
- new JavaFieldAccess(new JavaRef(otherSharedValue), typeId)
- )
+ new JavaInstanceofExpression(
+ new JavaRef(other),
+ new JavaPattern(taggedSharedValueRef(), otherSharedValue)
),
new JavaBinaryOperation(
JavaBinaryOperator.EQUAL_TO,
- new JavaFieldAccess(JavaRef.THIS, value),
- new JavaFieldAccess(new JavaRef(otherSharedValue), value)
+ new JavaFieldAccess(JavaRef.THIS, typeId),
+ new JavaFieldAccess(new JavaRef(otherSharedValue), typeId)
)
- ))
- )))
- ),
- generateHashCode(List.of(
- new JavaStaticMethodCall(
- JavaTypeRef.LONG_BOXED,
- JavaIdentifier.of("hashCode"),
- List.of(new JavaFieldAccess(JavaRef.THIS, typeId))
- ),
- new JavaStaticMethodCall(
- JavaTypeRef.SYSTEM,
- JavaIdentifier.of("identityHashCode"),
- List.of(new JavaFieldAccess(JavaRef.THIS, value))
- )
- ))
+ ),
+ new JavaBinaryOperation(
+ JavaBinaryOperator.EQUAL_TO,
+ new JavaFieldAccess(JavaRef.THIS, value),
+ new JavaFieldAccess(new JavaRef(otherSharedValue), value)
+ )
+ ))
+ )))
),
- DocComment.EMPTY
- ))
- );
+ generateHashCode(List.of(
+ new JavaStaticMethodCall(
+ JavaTypeRef.LONG_BOXED,
+ JavaIdentifier.of("hashCode"),
+ List.of(new JavaFieldAccess(JavaRef.THIS, typeId))
+ ),
+ new JavaStaticMethodCall(
+ JavaTypeRef.SYSTEM,
+ JavaIdentifier.of("identityHashCode"),
+ List.of(new JavaFieldAccess(JavaRef.THIS, value))
+ )
+ ))
+ ),
+ DocComment.EMPTY
+ ));
}
private JavaTypeRef taggedSharedValueRef() {
@@ -160,7 +166,86 @@ public class JavaTransient0Generator implements Generator {
.computeIfAbsent(type, _ -> (long) this.typeIds.size());
}
- private List<JavaCompilationUnit> generateBuiltins() {
+ private JavaCompilationUnit generateEncoderType() {
+ return new JavaCompilationUnit(new JavaInterfaceDeclaration(
+ encoderRef(),
+ JavaInterfaceOpenness.OPEN,
+ List.of(
+ new JavaTypeParameter(JavaIdentifier.of("T"))
+ ),
+ List.of(),
+ List.of(
+ new JavaMethodDeclaration(
+ JavaIdentifier.of("encode"),
+ JavaVisibility.PUBLIC,
+ JavaMemberKind.INSTANCE,
+ JavaTypeRef.VOID,
+ generateEncodeParams(JavaTypeRef.local(JavaIdentifier.of("T"))),
+ List.of(JavaTypeRef.IO_EXCEPTION),
+ Optional.empty()
+ )
+ ),
+ DocComment.EMPTY
+ ));
+ }
+
+ private List<JavaParam> generateEncodeParams(JavaTypeRef valueType) {
+ return List.of(
+ new JavaParam(valueType, VALUE_NAME),
+ new JavaParam(JavaTypeRef.OUTPUT_STREAM, OUTPUT_STREAM_NAME),
+ new JavaParam(generateEncoderSharedValuesTypeRef(), SHARED_VALUES_NAME)
+ );
+ }
+
+ private JavaTypeRef encoderRef() {
+ var packageName = this.namespaceToJavaTransient0PackageName(NamespaceName.of());
+
+ return JavaTypeRef.topLevel(
+ packageName,
+ JavaIdentifier.of("Encoder")
+ );
+ }
+
+ private JavaCompilationUnit generateDecoderType() {
+ return new JavaCompilationUnit(new JavaInterfaceDeclaration(
+ decoderRef(),
+ JavaInterfaceOpenness.OPEN,
+ List.of(
+ new JavaTypeParameter(JavaIdentifier.of("T"))
+ ),
+ List.of(),
+ List.of(
+ new JavaMethodDeclaration(
+ JavaIdentifier.of("decode"),
+ JavaVisibility.PUBLIC,
+ JavaMemberKind.INSTANCE,
+ JavaTypeRef.local(JavaIdentifier.of("T")),
+ generateDecodeParams(),
+ List.of(JavaTypeRef.IO_EXCEPTION),
+ Optional.empty()
+ )
+ ),
+ DocComment.EMPTY
+ ));
+ }
+
+ private static List<JavaParam> generateDecodeParams() {
+ return List.of(
+ new JavaParam(JavaTypeRef.INPUT_STREAM, INPUT_STREAM_NAME),
+ new JavaParam(generateDecoderSharedValuesType(), SHARED_VALUES_NAME)
+ );
+ }
+
+ private JavaTypeRef decoderRef() {
+ var packageName = this.namespaceToJavaTransient0PackageName(NamespaceName.of());
+
+ return JavaTypeRef.topLevel(
+ packageName,
+ JavaIdentifier.of("Decoder")
+ );
+ }
+
+ private List<JavaCompilationUnit> generateBuiltins(Context context) {
var packageName = this.namespaceToJavaTransient0PackageName(NamespaceName.of());
var transient0JavaName = generateTransient0ClassName("Builtins");
var transient0JavaTypeRef = JavaTypeRef.topLevel(
@@ -182,7 +267,7 @@ public class JavaTransient0Generator implements Generator {
generateDecodeInt32Method(),
generateEncodeInt64Method(),
generateDecodeInt64Method(),
- generateEncodeStringMethod(),
+ generateEncodeStringMethod(context),
generateDecodeStringMethod()
),
DocComment.EMPTY
@@ -323,7 +408,7 @@ public class JavaTransient0Generator implements Generator {
return generateDecodeMethod(type, new JavaBlock(statements));
}
- private JavaMethodDeclaration generateEncodeStringMethod() {
+ private JavaMethodDeclaration generateEncodeStringMethod(Context context) {
var bytesVariableName = JavaIdentifier.of("bytes");
var statements = new ArrayList<JavaBlockStatement>();
@@ -347,7 +432,8 @@ public class JavaTransient0Generator implements Generator {
new JavaRef(bytesVariableName),
JavaIdentifier.of("length")
)),
- NativeTypes.INT_64
+ NativeTypes.INT_64,
+ context
));
statements.add(new JavaExpressionStatement(generateOutputStreamWrite(
@@ -458,7 +544,7 @@ public class JavaTransient0Generator implements Generator {
return switch (statement) {
case TypedEnumDefinitionNode enumDefinition -> {
yield Stream.concat(
- Stream.of(generateEncodeEnumMethod(enumDefinition)),
+ Stream.of(generateEncodeEnumMethod(enumDefinition, context)),
generateDecodeEnumMethod(enumDefinition)
);
}
@@ -469,21 +555,24 @@ public class JavaTransient0Generator implements Generator {
case TypedStructDefinitionNode structDefinition -> {
yield Stream.of(
- generateEncodeStructMethod(structDefinition),
+ generateEncodeStructMethod(structDefinition, context),
generateDecodeStructMethod(structDefinition)
);
}
case TypedSumDefinitionNode sumDefinition -> {
yield Stream.of(
- generateEncodeSumMethod(sumDefinition, context.typesInfo),
+ generateEncodeSumMethod(sumDefinition, context),
generateDecodeSumMethod(sumDefinition, context.typesInfo)
);
}
};
}
- private JavaMethodDeclaration generateEncodeEnumMethod(TypedEnumDefinitionNode enumDefinition) {
+ private JavaMethodDeclaration generateEncodeEnumMethod(
+ TypedEnumDefinitionNode enumDefinition,
+ Context context
+ ) {
return generateEncodeMethod(
enumDefinition.type(),
new JavaBlock(generateEncode(
@@ -492,7 +581,8 @@ public class JavaTransient0Generator implements Generator {
JavaIdentifier.of("ordinal"),
List.of()
),
- NativeTypes.INT_32
+ NativeTypes.INT_32,
+ context
))
);
}
@@ -528,7 +618,10 @@ public class JavaTransient0Generator implements Generator {
);
}
- private JavaMethodDeclaration generateEncodeStructMethod(TypedStructDefinitionNode structDefinition) {
+ private JavaMethodDeclaration generateEncodeStructMethod(
+ TypedStructDefinitionNode structDefinition,
+ Context context
+ ) {
return generateEncodeMethod(
structDefinition.type(),
new JavaBlock(
@@ -539,7 +632,8 @@ public class JavaTransient0Generator implements Generator {
this.javaGenerator.generateFieldName(field.name()),
List.of()
),
- field.type().value()
+ field.type().value(),
+ context
).stream())
.toList()
)
@@ -575,11 +669,11 @@ public class JavaTransient0Generator implements Generator {
private JavaMethodDeclaration generateEncodeSumMethod(
TypedSumDefinitionNode sumDefinition,
- TypesInfo typesInfo
+ Context context
) {
var encodeStatements = List.<JavaBlockStatement>of(new JavaSwitchStatement(
new JavaRef(VALUE_NAME),
- typesInfo.sumVariants(sumDefinition.type()).stream()
+ context.typesInfo.sumVariants(sumDefinition.type()).stream()
.map(variant -> {
var variantVariable = JavaIdentifier.of(VALUE_NAME.value() + "$" + variant.tag());
@@ -587,12 +681,14 @@ public class JavaTransient0Generator implements Generator {
statements.addAll(generateEncode(
new JavaIntegerLiteral(variant.tag()),
- NativeTypes.INT_32
+ NativeTypes.INT_32,
+ context
));
statements.addAll(generateEncode(
new JavaRef(variantVariable),
- variant.containerType()
+ variant.containerType(),
+ context
));
return new JavaSwitchRule(
@@ -677,22 +773,16 @@ public class JavaTransient0Generator implements Generator {
JavaVisibility.PUBLIC,
JavaMemberKind.STATIC,
JavaTypeRef.VOID,
- List.of(
- new JavaParam(javaTypeRef, VALUE_NAME),
- new JavaParam(
- JavaTypeRef.OUTPUT_STREAM,
- OUTPUT_STREAM_NAME
- ),
- new JavaParam(
- JavaTypeRef.map(this.taggedSharedValueRef(), JavaTypeRef.LONG_BOXED),
- SHARED_VALUES_NAME
- )
- ),
+ generateEncodeParams(javaTypeRef),
List.of(JavaTypeRef.IO_EXCEPTION),
body
);
}
+ private JavaTypeRef generateEncoderSharedValuesTypeRef() {
+ return JavaTypeRef.map(this.taggedSharedValueRef(), JavaTypeRef.LONG_BOXED);
+ }
+
private JavaMethodDeclaration generateDecodeMethod(
Type type,
JavaBlock body
@@ -704,34 +794,38 @@ public class JavaTransient0Generator implements Generator {
JavaVisibility.PUBLIC,
JavaMemberKind.STATIC,
javaTypeRef,
- List.of(
- new JavaParam(
- JavaTypeRef.INPUT_STREAM,
- INPUT_STREAM_NAME
- ),
- new JavaParam(
- JavaTypeRef.list(JavaTypeRef.OBJECT),
- SHARED_VALUES_NAME
- )
- ),
+ generateDecodeParams(),
List.of(JavaTypeRef.IO_EXCEPTION),
body
);
}
- private List<JavaBlockStatement> generateEncode(JavaExpression value, Type type) {
+ private static JavaTypeRef generateDecoderSharedValuesType() {
+ return JavaTypeRef.list(JavaTypeRef.OBJECT);
+ }
+
+ private List<JavaBlockStatement> generateEncode(JavaExpression value, Type type, Context context) {
return switch (type) {
case ConstructedNativeType constructedNativeType -> {
if (constructedNativeType.constructor().equals(NativeTypes.BOX)) {
- yield generateEncode(value, constructedNativeType.args().getFirst());
+ yield generateEncode(value, constructedNativeType.args().getFirst(), context);
} else if (constructedNativeType.constructor().equals(NativeTypes.LIST)) {
- yield generateEncodeList(value, constructedNativeType.args().getFirst());
+ yield generateEncodeList(value, constructedNativeType.args().getFirst(), context);
} else if (constructedNativeType.constructor().equals(NativeTypes.OPTION)) {
- yield generateEncodeOption(value, constructedNativeType.args().getFirst());
+ yield generateEncodeOption(value, constructedNativeType.args().getFirst(), context);
} else if (constructedNativeType.constructor().equals(NativeTypes.SHARED)) {
- yield generateEncodeShared(value, constructedNativeType.args().getFirst());
+ yield generateEncodeShared(value, constructedNativeType.args().getFirst(), context);
} else {
- throw new UnsupportedOperationException("TODO");
+ yield List.of(
+ generateEncode(
+ value,
+ constructedNativeType.namespaceName(),
+ constructedNativeType,
+ constructedNativeType.args().stream()
+ .<JavaExpression>map(typeArg -> generateEncodeMethodRef(typeArg, context))
+ .toList()
+ )
+ );
}
}
@@ -739,7 +833,8 @@ public class JavaTransient0Generator implements Generator {
yield List.of(generateEncode(
value,
simpleType.namespaceName(),
- simpleType
+ simpleType,
+ List.of()
));
}
@@ -753,20 +848,47 @@ public class JavaTransient0Generator implements Generator {
};
}
+ private JavaMethodRef generateEncodeMethodRef(Type type, Context context) {
+ return switch (type) {
+ case ConstructedNativeType _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ case SimpleType simpleType -> {
+ yield new JavaMethodRef(
+ generateTransient0TypeRef(simpleType.namespaceName()),
+ encodeMethodName(simpleType)
+ );
+ }
+
+ case TypeLevelValueType _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ case TypeParam _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+ };
+ }
+
private JavaBlockStatement generateEncode(
JavaExpression value,
NamespaceName typeNamespaceName,
- Type type
+ Type type,
+ List<JavaExpression> encoders
) {
return new JavaExpressionStatement(
new JavaStaticMethodCall(
generateTransient0TypeRef(typeNamespaceName),
encodeMethodName(type),
- List.of(
- value,
- new JavaRef(OUTPUT_STREAM_NAME),
- new JavaRef(SHARED_VALUES_NAME)
- )
+ Lists.concat(List.of(
+ List.of(
+ value,
+ new JavaRef(OUTPUT_STREAM_NAME),
+ new JavaRef(SHARED_VALUES_NAME)
+ ),
+ encoders
+ ))
)
);
}
@@ -783,15 +905,26 @@ public class JavaTransient0Generator implements Generator {
} else if (constructedNativeType.constructor().equals(NativeTypes.SHARED)) {
yield generateDecodeShared(target, constructedNativeType.args().getFirst());
} else {
- throw new UnsupportedOperationException("TODO");
+ yield List.of(
+ generateDecode(
+ target,
+ constructedNativeType.namespaceName(),
+ constructedNativeType,
+ constructedNativeType.args().stream()
+ .<JavaExpression>map(typeArg -> generateDecodeMethodRef(typeArg))
+ .toList()
+ )
+ );
}
}
case SimpleType simpleType -> {
+ NamespaceName typeNamespaceName = simpleType.namespaceName();
yield List.of(generateDecode(
target,
- simpleType.namespaceName(),
- simpleType
+ typeNamespaceName,
+ simpleType,
+ List.of()
));
}
@@ -805,10 +938,34 @@ public class JavaTransient0Generator implements Generator {
};
}
+ private JavaMethodRef generateDecodeMethodRef(Type type) {
+ return switch (type) {
+ case ConstructedNativeType _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ case SimpleType simpleType -> {
+ yield new JavaMethodRef(
+ generateTransient0TypeRef(simpleType.namespaceName()),
+ decodeMethodName(simpleType)
+ );
+ }
+
+ case TypeLevelValueType _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ case TypeParam _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+ };
+ }
+
private JavaBlockStatement generateDecode(
JavaIdentifier target,
NamespaceName typeNamespaceName,
- Type type
+ Type type,
+ List<JavaExpression> decoders
) {
return new JavaLocalVariableDeclaration(
Optional.empty(),
@@ -816,17 +973,21 @@ public class JavaTransient0Generator implements Generator {
Optional.of(new JavaStaticMethodCall(
generateTransient0TypeRef(typeNamespaceName),
decodeMethodName(type),
- List.of(
- new JavaRef(INPUT_STREAM_NAME),
- new JavaRef(SHARED_VALUES_NAME)
- )
+ Lists.concat(List.of(
+ List.of(
+ new JavaRef(INPUT_STREAM_NAME),
+ new JavaRef(SHARED_VALUES_NAME)
+ ),
+ decoders
+ ))
))
);
}
private List<JavaBlockStatement> generateEncodeList(
JavaExpression value,
- Type elementType
+ Type elementType,
+ Context context
) {
var statements = new ArrayList<JavaBlockStatement>();
@@ -837,7 +998,8 @@ public class JavaTransient0Generator implements Generator {
JavaIdentifier.of("size"),
List.of()
)),
- NativeTypes.INT_64
+ NativeTypes.INT_64,
+ context
));
var element = JavaIdentifier.of("element");
@@ -847,7 +1009,8 @@ public class JavaTransient0Generator implements Generator {
value,
new JavaBlock(generateEncode(
new JavaRef(element),
- elementType
+ elementType,
+ context
))
));
@@ -917,7 +1080,8 @@ public class JavaTransient0Generator implements Generator {
private List<JavaBlockStatement> generateEncodeOption(
JavaExpression value,
- Type elementType
+ Type elementType,
+ Context context
) {
var statements = new ArrayList<JavaBlockStatement>();
var isPresent = new JavaMethodCall(
@@ -928,7 +1092,8 @@ public class JavaTransient0Generator implements Generator {
statements.addAll(generateEncode(
isPresent,
- NativeTypes.BOOL
+ NativeTypes.BOOL,
+ context
));
statements.add(new JavaIfStatement(
@@ -939,7 +1104,8 @@ public class JavaTransient0Generator implements Generator {
JavaIdentifier.of("get"),
List.of()
),
- elementType
+ elementType,
+ context
)),
new JavaBlock(List.of())
));
@@ -999,7 +1165,8 @@ public class JavaTransient0Generator implements Generator {
private List<JavaBlockStatement> generateEncodeShared(
JavaExpression value,
- Type type
+ Type type,
+ Context context
) {
var existingId = JavaIdentifier.of("existingId");
@@ -1021,7 +1188,11 @@ public class JavaTransient0Generator implements Generator {
new JavaNullLiteral()
),
new JavaBlock(
- generateEncode(new JavaRef(existingId), NativeTypes.INT_64)
+ generateEncode(
+ new JavaRef(existingId),
+ NativeTypes.INT_64,
+ context
+ )
),
new JavaBlock(Lists.concat(List.of(
generateEncode(
@@ -1030,7 +1201,8 @@ public class JavaTransient0Generator implements Generator {
JavaIdentifier.of("size"),
List.of()
),
- NativeTypes.INT_64
+ NativeTypes.INT_64,
+ context
),
List.of(
new JavaExpressionStatement(new JavaMethodCall(
@@ -1048,7 +1220,7 @@ public class JavaTransient0Generator implements Generator {
)
))
),
- generateEncode(value, type)
+ generateEncode(value, type, context)
)))
)
))