From ee3d75f1f230ae05803db83ce387eb8b79bc1d95 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Mon, 31 Jul 2023 22:13:28 +0100 Subject: Extract Variable to be top-level interface --- .../compiler/typechecker/EnvironmentBuilder.java | 10 ++++----- .../shedlang/compiler/typechecker/TypeChecker.java | 10 ++++----- .../compiler/typechecker/TypeCheckerContext.java | 15 +------------- .../shedlang/compiler/typechecker/Variable.java | 19 +++++++++++++++++ .../typechecker/TypeCheckerAssignTests.java | 4 ++-- .../compiler/typechecker/TypeCheckerCallTests.java | 4 ++-- .../typechecker/TypeCheckerContextTests.java | 24 +++++++++++----------- .../compiler/typechecker/TypeCheckerIfTests.java | 2 +- 8 files changed, 47 insertions(+), 41 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/typechecker/Variable.java (limited to 'src') diff --git a/src/main/java/org/shedlang/compiler/typechecker/EnvironmentBuilder.java b/src/main/java/org/shedlang/compiler/typechecker/EnvironmentBuilder.java index 53853305..c30c745a 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/EnvironmentBuilder.java +++ b/src/main/java/org/shedlang/compiler/typechecker/EnvironmentBuilder.java @@ -11,9 +11,9 @@ import java.util.List; public class EnvironmentBuilder { public static final EnvironmentBuilder EMPTY = new EnvironmentBuilder(Empty.map()); - private PMap environment; + private PMap environment; - private EnvironmentBuilder(PMap environment) { + private EnvironmentBuilder(PMap environment) { this.environment = environment; } @@ -31,17 +31,17 @@ public class EnvironmentBuilder { if (environment.containsKey(name)) { throw new DuplicateVariableName(name, source); } - return new EnvironmentBuilder(environment.plus(name, new TypeCheckerContext.Variable.Undefined())); + return new EnvironmentBuilder(environment.plus(name, new Variable.Undefined())); } - public EnvironmentBuilder add(String name, TypeCheckerContext.Variable variable, Source source) { + public EnvironmentBuilder add(String name, Variable variable, Source source) { if (environment.containsKey(name)) { throw new DuplicateVariableName(name, source); } return new EnvironmentBuilder(environment.plus(name, variable)); } - public PMap build() { + public PMap build() { return environment; } diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index ee35fa1f..5377f562 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -49,10 +49,10 @@ public class TypeChecker { } return switch (type.get()) { - case TypeCheckerContext.Variable.Defined defined -> + case Variable.Defined defined -> defined.type(); - case TypeCheckerContext.Variable.Undefined undefined -> + case Variable.Undefined undefined -> throw new ReferenceBeforeDefinitionError(name, source); }; } @@ -64,10 +64,10 @@ public class TypeChecker { } return switch (type.get()) { - case TypeCheckerContext.Variable.Defined defined -> + case Variable.Defined defined -> defined.type(); - case TypeCheckerContext.Variable.Undefined undefined -> + case Variable.Undefined undefined -> throw new ReferenceBeforeDefinitionError(name, source); }; }); @@ -458,7 +458,7 @@ public class TypeChecker { for (var param : typedParams.all()) { bodyEnvironment = bodyEnvironment.add( param.name(), - TypeCheckerContext.defined(param.type().value()), + Variable.defined(param.type().value()), param.source() ); } diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java index d6a10d35..30778094 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java @@ -30,19 +30,6 @@ public class TypeCheckerContext { )) ); - public sealed interface Variable { - record Undefined() implements Variable {} - record Defined(Type type) implements Variable {} - } - - public static Variable defined(Type type) { - return new Variable.Defined(type); - } - - public static Variable undefined() { - return new Variable.Undefined(); - } - private sealed interface StackElement { boolean isBoundInElement(String name); StackElement withFreeVariable(String name, Source referenceSource); @@ -152,7 +139,7 @@ public class TypeCheckerContext { public TypeCheckerContext enterNamespaceWithDefinedVariables(PMap variables) { var environment = variables.entrySet().stream() - .map(x -> Map.entry(x.getKey(), TypeCheckerContext.defined(x.getValue()))) + .map(x -> Map.entry(x.getKey(), Variable.defined(x.getValue()))) .collect(PCollectors.toMap()); return enterNamespace(environment); diff --git a/src/main/java/org/shedlang/compiler/typechecker/Variable.java b/src/main/java/org/shedlang/compiler/typechecker/Variable.java new file mode 100644 index 00000000..7fd7ca23 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/typechecker/Variable.java @@ -0,0 +1,19 @@ +package org.shedlang.compiler.typechecker; + +import org.shedlang.compiler.types.Type; + +public sealed interface Variable { + static Variable defined(Type type) { + return new Variable.Defined(type); + } + + static Variable undefined() { + return new Variable.Undefined(); + } + + record Undefined() implements Variable { + } + + record Defined(Type type) implements Variable { + } +} diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java index 21ebfbc3..1f5d82ee 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerAssignTests.java @@ -24,7 +24,7 @@ public class TypeCheckerAssignTests { var untyped = Untyped.assign(Untyped.targetVariable("x"), Untyped.stringLiteral("hello")); var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("x", TypeCheckerContext.defined(Types.STRING)) + Map.entry("x", Variable.defined(Types.STRING)) )); var typed = typeCheckFunctionStatement(untyped, context); @@ -40,7 +40,7 @@ public class TypeCheckerAssignTests { var untyped = Untyped.assign(Untyped.targetVariable("x"), Untyped.stringLiteral("hello")); var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("x", TypeCheckerContext.defined(Types.INT)) + Map.entry("x", Variable.defined(Types.INT)) )); var error = assertThrows( diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerCallTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerCallTests.java index 33cfda12..59576069 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerCallTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerCallTests.java @@ -307,7 +307,7 @@ public class TypeCheckerCallTests { .build(); var context = TypeCheckerContext.EMPTY .enterFunction( - P.map(Map.entry("f", TypeCheckerContext.defined(functionType))), + P.map(Map.entry("f", Variable.defined(functionType))), Effects.IO, Types.UNIT ); @@ -334,7 +334,7 @@ public class TypeCheckerCallTests { .build(); var context = TypeCheckerContext.EMPTY .enterFunction( - P.map(Map.entry("f", TypeCheckerContext.defined(functionType))), + P.map(Map.entry("f", Variable.defined(functionType))), Effects.NONE, Types.UNIT ); diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java index a9198b86..3c622348 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerContextTests.java @@ -19,21 +19,21 @@ public class TypeCheckerContextTests { public void givenVariableIsUndefinedWhenVariableIsDefinedThenVariableHasTypeSet() { var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("x", TypeCheckerContext.undefined()), - Map.entry("y", TypeCheckerContext.undefined()) + Map.entry("x", Variable.undefined()), + Map.entry("y", Variable.undefined()) )); context = context.define("x", Types.STRING, Sources.NULL); var result = context.runtimeLookup("x", Sources.NULL); - assertThat(result.value(), isOptionalOf(equalTo(TypeCheckerContext.defined(Types.STRING)))); + assertThat(result.value(), isOptionalOf(equalTo(Variable.defined(Types.STRING)))); } @Test public void givenVariableIsUnknownWhenVariableIsDefinedThenErrorIsThrown() { var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("y", TypeCheckerContext.undefined()) + Map.entry("y", Variable.undefined()) )); var error = assertThrows( @@ -48,7 +48,7 @@ public class TypeCheckerContextTests { public void givenVariableIsDefinedWhenVariableIsDefinedThenErrorIsThrown() { var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("x", TypeCheckerContext.defined(Types.STRING)) + Map.entry("x", Variable.defined(Types.STRING)) )); var error = assertThrows( @@ -63,7 +63,7 @@ public class TypeCheckerContextTests { public void givenVariableIsBoundInOuterScopeWhenVariableIsDefinedThenErrorIsThrown() { var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("x", TypeCheckerContext.undefined()) + Map.entry("x", Variable.undefined()) )) .enterNamespace(P.map()); @@ -79,23 +79,23 @@ public class TypeCheckerContextTests { public void definingVariableOnlyAffectsTopMostLexicalContext() { var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("x", TypeCheckerContext.undefined()), - Map.entry("y", TypeCheckerContext.undefined()) + Map.entry("x", Variable.undefined()), + Map.entry("y", Variable.undefined()) )); context = context.enterBlock(P.map( - Map.entry("x", TypeCheckerContext.undefined()) + Map.entry("x", Variable.undefined()) )); context = context.define("x", Types.STRING, Sources.NULL); assertThat( context.runtimeLookup("x", Sources.NULL).value(), - isOptionalOf(equalTo(TypeCheckerContext.defined(Types.STRING))) + isOptionalOf(equalTo(Variable.defined(Types.STRING))) ); context = context.exit(); assertThat( context.runtimeLookup("x", Sources.NULL).value(), - isOptionalOf(equalTo(TypeCheckerContext.undefined())) + isOptionalOf(equalTo(Variable.undefined())) ); } @@ -104,7 +104,7 @@ public class TypeCheckerContextTests { var context = TypeCheckerContext.EMPTY .enterBlock(P.map()) .enterBlock(P.map( - Map.entry("x", TypeCheckerContext.undefined()) + Map.entry("x", Variable.undefined()) )) .enterBlock(P.map()) .enterBlock(P.map()); diff --git a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIfTests.java b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIfTests.java index a52fdfac..69ae78af 100644 --- a/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIfTests.java +++ b/src/test/java/org/shedlang/compiler/typechecker/TypeCheckerIfTests.java @@ -129,7 +129,7 @@ public class TypeCheckerIfTests { ); var context = TypeCheckerContext.EMPTY .enterNamespace(P.map( - Map.entry("x", TypeCheckerContext.defined(Types.STRING)) + Map.entry("x", Variable.defined(Types.STRING)) )); var result = TypeChecker.typeCheckExpression(untyped, context); -- cgit v1.2.3