From 5f4b45ec7634f2728693e93f862419e495db6979 Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Thu, 22 Aug 2024 22:55:13 +0800 Subject: Move Evaluator to a new module --- evaluator/build.gradle.kts | 9 ++ .../main/java/lv/enes/orang/evaluator/Array.java | 65 +++++++++ .../lv/enes/orang/evaluator/BuiltinFunction.java | 31 ++++ .../java/lv/enes/orang/evaluator/Evaluator.java | 152 ++++++++++++++++++++ .../java/lv/enes/orang/evaluator/Function.java | 25 ++++ .../main/java/lv/enes/orang/evaluator/Nothing.java | 21 +++ .../java/lv/enes/orang/evaluator/OrangBoolean.java | 55 ++++++++ .../java/lv/enes/orang/evaluator/OrangInteger.java | 70 +++++++++ .../java/lv/enes/orang/evaluator/OrangString.java | 49 +++++++ .../orang/evaluator/PartialBuiltinFunction.java | 32 +++++ .../lv/enes/orang/evaluator/PartialFunction.java | 45 ++++++ .../java/lv/enes/orang/evaluator/Undefined.java | 21 +++ .../main/java/lv/enes/orang/evaluator/Value.java | 76 ++++++++++ evaluator/src/main/java/module-info.java | 9 ++ orang/build.gradle.kts | 1 + orang/src/main/java/lv/enes/orang/Builtins.java | 2 +- orang/src/main/java/lv/enes/orang/Evaluator.java | 157 --------------------- orang/src/main/java/lv/enes/orang/Main.java | 3 +- orang/src/main/java/lv/enes/orang/value/Array.java | 65 --------- .../java/lv/enes/orang/value/BuiltinFunction.java | 31 ---- .../main/java/lv/enes/orang/value/Function.java | 25 ---- .../src/main/java/lv/enes/orang/value/Nothing.java | 21 --- .../java/lv/enes/orang/value/OrangBoolean.java | 55 -------- .../java/lv/enes/orang/value/OrangInteger.java | 70 --------- .../main/java/lv/enes/orang/value/OrangString.java | 49 ------- .../enes/orang/value/PartialBuiltinFunction.java | 32 ----- .../java/lv/enes/orang/value/PartialFunction.java | 46 ------ .../main/java/lv/enes/orang/value/Undefined.java | 21 --- orang/src/main/java/lv/enes/orang/value/Value.java | 76 ---------- orang/src/main/java/module-info.java | 2 +- settings.gradle.kts | 2 +- 31 files changed, 666 insertions(+), 652 deletions(-) create mode 100644 evaluator/build.gradle.kts create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/Array.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/BuiltinFunction.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/Function.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/Nothing.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/OrangBoolean.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/OrangInteger.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/OrangString.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/PartialBuiltinFunction.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/Undefined.java create mode 100644 evaluator/src/main/java/lv/enes/orang/evaluator/Value.java create mode 100644 evaluator/src/main/java/module-info.java delete mode 100644 orang/src/main/java/lv/enes/orang/Evaluator.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/Array.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/Function.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/Nothing.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/OrangBoolean.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/OrangInteger.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/OrangString.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/PartialFunction.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/Undefined.java delete mode 100644 orang/src/main/java/lv/enes/orang/value/Value.java diff --git a/evaluator/build.gradle.kts b/evaluator/build.gradle.kts new file mode 100644 index 0000000..9172259 --- /dev/null +++ b/evaluator/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("orang.java-conventions") +} + +dependencies { + implementation(project(":ast")) + implementation(project(":core")) + implementation(project(":utils")) +} \ No newline at end of file diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Array.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Array.java new file mode 100644 index 0000000..4c76eff --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Array.java @@ -0,0 +1,65 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.core.OrangRuntimeException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public record Array(List items) implements Value { + @Override + public String typeName() { + return "Array"; + } + + @Override + public String stringify() { + if (items.isEmpty()) { + return "[]"; + } + var sb = new StringBuilder("["); + sb.append(items.getFirst().stringify()); + for (int i = 1; i < items.size(); i++) { + sb.append(", ").append(items.get(i).stringify()); + } + sb.append("]"); + return sb.toString(); + } + + @Override + public String display() { + if (items.isEmpty()) { + return ""; + } + var sb = new StringBuilder(); + sb.append(items.getFirst().display()); + for (var i = 1; i < items.size(); i++) { + sb.append(" ").append(items.get(i).display()); + } + return sb.toString(); + } + + @Override + public Value add(Value rhs) throws OrangRuntimeException { + if (rhs instanceof Array(var rhsi)) { + var newItems = new ArrayList<>(this.items); + newItems.addAll(rhsi); + return new Array(Collections.unmodifiableList(newItems)); + } else { + throw new OrangRuntimeException(STR."add not implemented for Array and \{rhs.typeName()}"); + } + } + + @Override + public Value multiply(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangInteger(var repeat)) { + var newItems = new ArrayList(items.size() * repeat); + for (var i = 0; i < repeat; i++) { + newItems.addAll(items); + } + return new Array(Collections.unmodifiableList(newItems)); + } else { + throw new OrangRuntimeException(STR."multiply not implemented for Array and \{rhs.typeName()}"); + } + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/BuiltinFunction.java b/evaluator/src/main/java/lv/enes/orang/evaluator/BuiltinFunction.java new file mode 100644 index 0000000..1f37280 --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/BuiltinFunction.java @@ -0,0 +1,31 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.core.OrangRuntimeException; + +import java.util.List; + +public record BuiltinFunction(int argCount, Impl impl) implements Value { + @FunctionalInterface + public interface Impl { + Value apply(List args) throws OrangRuntimeException; + } + + @Override + public String typeName() { + return "BuiltinFunction"; + } + + @Override + public String stringify() { + return "#builtinFunction"; + } + + @Override + public Value call(Value param) throws OrangRuntimeException { + if (argCount == 1) { + return impl.apply(List.of(param)); + } else { + return new PartialBuiltinFunction(argCount, List.of(param), impl); + } + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java new file mode 100644 index 0000000..6925bac --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java @@ -0,0 +1,152 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.ast.*; +import lv.enes.orang.core.OrangRuntimeException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public record Evaluator(Map scope, Value lastResult) implements ExpressionVisitor, StatementVisitor { + public Evaluator(Map scope) { + this(scope, Undefined.INSTANCE); + } + + @Override + public Value visitArray(ArrayExpression expr) throws OrangRuntimeException { + var values = new ArrayList(expr.items().size()); + for (var item : expr.items()) { + values.add(visit(item)); + } + values.trimToSize(); + return new Array(Collections.unmodifiableList(values)); + } + + @Override + public Value visitBinaryExpression(BinaryExpression expr) throws OrangRuntimeException { + var lhs = visit(expr.lhs()); + var rhs = visit(expr.rhs()); + return switch (expr.operator()) { + case EQUALS -> lhs.orangEquals(rhs); + case NOT_EQUALS -> lhs.notEquals(rhs); + case GT -> lhs.greaterThan(rhs); + case GTE -> lhs.greaterThanOrEqual(rhs); + case LT -> lhs.lessThan(rhs); + case LTE -> lhs.lessThanOrEqual(rhs); + case ADD -> lhs.add(rhs); + case SUBTRACT -> lhs.subtract(rhs); + case MULTIPLY -> lhs.multiply(rhs); + case DIVIDE -> lhs.divide(rhs); + }; + } + + @Override + public Value visitBoolean(BooleanLiteral expr) { + return OrangBoolean.of(expr.value()); + } + + @Override + public Value visitCallExpression(CallExpression expr) throws OrangRuntimeException { + var arg = visit(expr.arg()); + return visit(expr.callee()).call(arg); + } + + @Override + public Evaluator visitDefinition(Definition def) throws OrangRuntimeException { + var newScope = new HashMap<>(scope); + newScope.put(def.name(), Undefined.INSTANCE); + var newEvaluator = new Evaluator(newScope); + newScope.put(def.name(), newEvaluator.visit(def.body())); + return newEvaluator; + } + + @Override + public Value visitDoExpression(DoExpression expr) throws OrangRuntimeException { + Value value = Undefined.INSTANCE; + for (var child : expr.body()) { + value = visit(child); + } + return value; + } + + @Override + public Evaluator visitExpression(ExpressionStatement expr) throws OrangRuntimeException { + return new Evaluator(this.scope(), visit(expr.expr())); + } + + @Override + public Value visitFnExpression(FnExpression expr) { + return new Function(this.scope, expr.args(), expr.body()); + } + + @Override + public Value visitIfElseExpression(IfElseExpression expr) throws OrangRuntimeException { + var cond = visit(expr.condition()); + if (cond instanceof OrangBoolean value) { + if (value.value()) { + return visit(expr.trueBranch()); + } else { + return visit(expr.falseBranch()); + } + } else { + throw new OrangRuntimeException(STR."Condition in an if-else statement should be a boolean not a \{cond.typeName()}"); + } + } + + @Override + public Value visitIntLiteral(IntLiteral expr) { + return new OrangInteger(expr.value()); + } + + @Override + public Value visitLetInExpression(LetInExpression expr) throws OrangRuntimeException { + var newScope = new HashMap<>(scope); + for (var binding : expr.bindings()) { + newScope.put(binding.name(), Undefined.INSTANCE); + } + var newEvaluator = new Evaluator(newScope); + for (var binding : expr.bindings()) { + newScope.put(binding.name(), newEvaluator.visit(binding.value())); + } + return newEvaluator.visit(expr.body()); + } + + @Override + public Evaluator visitProgram(Program prog) throws OrangRuntimeException { + var evaluator = this; + for (var statement : prog.statements()) { + evaluator = evaluator.visit(statement); + } + return evaluator; + } + + @Override + public Value visitUnaryExpression(UnaryExpression expr) throws OrangRuntimeException { + var child = visit(expr.child()); + return switch (expr.operator()) { + case PLUS -> child.plus(); + case NEGATE -> child.negate(); + case NOT -> child.not(); + }; + } + + @Override + public Value visitStringLiteral(StringLiteral expr) { + return new OrangString(expr.value()); + } + + @Override + public Value visitVariable(VariableExpression expr) throws OrangRuntimeException { + if (scope.containsKey(expr.name())) { + return scope.get(expr.name()); + } + + throw new OrangRuntimeException(STR."Value named \{expr.name()} is not defined!"); + } + + @Override + public Value visitVoidExpression() { + return Nothing.INSTANCE; + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Function.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Function.java new file mode 100644 index 0000000..33102fb --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Function.java @@ -0,0 +1,25 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.ast.ArgSpec; +import lv.enes.orang.ast.Expression; +import lv.enes.orang.core.OrangRuntimeException; +import lv.enes.orang.utils.NonEmptyList; + +import java.util.Map; + +public record Function(Map scope, NonEmptyList args, Expression body) implements Value { + @Override + public String typeName() { + return "Function"; + } + + @Override + public String stringify() { + return "#function"; + } + + @Override + public Value call(Value param) throws OrangRuntimeException { + return PartialFunction.of(scope, args, body, param); + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Nothing.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Nothing.java new file mode 100644 index 0000000..c971649 --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Nothing.java @@ -0,0 +1,21 @@ +package lv.enes.orang.evaluator; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode +public final class Nothing implements Value { + public static final Nothing INSTANCE = new Nothing(); + + private Nothing() { + } + + @Override + public String typeName() { + return "Nothing"; + } + + @Override + public String stringify() { + return "()"; + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/OrangBoolean.java b/evaluator/src/main/java/lv/enes/orang/evaluator/OrangBoolean.java new file mode 100644 index 0000000..3564a9c --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/OrangBoolean.java @@ -0,0 +1,55 @@ +package lv.enes.orang.evaluator; + +import lombok.EqualsAndHashCode; +import lv.enes.orang.core.OrangRuntimeException; + +@EqualsAndHashCode +public final class OrangBoolean implements Value { + public final static OrangBoolean TRUE = new OrangBoolean(true); + public final static OrangBoolean FALSE = new OrangBoolean(false); + + private final boolean value; + + private OrangBoolean(boolean value) { + this.value = value; + } + + public static OrangBoolean of(boolean value) { + if (value) { + return TRUE; + } + return FALSE; + } + + public boolean value() { + return value; + } + + @Override + public String typeName() { + return "Boolean"; + } + + @Override + public String stringify() { + if (value) { + return "true"; + } else { + return "false"; + } + } + + @Override + public OrangBoolean not() { + return new OrangBoolean(!value); + } + + @Override + public OrangBoolean or(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangBoolean rhsb) { + return new OrangBoolean(value || rhsb.value); + } else { + throw new OrangRuntimeException(STR."or is not implemented for Boolean and \{rhs.typeName()}"); + } + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/OrangInteger.java b/evaluator/src/main/java/lv/enes/orang/evaluator/OrangInteger.java new file mode 100644 index 0000000..90de0b5 --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/OrangInteger.java @@ -0,0 +1,70 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.core.OrangRuntimeException; + +public record OrangInteger(int value) implements Value { + @Override + public String typeName() { + return "Integer"; + } + + @Override + public String stringify() { + return Integer.toString(value); + } + + @Override + public OrangInteger negate() { + return new OrangInteger(-value); + } + + @Override + public OrangInteger plus() { + return this; + } + + @Override + public OrangInteger add(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangInteger(int rhsi)) { + return new OrangInteger(value + rhsi); + } else { + throw new OrangRuntimeException(STR."add is not implemented for Integer and \{rhs.typeName()}"); + } + } + + @Override + public OrangInteger divide(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangInteger(int rhsi)) { + return new OrangInteger(value / rhsi); + } else { + throw new OrangRuntimeException(STR."divide is not implemented for Integer and \{rhs.typeName()}"); + } + } + + @Override + public OrangInteger multiply(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangInteger(int rhsi)) { + return new OrangInteger(value * rhsi); + } else { + throw new OrangRuntimeException(STR."multiply is not implemented for Integer and \{rhs.typeName()}"); + } + } + + @Override + public OrangInteger subtract(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangInteger(int rhsi)) { + return new OrangInteger(value - rhsi); + } else { + throw new OrangRuntimeException(STR."subtract is not implemented for Integer and \{rhs.typeName()}"); + } + } + + @Override + public OrangBoolean greaterThan(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangInteger(int rhsi)) { + return OrangBoolean.of(value > rhsi); + } else { + throw new OrangRuntimeException(STR."greaterThan is not implemented for Integer and \{rhs.typeName()}"); + } + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/OrangString.java b/evaluator/src/main/java/lv/enes/orang/evaluator/OrangString.java new file mode 100644 index 0000000..5c38842 --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/OrangString.java @@ -0,0 +1,49 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.core.OrangRuntimeException; + +public record OrangString(String value) implements Value { + @Override + public String typeName() { + return "String"; + } + + @Override + public String stringify() { + var sb = new StringBuilder("\""); + var cps = value.codePoints().iterator(); + while (cps.hasNext()) { + var cp = cps.next(); + if (cp == '"') { + sb.append("\\\""); + } else { + sb.appendCodePoint(cp); + } + } + sb.append('"'); + return sb.toString(); + } + + @Override + public String display() { + return value; + } + + @Override + public OrangString add(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangString(String rhss)) { + return new OrangString(value + rhss); + } else { + throw new OrangRuntimeException(STR."add is not implemented for Integer and \{rhs.typeName()}"); + } + } + + @Override + public Value multiply(Value rhs) throws OrangRuntimeException { + if (rhs instanceof OrangInteger(var repeat)) { + return new OrangString(value.repeat(Math.max(0, repeat))); + } else { + throw new OrangRuntimeException(STR."multiply not implemented for Array and \{rhs.typeName()}"); + } + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/PartialBuiltinFunction.java b/evaluator/src/main/java/lv/enes/orang/evaluator/PartialBuiltinFunction.java new file mode 100644 index 0000000..f1e8cc6 --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/PartialBuiltinFunction.java @@ -0,0 +1,32 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.core.OrangRuntimeException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public record PartialBuiltinFunction(int argCount, List params, BuiltinFunction.Impl impl) implements Value { + @Override + public String typeName() { + return "BuiltinFunction"; + } + + @Override + public String stringify() { + return "#builtinFunction"; + } + + @Override + public Value call(Value param) throws OrangRuntimeException { + List newParams = new ArrayList<>(params); + newParams.add(param); + newParams = Collections.unmodifiableList(newParams); + + if (newParams.size() == argCount) { + return impl.apply(newParams); + } else { + return new PartialBuiltinFunction(argCount, newParams, impl); + } + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java b/evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java new file mode 100644 index 0000000..d0125f6 --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java @@ -0,0 +1,45 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.ast.ArgSpec; +import lv.enes.orang.ast.Expression; +import lv.enes.orang.core.OrangRuntimeException; +import lv.enes.orang.utils.NonEmptyList; + +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 = new HashMap<>(scope); + switch (spec.getType()) { + 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()}"); + } + } + } + + if (remainingArgs.size() == 1) { + return new Evaluator(newScope).visit(body); + } else { + return new PartialFunction(newScope, new NonEmptyList<>(remainingArgs.subList(1, remainingArgs.size())), body); + } + } + + @Override + public String typeName() { + return "Function"; + } + + @Override + public String stringify() { + return "#function"; + } + + @Override + public Value call(Value param) throws OrangRuntimeException { + return PartialFunction.of(scope, remainingArgs, body, param); + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Undefined.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Undefined.java new file mode 100644 index 0000000..2aec74b --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Undefined.java @@ -0,0 +1,21 @@ +package lv.enes.orang.evaluator; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode +public final class Undefined implements Value { + public static final Undefined INSTANCE = new Undefined(); + + private Undefined() { + } + + @Override + public String typeName() { + return "Undefined"; + } + + @Override + public String stringify() { + return "#undefined"; + } +} diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java new file mode 100644 index 0000000..d8c8b9c --- /dev/null +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java @@ -0,0 +1,76 @@ +package lv.enes.orang.evaluator; + +import lv.enes.orang.core.OrangRuntimeException; + +public sealed interface Value + permits Array, BuiltinFunction, Function, Nothing, OrangBoolean, OrangInteger, OrangString, PartialBuiltinFunction, PartialFunction, Undefined { + String typeName(); + String stringify(); + + default String display() { + return stringify(); + } + + + default Value negate() throws OrangRuntimeException { + throw new OrangRuntimeException(STR."negate is not implemented for \{typeName()}"); + } + + default Value not() throws OrangRuntimeException { + throw new OrangRuntimeException(STR."not is not implemented for \{typeName()}"); + } + + default Value plus() throws OrangRuntimeException { + throw new OrangRuntimeException(STR."plus is not implemented for \{typeName()}"); + } + + + default Value add(Value rhs) throws OrangRuntimeException { + throw new OrangRuntimeException(STR."add is not implemented for \{typeName()} and \{rhs.typeName()}"); + } + + default Value call(Value rhs) throws OrangRuntimeException { + throw new OrangRuntimeException(STR."call is not implemented for \{typeName()} and \{rhs.typeName()}"); + } + + default Value divide(Value rhs) throws OrangRuntimeException { + throw new OrangRuntimeException(STR."divide is not implemented for \{typeName()} and \{rhs.typeName()}"); + } + + default Value multiply(Value rhs) throws OrangRuntimeException { + throw new OrangRuntimeException(STR."multiply is not implemented for \{typeName()} and \{rhs.typeName()}"); + } + + default Value or(Value rhs) throws OrangRuntimeException { + throw new OrangRuntimeException(STR."or is not implemented for \{typeName()} and \{rhs.typeName()}"); + } + + default Value subtract(Value rhs) throws OrangRuntimeException { + throw new OrangRuntimeException(STR."subtract is not implemented for \{typeName()} and \{rhs.typeName()}"); + } + + + default OrangBoolean greaterThan(Value rhs) throws OrangRuntimeException { + throw new OrangRuntimeException(STR."greater than is not implemented for \{typeName()} and \{rhs.typeName()}"); + } + + default OrangBoolean greaterThanOrEqual(Value rhs) throws OrangRuntimeException { + return greaterThan(rhs).or(orangEquals(rhs)); + } + + default OrangBoolean lessThan(Value rhs) throws OrangRuntimeException { + return greaterThanOrEqual(rhs).not(); + } + + default OrangBoolean lessThanOrEqual(Value rhs) throws OrangRuntimeException { + return greaterThan(rhs).not(); + } + + default OrangBoolean orangEquals(Value rhs) { + return OrangBoolean.of(this.equals(rhs)); + } + + default OrangBoolean notEquals(Value rhs) { + return orangEquals(rhs).not(); + } +} diff --git a/evaluator/src/main/java/module-info.java b/evaluator/src/main/java/module-info.java new file mode 100644 index 0000000..4cb992c --- /dev/null +++ b/evaluator/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module lv.enes.orang.evaluator { + exports lv.enes.orang.evaluator; + + requires lv.enes.orang.ast; + requires lv.enes.orang.core; + requires lv.enes.orang.utils; + + requires static lombok; +} \ No newline at end of file diff --git a/orang/build.gradle.kts b/orang/build.gradle.kts index 4be19a4..8c9de5f 100644 --- a/orang/build.gradle.kts +++ b/orang/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { implementation(project(":ast")) implementation(project(":checker")) implementation(project(":core")) + implementation(project(":evaluator")) implementation(project(":parser")) implementation(project(":utils")) } diff --git a/orang/src/main/java/lv/enes/orang/Builtins.java b/orang/src/main/java/lv/enes/orang/Builtins.java index a83f4c5..eea8ef4 100644 --- a/orang/src/main/java/lv/enes/orang/Builtins.java +++ b/orang/src/main/java/lv/enes/orang/Builtins.java @@ -2,7 +2,7 @@ package lv.enes.orang; import lombok.extern.slf4j.Slf4j; import lv.enes.orang.core.OrangRuntimeException; -import lv.enes.orang.value.*; +import lv.enes.orang.evaluator.*; import java.io.IOException; import java.util.List; diff --git a/orang/src/main/java/lv/enes/orang/Evaluator.java b/orang/src/main/java/lv/enes/orang/Evaluator.java deleted file mode 100644 index 69a256f..0000000 --- a/orang/src/main/java/lv/enes/orang/Evaluator.java +++ /dev/null @@ -1,157 +0,0 @@ -package lv.enes.orang; - -import lv.enes.orang.ast.*; -import lv.enes.orang.core.OrangRuntimeException; -import lv.enes.orang.value.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public record Evaluator(Map scope, Value lastResult) implements ExpressionVisitor, StatementVisitor { - public Evaluator() { - this(new HashMap<>(Builtins.BUILTINS)); - } - - public Evaluator(Map scope) { - this(scope, Undefined.INSTANCE); - } - - @Override - public Value visitArray(ArrayExpression expr) throws OrangRuntimeException { - var values = new ArrayList(expr.items().size()); - for (var item : expr.items()) { - values.add(visit(item)); - } - values.trimToSize(); - return new Array(Collections.unmodifiableList(values)); - } - - @Override - public Value visitBinaryExpression(BinaryExpression expr) throws OrangRuntimeException { - var lhs = visit(expr.lhs()); - var rhs = visit(expr.rhs()); - return switch (expr.operator()) { - case EQUALS -> lhs.orangEquals(rhs); - case NOT_EQUALS -> lhs.notEquals(rhs); - case GT -> lhs.greaterThan(rhs); - case GTE -> lhs.greaterThanOrEqual(rhs); - case LT -> lhs.lessThan(rhs); - case LTE -> lhs.lessThanOrEqual(rhs); - case ADD -> lhs.add(rhs); - case SUBTRACT -> lhs.subtract(rhs); - case MULTIPLY -> lhs.multiply(rhs); - case DIVIDE -> lhs.divide(rhs); - }; - } - - @Override - public Value visitBoolean(BooleanLiteral expr) { - return OrangBoolean.of(expr.value()); - } - - @Override - public Value visitCallExpression(CallExpression expr) throws OrangRuntimeException { - var arg = visit(expr.arg()); - return visit(expr.callee()).call(arg); - } - - @Override - public Evaluator visitDefinition(Definition def) throws OrangRuntimeException { - var newScope = new HashMap<>(scope); - newScope.put(def.name(), Undefined.INSTANCE); - var newEvaluator = new Evaluator(newScope); - newScope.put(def.name(), newEvaluator.visit(def.body())); - return newEvaluator; - } - - @Override - public Value visitDoExpression(DoExpression expr) throws OrangRuntimeException { - Value value = Undefined.INSTANCE; - for (var child : expr.body()) { - value = visit(child); - } - return value; - } - - @Override - public Evaluator visitExpression(ExpressionStatement expr) throws OrangRuntimeException { - return new Evaluator(this.scope(), visit(expr.expr())); - } - - @Override - public Value visitFnExpression(FnExpression expr) { - return new Function(this.scope, expr.args(), expr.body()); - } - - @Override - public Value visitIfElseExpression(IfElseExpression expr) throws OrangRuntimeException { - var cond = visit(expr.condition()); - if (cond instanceof OrangBoolean value) { - if (value.value()) { - return visit(expr.trueBranch()); - } else { - return visit(expr.falseBranch()); - } - } else { - throw new OrangRuntimeException(STR."Condition in an if-else statement should be a boolean not a \{cond.typeName()}"); - } - } - - @Override - public Value visitIntLiteral(IntLiteral expr) { - return new OrangInteger(expr.value()); - } - - @Override - public Value visitLetInExpression(LetInExpression expr) throws OrangRuntimeException { - var newScope = new HashMap<>(scope); - for (var binding : expr.bindings()) { - newScope.put(binding.name(), Undefined.INSTANCE); - } - var newEvaluator = new Evaluator(newScope); - for (var binding : expr.bindings()) { - newScope.put(binding.name(), newEvaluator.visit(binding.value())); - } - return newEvaluator.visit(expr.body()); - } - - @Override - public Evaluator visitProgram(Program prog) throws OrangRuntimeException { - var evaluator = this; - for (var statement : prog.statements()) { - evaluator = evaluator.visit(statement); - } - return evaluator; - } - - @Override - public Value visitUnaryExpression(UnaryExpression expr) throws OrangRuntimeException { - var child = visit(expr.child()); - return switch (expr.operator()) { - case PLUS -> child.plus(); - case NEGATE -> child.negate(); - case NOT -> child.not(); - }; - } - - @Override - public Value visitStringLiteral(StringLiteral expr) { - return new OrangString(expr.value()); - } - - @Override - public Value visitVariable(VariableExpression expr) throws OrangRuntimeException { - if (scope.containsKey(expr.name())) { - return scope.get(expr.name()); - } - - throw new OrangRuntimeException(STR."Value named \{expr.name()} is not defined!"); - } - - @Override - public Value visitVoidExpression() { - return Nothing.INSTANCE; - } -} diff --git a/orang/src/main/java/lv/enes/orang/Main.java b/orang/src/main/java/lv/enes/orang/Main.java index 9a061fe..5730fd1 100644 --- a/orang/src/main/java/lv/enes/orang/Main.java +++ b/orang/src/main/java/lv/enes/orang/Main.java @@ -2,6 +2,7 @@ package lv.enes.orang; import lv.enes.orang.checker.Checker; import lv.enes.orang.core.OrangException; +import lv.enes.orang.evaluator.Evaluator; import lv.enes.orang.parser.Parser; import java.io.FileReader; @@ -19,7 +20,7 @@ public class Main { private static void repl() throws IOException { var checker = Checker.of(Builtins.BUILTINS); - var evaluator = new Evaluator(); + var evaluator = new Evaluator(Builtins.BUILTINS); try (var stream = Main.class.getResourceAsStream("prelude.orang")) { var prog = Parser.parseProgram(stream); diff --git a/orang/src/main/java/lv/enes/orang/value/Array.java b/orang/src/main/java/lv/enes/orang/value/Array.java deleted file mode 100644 index 33e1516..0000000 --- a/orang/src/main/java/lv/enes/orang/value/Array.java +++ /dev/null @@ -1,65 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.core.OrangRuntimeException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public record Array(List items) implements Value { - @Override - public String typeName() { - return "Array"; - } - - @Override - public String stringify() { - if (items.isEmpty()) { - return "[]"; - } - var sb = new StringBuilder("["); - sb.append(items.getFirst().stringify()); - for (int i = 1; i < items.size(); i++) { - sb.append(", ").append(items.get(i).stringify()); - } - sb.append("]"); - return sb.toString(); - } - - @Override - public String display() { - if (items.isEmpty()) { - return ""; - } - var sb = new StringBuilder(); - sb.append(items.getFirst().display()); - for (var i = 1; i < items.size(); i++) { - sb.append(" ").append(items.get(i).display()); - } - return sb.toString(); - } - - @Override - public Value add(Value rhs) throws OrangRuntimeException { - if (rhs instanceof Array(var rhsi)) { - var newItems = new ArrayList<>(this.items); - newItems.addAll(rhsi); - return new Array(Collections.unmodifiableList(newItems)); - } else { - throw new OrangRuntimeException(STR."add not implemented for Array and \{rhs.typeName()}"); - } - } - - @Override - public Value multiply(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(var repeat)) { - var newItems = new ArrayList(items.size() * repeat); - for (var i = 0; i < repeat; i++) { - newItems.addAll(items); - } - return new Array(Collections.unmodifiableList(newItems)); - } else { - throw new OrangRuntimeException(STR."multiply not implemented for Array and \{rhs.typeName()}"); - } - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java b/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java deleted file mode 100644 index 1a61cfb..0000000 --- a/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java +++ /dev/null @@ -1,31 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.core.OrangRuntimeException; - -import java.util.List; - -public record BuiltinFunction(int argCount, Impl impl) implements Value { - @FunctionalInterface - public interface Impl { - Value apply(List args) throws OrangRuntimeException; - } - - @Override - public String typeName() { - return "BuiltinFunction"; - } - - @Override - public String stringify() { - return "#builtinFunction"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - if (argCount == 1) { - return impl.apply(List.of(param)); - } else { - return new PartialBuiltinFunction(argCount, List.of(param), impl); - } - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/Function.java b/orang/src/main/java/lv/enes/orang/value/Function.java deleted file mode 100644 index f8c1a7f..0000000 --- a/orang/src/main/java/lv/enes/orang/value/Function.java +++ /dev/null @@ -1,25 +0,0 @@ -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.utils.NonEmptyList; - -import java.util.Map; - -public record Function(Map scope, NonEmptyList args, Expression body) implements Value { - @Override - public String typeName() { - return "Function"; - } - - @Override - public String stringify() { - return "#function"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - return PartialFunction.of(scope, args, body, param); - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/Nothing.java b/orang/src/main/java/lv/enes/orang/value/Nothing.java deleted file mode 100644 index 4a90010..0000000 --- a/orang/src/main/java/lv/enes/orang/value/Nothing.java +++ /dev/null @@ -1,21 +0,0 @@ -package lv.enes.orang.value; - -import lombok.EqualsAndHashCode; - -@EqualsAndHashCode -public final class Nothing implements Value { - public static final Nothing INSTANCE = new Nothing(); - - private Nothing() { - } - - @Override - public String typeName() { - return "Nothing"; - } - - @Override - public String stringify() { - return "()"; - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java b/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java deleted file mode 100644 index 59aa9b7..0000000 --- a/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java +++ /dev/null @@ -1,55 +0,0 @@ -package lv.enes.orang.value; - -import lombok.EqualsAndHashCode; -import lv.enes.orang.core.OrangRuntimeException; - -@EqualsAndHashCode -public final class OrangBoolean implements Value { - public final static OrangBoolean TRUE = new OrangBoolean(true); - public final static OrangBoolean FALSE = new OrangBoolean(false); - - private final boolean value; - - private OrangBoolean(boolean value) { - this.value = value; - } - - public static OrangBoolean of(boolean value) { - if (value) { - return TRUE; - } - return FALSE; - } - - public boolean value() { - return value; - } - - @Override - public String typeName() { - return "Boolean"; - } - - @Override - public String stringify() { - if (value) { - return "true"; - } else { - return "false"; - } - } - - @Override - public OrangBoolean not() { - return new OrangBoolean(!value); - } - - @Override - public OrangBoolean or(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangBoolean rhsb) { - return new OrangBoolean(value || rhsb.value); - } else { - throw new OrangRuntimeException(STR."or is not implemented for Boolean and \{rhs.typeName()}"); - } - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/OrangInteger.java b/orang/src/main/java/lv/enes/orang/value/OrangInteger.java deleted file mode 100644 index 63a44da..0000000 --- a/orang/src/main/java/lv/enes/orang/value/OrangInteger.java +++ /dev/null @@ -1,70 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.core.OrangRuntimeException; - -public record OrangInteger(int value) implements Value { - @Override - public String typeName() { - return "Integer"; - } - - @Override - public String stringify() { - return Integer.toString(value); - } - - @Override - public OrangInteger negate() { - return new OrangInteger(-value); - } - - @Override - public OrangInteger plus() { - return this; - } - - @Override - public OrangInteger add(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value + rhsi); - } else { - throw new OrangRuntimeException(STR."add is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangInteger divide(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value / rhsi); - } else { - throw new OrangRuntimeException(STR."divide is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangInteger multiply(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value * rhsi); - } else { - throw new OrangRuntimeException(STR."multiply is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangInteger subtract(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value - rhsi); - } else { - throw new OrangRuntimeException(STR."subtract is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangBoolean greaterThan(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return OrangBoolean.of(value > rhsi); - } else { - throw new OrangRuntimeException(STR."greaterThan is not implemented for Integer and \{rhs.typeName()}"); - } - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/OrangString.java b/orang/src/main/java/lv/enes/orang/value/OrangString.java deleted file mode 100644 index b4ede1f..0000000 --- a/orang/src/main/java/lv/enes/orang/value/OrangString.java +++ /dev/null @@ -1,49 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.core.OrangRuntimeException; - -public record OrangString(String value) implements Value { - @Override - public String typeName() { - return "String"; - } - - @Override - public String stringify() { - var sb = new StringBuilder("\""); - var cps = value.codePoints().iterator(); - while (cps.hasNext()) { - var cp = cps.next(); - if (cp == '"') { - sb.append("\\\""); - } else { - sb.appendCodePoint(cp); - } - } - sb.append('"'); - return sb.toString(); - } - - @Override - public String display() { - return value; - } - - @Override - public OrangString add(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangString(String rhss)) { - return new OrangString(value + rhss); - } else { - throw new OrangRuntimeException(STR."add is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public Value multiply(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(var repeat)) { - return new OrangString(value.repeat(Math.max(0, repeat))); - } else { - throw new OrangRuntimeException(STR."multiply not implemented for Array and \{rhs.typeName()}"); - } - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java b/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java deleted file mode 100644 index c1be22a..0000000 --- a/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java +++ /dev/null @@ -1,32 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.core.OrangRuntimeException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public record PartialBuiltinFunction(int argCount, List params, BuiltinFunction.Impl impl) implements Value { - @Override - public String typeName() { - return "BuiltinFunction"; - } - - @Override - public String stringify() { - return "#builtinFunction"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - List newParams = new ArrayList<>(params); - newParams.add(param); - newParams = Collections.unmodifiableList(newParams); - - if (newParams.size() == argCount) { - return impl.apply(newParams); - } else { - return new PartialBuiltinFunction(argCount, newParams, impl); - } - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/PartialFunction.java b/orang/src/main/java/lv/enes/orang/value/PartialFunction.java deleted file mode 100644 index 427da76..0000000 --- a/orang/src/main/java/lv/enes/orang/value/PartialFunction.java +++ /dev/null @@ -1,46 +0,0 @@ -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.OrangRuntimeException; -import lv.enes.orang.utils.NonEmptyList; - -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 = new HashMap<>(scope); - switch (spec.getType()) { - 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()}"); - } - } - } - - if (remainingArgs.size() == 1) { - return new Evaluator(newScope).visit(body); - } else { - return new PartialFunction(newScope, new NonEmptyList<>(remainingArgs.subList(1, remainingArgs.size())), body); - } - } - - @Override - public String typeName() { - return "Function"; - } - - @Override - public String stringify() { - return "#function"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - return PartialFunction.of(scope, remainingArgs, body, param); - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/Undefined.java b/orang/src/main/java/lv/enes/orang/value/Undefined.java deleted file mode 100644 index a341ee8..0000000 --- a/orang/src/main/java/lv/enes/orang/value/Undefined.java +++ /dev/null @@ -1,21 +0,0 @@ -package lv.enes.orang.value; - -import lombok.EqualsAndHashCode; - -@EqualsAndHashCode -public final class Undefined implements Value { - public static final Undefined INSTANCE = new Undefined(); - - private Undefined() { - } - - @Override - public String typeName() { - return "Undefined"; - } - - @Override - public String stringify() { - return "#undefined"; - } -} diff --git a/orang/src/main/java/lv/enes/orang/value/Value.java b/orang/src/main/java/lv/enes/orang/value/Value.java deleted file mode 100644 index 07e6848..0000000 --- a/orang/src/main/java/lv/enes/orang/value/Value.java +++ /dev/null @@ -1,76 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.core.OrangRuntimeException; - -public sealed interface Value - permits Array, BuiltinFunction, Function, Nothing, OrangBoolean, OrangInteger, OrangString, PartialBuiltinFunction, PartialFunction, Undefined { - String typeName(); - String stringify(); - - default String display() { - return stringify(); - } - - - default Value negate() throws OrangRuntimeException { - throw new OrangRuntimeException(STR."negate is not implemented for \{typeName()}"); - } - - default Value not() throws OrangRuntimeException { - throw new OrangRuntimeException(STR."not is not implemented for \{typeName()}"); - } - - default Value plus() throws OrangRuntimeException { - throw new OrangRuntimeException(STR."plus is not implemented for \{typeName()}"); - } - - - default Value add(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."add is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value call(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."call is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value divide(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."divide is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value multiply(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."multiply is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value or(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."or is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value subtract(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."subtract is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - - default OrangBoolean greaterThan(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."greater than is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default OrangBoolean greaterThanOrEqual(Value rhs) throws OrangRuntimeException { - return greaterThan(rhs).or(orangEquals(rhs)); - } - - default OrangBoolean lessThan(Value rhs) throws OrangRuntimeException { - return greaterThanOrEqual(rhs).not(); - } - - default OrangBoolean lessThanOrEqual(Value rhs) throws OrangRuntimeException { - return greaterThan(rhs).not(); - } - - default OrangBoolean orangEquals(Value rhs) { - return OrangBoolean.of(this.equals(rhs)); - } - - default OrangBoolean notEquals(Value rhs) { - return orangEquals(rhs).not(); - } -} diff --git a/orang/src/main/java/module-info.java b/orang/src/main/java/module-info.java index 5b7b601..cb61de3 100644 --- a/orang/src/main/java/module-info.java +++ b/orang/src/main/java/module-info.java @@ -1,10 +1,10 @@ module lv.enes.orang { exports lv.enes.orang; - exports lv.enes.orang.value; requires lv.enes.orang.ast; requires lv.enes.orang.checker; requires lv.enes.orang.core; + requires lv.enes.orang.evaluator; requires lv.enes.orang.parser; requires lv.enes.orang.utils; diff --git a/settings.gradle.kts b/settings.gradle.kts index a64dfa6..bd27876 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,3 @@ rootProject.name = "orang" -include("ast", "checker", "core", "lexer", "orang", "parser", "utils") \ No newline at end of file +include("ast", "checker", "core", "evaluator", "lexer", "orang", "parser", "utils") \ No newline at end of file -- cgit v1.2.3