From 4cbcd1493487745547940d7095ac6503ea4a7c45 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 20 May 2026 23:30:22 +0100 Subject: Support mapping custom native types to Java types --- .../generators/javatypes/JavaNativeTypeConfig.java | 6 ++ .../generators/javatypes/JavaTypesGenerator.java | 80 +++++++++++++++++----- 2 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaNativeTypeConfig.java (limited to 'src/main') diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaNativeTypeConfig.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaNativeTypeConfig.java new file mode 100644 index 0000000..0cd2a65 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaNativeTypeConfig.java @@ -0,0 +1,6 @@ +package org.zwobble.hobgoblin.compiler.output.generators.javatypes; + +import org.zwobble.hobgoblin.compiler.output.lang.java.ast.JavaTypeRef; + +public record JavaNativeTypeConfig(JavaTypeRef javaTypeRef) { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java index 2cf8fe7..99b827e 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java @@ -10,15 +10,14 @@ import org.zwobble.hobgoblin.compiler.output.lang.java.JavaWriter; import org.zwobble.hobgoblin.compiler.output.lang.java.ast.*; import org.zwobble.hobgoblin.compiler.typechecker.TypesInfo; import org.zwobble.hobgoblin.compiler.types.*; +import org.zwobble.json5.values.Json5Array; import org.zwobble.json5.values.Json5Object; import org.zwobble.json5.values.Json5String; import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; +import java.util.*; public class JavaTypesGenerator implements Generator { public static final String NAME = "java-types"; @@ -29,16 +28,43 @@ public class JavaTypesGenerator implements Generator { var relativeOutputPath = ((Json5String) output.getValue("path").orElseThrow()).value(); var outputPath = projectRoot.resolve(relativeOutputPath); var packageName = ((Json5String) output.getValue("packageName").orElseThrow()).value(); - return new JavaTypesGenerator(outputPath, packageName); + + var nativeTypeConfigs = new HashMap(); + output.getValue("nativeTypes").ifPresent(nativeTypesJson -> { + for (var nativeTypeJson : ((Json5Array) nativeTypesJson).elements()) { + var nativeTypeJsonObject = (Json5Object) nativeTypeJson; + + var hobgoblinTypeString = ((Json5String) nativeTypeJsonObject.getValue("hobgoblin").orElseThrow()).value(); + var hobgoblinTypeParts = Arrays.asList(hobgoblinTypeString.split("\\.")); + var hobgoblinType = new SimpleNativeType( + new NamespaceName(hobgoblinTypeParts.subList(0, hobgoblinTypeParts.size() - 1)), + hobgoblinTypeParts.getLast() + ); + + var javaTypeString = ((Json5String) nativeTypeJsonObject.getValue("java").orElseThrow()).value(); + var javaTypeParts = Arrays.asList(javaTypeString.split("\\.")); + var javaTypeRef = JavaTypeRef.topLevel(javaTypeParts.subList(0, javaTypeParts.size() - 1), javaTypeParts.getLast()); + + nativeTypeConfigs.put(hobgoblinType, new JavaNativeTypeConfig(javaTypeRef)); + } + }); + + return new JavaTypesGenerator(outputPath, packageName, nativeTypeConfigs); }; } private final Path sourceRootDirectory; private final List packageName; + private final Map nativeTypeConfigs; - public JavaTypesGenerator(Path sourceRootDirectory, String packageName) { + public JavaTypesGenerator( + Path sourceRootDirectory, + String packageName, + Map nativeTypeConfigs + ) { this.sourceRootDirectory = sourceRootDirectory; this.packageName = List.of(packageName.split("\\.")); + this.nativeTypeConfigs = nativeTypeConfigs; } @Override @@ -69,7 +95,7 @@ public class JavaTypesGenerator implements Generator { for (var statement : namespace.body()) { switch (statement) { - case TypedNativeTypeDefinitionNode _ -> { + case TypedNativeTypeDefinitionNode nativeTypeDefinition -> { } case TypedStructDefinitionNode structDefinition -> { @@ -87,7 +113,7 @@ public class JavaTypesGenerator implements Generator { new JavaInterfaceDeclaration( sumDefinition.name(), sumDefinition.variants().stream() - .map(variant -> generateTypeRef(variant.type())) + .map(variant -> generateTypeRef(variant.type(), context)) .toList(), sumDefinition.docComment() ) @@ -107,13 +133,13 @@ public class JavaTypesGenerator implements Generator { ) { var components = structDefinition.fields().stream() .map(field -> new JavaRecordComponent( - generateTypeRef(field.type()), + generateTypeRef(field.type(), context), field.name() )) .toList(); var implementsTypes = context.variantOf(structDefinition.type()).stream() - .map(this::generateTypeRef) + .map(sumType -> this.generateTypeRef(sumType, context)) .toList(); var builderJavaTypeRef = generateBuilderTypeRef(structDefinition.type()); @@ -139,7 +165,7 @@ public class JavaTypesGenerator implements Generator { )) )) ), - generateStructDefinitionBuilder(structDefinition, components) + generateStructDefinitionBuilder(structDefinition, components, context) ), structDefinition.docComment() ); @@ -147,7 +173,8 @@ public class JavaTypesGenerator implements Generator { private JavaRecordDeclaration generateStructDefinitionBuilder( TypedStructDefinitionNode structDefinition, - List components + List components, + Context context ) { var builderJavaTypeRef = generateBuilderTypeRef(structDefinition.type()); @@ -155,11 +182,11 @@ public class JavaTypesGenerator implements Generator { body.add(new JavaMethodDeclaration( "build", JavaMethodKind.INSTANCE, - generateTypeRef(structDefinition.type()), + generateTypeRef(structDefinition.type(), context), List.of(), new JavaBlock(List.of( new JavaReturn(new JavaNewExpression( - generateTypeRef(structDefinition.type()), + generateTypeRef(structDefinition.type(), context), components.stream().map(component -> new JavaRef(component.name())).toList() )) )) @@ -197,23 +224,34 @@ public class JavaTypesGenerator implements Generator { return packageParts; } - private JavaTypeRef generateTypeRef(TypedTypeLevelExpressionNode typeNode) { + private JavaTypeRef generateTypeRef( + TypedTypeLevelExpressionNode typeNode, + Context context + ) { var type = typeNode.value(); - return generateTypeRef(type); + return generateTypeRef(type, context); } - private JavaTypeRef generateTypeRef(Type type) { + private JavaTypeRef generateTypeRef(Type type, Context context) { return switch (type) { case ConstructedNativeType constructedNativeType -> { - var innerTypeRef = generateTypeRef(constructedNativeType.constructor().genericType()); + var innerTypeRef = generateTypeRef( + constructedNativeType.constructor().genericType(), + context + ); var argRefs = constructedNativeType.args().stream() - .map(arg -> generateTypeRef(arg)) + .map(arg -> generateTypeRef(arg, context)) .toList(); // TODO: separate type for constructed types? yield JavaTypeRef.generic(innerTypeRef.packageName(), innerTypeRef.typeNames(), argRefs); } case SimpleNativeType simpleNativeType -> { + var nativeTypeConfig = nativeTypeConfig(simpleNativeType); + if (nativeTypeConfig.isPresent()) { + yield nativeTypeConfig.get().javaTypeRef(); + } + if (type.equals(NativeTypes.INT_32)) { yield JavaTypeRef.INT; } else if (type.equals(NativeTypes.STRING)) { @@ -275,7 +313,7 @@ public class JavaTypesGenerator implements Generator { case StructType structType -> { yield new JavaMethodCall( - new JavaStaticMethodCall(generateTypeRef(structType), "arbitrary", List.of()), + new JavaStaticMethodCall(generateTypeRef(structType, context), "arbitrary", List.of()), "build", List.of() ); @@ -299,6 +337,10 @@ public class JavaTypesGenerator implements Generator { return name.substring(0, 1).toUpperCase(Locale.ROOT) + name.substring(1); } + private Optional nativeTypeConfig(SimpleNativeType type) { + return Optional.ofNullable(this.nativeTypeConfigs.get(type)); + } + private static class Context { private final TypesInfo typesInfo; -- cgit v1.2.3