From 1ddcda7bd2b7148f4c6ba4f23791786c64d1fbec Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Thu, 22 Aug 2024 22:46:49 +0800 Subject: Get rid of that Scope mess --- .../main/java/lv/enes/orang/checker/Checker.java | 39 ++++++++---------- .../java/lv/enes/orang/core/ImmutableScope.java | 47 ---------------------- .../main/java/lv/enes/orang/core/MutableScope.java | 26 ------------ core/src/main/java/lv/enes/orang/core/Scope.java | 31 -------------- orang/src/main/java/lv/enes/orang/Evaluator.java | 27 ++++++++----- .../main/java/lv/enes/orang/value/Function.java | 5 ++- .../java/lv/enes/orang/value/PartialFunction.java | 13 +++--- 7 files changed, 42 insertions(+), 146 deletions(-) delete mode 100644 core/src/main/java/lv/enes/orang/core/ImmutableScope.java delete mode 100644 core/src/main/java/lv/enes/orang/core/MutableScope.java delete mode 100644 core/src/main/java/lv/enes/orang/core/Scope.java diff --git a/checker/src/main/java/lv/enes/orang/checker/Checker.java b/checker/src/main/java/lv/enes/orang/checker/Checker.java index 14604b8..ee0914f 100644 --- a/checker/src/main/java/lv/enes/orang/checker/Checker.java +++ b/checker/src/main/java/lv/enes/orang/checker/Checker.java @@ -1,27 +1,17 @@ package lv.enes.orang.checker; import lv.enes.orang.ast.*; -import lv.enes.orang.core.ImmutableScope; -import lv.enes.orang.core.Scope; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class Checker implements ExpressionVisitor, StatementVisitor { - private final Scope definitions; + private final Set definitions; public static Checker of(Map builtins) { - var boolMap = builtins.keySet() - .stream() - .>collect( - HashMap::new, - (map, elem) -> map.put(elem, true), - Map::putAll - ); - return new Checker(ImmutableScope.of(boolMap)); + return new Checker(Collections.unmodifiableSet(builtins.keySet())); } - private Checker(Scope definitions) { + private Checker(Set definitions) { this.definitions = definitions; } @@ -55,10 +45,13 @@ public class Checker implements ExpressionVisitor, State @Override public Checker visitDefinition(Definition def) throws CheckerException { - if (definitions.hasDefinition(def.name())) { + if (definitions.contains(def.name())) { throw new CheckerException(STR."Top-level definition '\{def.name()}' redefined!"); } - var ch = new Checker(ImmutableScope.of(definitions, def.name(), true)); + + var newScope = new HashSet<>(definitions); + newScope.add(def.name()); + var ch = new Checker(newScope); ch.visit(def.body()); return ch; } @@ -79,13 +72,13 @@ public class Checker implements ExpressionVisitor, State @Override public Void visitFnExpression(FnExpression expr) throws CheckerException { - var args = new HashMap(); + var newScope = new HashSet<>(definitions); for (var arg : expr.args()) { if (arg instanceof ArgSpec.Named(String name)) { - args.put(name, true); + newScope.add(name); } } - new Checker(ImmutableScope.of(definitions, args)).visit(expr.body()); + new Checker(newScope).visit(expr.body()); return null; } @@ -105,11 +98,11 @@ public class Checker implements ExpressionVisitor, State @Override public Void visitLetInExpression(LetInExpression expr) throws CheckerException { - var locals = new HashMap(); + var newScope = new HashSet<>(definitions); for (var local : expr.bindings()) { - locals.put(local.name(), true); + newScope.add(local.name()); } - new Checker(ImmutableScope.of(definitions, locals)).visit(expr.body()); + new Checker(newScope).visit(expr.body()); return null; } @@ -136,7 +129,7 @@ public class Checker implements ExpressionVisitor, State @Override public Void visitVariable(VariableExpression expr) throws CheckerException { - if (!definitions.hasDefinition(expr.name())) { + if (!definitions.contains(expr.name())) { throw new CheckerException(STR."Variable named '\{expr.name()}' not defined!"); } return null; diff --git a/core/src/main/java/lv/enes/orang/core/ImmutableScope.java b/core/src/main/java/lv/enes/orang/core/ImmutableScope.java deleted file mode 100644 index 5120b08..0000000 --- a/core/src/main/java/lv/enes/orang/core/ImmutableScope.java +++ /dev/null @@ -1,47 +0,0 @@ -package lv.enes.orang.core; - -import java.util.HashMap; -import java.util.Map; - -public class ImmutableScope extends Scope { - public static ImmutableScope of(Map builtins) { - return new ImmutableScope<>(null, new HashMap<>(builtins)); - } - - public static ImmutableScope of(Scope parent) { - if (parent instanceof ImmutableScope imm) { - return imm; - } - return ImmutableScope.of(parent, Map.of()); - } - - public static ImmutableScope of(Scope parent, String key, E value) { - return ImmutableScope.of(parent, Map.of(key, value)); - } - - public static ImmutableScope of(Scope parent, Map definitions) { - return new ImmutableScope<>(parent, definitions).maybeFlattened(); - } - - protected ImmutableScope(Scope parent, Map definitions) { - super(parent, Map.copyOf(definitions)); - } - - public ImmutableScope maybeFlattened() { - if (depth > MAX_DEPTH) { - return flattened(); - } - return this; - } - - private ImmutableScope flattened() { - if (parent instanceof ImmutableScope immParent) { - var flatParent = immParent.flattened(); - var newDefs = new HashMap<>(flatParent.definitions); - newDefs.putAll(definitions); - return new ImmutableScope<>(flatParent.parent, newDefs); - } - - return this; - } -} diff --git a/core/src/main/java/lv/enes/orang/core/MutableScope.java b/core/src/main/java/lv/enes/orang/core/MutableScope.java deleted file mode 100644 index 8d8b455..0000000 --- a/core/src/main/java/lv/enes/orang/core/MutableScope.java +++ /dev/null @@ -1,26 +0,0 @@ -package lv.enes.orang.core; - -import java.util.HashMap; -import java.util.Map; - -public class MutableScope extends Scope { - public static MutableScope of(Map builtins) { - return new MutableScope<>(null, new HashMap<>(builtins)); - } - - public static MutableScope of(Scope parent) { - return new MutableScope<>(parent, Map.of()); - } - - public static MutableScope of(Scope parent, String name, E value) { - return new MutableScope<>(parent, Map.of(name, value)); - } - - protected MutableScope(Scope parent, Map definitions) { - super(parent, new HashMap<>(definitions)); - } - - public void setDefinition(String key, E value) { - definitions.put(key, value); - } -} diff --git a/core/src/main/java/lv/enes/orang/core/Scope.java b/core/src/main/java/lv/enes/orang/core/Scope.java deleted file mode 100644 index 0f4d23a..0000000 --- a/core/src/main/java/lv/enes/orang/core/Scope.java +++ /dev/null @@ -1,31 +0,0 @@ -package lv.enes.orang.core; - -import java.util.Map; - -public abstract class Scope { - public static final int MAX_DEPTH = 4; - - protected final Scope parent; - protected final Map definitions; - protected final int depth; - - protected Scope(Scope parent, Map definitions) { - this.parent = parent; - this.definitions = definitions; - this.depth = parent == null ? 0 : parent.depth + 1; - } - - public E getDefinition(String name) throws OrangRuntimeException { - if (definitions.containsKey(name)) { - return definitions.get(name); - } else if (parent != null) { - return parent.getDefinition(name); - } else { - throw new OrangRuntimeException(STR."Value named \{name} is not defined!"); - } - } - - public boolean hasDefinition(String name) { - return definitions.containsKey(name) || parent != null && parent.hasDefinition(name); - } -} diff --git a/orang/src/main/java/lv/enes/orang/Evaluator.java b/orang/src/main/java/lv/enes/orang/Evaluator.java index 8930f5c..69a256f 100644 --- a/orang/src/main/java/lv/enes/orang/Evaluator.java +++ b/orang/src/main/java/lv/enes/orang/Evaluator.java @@ -1,20 +1,20 @@ package lv.enes.orang; import lv.enes.orang.ast.*; -import lv.enes.orang.core.MutableScope; import lv.enes.orang.core.OrangRuntimeException; -import lv.enes.orang.core.Scope; import lv.enes.orang.value.*; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; -public record Evaluator(Scope scope, Value lastResult) implements ExpressionVisitor, StatementVisitor { +public record Evaluator(Map scope, Value lastResult) implements ExpressionVisitor, StatementVisitor { public Evaluator() { - this(MutableScope.of(Builtins.BUILTINS)); + this(new HashMap<>(Builtins.BUILTINS)); } - public Evaluator(Scope scope) { + public Evaluator(Map scope) { this(scope, Undefined.INSTANCE); } @@ -59,9 +59,10 @@ public record Evaluator(Scope scope, Value lastResult) implements Express @Override public Evaluator visitDefinition(Definition def) throws OrangRuntimeException { - var newScope = MutableScope.of(scope, def.name(), Undefined.INSTANCE); + var newScope = new HashMap<>(scope); + newScope.put(def.name(), Undefined.INSTANCE); var newEvaluator = new Evaluator(newScope); - newScope.setDefinition(def.name(), newEvaluator.visit(def.body())); + newScope.put(def.name(), newEvaluator.visit(def.body())); return newEvaluator; } @@ -105,13 +106,13 @@ public record Evaluator(Scope scope, Value lastResult) implements Express @Override public Value visitLetInExpression(LetInExpression expr) throws OrangRuntimeException { - var newScope = MutableScope.of(scope); + var newScope = new HashMap<>(scope); for (var binding : expr.bindings()) { - newScope.setDefinition(binding.name(), Undefined.INSTANCE); + newScope.put(binding.name(), Undefined.INSTANCE); } var newEvaluator = new Evaluator(newScope); for (var binding : expr.bindings()) { - newScope.setDefinition(binding.name(), newEvaluator.visit(binding.value())); + newScope.put(binding.name(), newEvaluator.visit(binding.value())); } return newEvaluator.visit(expr.body()); } @@ -142,7 +143,11 @@ public record Evaluator(Scope scope, Value lastResult) implements Express @Override public Value visitVariable(VariableExpression expr) throws OrangRuntimeException { - return scope.getDefinition(expr.name()); + if (scope.containsKey(expr.name())) { + return scope.get(expr.name()); + } + + throw new OrangRuntimeException(STR."Value named \{expr.name()} is not defined!"); } @Override diff --git a/orang/src/main/java/lv/enes/orang/value/Function.java b/orang/src/main/java/lv/enes/orang/value/Function.java index d0500b9..f8c1a7f 100644 --- a/orang/src/main/java/lv/enes/orang/value/Function.java +++ b/orang/src/main/java/lv/enes/orang/value/Function.java @@ -3,10 +3,11 @@ package lv.enes.orang.value; import lv.enes.orang.ast.ArgSpec; import lv.enes.orang.ast.Expression; import lv.enes.orang.core.OrangRuntimeException; -import lv.enes.orang.core.Scope; import lv.enes.orang.utils.NonEmptyList; -public record Function(Scope scope, NonEmptyList args, Expression body) implements Value { +import java.util.Map; + +public record Function(Map scope, NonEmptyList args, Expression body) implements Value { @Override public String typeName() { return "Function"; diff --git a/orang/src/main/java/lv/enes/orang/value/PartialFunction.java b/orang/src/main/java/lv/enes/orang/value/PartialFunction.java index d03bb13..427da76 100644 --- a/orang/src/main/java/lv/enes/orang/value/PartialFunction.java +++ b/orang/src/main/java/lv/enes/orang/value/PartialFunction.java @@ -3,17 +3,18 @@ package lv.enes.orang.value; import lv.enes.orang.*; import lv.enes.orang.ast.ArgSpec; import lv.enes.orang.ast.Expression; -import lv.enes.orang.core.MutableScope; import lv.enes.orang.core.OrangRuntimeException; -import lv.enes.orang.core.Scope; import lv.enes.orang.utils.NonEmptyList; -public record PartialFunction(Scope scope, NonEmptyList remainingArgs, Expression body) implements Value { - public static Value of(Scope scope, NonEmptyList remainingArgs, Expression body, Value param) throws OrangRuntimeException { +import java.util.HashMap; +import java.util.Map; + +public record PartialFunction(Map scope, NonEmptyList remainingArgs, Expression body) implements Value { + public static Value of(Map scope, NonEmptyList remainingArgs, Expression body, Value param) throws OrangRuntimeException { var spec = remainingArgs.getFirst(); - var newScope = MutableScope.of(scope); + var newScope = new HashMap<>(scope); switch (spec.getType()) { - case NAMED -> newScope.setDefinition(((ArgSpec.Named)spec).name(), param); + case NAMED -> newScope.put(((ArgSpec.Named)spec).name(), param); case NOTHING -> { if (!(param instanceof Nothing)) { throw new OrangRuntimeException(STR."Expected () as a parameter but got \{param.typeName()}"); -- cgit v1.2.3