From 39ef07c887e33aff56c087388980a92e750b547c Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 25 Apr 2026 10:44:02 +0100 Subject: Type check namespace bodies --- .../hobgoblin/compiler/HobgoblinCompiler.java | 4 +- .../compiler/typechecker/TypeChecker.java | 25 +++++++----- .../compiler/typechecker/TypeCheckerContext.java | 44 ---------------------- .../typechecker/TypeCheckerGlobalContext.java | 16 ++++++++ .../typechecker/TypeCheckerNamespaceContext.java | 43 +++++++++++++++++++++ 5 files changed, 77 insertions(+), 55 deletions(-) delete mode 100644 src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerContext.java create mode 100644 src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java create mode 100644 src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java (limited to 'src/main/java/org') diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java index 6daa31b..4f56fb1 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java @@ -2,7 +2,7 @@ package org.zwobble.hobgoblin.compiler; import org.zwobble.hobgoblin.compiler.parser.Parser; import org.zwobble.hobgoblin.compiler.typechecker.TypeChecker; -import org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerContext; +import org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerGlobalContext; import org.zwobble.hobgoblin.compiler.types.NamespaceName; import org.zwobble.sourcetext.SourceText; @@ -28,7 +28,7 @@ public class HobgoblinCompiler { var sourceText = SourceText.fromString(sourceFile.toPath().toString(), sourceContents); var untypedNamespaceNode = Parser.parseNamespace(sourceText, namespaceName); - var typeCheckerContext = TypeCheckerContext.initial(); + var typeCheckerContext = TypeCheckerGlobalContext.initial(); var typedNamespaceNode = TypeChecker.typeCheckNamespace(untypedNamespaceNode, typeCheckerContext); } } 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 0a301c6..b8bdd7f 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -7,6 +7,7 @@ import org.zwobble.hobgoblin.compiler.types.TypeLevelValue; import org.zwobble.hobgoblin.compiler.types.TypeLevelValueType; import org.zwobble.hobgoblin.compiler.types.TypeSet; +import java.util.ArrayList; import java.util.List; public class TypeChecker { @@ -15,18 +16,26 @@ public class TypeChecker { public static TypedNamespaceNode typeCheckNamespace( UntypedNamespaceNode untyped, - TypeCheckerContext context + TypeCheckerGlobalContext context ) { + var namespaceContext = context.enterNamespace(untyped.namespaceName()); + + var typedBody = new ArrayList(); + for (var untypedStatement : untyped.body()) { + var typedStatement = typeCheckNamespaceStatement(untypedStatement, namespaceContext); + typedBody.add(typedStatement); + } + return new TypedNamespaceNode( untyped.namespaceName(), - List.of(), + typedBody, untyped.source() ); } static TypedNamespaceStatementNode typeCheckNamespaceStatement( UntypedNamespaceStatementNode untyped, - TypeCheckerContext context + TypeCheckerNamespaceContext context ) { return switch (untyped) { case UntypedStructDefinitionNode untypedStructDefinition -> @@ -36,11 +45,9 @@ public class TypeChecker { private static TypedStructDefinitionNode typeCheckStructDefinition( UntypedStructDefinitionNode untyped, - TypeCheckerContext context + TypeCheckerNamespaceContext context ) { - // TODO: better error when not in namespace - var namespaceName = context.namespaceName().orElseThrow(); - var structType = new StructType(namespaceName, untyped.name()); + var structType = new StructType(context.namespaceName(), untyped.name()); return new TypedStructDefinitionNode( structType, @@ -51,7 +58,7 @@ public class TypeChecker { static TypedTypeLevelExpressionNode typeCheckTypeLevelExpression( UntypedTypeLevelExpressionNode untyped, - TypeCheckerContext context + TypeCheckerNamespaceContext context ) { return switch (untyped) { case UntypedTypeLevelReferenceNode untypedTypeLevelReference -> @@ -61,7 +68,7 @@ public class TypeChecker { private static TypedTypeLevelExpressionNode typeCheckTypeLevelReference( UntypedTypeLevelReferenceNode untyped, - TypeCheckerContext context + TypeCheckerNamespaceContext context ) { var variable = context.lookup(untyped.name()) .orElseThrow(() -> new UndeclaredVariableError(untyped.name(), untyped.source())); diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerContext.java deleted file mode 100644 index e1109f9..0000000 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerContext.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.zwobble.hobgoblin.compiler.typechecker; - -import org.zwobble.hobgoblin.compiler.types.NamespaceName; -import org.zwobble.hobgoblin.compiler.types.Type; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -public class TypeCheckerContext { - private Optional namespaceName; - private final Map variables; - - private TypeCheckerContext(Optional namespaceName, Map variables) { - this.namespaceName = namespaceName; - this.variables = variables; - } - - public static TypeCheckerContext initial() { - return new TypeCheckerContext(Optional.empty(), new HashMap<>()); - } - - public Optional namespaceName() { - return this.namespaceName; - } - - public void declare(String name) { - // TODO: Check variable is not already declared. - this.variables.put(name, new Variable.Declared()); - } - - public void define(String name, Type type) { - // TODO: Check variable is not already defined. - this.variables.put(name, new Variable.Defined(type)); - } - - public Optional lookup(String name) { - return Optional.ofNullable(this.variables.get(name)); - } - - public void enterNamespace(NamespaceName namespaceName) { - this.namespaceName = Optional.of(namespaceName); - } -} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java new file mode 100644 index 0000000..3915767 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerGlobalContext.java @@ -0,0 +1,16 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.types.NamespaceName; + +public class TypeCheckerGlobalContext { + public static TypeCheckerGlobalContext initial() { + return new TypeCheckerGlobalContext(); + } + + private TypeCheckerGlobalContext() { + } + + public TypeCheckerNamespaceContext enterNamespace(NamespaceName namespaceName) { + return TypeCheckerNamespaceContext.initial(namespaceName); + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java new file mode 100644 index 0000000..c1a23fd --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java @@ -0,0 +1,43 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.types.NamespaceName; +import org.zwobble.hobgoblin.compiler.types.Type; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class TypeCheckerNamespaceContext { + public static TypeCheckerNamespaceContext initial(NamespaceName namespaceName) { + return new TypeCheckerNamespaceContext(namespaceName, new HashMap<>()); + } + + private final NamespaceName namespaceName; + private final Map variables; + + private TypeCheckerNamespaceContext( + NamespaceName namespaceName, + Map variables + ) { + this.namespaceName = namespaceName; + this.variables = variables; + } + + public NamespaceName namespaceName() { + return this.namespaceName; + } + + public void declare(String name) { + // TODO: Check variable is not already declared. + this.variables.put(name, new Variable.Declared()); + } + + public void define(String name, Type type) { + // TODO: Check variable is not already defined. + this.variables.put(name, new Variable.Defined(type)); + } + + public Optional lookup(String name) { + return Optional.ofNullable(this.variables.get(name)); + } +} -- cgit v1.2.3