diff options
Diffstat (limited to 'src/main/java/org')
14 files changed, 215 insertions, 0 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNode.java new file mode 100644 index 0000000..6baa8d6 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNode.java @@ -0,0 +1,7 @@ +package org.zwobble.hobgoblin.compiler.ast.typed; + +import org.zwobble.hobgoblin.compiler.sources.Source; + +public interface TypedNode { + Source source(); +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedTypeLevelExpressionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedTypeLevelExpressionNode.java new file mode 100644 index 0000000..c588f95 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedTypeLevelExpressionNode.java @@ -0,0 +1,7 @@ +package org.zwobble.hobgoblin.compiler.ast.typed; + +import org.zwobble.hobgoblin.compiler.types.TypeLevelValue; + +public sealed interface TypedTypeLevelExpressionNode<T extends TypeLevelValue> extends TypedNode permits TypedTypeLevelReferenceNode { + T value(); +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedTypeLevelReferenceNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedTypeLevelReferenceNode.java new file mode 100644 index 0000000..bc2c50d --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedTypeLevelReferenceNode.java @@ -0,0 +1,11 @@ +package org.zwobble.hobgoblin.compiler.ast.typed; + +import org.zwobble.hobgoblin.compiler.sources.Source; +import org.zwobble.hobgoblin.compiler.types.TypeLevelValue; + +public record TypedTypeLevelReferenceNode<T extends TypeLevelValue>( + String name, + T value, + Source source +) implements TypedTypeLevelExpressionNode<T> { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java new file mode 100644 index 0000000..56d4645 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -0,0 +1,51 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.ast.typed.TypedTypeLevelExpressionNode; +import org.zwobble.hobgoblin.compiler.ast.typed.TypedTypeLevelReferenceNode; +import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode; +import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode; +import org.zwobble.hobgoblin.compiler.types.TypeLevelValue; +import org.zwobble.hobgoblin.compiler.types.TypeLevelValueType; +import org.zwobble.hobgoblin.compiler.types.TypeSet; + +public class TypeChecker { + private TypeChecker() { + } + + public static TypedTypeLevelExpressionNode<? extends TypeLevelValue> typeCheckTypeLevelExpression( + UntypedTypeLevelExpressionNode untyped, + TypeCheckerContext context + ) { + return switch (untyped) { + case UntypedTypeLevelReferenceNode untypedTypeLevelReference -> + typeCheckTypeLevelReference(untypedTypeLevelReference, context); + }; + } + + private static TypedTypeLevelExpressionNode<? extends TypeLevelValue> typeCheckTypeLevelReference( + UntypedTypeLevelReferenceNode untyped, + TypeCheckerContext context + ) { + var variable = context.lookup(untyped.name()) + .orElseThrow(() -> new UndeclaredVariableError(untyped.name(), untyped.source())); + + var type = switch (variable) { + case Variable.Declared declared -> + throw new UndefinedVariableError(untyped.name(), untyped.source()); + + case Variable.Defined defined -> + defined.type(); + }; + + // TODO: handle not a type-level value + if (!(type instanceof TypeLevelValueType(TypeLevelValue value))) { + throw new UnexpectedTypeError(new TypeSet.MetaType(), type, untyped.source()); + } + + return new TypedTypeLevelReferenceNode<>( + untyped.name(), + value, + 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 new file mode 100644 index 0000000..e861c30 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerContext.java @@ -0,0 +1,25 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.types.Type; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class TypeCheckerContext { + private final Map<String, Variable> variables = new HashMap<>(); + + 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<Variable> lookup(String name) { + return Optional.ofNullable(this.variables.get(name)); + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UndeclaredVariableError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UndeclaredVariableError.java new file mode 100644 index 0000000..c6130fa --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UndeclaredVariableError.java @@ -0,0 +1,17 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.errors.SourceError; +import org.zwobble.hobgoblin.compiler.sources.Source; + +public class UndeclaredVariableError extends SourceError { + private final String variableName; + + public UndeclaredVariableError(String variableName, Source source) { + super("Undeclared variable: " + variableName, source); + this.variableName = variableName; + } + + public String variableName() { + return variableName; + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UndefinedVariableError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UndefinedVariableError.java new file mode 100644 index 0000000..95be5a6 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UndefinedVariableError.java @@ -0,0 +1,17 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.errors.SourceError; +import org.zwobble.hobgoblin.compiler.sources.Source; + +public class UndefinedVariableError extends SourceError { + private final String variableName; + + public UndefinedVariableError(String variableName, Source source) { + super("Variable has been declared but not defined: " + variableName, source); + this.variableName = variableName; + } + + public String variableName() { + return variableName; + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UnexpectedTypeError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UnexpectedTypeError.java new file mode 100644 index 0000000..c2ca4b6 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/UnexpectedTypeError.java @@ -0,0 +1,25 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.errors.SourceError; +import org.zwobble.hobgoblin.compiler.sources.Source; +import org.zwobble.hobgoblin.compiler.types.Type; +import org.zwobble.hobgoblin.compiler.types.TypeSet; + +public class UnexpectedTypeError extends SourceError { + private final TypeSet expected; + private final Type actual; + + public UnexpectedTypeError(TypeSet expected, Type actual, Source source) { + super("Expected " + expected.describe() + " but was " + actual.describe(), source); + this.expected = expected; + this.actual = actual; + } + + public TypeSet expected() { + return expected; + } + + public Type actual() { + return actual; + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/Variable.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/Variable.java new file mode 100644 index 0000000..1d3a4b6 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/Variable.java @@ -0,0 +1,11 @@ +package org.zwobble.hobgoblin.compiler.typechecker; + +import org.zwobble.hobgoblin.compiler.types.Type; + +public sealed interface Variable { + record Declared() implements Variable { + } + + record Defined(Type type) implements Variable { + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/ScalarType.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/ScalarType.java new file mode 100644 index 0000000..22032a1 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/ScalarType.java @@ -0,0 +1,8 @@ +package org.zwobble.hobgoblin.compiler.types; + +public record ScalarType(String name) implements Type { + @Override + public String describe() { + return name; + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java new file mode 100644 index 0000000..2692261 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/Type.java @@ -0,0 +1,4 @@ +package org.zwobble.hobgoblin.compiler.types; + +public sealed interface Type extends TypeLevelValue permits ScalarType, TypeLevelValueType { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java new file mode 100644 index 0000000..9740cf9 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java @@ -0,0 +1,5 @@ +package org.zwobble.hobgoblin.compiler.types; + +public sealed interface TypeLevelValue permits Type { + String describe(); +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValueType.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValueType.java new file mode 100644 index 0000000..b885c25 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValueType.java @@ -0,0 +1,8 @@ +package org.zwobble.hobgoblin.compiler.types; + +public record TypeLevelValueType(TypeLevelValue value) implements Type { + @Override + public String describe() { + return "TypeLevelValue[" + value.describe() + "]"; + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeSet.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeSet.java new file mode 100644 index 0000000..f587897 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeSet.java @@ -0,0 +1,19 @@ +package org.zwobble.hobgoblin.compiler.types; + +public sealed interface TypeSet { + String describe(); + + record SingleType(Type type) implements TypeSet { + @Override + public String describe() { + return type.describe(); + } + } + + record MetaType() implements TypeSet { + @Override + public String describe() { + return "metatype"; + } + } +} |
