diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-07-28 22:18:28 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-07-28 22:18:28 +0100 |
| commit | f3da8bbffe9cdf80ba3f422ec2d8ff7ce13ea2ae (patch) | |
| tree | ae663ed62d128b7df8887395cf7e1eb2d48ee864 /src | |
| parent | e4772ab0d4466f3844091ad603938b24c442e75b (diff) | |
Type check var statements
Diffstat (limited to 'src')
7 files changed, 131 insertions, 2 deletions
diff --git a/src/main/java/org/shedlang/compiler/ast/typed/TypedFunctionStatementNode.java b/src/main/java/org/shedlang/compiler/ast/typed/TypedFunctionStatementNode.java index 82fc3a8c..b1fcd49b 100644 --- a/src/main/java/org/shedlang/compiler/ast/typed/TypedFunctionStatementNode.java +++ b/src/main/java/org/shedlang/compiler/ast/typed/TypedFunctionStatementNode.java @@ -1,5 +1,5 @@ package org.shedlang.compiler.ast.typed; -public sealed interface TypedFunctionStatementNode extends TypedNode permits TypedBlockReturnNode, TypedExpressionStatementNode, TypedFunctionReturnNode, TypedValNode { +public sealed interface TypedFunctionStatementNode extends TypedNode permits TypedBlockReturnNode, TypedExpressionStatementNode, TypedFunctionReturnNode, TypedValNode, TypedVarNode { TypedFunctionStatementBehaviour behaviour(); } diff --git a/src/main/java/org/shedlang/compiler/ast/typed/TypedVarNode.java b/src/main/java/org/shedlang/compiler/ast/typed/TypedVarNode.java new file mode 100644 index 00000000..3c698b52 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/ast/typed/TypedVarNode.java @@ -0,0 +1,14 @@ +package org.shedlang.compiler.ast.typed; + +import org.shedlang.compiler.sources.Source; + +public record TypedVarNode( + TypedTargetNode target, + TypedExpressionNode expression, + Source source +) implements TypedFunctionStatementNode { + @Override + public TypedFunctionStatementBehaviour behaviour() { + return TypedFunctionStatementBehaviour.CONTINUE; + } +} diff --git a/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java b/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java index 167983bb..2be8480d 100644 --- a/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java +++ b/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java @@ -212,6 +212,9 @@ public class StackCompiler { case TypedValNode val -> compileVal(val, context); + + case TypedVarNode var -> + throw new UnsupportedOperationException(); }; } diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index e0be25eb..8cf38fc1 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -541,7 +541,7 @@ public class TypeChecker { typeCheckVal(val).typeCheckAllPhases(context); case UntypedVarNode var -> - throw new UnsupportedOperationException(); + typeCheckVar(var, context); }; } @@ -802,6 +802,21 @@ public class TypeChecker { return context.toResult(new TypedValNode(target, expression, untyped.source())); } + private static TypeCheckerResult<TypedVarNode> typeCheckVar( + UntypedVarNode untyped, + TypeCheckerContext context + ) { + var expressionResult = typeCheckExpression(untyped.expression(), context); + var expression = expressionResult.value(); + context = expressionResult.context(); + + var targetResult = typeCheckTarget(untyped.target(), expression.type(), context); + var target = targetResult.value(); + context = targetResult.context(); + + return context.toResult(new TypedVarNode(target, expression, untyped.source())); + } + private static TypeCheckerResult<TypedTargetNode> typeCheckTarget( UntypedTargetNode target, Type expressionType, diff --git a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java index 3a46fa54..ef2e4686 100644 --- a/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java +++ b/src/test/java/org/shedlang/compiler/ast/typed/TypedNodeMatchers.java @@ -237,4 +237,15 @@ public class TypedNodeMatchers { has("expression", x -> x.expression(), expression) ); } + + public static Matcher<TypedNode> isTypedVarNode( + Matcher<? super TypedTargetNode> target, + Matcher<? super TypedExpressionNode> expression + ) { + return instanceOf( + TypedVarNode.class, + has("target", x -> x.target(), target), + has("expression", x -> x.expression(), expression) + ); + } } diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java index 8dddfa58..141212cc 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java @@ -157,4 +157,11 @@ public class Untyped { ) { return new UntypedValNode(target, expression, Sources.NULL); } + + public static UntypedVarNode var( + UntypedTargetNode target, + UntypedExpressionNode expression + ) { + return new UntypedVarNode(target, expression, Sources.NULL); + } } diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerVarTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerVarTests.java new file mode 100644 index 00000000..244ddc98 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerVarTests.java @@ -0,0 +1,79 @@ +package org.shedlang.compiler.typechecker; + +import org.junit.jupiter.api.Test; +import org.shedlang.compiler.ast.typed.TypedFunctionStatementNode; +import org.shedlang.compiler.ast.typed.TypedNamespaceStatementNode; +import org.shedlang.compiler.ast.untyped.Untyped; +import org.shedlang.compiler.ast.untyped.UntypedFunctionDefinitionNode; +import org.shedlang.compiler.ast.untyped.UntypedFunctionStatementNode; +import org.shedlang.compiler.ast.untyped.UntypedNamespaceStatementNode; +import org.shedlang.compiler.types.Types; +import org.shedlang.compiler.util.P; + +import java.util.Map; + +import static org.shedlang.compiler.ast.typed.TypedNodeMatchers.*; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.anything; +import static org.zwobble.precisely.Matchers.isSequence; + +public class TypeCheckerVarTests { + @Test + public void canTypeCheckAsFunctionStatement() { + var untyped = Untyped.var(Untyped.targetVariable("x"), Untyped.stringLiteral("hello")); + + var typed = typeCheckFunctionStatement(untyped, TypeCheckerContext.EMPTY); + + assertThat(typed.value(), isTypedVarNode( + isTypedTargetVariable("x"), + isTypedStringLiteralNode("hello") + )); + } + + @Test + public void varCanBeReferencedAfterDefinitionInFunction() { + var untyped = UntypedFunctionDefinitionNode.builder() + .addStatement(Untyped.var(Untyped.targetVariable("x"), Untyped.stringLiteral("hello"))) + .addStatement(Untyped.expressionStatement(Untyped.reference("x"))) + .build(); + var context = TypeCheckerContext.EMPTY + .enterNamespaceWithDefinedVariables(P.map( + Map.entry("Unit", Types.metaType(Types.UNIT)) + )); + + var typed = typeCheckNamespaceStatement(untyped, context); + + assertThat( + typed.value(), + isTypedFunctionDefinitionNode() + .withBody(isTypedBlockNode(isSequence( + isTypedVarNode(anything(), anything()), + isTypedExpressionStatementNode(isTypedReferenceNode("x", Types.STRING)) + ))) + ); + } + + private static TypeCheckerResult<? extends TypedFunctionStatementNode> typeCheckFunctionStatement( + UntypedFunctionStatementNode untyped, + TypeCheckerContext context + ) { + var declaredVariables = DeclaredVariables.forFunctionStatement(untyped, P.vector()); + var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); + + context = context.enterNamespace(environment.build()); + + return TypeChecker.typeCheckFunctionStatement(untyped, context); + } + + private static TypeCheckerResult<? extends TypedNamespaceStatementNode> typeCheckNamespaceStatement( + UntypedNamespaceStatementNode untyped, + TypeCheckerContext context + ) { + var declaredVariables = DeclaredVariables.forNamespaceStatement(untyped, P.vector()); + var environment = EnvironmentBuilder.EMPTY.addUndefined(declaredVariables); + + context = context.enterNamespace(environment.build()); + + return TypeChecker.typeCheckNamespaceStatement(untyped).typeCheckAllPhases(context); + } +} |
