summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-04-26 21:31:44 +0100
committerMichael Williamson <mike@zwobble.org>2026-04-26 21:31:44 +0100
commit92708742a18a1a3de5eb59a2e7c12788aa199d9a (patch)
treec50d46c56b5a80df00046f3cad244794056f05eb /src/main
parent9f6c9b42073373b18c8a92a9428f35986effc77b (diff)
Declare types ahead of defining them
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java15
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java70
2 files changed, 69 insertions, 16 deletions
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 54796e2..c638763 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
@@ -11,6 +11,8 @@ 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.NamespaceName;
+import org.zwobble.hobgoblin.compiler.types.StructType;
import org.zwobble.hobgoblin.compiler.types.Type;
import java.io.File;
@@ -36,8 +38,7 @@ public class JavaTypesGenerator implements Generator {
}
private void generateNamespace(TypedNamespaceNode namespace) throws IOException {
- var packageParts = new ArrayList<>(this.packageName);
- packageParts.addAll(namespace.namespaceName().parts());
+ var packageParts = namespaceToJavaPackageParts(namespace.namespaceName());
for (var statement : namespace.body()) {
switch (statement) {
@@ -69,10 +70,18 @@ public class JavaTypesGenerator implements Generator {
}
}
+ private ArrayList<String> namespaceToJavaPackageParts(NamespaceName namespaceName) {
+ var packageParts = new ArrayList<>(this.packageName);
+ packageParts.addAll(namespaceName.parts());
+ return packageParts;
+ }
+
private JavaTypeRef generateTypeRef(TypedTypeLevelExpressionNode<Type> typeNode) {
var type = typeNode.value();
- if (type.equals(BuiltinTypes.INT_32)) {
+ if (type instanceof StructType structType) {
+ return new JavaTypeRef(namespaceToJavaPackageParts(structType.namespaceName()), structType.name());
+ } else 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/typechecker/TypeChecker.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
index d9a37e2..7678f94 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
@@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.typechecker;
import org.zwobble.hobgoblin.compiler.ast.typed.*;
import org.zwobble.hobgoblin.compiler.ast.untyped.*;
+import org.zwobble.hobgoblin.compiler.sources.Source;
import org.zwobble.hobgoblin.compiler.types.*;
import java.util.ArrayList;
@@ -16,9 +17,13 @@ public class TypeChecker {
) {
var namespaceContext = context.enterNamespace(untyped.namespaceName());
+ for (var untypedStatement : untyped.body()) {
+ declareNamespaceStatement(untypedStatement, namespaceContext);
+ }
+
var typedBody = new ArrayList<TypedNamespaceStatementNode>();
for (var untypedStatement : untyped.body()) {
- var typedStatement = typeCheckNamespaceStatement(untypedStatement, namespaceContext);
+ var typedStatement = defineNamespaceStatement(untypedStatement, namespaceContext);
typedBody.add(typedStatement);
}
@@ -29,21 +34,41 @@ public class TypeChecker {
);
}
- static TypedNamespaceStatementNode typeCheckNamespaceStatement(
+ static void declareNamespaceStatement(
+ UntypedNamespaceStatementNode untyped,
+ TypeCheckerNamespaceContext context
+ ) {
+ switch (untyped) {
+ case UntypedStructDefinitionNode untypedStructDefinition ->
+ declareStructDefinition(untypedStructDefinition, context);
+ }
+ }
+
+ static TypedNamespaceStatementNode defineNamespaceStatement(
UntypedNamespaceStatementNode untyped,
TypeCheckerNamespaceContext context
) {
return switch (untyped) {
case UntypedStructDefinitionNode untypedStructDefinition ->
- typeCheckStructDefinition(untypedStructDefinition, context);
+ defineStructDefinition(untypedStructDefinition, context);
};
}
- private static TypedStructDefinitionNode typeCheckStructDefinition(
+ private static void declareStructDefinition(
UntypedStructDefinitionNode untyped,
TypeCheckerNamespaceContext context
) {
var structType = new StructType(context.namespaceName(), untyped.name());
+ // TODO: tidy up declare vs define
+ context.declare(untyped.name());
+ context.define(untyped.name(), new TypeLevelValueType(structType));
+ }
+
+ private static TypedStructDefinitionNode defineStructDefinition(
+ UntypedStructDefinitionNode untyped,
+ TypeCheckerNamespaceContext context
+ ) {
+ var structType = (StructType) lookupMetaType(untyped.name(), untyped.source(), context);
var typedFields = new ArrayList<TypedStructFieldDefinitionNode>();
for (var untypedField : untyped.fields()) {
@@ -89,12 +114,35 @@ public class TypeChecker {
UntypedTypeLevelReferenceNode untyped,
TypeCheckerNamespaceContext context
) {
- var variable = context.lookup(untyped.name())
- .orElseThrow(() -> new UndeclaredVariableError(untyped.name(), untyped.source()));
+ var value = lookupTypeLevelValue(untyped.name(), untyped.source(), context);
+
+ return new TypedTypeLevelReferenceNode<>(
+ untyped.name(),
+ value,
+ untyped.source()
+ );
+ }
+
+ private static Type lookupMetaType(
+ String name,
+ Source source,
+ TypeCheckerNamespaceContext context
+ ) {
+ // TODO: handle not a type properly
+ return (Type) lookupTypeLevelValue(name, source, context);
+ }
+
+ private static TypeLevelValue lookupTypeLevelValue(
+ String name,
+ Source source,
+ TypeCheckerNamespaceContext context
+ ) {
+ var variable = context.lookup(name)
+ .orElseThrow(() -> new UndeclaredVariableError(name, source));
var type = switch (variable) {
case Variable.Declared declared ->
- throw new UndefinedVariableError(untyped.name(), untyped.source());
+ throw new UndefinedVariableError(name, source);
case Variable.Defined defined ->
defined.type();
@@ -102,13 +150,9 @@ public class TypeChecker {
// TODO: handle not a type-level value
if (!(type instanceof TypeLevelValueType(TypeLevelValue value))) {
- throw new UnexpectedTypeError(new TypeSet.MetaType(), type, untyped.source());
+ throw new UnexpectedTypeError(new TypeSet.MetaType(), type, source);
}
- return new TypedTypeLevelReferenceNode<>(
- untyped.name(),
- value,
- untyped.source()
- );
+ return value;
}
}