summaryrefslogtreecommitdiff
path: root/src/main/java/org
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-04-26 18:03:39 +0100
committerMichael Williamson <mike@zwobble.org>2026-04-26 18:03:39 +0100
commit9f6c9b42073373b18c8a92a9428f35986effc77b (patch)
tree184d11748625f0181823f4b51e59719bf1e3a110 /src/main/java/org
parent8d3923b4371580b48c3c6668c828a7dd63e61255 (diff)
Hack together basic Java types generator
Diffstat (limited to 'src/main/java/org')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java8
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedStructDefinitionNode.java3
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/builtins/BuiltinTypes.java7
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/generators/Generator.java9
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/generators/java/JavaGenerator.java22
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java34
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java10
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java81
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/java/JavaWriter.java76
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaCompilationUnit.java7
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordComponent.java4
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaRecordDeclaration.java9
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeDeclaration.java4
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/java/ast/JavaTypeRef.java6
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) {
+}