diff options
| author | 2024-08-24 03:54:25 +0800 | |
|---|---|---|
| committer | 2024-08-24 03:54:25 +0800 | |
| commit | 16a20ee8b08df919e93ea1b878013f9a2ad709fa (patch) | |
| tree | 80d59e93c566ddba1e2116e8d64222b8036b216e /evaluator | |
| parent | Add tuples. (diff) | |
| download | orang-16a20ee8b08df919e93ea1b878013f9a2ad709fa.tar.gz orang-16a20ee8b08df919e93ea1b878013f9a2ad709fa.tar.xz orang-16a20ee8b08df919e93ea1b878013f9a2ad709fa.zip | |
Added fancier tuple argument specs.
Made ArgSpec use visitor pattern to avoid problems the best way.
Merged empty tuple and non-empty tuple classes.
Diffstat (limited to 'evaluator')
5 files changed, 48 insertions, 40 deletions
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/EmptyTuple.java b/evaluator/src/main/java/lv/enes/orang/evaluator/EmptyTuple.java deleted file mode 100644 index f8e043b..0000000 --- a/evaluator/src/main/java/lv/enes/orang/evaluator/EmptyTuple.java +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | package lv.enes.orang.evaluator; | ||
| 2 | |||
| 3 | import lombok.EqualsAndHashCode; | ||
| 4 | |||
| 5 | @EqualsAndHashCode | ||
| 6 | public final class EmptyTuple implements Value { | ||
| 7 | public static final EmptyTuple INSTANCE = new EmptyTuple(); | ||
| 8 | |||
| 9 | private EmptyTuple() { | ||
| 10 | } | ||
| 11 | |||
| 12 | @Override | ||
| 13 | public String typeName() { | ||
| 14 | return "Nothing"; | ||
| 15 | } | ||
| 16 | |||
| 17 | @Override | ||
| 18 | public String stringify() { | ||
| 19 | return "()"; | ||
| 20 | } | ||
| 21 | } | ||
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java index f0299b4..1f51b9d 100644 --- a/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java | |||
| @@ -2,7 +2,6 @@ package lv.enes.orang.evaluator; | |||
| 2 | 2 | ||
| 3 | import lv.enes.orang.ast.*; | 3 | import lv.enes.orang.ast.*; |
| 4 | import lv.enes.orang.core.OrangRuntimeException; | 4 | import lv.enes.orang.core.OrangRuntimeException; |
| 5 | import lv.enes.orang.utils.NonEmptyList; | ||
| 6 | 5 | ||
| 7 | import java.util.ArrayList; | 6 | import java.util.ArrayList; |
| 8 | import java.util.Collections; | 7 | import java.util.Collections; |
| @@ -72,11 +71,6 @@ public record Evaluator(Map<String, Value> scope, Value lastResult) implements E | |||
| 72 | } | 71 | } |
| 73 | 72 | ||
| 74 | @Override | 73 | @Override |
| 75 | public Value visitEmptyTupleExpression() { | ||
| 76 | return EmptyTuple.INSTANCE; | ||
| 77 | } | ||
| 78 | |||
| 79 | @Override | ||
| 80 | public Evaluator visitExpression(ExpressionStatement expr) throws OrangRuntimeException { | 74 | public Evaluator visitExpression(ExpressionStatement expr) throws OrangRuntimeException { |
| 81 | return new Evaluator(this.scope(), visit(expr.expr())); | 75 | return new Evaluator(this.scope(), visit(expr.expr())); |
| 82 | } | 76 | } |
| @@ -148,7 +142,7 @@ public record Evaluator(Map<String, Value> scope, Value lastResult) implements E | |||
| 148 | for (var tailExpr : expr.children()) { | 142 | for (var tailExpr : expr.children()) { |
| 149 | values.add(visit(tailExpr)); | 143 | values.add(visit(tailExpr)); |
| 150 | } | 144 | } |
| 151 | return new Tuple(new NonEmptyList<>(values)); | 145 | return new Tuple(values); |
| 152 | } | 146 | } |
| 153 | 147 | ||
| 154 | @Override | 148 | @Override |
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java b/evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java index 7c0ca20..bea3d02 100644 --- a/evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/PartialFunction.java | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | package lv.enes.orang.evaluator; | 1 | package lv.enes.orang.evaluator; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.ast.ArgSpec; | 3 | import lv.enes.orang.ast.*; |
| 4 | import lv.enes.orang.ast.Expression; | ||
| 5 | import lv.enes.orang.core.OrangRuntimeException; | 4 | import lv.enes.orang.core.OrangRuntimeException; |
| 6 | import lv.enes.orang.utils.NonEmptyList; | 5 | import lv.enes.orang.utils.NonEmptyList; |
| 7 | 6 | ||
| @@ -10,17 +9,45 @@ import java.util.Map; | |||
| 10 | 9 | ||
| 11 | public record PartialFunction(Map<String, Value> scope, NonEmptyList<ArgSpec> remainingArgs, Expression body) implements Value { | 10 | public record PartialFunction(Map<String, Value> scope, NonEmptyList<ArgSpec> remainingArgs, Expression body) implements Value { |
| 12 | public static Value of(Map<String, Value> scope, NonEmptyList<ArgSpec> remainingArgs, Expression body, Value param) throws OrangRuntimeException { | 11 | public static Value of(Map<String, Value> scope, NonEmptyList<ArgSpec> remainingArgs, Expression body, Value param) throws OrangRuntimeException { |
| 13 | var spec = remainingArgs.getFirst(); | 12 | class Helper implements ArgSpecVisitor<Void, OrangRuntimeException> { |
| 14 | var newScope = new HashMap<>(scope); | 13 | private final HashMap<String, Value> newScope; |
| 15 | switch (spec.getType()) { | 14 | private final Value param; |
| 16 | case NAMED -> newScope.put(((ArgSpec.Named)spec).name(), param); | 15 | |
| 17 | case NOTHING -> { | 16 | public Helper(HashMap<String, Value> newScope, Value param) { |
| 18 | if (!(param instanceof EmptyTuple)) { | 17 | this.newScope = newScope; |
| 19 | throw new OrangRuntimeException(STR."Expected () as a parameter but got \{param.typeName()}"); | 18 | this.param = param; |
| 19 | } | ||
| 20 | |||
| 21 | @Override | ||
| 22 | public Void visitIgnored() { | ||
| 23 | // Do nothing :3 | ||
| 24 | return null; | ||
| 25 | } | ||
| 26 | |||
| 27 | @Override | ||
| 28 | public Void visitNamed(ArgSpecNamed named) { | ||
| 29 | newScope.put(named.name(), param); | ||
| 30 | return null; | ||
| 31 | } | ||
| 32 | |||
| 33 | @Override | ||
| 34 | public Void visitTuple(ArgSpecTuple tuple) throws OrangRuntimeException { | ||
| 35 | if (param instanceof Tuple(var children)) { | ||
| 36 | if (children.size() == tuple.children().size()) { | ||
| 37 | for (var i = 0; i < children.size(); i++) { | ||
| 38 | new Helper(newScope, children.get(i)).visit(tuple.children().get(i)); | ||
| 39 | } | ||
| 40 | return null; | ||
| 41 | } | ||
| 20 | } | 42 | } |
| 43 | throw new OrangRuntimeException(STR."Expected a tuple with \{tuple.children().size()} members as a parameter but got \{param.typeName()}"); | ||
| 21 | } | 44 | } |
| 22 | } | 45 | } |
| 23 | 46 | ||
| 47 | var spec = remainingArgs.getFirst(); | ||
| 48 | var newScope = new HashMap<>(scope); | ||
| 49 | new Helper(newScope, param).visit(spec); | ||
| 50 | |||
| 24 | if (remainingArgs.size() == 1) { | 51 | if (remainingArgs.size() == 1) { |
| 25 | return new Evaluator(newScope).visit(body); | 52 | return new Evaluator(newScope).visit(body); |
| 26 | } else { | 53 | } else { |
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Tuple.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Tuple.java index d5a1df5..fb607db 100644 --- a/evaluator/src/main/java/lv/enes/orang/evaluator/Tuple.java +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Tuple.java | |||
| @@ -1,10 +1,14 @@ | |||
| 1 | package lv.enes.orang.evaluator; | 1 | package lv.enes.orang.evaluator; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.utils.NonEmptyList; | 3 | import java.util.List; |
| 4 | 4 | ||
| 5 | public record Tuple(NonEmptyList<Value> contents) implements Value { | 5 | public record Tuple(List<Value> contents) implements Value { |
| 6 | @Override | 6 | @Override |
| 7 | public String typeName() { | 7 | public String typeName() { |
| 8 | if (contents.isEmpty()) { | ||
| 9 | return "()"; | ||
| 10 | } | ||
| 11 | |||
| 8 | var sb = new StringBuilder("("); | 12 | var sb = new StringBuilder("("); |
| 9 | sb.append(contents.getFirst().typeName()); | 13 | sb.append(contents.getFirst().typeName()); |
| 10 | for (var i = 1; i < contents.size(); i++) { | 14 | for (var i = 1; i < contents.size(); i++) { |
| @@ -15,6 +19,10 @@ public record Tuple(NonEmptyList<Value> contents) implements Value { | |||
| 15 | 19 | ||
| 16 | @Override | 20 | @Override |
| 17 | public String stringify() { | 21 | public String stringify() { |
| 22 | if (contents.isEmpty()) { | ||
| 23 | return "()"; | ||
| 24 | } | ||
| 25 | |||
| 18 | var sb = new StringBuilder("("); | 26 | var sb = new StringBuilder("("); |
| 19 | sb.append(contents.getFirst().stringify()); | 27 | sb.append(contents.getFirst().stringify()); |
| 20 | for (var i = 1; i < contents.size(); i++) { | 28 | for (var i = 1; i < contents.size(); i++) { |
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java index 2ef5136..1a1aad6 100644 --- a/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java +++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java | |||
| @@ -3,7 +3,7 @@ package lv.enes.orang.evaluator; | |||
| 3 | import lv.enes.orang.core.OrangRuntimeException; | 3 | import lv.enes.orang.core.OrangRuntimeException; |
| 4 | 4 | ||
| 5 | public sealed interface Value | 5 | public sealed interface Value |
| 6 | permits Array, BuiltinFunction, EmptyTuple, Function, OrangBoolean, OrangInteger, OrangString, | 6 | permits Array, BuiltinFunction, Function, OrangBoolean, OrangInteger, OrangString, |
| 7 | PartialBuiltinFunction, PartialFunction, Tuple, Undefined { | 7 | PartialBuiltinFunction, PartialFunction, Tuple, Undefined { |
| 8 | String typeName(); | 8 | String typeName(); |
| 9 | String stringify(); | 9 | String stringify(); |