From 8bb79efe44cf56df9e232de89ce304618e23f2e2 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Mon, 6 Jul 2026 21:27:02 +0100 Subject: Generate methods for encoding/decoding builtin types --- .../javatransient0/JavaTransient0Generator.java | 289 ++++++++++++--------- .../hobgoblin/compiler/types/NamespaceName.java | 9 +- 2 files changed, 171 insertions(+), 127 deletions(-) (limited to 'src/main/java/org/zwobble') 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 7a29814..6078578 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,6 +60,8 @@ public class JavaTransient0Generator implements Generator { ) throws IOException { var context = new Context(typesInfo); + generateBuiltins(); + for (var namespace : namespaces) { var javaCompilationUnits = generateNamespace(namespace, context); @@ -67,6 +69,143 @@ public class JavaTransient0Generator implements Generator { } } + private void generateBuiltins() throws IOException { + var packageName = this.javaGenerator.namespaceToJavaPackageName(NamespaceName.of()); + var transient0JavaName = generateTransient0ClassName("Builtins"); + var transient0JavaTypeRef = JavaTypeRef.topLevel( + packageName, + transient0JavaName + ); + + JavaGenerator.write(this.sourceRootDirectory, List.of( + new JavaCompilationUnit( + packageName, + new JavaCustomArea(transient0JavaTypeRef, "imports"), + new JavaClassDeclaration( + transient0JavaName, + List.of(), + List.of( + generateEncodeBoolMethod(), + generateDecodeBoolMethod(), + generateEncodeInt32Method(), + generateDecodeInt32Method(), + generateEncodeInt64Method(), + generateDecodeInt64Method() + ), + new JavaCustomArea(transient0JavaTypeRef, "body"), + DocComment.EMPTY + ) + ) + )); + } + + private JavaMethodDeclaration generateEncodeBoolMethod() { + return generateEncodeMethod( + NativeTypes.BOOL, + new JavaBlock(List.of( + new JavaExpressionStatement(generateOutputStreamWrite(new JavaTernaryConditional( + new JavaRef(VALUE_NAME), + new JavaIntegerLiteral(1), + new JavaIntegerLiteral(0) + ))) + )) + ); + } + + private JavaMethodDeclaration generateDecodeBoolMethod() { + return generateDecodeMethod( + NativeTypes.BOOL, + new JavaBlock(List.of( + new JavaReturn(new JavaBinaryOperation( + JavaBinaryOperator.NOT_EQUAL_TO, + generateInputStreamRead(), + new JavaIntegerLiteral(0) + )) + )) + ); + } + + private JavaMethodDeclaration generateEncodeInt32Method() { + return generateEncodeIntMethod(NativeTypes.INT_32, 32); + } + + private JavaMethodDeclaration generateDecodeInt32Method() { + return generateDecodeIntMethod(NativeTypes.INT_32, 32); + } + + private JavaMethodDeclaration generateEncodeInt64Method() { + return generateEncodeIntMethod(NativeTypes.INT_64, 64); + } + + private JavaMethodDeclaration generateDecodeInt64Method() { + return generateDecodeIntMethod(NativeTypes.INT_64, 64); + } + + private JavaMethodDeclaration generateEncodeIntMethod( + Type type, + int bits + ) { + var statements = byteIndicesInBits(bits) + .mapToObj(shiftBy -> { + JavaExpression byteToWrite = new JavaBinaryOperation( + JavaBinaryOperator.BITWISE_AND, + new JavaBinaryOperation( + JavaBinaryOperator.UNSIGNED_RIGHT_SHIFT, + new JavaRef(VALUE_NAME), + new JavaIntegerLiteral(shiftBy) + ), + new JavaIntegerLiteral(0xff) + ); + + if (bits > 32) { + byteToWrite = new JavaCast(JavaTypeRef.INT, byteToWrite); + } + + return new JavaExpressionStatement( + generateOutputStreamWrite(byteToWrite) + ); + }) + .toList(); + + return generateEncodeMethod(type, new JavaBlock(statements)); + } + + private JavaMethodDeclaration generateDecodeIntMethod( + Type type, + int bits + ) { + var statements = new ArrayList(); + + statements.add(new JavaLocalVariableDeclaration( + Optional.of(this.javaGenerator.generateTypeRef(type)), + VALUE_NAME, + new JavaIntegerLiteral(0) + )); + + Iterable shiftBys = () -> byteIndicesInBits(bits) + .iterator(); + + for (var shiftBy : shiftBys) { + statements.add(new JavaExpressionStatement(new JavaBinaryOperation( + JavaBinaryOperator.ASSIGN, + new JavaRef(VALUE_NAME), + new JavaBinaryOperation( + JavaBinaryOperator.BITWISE_OR, + new JavaRef(VALUE_NAME), + new JavaBinaryOperation( + JavaBinaryOperator.LEFT_SHIFT, + generateInputStreamRead(), + new JavaIntegerLiteral(shiftBy) + ) + ) + ))); + } + + statements.add(new JavaReturn(new JavaRef(VALUE_NAME))); + + return generateDecodeMethod(type, new JavaBlock(statements)); + } + private List generateNamespace( TypedNamespaceNode namespace, Context context @@ -103,9 +242,12 @@ public class JavaTransient0Generator implements Generator { } private JavaIdentifier generateTransient0ClassName(NamespaceName namespaceName) { - var namespaceShortName = namespaceName.shortName(); + return generateTransient0ClassName(namespaceName.shortName().orElse("Builtins")); + } + + private JavaIdentifier generateTransient0ClassName(String shortName) { return this.javaGenerator.generateTypeName( - "HobgoblinTransient0" + Casing.lowerCamelCaseToUpperCamelCase(namespaceShortName) + "HobgoblinTransient0" + Casing.lowerCamelCaseToUpperCamelCase(shortName) ); } @@ -224,15 +366,15 @@ public class JavaTransient0Generator implements Generator { } case SimpleNativeType simpleNativeType -> { - if (simpleNativeType.equals(NativeTypes.BOOL)) { - yield generateEncodeBool(value); - } else if (simpleNativeType.equals(NativeTypes.INT_32)) { - yield generateEncodeInt32(value); - } else if (simpleNativeType.equals(NativeTypes.INT_64)) { - yield generateEncodeInt64(value); - } else { - throw new UnsupportedOperationException("TODO"); - } + yield Stream.of( + new JavaExpressionStatement( + new JavaStaticMethodCall( + generateTransient0TypeRef(simpleNativeType.namespaceName()), + encodeMethodName(simpleNativeType), + List.of(value, new JavaRef(OUTPUT_STREAM_NAME)) + ) + ) + ); } case StructType structType -> { @@ -272,15 +414,17 @@ public class JavaTransient0Generator implements Generator { } case SimpleNativeType simpleNativeType -> { - if (simpleNativeType.equals(NativeTypes.BOOL)) { - yield generateDecodeBool(target); - } else if (simpleNativeType.equals(NativeTypes.INT_32)) { - yield generateDecodeInt32(target); - } else if (simpleNativeType.equals(NativeTypes.INT_64)) { - yield generateDecodeInt64(target); - } else { - throw new UnsupportedOperationException("TODO"); - } + yield Stream.of( + new JavaLocalVariableDeclaration( + Optional.empty(), + target, + new JavaStaticMethodCall( + generateTransient0TypeRef(simpleNativeType.namespaceName()), + decodeMethodName(simpleNativeType), + List.of(new JavaRef(INPUT_STREAM_NAME)) + ) + ) + ); } case StructType structType -> { @@ -311,111 +455,6 @@ public class JavaTransient0Generator implements Generator { }; } - private static Stream generateEncodeBool(JavaExpression value) { - return Stream.of( - new JavaExpressionStatement(generateOutputStreamWrite(new JavaTernaryConditional( - value, - new JavaIntegerLiteral(1), - new JavaIntegerLiteral(0) - )) - )); - } - - private static Stream generateDecodeBool(JavaIdentifier target) { - return Stream.of( - new JavaLocalVariableDeclaration( - Optional.empty(), - target, - new JavaBinaryOperation( - JavaBinaryOperator.NOT_EQUAL_TO, - generateInputStreamRead(), - new JavaIntegerLiteral(0) - ) - ) - ); - } - - private static Stream generateEncodeInt32(JavaExpression value) { - return generateEncodeInt(value, 32); - } - - private static Stream generateDecodeInt32( - JavaIdentifier target - ) { - return generateDecodeInt(target, 32, JavaTypeRef.INT); - } - - private static Stream generateEncodeInt64(JavaExpression value) { - return generateEncodeInt(value, 64); - } - - private static Stream generateDecodeInt64( - JavaIdentifier target - ) { - return generateDecodeInt(target, 64, JavaTypeRef.INT); - } - - private static Stream generateEncodeInt( - JavaExpression value, - int bits - ) { - return byteIndicesInBits(bits) - .mapToObj(shiftBy -> { - JavaExpression byteToWrite = new JavaBinaryOperation( - JavaBinaryOperator.BITWISE_AND, - new JavaBinaryOperation( - JavaBinaryOperator.UNSIGNED_RIGHT_SHIFT, - value, - new JavaIntegerLiteral(shiftBy) - ), - new JavaIntegerLiteral(0xff) - ); - - if (bits > 32) { - byteToWrite = new JavaCast(JavaTypeRef.INT, byteToWrite); - } - - return new JavaExpressionStatement( - generateOutputStreamWrite(byteToWrite) - ); - }); - } - - private static Stream generateDecodeInt( - JavaIdentifier target, - int bits, - JavaTypeRef javaType - ) { - var statements = new ArrayList(); - - statements.add(new JavaLocalVariableDeclaration( - Optional.of(javaType), - target, - new JavaIntegerLiteral(0) - )); - - Iterable shiftBys = () -> byteIndicesInBits(bits) - .iterator(); - - for (var shiftBy : shiftBys) { - statements.add(new JavaExpressionStatement(new JavaBinaryOperation( - JavaBinaryOperator.ASSIGN, - new JavaRef(target), - new JavaBinaryOperation( - JavaBinaryOperator.BITWISE_OR, - new JavaRef(target), - new JavaBinaryOperation( - JavaBinaryOperator.LEFT_SHIFT, - generateInputStreamRead(), - new JavaIntegerLiteral(shiftBy) - ) - ) - ))); - } - - return statements.stream(); - } - private static JavaMethodCall generateOutputStreamWrite(JavaExpression byteToWrite) { return new JavaMethodCall( new JavaRef(OUTPUT_STREAM_NAME), diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/NamespaceName.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/NamespaceName.java index c7f4431..c01140a 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/types/NamespaceName.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/NamespaceName.java @@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.types; import java.util.Arrays; import java.util.List; +import java.util.Optional; public record NamespaceName(List parts) { public static NamespaceName of(String... parts) { @@ -12,8 +13,12 @@ public record NamespaceName(List parts) { return new NamespaceName(parts.subList(0, parts.size() - 1)); } - public String shortName() { - return parts.getLast(); + public Optional shortName() { + if (parts.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(parts.getLast()); + } } public boolean isRoot() { -- cgit v1.2.3