diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-04-26 18:03:39 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-04-26 18:03:39 +0100 |
| commit | 9f6c9b42073373b18c8a92a9428f35986effc77b (patch) | |
| tree | 184d11748625f0181823f4b51e59719bf1e3a110 /src/main | |
| parent | 8d3923b4371580b48c3c6668c828a7dd63e61255 (diff) | |
Hack together basic Java types generator
Diffstat (limited to 'src/main')
14 files changed, 245 insertions, 35 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java index 5d59d96..698d68f 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java @@ -1,12 +1,12 @@ package org.zwobble.hobgoblin.compiler; import org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceNode; -import org.zwobble.hobgoblin.compiler.generators.Generator; +import org.zwobble.hobgoblin.compiler.builtins.BuiltinTypes; +import org.zwobble.hobgoblin.compiler.output.generators.Generator; import org.zwobble.hobgoblin.compiler.parser.Parser; import org.zwobble.hobgoblin.compiler.typechecker.TypeChecker; import org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerGlobalContext; import org.zwobble.hobgoblin.compiler.types.NamespaceName; -import org.zwobble.hobgoblin.compiler.types.ScalarType; import org.zwobble.sourcetext.SourceText; import java.io.IOException; @@ -22,7 +22,7 @@ public class HobgoblinCompiler { private HobgoblinCompiler() { } - public static void compile(Path projectRoot, List<Generator> generators) throws IOException { + public static void compile(Path projectRoot, List<? extends Generator> generators) throws IOException { var sourceDirectory = projectRoot.resolve("src"); var sourceFiles = sourceDirectory.toFile() .listFiles(file -> file.toPath().toString().endsWith(FILE_NAME_EXTENSION)); @@ -35,7 +35,7 @@ public class HobgoblinCompiler { var untypedNamespaceNode = Parser.parseNamespace(sourceText, namespaceName); var typeCheckerContext = TypeCheckerGlobalContext.initial(); - typeCheckerContext.addBuiltinScalarType(new ScalarType("Int32")); + typeCheckerContext.addBuiltinScalarType(BuiltinTypes.INT_32); var typedNamespaceNode = TypeChecker.typeCheckNamespace(untypedNamespaceNode, typeCheckerContext); typedNamespaceNodes.add(typedNamespaceNode); diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedStructDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedStructDefinitionNode.java index 0f966ab..d1666c2 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedStructDefinitionNode.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedStructDefinitionNode.java @@ -10,4 +10,7 @@ public record TypedStructDefinitionNode( List<TypedStructFieldDefinitionNode> fields, Source source ) implements TypedNamespaceStatementNode { + public String name() { + return this.type.name(); + } } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/builtins/BuiltinTypes.java b/src/main/java/org/zwobble/hobgoblin/compiler/builtins/BuiltinTypes.java new file mode 100644 index 0000000..9ed5fcf --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/builtins/BuiltinTypes.java @@ -0,0 +1,7 @@ +package org.zwobble.hobgoblin.compiler.builtins; + +import org.zwobble.hobgoblin.compiler.types.ScalarType; + +public class BuiltinTypes { + public static ScalarType INT_32 = new ScalarType("Int32"); +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/generators/Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/generators/Generator.java deleted file mode 100644 index 2457609..0000000 --- a/src/main/java/org/zwobble/hobgoblin/compiler/generators/Generator.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.zwobble.hobgoblin.compiler.generators; - -import org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceNode; - -import java.util.List; - -public interface Generator { - void generate(List<TypedNamespaceNode> namespaces); -} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/generators/java/JavaGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/generators/java/JavaGenerator.java deleted file mode 100644 index ced3d81..0000000 --- a/src/main/java/org/zwobble/hobgoblin/compiler/generators/java/JavaGenerator.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.zwobble.hobgoblin.compiler.generators.java; - -import org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceNode; -import org.zwobble.hobgoblin.compiler.generators.Generator; - -import java.nio.file.Path; -import java.util.List; - -public class JavaGenerator implements Generator { - private final Path root; - private final String packageName; - - public JavaGenerator(Path root, String packageName) { - this.root = root; - this.packageName = packageName; - } - - @Override - public void generate(List<TypedNamespaceNode> namespaces) { - - } -} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java new file mode 100644 index 0000000..6a5f784 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java @@ -0,0 +1,34 @@ +package org.zwobble.hobgoblin.compiler.output; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CodeWriter implements AutoCloseable { + public static CodeWriter file(Path path) throws IOException { + Files.createDirectories(path.getParent()); + var writer = new FileWriter(path.toFile()); + return new CodeWriter(writer); + } + + private final Writer writer; + + public CodeWriter(Writer writer) { + this.writer = writer; + } + + public void write(String value) throws IOException { + this.writer.write(value); + } + + public void newLine() throws IOException { + this.writer.write("\n"); + } + + @Override + public void close() throws Exception { + this.writer.close(); + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java new file mode 100644 index 0000000..67f8d91 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java @@ -0,0 +1,10 @@ +package org.zwobble.hobgoblin.compiler.output.generators; + +import org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceNode; + +import java.io.IOException; +import java.util.List; + +public interface Generator { + void generate(List<TypedNamespaceNode> namespaces) throws IOException; +} 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 new file mode 100644 index 0000000..54796e2 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java @@ -0,0 +1,81 @@ +package org.zwobble.hobgoblin.compiler.output.generators.javatypes; + +import org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceNode; +import org.zwobble.hobgoblin.compiler.ast.typed.TypedStructDefinitionNode; +import org.zwobble.hobgoblin.compiler.ast.typed.TypedTypeLevelExpressionNode; +import org.zwobble.hobgoblin.compiler.builtins.BuiltinTypes; +import org.zwobble.hobgoblin.compiler.output.CodeWriter; +import org.zwobble.hobgoblin.compiler.output.generators.Generator; +import org.zwobble.hobgoblin.compiler.output.java.JavaWriter; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaRecordComponent; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaRecordDeclaration; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaCompilationUnit; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaTypeRef; +import org.zwobble.hobgoblin.compiler.types.Type; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class JavaTypesGenerator implements Generator { + private final Path sourceRootDirectory; + private final List<String> packageName; + + public JavaTypesGenerator(Path sourceRootDirectory, String packageName) { + this.sourceRootDirectory = sourceRootDirectory; + this.packageName = List.of(packageName.split("\\.")); + } + + @Override + public void generate(List<TypedNamespaceNode> namespaces) throws IOException { + for (var namespace : namespaces) { + generateNamespace(namespace); + } + } + + private void generateNamespace(TypedNamespaceNode namespace) throws IOException { + var packageParts = new ArrayList<>(this.packageName); + packageParts.addAll(namespace.namespaceName().parts()); + + for (var statement : namespace.body()) { + switch (statement) { + case TypedStructDefinitionNode structDefinition -> { + var javaCompilationUnit = new JavaCompilationUnit( + String.join(".", packageParts), + new JavaRecordDeclaration( + structDefinition.name(), + structDefinition.fields().stream() + .map(field -> new JavaRecordComponent( + generateTypeRef(field.type()), + field.name() + )) + .toList() + ) + ); + + var javaCompilationUnitPath = this.sourceRootDirectory + .resolve(String.join(File.separator, packageParts)) + .resolve(structDefinition.name() + ".java"); + try (var writer = new JavaWriter(CodeWriter.file(javaCompilationUnitPath))) { + writer.writeCompilationUnit(javaCompilationUnit); + } catch (Exception e) { + // TODO: better handling + throw new RuntimeException(e); + } + } + } + } + } + + private JavaTypeRef generateTypeRef(TypedTypeLevelExpressionNode<Type> typeNode) { + var type = typeNode.value(); + + if (type.equals(BuiltinTypes.INT_32)) { + return new JavaTypeRef(List.of(), "int"); + } else { + throw new UnsupportedOperationException("TODO"); + } + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/java/JavaWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/JavaWriter.java new file mode 100644 index 0000000..5e169c5 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/JavaWriter.java @@ -0,0 +1,76 @@ +package org.zwobble.hobgoblin.compiler.output.java; + +import org.zwobble.hobgoblin.compiler.output.CodeWriter; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaRecordDeclaration; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaCompilationUnit; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaTypeDeclaration; +import org.zwobble.hobgoblin.compiler.output.java.ast.JavaTypeRef; + +import java.io.IOException; + +public class JavaWriter implements AutoCloseable { + private final CodeWriter writer; + + public JavaWriter(CodeWriter writer) { + this.writer = writer; + } + + @Override + public void close() throws Exception { + this.writer.close(); + } + + public void writeCompilationUnit(JavaCompilationUnit compilationUnit) throws IOException { + this.writer.write("package "); + this.writer.write(compilationUnit.packageName()); + this.writer.write(";"); + this.writer.newLine(); + this.writer.newLine(); + + writeTypeDeclaration(compilationUnit.typeDeclaration()); + } + + private void writeTypeDeclaration(JavaTypeDeclaration typeDeclaration) throws IOException { + switch (typeDeclaration) { + case JavaRecordDeclaration recordDeclaration -> { + writeRecordDeclaration(recordDeclaration); + } + } + } + + private void writeRecordDeclaration(JavaRecordDeclaration recordDeclaration) throws IOException { + this.writer.write("public record "); + this.writer.write(recordDeclaration.name()); + this.writer.write("("); + + var isFirst = true; + for (var component : recordDeclaration.components()) { + if (!isFirst) { + writer.write(", "); + } + + writeTypeRef(component.type()); + writer.write(" "); + writer.write(component.name()); + + if (isFirst) { + isFirst = false; + } + } + + this.writer.write(") {"); + this.writer.newLine(); + + this.writer.write("}"); + this.writer.newLine(); + } + + private void writeTypeRef(JavaTypeRef type) throws IOException { + for (var part : type.packageName()) { + writer.write(part); + writer.write("."); + } + + writer.write(type.name()); + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaCompilationUnit.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaCompilationUnit.java new file mode 100644 index 0000000..de88d7b --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaCompilationUnit.java @@ -0,0 +1,7 @@ +package org.zwobble.hobgoblin.compiler.output.java.ast; + +public record JavaCompilationUnit( + String packageName, + JavaTypeDeclaration typeDeclaration +) { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordComponent.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordComponent.java new file mode 100644 index 0000000..6954753 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordComponent.java @@ -0,0 +1,4 @@ +package org.zwobble.hobgoblin.compiler.output.java.ast; + +public record JavaRecordComponent(JavaTypeRef type, String name) { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordDeclaration.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordDeclaration.java new file mode 100644 index 0000000..cbebf74 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordDeclaration.java @@ -0,0 +1,9 @@ +package org.zwobble.hobgoblin.compiler.output.java.ast; + +import java.util.List; + +public record JavaRecordDeclaration( + String name, + List<JavaRecordComponent> components +) implements JavaTypeDeclaration { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeDeclaration.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeDeclaration.java new file mode 100644 index 0000000..5f0a3a5 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeDeclaration.java @@ -0,0 +1,4 @@ +package org.zwobble.hobgoblin.compiler.output.java.ast; + +public sealed interface JavaTypeDeclaration permits JavaRecordDeclaration { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeRef.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeRef.java new file mode 100644 index 0000000..b657162 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeRef.java @@ -0,0 +1,6 @@ +package org.zwobble.hobgoblin.compiler.output.java.ast; + +import java.util.List; + +public record JavaTypeRef(List<String> packageName, String name) { +} |
