diff options
25 files changed, 311 insertions, 103 deletions
diff --git a/checker/build.gradle.kts b/checker/build.gradle.kts new file mode 100644 index 0000000..08e9b33 --- /dev/null +++ b/checker/build.gradle.kts | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | plugins { | ||
| 2 | java | ||
| 3 | id("io.freefair.lombok") version "8.6" | ||
| 4 | } | ||
| 5 | |||
| 6 | val slf4jVersion = "2.0.13" | ||
| 7 | |||
| 8 | repositories { | ||
| 9 | mavenCentral() | ||
| 10 | } | ||
| 11 | |||
| 12 | dependencies { | ||
| 13 | implementation("org.slf4j:slf4j-api:$slf4jVersion") | ||
| 14 | |||
| 15 | implementation(project(":ast")) | ||
| 16 | implementation(project(":core")) | ||
| 17 | implementation(project(":utils")) | ||
| 18 | } | ||
| 19 | |||
| 20 | java { | ||
| 21 | sourceCompatibility = JavaVersion.VERSION_22 | ||
| 22 | targetCompatibility = JavaVersion.VERSION_22 | ||
| 23 | toolchain { | ||
| 24 | languageVersion = JavaLanguageVersion.of(22) | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | tasks.withType<JavaCompile> { | ||
| 29 | options.compilerArgs.add("--enable-preview") | ||
| 30 | } \ No newline at end of file | ||
diff --git a/checker/src/main/java/lv/enes/orang/checker/Checker.java b/checker/src/main/java/lv/enes/orang/checker/Checker.java new file mode 100644 index 0000000..446d3f1 --- /dev/null +++ b/checker/src/main/java/lv/enes/orang/checker/Checker.java | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | package lv.enes.orang.checker; | ||
| 2 | |||
| 3 | import lv.enes.orang.ast.*; | ||
| 4 | import lv.enes.orang.core.ImmutableScope; | ||
| 5 | import lv.enes.orang.core.Scope; | ||
| 6 | |||
| 7 | import java.util.HashMap; | ||
| 8 | import java.util.Map; | ||
| 9 | |||
| 10 | public class Checker implements ExpressionVisitor<Void, CheckerException>, StatementVisitor<Checker, CheckerException> { | ||
| 11 | private final Scope<Boolean> definitions; | ||
| 12 | |||
| 13 | public static <E> Checker of(Map<String, E> builtins) { | ||
| 14 | var boolMap = builtins.keySet() | ||
| 15 | .stream() | ||
| 16 | .<Map<String, Boolean>>collect( | ||
| 17 | HashMap::new, | ||
| 18 | (map, elem) -> map.put(elem, true), | ||
| 19 | Map::putAll | ||
| 20 | ); | ||
| 21 | return new Checker(ImmutableScope.of(boolMap)); | ||
| 22 | } | ||
| 23 | |||
| 24 | private Checker(Scope<Boolean> definitions) { | ||
| 25 | this.definitions = definitions; | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override | ||
| 29 | public Void visitArray(ArrayExpression array) throws CheckerException { | ||
| 30 | for (var expr : array.items()) { | ||
| 31 | visit(expr); | ||
| 32 | } | ||
| 33 | return null; | ||
| 34 | } | ||
| 35 | |||
| 36 | @Override | ||
| 37 | public Void visitBoolean(BooleanLiteral expr) { | ||
| 38 | // Always ok | ||
| 39 | return null; | ||
| 40 | } | ||
| 41 | |||
| 42 | @Override | ||
| 43 | public Void visitBinaryExpression(BinaryExpression expr) throws CheckerException { | ||
| 44 | visit(expr.lhs()); | ||
| 45 | visit(expr.rhs()); | ||
| 46 | return null; | ||
| 47 | } | ||
| 48 | |||
| 49 | @Override | ||
| 50 | public Void visitCallExpression(CallExpression expr) throws CheckerException { | ||
| 51 | visit(expr.callee()); | ||
| 52 | visit(expr.arg()); | ||
| 53 | return null; | ||
| 54 | } | ||
| 55 | |||
| 56 | @Override | ||
| 57 | public Checker visitDefinition(Definition def) throws CheckerException { | ||
| 58 | if (definitions.hasDefinition(def.name())) { | ||
| 59 | throw new CheckerException(STR."Top-level definition '\{def.name()}' redefined!"); | ||
| 60 | } | ||
| 61 | return new Checker(ImmutableScope.of(definitions, def.name(), true)); | ||
| 62 | } | ||
| 63 | |||
| 64 | @Override | ||
| 65 | public Void visitDoExpression(DoExpression expr) throws CheckerException { | ||
| 66 | for (var child : expr.body()) { | ||
| 67 | visit(child); | ||
| 68 | } | ||
| 69 | return null; | ||
| 70 | } | ||
| 71 | |||
| 72 | @Override | ||
| 73 | public Checker visitExpression(ExpressionStatement expr) throws CheckerException { | ||
| 74 | visit(expr.expr()); | ||
| 75 | return this; | ||
| 76 | } | ||
| 77 | |||
| 78 | @Override | ||
| 79 | public Void visitFnExpression(FnExpression expr) throws CheckerException { | ||
| 80 | var args = new HashMap<String, Boolean>(); | ||
| 81 | for (var arg : expr.args()) { | ||
| 82 | args.put(arg.name, true); | ||
| 83 | } | ||
| 84 | new Checker(ImmutableScope.of(definitions, args)).visit(expr.body()); | ||
| 85 | return null; | ||
| 86 | } | ||
| 87 | |||
| 88 | @Override | ||
| 89 | public Void visitIfElseExpression(IfElseExpression expr) throws CheckerException { | ||
| 90 | visit(expr.condition()); | ||
| 91 | visit(expr.trueBranch()); | ||
| 92 | visit(expr.falseBranch()); | ||
| 93 | return null; | ||
| 94 | } | ||
| 95 | |||
| 96 | @Override | ||
| 97 | public Void visitIntLiteral(IntLiteral expr) { | ||
| 98 | // Always ok | ||
| 99 | return null; | ||
| 100 | } | ||
| 101 | |||
| 102 | @Override | ||
| 103 | public Void visitLetInExpression(LetInExpression expr) throws CheckerException { | ||
| 104 | var locals = new HashMap<String, Boolean>(); | ||
| 105 | for (var local : expr.bindings()) { | ||
| 106 | locals.put(local.name(), true); | ||
| 107 | } | ||
| 108 | new Checker(ImmutableScope.of(definitions, locals)).visit(expr.body()); | ||
| 109 | return null; | ||
| 110 | } | ||
| 111 | |||
| 112 | @Override | ||
| 113 | public Checker visitProgram(Program program) throws CheckerException { | ||
| 114 | var checker = this; | ||
| 115 | for (var stmt : program.statements()) { | ||
| 116 | checker = checker.visit(stmt); | ||
| 117 | } | ||
| 118 | return checker; | ||
| 119 | } | ||
| 120 | |||
| 121 | @Override | ||
| 122 | public Void visitStringLiteral(StringLiteral expr) { | ||
| 123 | // Always ok | ||
| 124 | return null; | ||
| 125 | } | ||
| 126 | |||
| 127 | @Override | ||
| 128 | public Void visitUnaryExpression(UnaryExpression expr) throws CheckerException { | ||
| 129 | visit(expr.child()); | ||
| 130 | return null; | ||
| 131 | } | ||
| 132 | |||
| 133 | @Override | ||
| 134 | public Void visitVariable(VariableExpression expr) throws CheckerException { | ||
| 135 | if (!definitions.hasDefinition(expr.name())) { | ||
| 136 | throw new CheckerException(STR."Variable named '\{expr.name()}' not defined!"); | ||
| 137 | } | ||
| 138 | return null; | ||
| 139 | } | ||
| 140 | |||
| 141 | @Override | ||
| 142 | public Void visitVoidExpression() { | ||
| 143 | // Always ok | ||
| 144 | return null; | ||
| 145 | } | ||
| 146 | } | ||
diff --git a/checker/src/main/java/lv/enes/orang/checker/CheckerException.java b/checker/src/main/java/lv/enes/orang/checker/CheckerException.java new file mode 100644 index 0000000..9354f27 --- /dev/null +++ b/checker/src/main/java/lv/enes/orang/checker/CheckerException.java | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | package lv.enes.orang.checker; | ||
| 2 | |||
| 3 | import lv.enes.orang.core.OrangException; | ||
| 4 | |||
| 5 | public class CheckerException extends OrangException { | ||
| 6 | public CheckerException(String message) { | ||
| 7 | super(message); | ||
| 8 | } | ||
| 9 | } | ||
diff --git a/checker/src/main/java/module-info.java b/checker/src/main/java/module-info.java new file mode 100644 index 0000000..6e5fa47 --- /dev/null +++ b/checker/src/main/java/module-info.java | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | module lv.enes.orang.checker { | ||
| 2 | exports lv.enes.orang.checker; | ||
| 3 | |||
| 4 | requires lv.enes.orang.ast; | ||
| 5 | requires lv.enes.orang.core; | ||
| 6 | requires lv.enes.orang.utils; | ||
| 7 | |||
| 8 | requires static lombok; | ||
| 9 | } \ No newline at end of file | ||
diff --git a/core/src/main/java/lv/enes/orang/core/ImmutableScope.java b/core/src/main/java/lv/enes/orang/core/ImmutableScope.java new file mode 100644 index 0000000..5120b08 --- /dev/null +++ b/core/src/main/java/lv/enes/orang/core/ImmutableScope.java | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | package lv.enes.orang.core; | ||
| 2 | |||
| 3 | import java.util.HashMap; | ||
| 4 | import java.util.Map; | ||
| 5 | |||
| 6 | public class ImmutableScope<E> extends Scope<E> { | ||
| 7 | public static <E> ImmutableScope<E> of(Map<String, E> builtins) { | ||
| 8 | return new ImmutableScope<>(null, new HashMap<>(builtins)); | ||
| 9 | } | ||
| 10 | |||
| 11 | public static <E> ImmutableScope<E> of(Scope<E> parent) { | ||
| 12 | if (parent instanceof ImmutableScope<E> imm) { | ||
| 13 | return imm; | ||
| 14 | } | ||
| 15 | return ImmutableScope.of(parent, Map.of()); | ||
| 16 | } | ||
| 17 | |||
| 18 | public static <E> ImmutableScope<E> of(Scope<E> parent, String key, E value) { | ||
| 19 | return ImmutableScope.of(parent, Map.of(key, value)); | ||
| 20 | } | ||
| 21 | |||
| 22 | public static <E> ImmutableScope<E> of(Scope<E> parent, Map<String, E> definitions) { | ||
| 23 | return new ImmutableScope<>(parent, definitions).maybeFlattened(); | ||
| 24 | } | ||
| 25 | |||
| 26 | protected ImmutableScope(Scope<E> parent, Map<String, E> definitions) { | ||
| 27 | super(parent, Map.copyOf(definitions)); | ||
| 28 | } | ||
| 29 | |||
| 30 | public ImmutableScope<E> maybeFlattened() { | ||
| 31 | if (depth > MAX_DEPTH) { | ||
| 32 | return flattened(); | ||
| 33 | } | ||
| 34 | return this; | ||
| 35 | } | ||
| 36 | |||
| 37 | private ImmutableScope<E> flattened() { | ||
| 38 | if (parent instanceof ImmutableScope<E> immParent) { | ||
| 39 | var flatParent = immParent.flattened(); | ||
| 40 | var newDefs = new HashMap<>(flatParent.definitions); | ||
| 41 | newDefs.putAll(definitions); | ||
| 42 | return new ImmutableScope<>(flatParent.parent, newDefs); | ||
| 43 | } | ||
| 44 | |||
| 45 | return this; | ||
| 46 | } | ||
| 47 | } | ||
diff --git a/core/src/main/java/lv/enes/orang/core/MutableScope.java b/core/src/main/java/lv/enes/orang/core/MutableScope.java new file mode 100644 index 0000000..8d8b455 --- /dev/null +++ b/core/src/main/java/lv/enes/orang/core/MutableScope.java | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | package lv.enes.orang.core; | ||
| 2 | |||
| 3 | import java.util.HashMap; | ||
| 4 | import java.util.Map; | ||
| 5 | |||
| 6 | public class MutableScope<E> extends Scope<E> { | ||
| 7 | public static <E> MutableScope<E> of(Map<String, E> builtins) { | ||
| 8 | return new MutableScope<>(null, new HashMap<>(builtins)); | ||
| 9 | } | ||
| 10 | |||
| 11 | public static <E> MutableScope<E> of(Scope<E> parent) { | ||
| 12 | return new MutableScope<>(parent, Map.of()); | ||
| 13 | } | ||
| 14 | |||
| 15 | public static <E> MutableScope<E> of(Scope<E> parent, String name, E value) { | ||
| 16 | return new MutableScope<>(parent, Map.of(name, value)); | ||
| 17 | } | ||
| 18 | |||
| 19 | protected MutableScope(Scope<E> parent, Map<String, E> definitions) { | ||
| 20 | super(parent, new HashMap<>(definitions)); | ||
| 21 | } | ||
| 22 | |||
| 23 | public void setDefinition(String key, E value) { | ||
| 24 | definitions.put(key, value); | ||
| 25 | } | ||
| 26 | } | ||
diff --git a/orang/src/main/java/lv/enes/orang/OrangRuntimeException.java b/core/src/main/java/lv/enes/orang/core/OrangRuntimeException.java index 8a7d575..6ce5f70 100644 --- a/orang/src/main/java/lv/enes/orang/OrangRuntimeException.java +++ b/core/src/main/java/lv/enes/orang/core/OrangRuntimeException.java | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | package lv.enes.orang; | 1 | package lv.enes.orang.core; |
| 2 | |||
| 3 | import lv.enes.orang.core.OrangException; | ||
| 4 | 2 | ||
| 5 | public class OrangRuntimeException extends OrangException { | 3 | public class OrangRuntimeException extends OrangException { |
| 6 | public OrangRuntimeException(String message) { | 4 | public OrangRuntimeException(String message) { |
diff --git a/orang/src/main/java/lv/enes/orang/Scope.java b/core/src/main/java/lv/enes/orang/core/Scope.java index 7fe57c7..0f4d23a 100644 --- a/orang/src/main/java/lv/enes/orang/Scope.java +++ b/core/src/main/java/lv/enes/orang/core/Scope.java | |||
| @@ -1,28 +1,21 @@ | |||
| 1 | package lv.enes.orang; | 1 | package lv.enes.orang.core; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.value.Value; | ||
| 4 | |||
| 5 | import java.util.HashMap; | ||
| 6 | import java.util.Map; | 3 | import java.util.Map; |
| 7 | 4 | ||
| 8 | public abstract class Scope { | 5 | public abstract class Scope<E> { |
| 9 | public static final int MAX_DEPTH = 4; | 6 | public static final int MAX_DEPTH = 4; |
| 10 | 7 | ||
| 11 | protected final Scope parent; | 8 | protected final Scope<E> parent; |
| 12 | protected final Map<String, Value> definitions; | 9 | protected final Map<String, E> definitions; |
| 13 | protected final int depth; | 10 | protected final int depth; |
| 14 | 11 | ||
| 15 | public static MutableScope topLevel() { | 12 | protected Scope(Scope<E> parent, Map<String, E> definitions) { |
| 16 | return new MutableScope(null, new HashMap<>(Builtins.BUILTINS)); | ||
| 17 | } | ||
| 18 | |||
| 19 | protected Scope(Scope parent, Map<String, Value> definitions) { | ||
| 20 | this.parent = parent; | 13 | this.parent = parent; |
| 21 | this.definitions = definitions; | 14 | this.definitions = definitions; |
| 22 | this.depth = parent == null ? 0 : parent.depth + 1; | 15 | this.depth = parent == null ? 0 : parent.depth + 1; |
| 23 | } | 16 | } |
| 24 | 17 | ||
| 25 | public Value getDefinition(String name) throws OrangRuntimeException { | 18 | public E getDefinition(String name) throws OrangRuntimeException { |
| 26 | if (definitions.containsKey(name)) { | 19 | if (definitions.containsKey(name)) { |
| 27 | return definitions.get(name); | 20 | return definitions.get(name); |
| 28 | } else if (parent != null) { | 21 | } else if (parent != null) { |
| @@ -31,4 +24,8 @@ public abstract class Scope { | |||
| 31 | throw new OrangRuntimeException(STR."Value named \{name} is not defined!"); | 24 | throw new OrangRuntimeException(STR."Value named \{name} is not defined!"); |
| 32 | } | 25 | } |
| 33 | } | 26 | } |
| 27 | |||
| 28 | public boolean hasDefinition(String name) { | ||
| 29 | return definitions.containsKey(name) || parent != null && parent.hasDefinition(name); | ||
| 30 | } | ||
| 34 | } | 31 | } |
diff --git a/orang/build.gradle.kts b/orang/build.gradle.kts index ef78ded..ea8fbe0 100644 --- a/orang/build.gradle.kts +++ b/orang/build.gradle.kts | |||
| @@ -23,6 +23,7 @@ dependencies { | |||
| 23 | implementation("org.slf4j:slf4j-simple:$slf4jVersion") | 23 | implementation("org.slf4j:slf4j-simple:$slf4jVersion") |
| 24 | 24 | ||
| 25 | implementation(project(":ast")) | 25 | implementation(project(":ast")) |
| 26 | implementation(project(":checker")) | ||
| 26 | implementation(project(":core")) | 27 | implementation(project(":core")) |
| 27 | implementation(project(":parser")) | 28 | implementation(project(":parser")) |
| 28 | implementation(project(":utils")) | 29 | 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 de296ac..a83f4c5 100644 --- a/orang/src/main/java/lv/enes/orang/Builtins.java +++ b/orang/src/main/java/lv/enes/orang/Builtins.java | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | package lv.enes.orang; | 1 | package lv.enes.orang; |
| 2 | 2 | ||
| 3 | import lombok.extern.slf4j.Slf4j; | 3 | import lombok.extern.slf4j.Slf4j; |
| 4 | import lv.enes.orang.core.OrangRuntimeException; | ||
| 4 | import lv.enes.orang.value.*; | 5 | import lv.enes.orang.value.*; |
| 5 | 6 | ||
| 6 | import java.io.IOException; | 7 | import java.io.IOException; |
diff --git a/orang/src/main/java/lv/enes/orang/Evaluator.java b/orang/src/main/java/lv/enes/orang/Evaluator.java index 5d09508..8930f5c 100644 --- a/orang/src/main/java/lv/enes/orang/Evaluator.java +++ b/orang/src/main/java/lv/enes/orang/Evaluator.java | |||
| @@ -1,17 +1,20 @@ | |||
| 1 | package lv.enes.orang; | 1 | package lv.enes.orang; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.ast.*; | 3 | import lv.enes.orang.ast.*; |
| 4 | import lv.enes.orang.core.MutableScope; | ||
| 5 | import lv.enes.orang.core.OrangRuntimeException; | ||
| 6 | import lv.enes.orang.core.Scope; | ||
| 4 | import lv.enes.orang.value.*; | 7 | import lv.enes.orang.value.*; |
| 5 | 8 | ||
| 6 | import java.util.ArrayList; | 9 | import java.util.ArrayList; |
| 7 | import java.util.Collections; | 10 | import java.util.Collections; |
| 8 | 11 | ||
| 9 | public record Evaluator(Scope scope, Value lastResult) implements ExpressionVisitor<Value, OrangRuntimeException>, StatementVisitor<Evaluator, OrangRuntimeException> { | 12 | public record Evaluator(Scope<Value> scope, Value lastResult) implements ExpressionVisitor<Value, OrangRuntimeException>, StatementVisitor<Evaluator, OrangRuntimeException> { |
| 10 | public Evaluator() { | 13 | public Evaluator() { |
| 11 | this(Scope.topLevel()); | 14 | this(MutableScope.of(Builtins.BUILTINS)); |
| 12 | } | 15 | } |
| 13 | 16 | ||
| 14 | public Evaluator(Scope scope) { | 17 | public Evaluator(Scope<Value> scope) { |
| 15 | this(scope, Undefined.INSTANCE); | 18 | this(scope, Undefined.INSTANCE); |
| 16 | } | 19 | } |
| 17 | 20 | ||
diff --git a/orang/src/main/java/lv/enes/orang/ImmutableScope.java b/orang/src/main/java/lv/enes/orang/ImmutableScope.java deleted file mode 100644 index 9cb6138..0000000 --- a/orang/src/main/java/lv/enes/orang/ImmutableScope.java +++ /dev/null | |||
| @@ -1,45 +0,0 @@ | |||
| 1 | package lv.enes.orang; | ||
| 2 | |||
| 3 | import lv.enes.orang.value.Value; | ||
| 4 | |||
| 5 | import java.util.HashMap; | ||
| 6 | import java.util.Map; | ||
| 7 | |||
| 8 | public class ImmutableScope extends Scope { | ||
| 9 | public static ImmutableScope of(Scope parent) { | ||
| 10 | if (parent instanceof ImmutableScope imm) { | ||
| 11 | return imm; | ||
| 12 | } | ||
| 13 | return ImmutableScope.of(parent, Map.of()); | ||
| 14 | } | ||
| 15 | |||
| 16 | public static ImmutableScope of(Scope parent, String key, Value value) { | ||
| 17 | return ImmutableScope.of(parent, Map.of(key, value)); | ||
| 18 | } | ||
| 19 | |||
| 20 | public static ImmutableScope of(Scope parent, Map<String, Value> definitions) { | ||
| 21 | return new ImmutableScope(parent, definitions).maybeFlattened(); | ||
| 22 | } | ||
| 23 | |||
| 24 | protected ImmutableScope(Scope parent, Map<String, Value> definitions) { | ||
| 25 | super(parent, Map.copyOf(definitions)); | ||
| 26 | } | ||
| 27 | |||
| 28 | public ImmutableScope maybeFlattened() { | ||
| 29 | if (depth > MAX_DEPTH) { | ||
| 30 | return flattened(); | ||
| 31 | } | ||
| 32 | return this; | ||
| 33 | } | ||
| 34 | |||
| 35 | private ImmutableScope flattened() { | ||
| 36 | if (parent instanceof ImmutableScope immParent) { | ||
| 37 | var flatParent = immParent.flattened(); | ||
| 38 | var newDefs = new HashMap<>(flatParent.definitions); | ||
| 39 | newDefs.putAll(definitions); | ||
| 40 | return new ImmutableScope(flatParent.parent, newDefs); | ||
| 41 | } | ||
| 42 | |||
| 43 | return this; | ||
| 44 | } | ||
| 45 | } | ||
diff --git a/orang/src/main/java/lv/enes/orang/Main.java b/orang/src/main/java/lv/enes/orang/Main.java index 7175dac..9a061fe 100644 --- a/orang/src/main/java/lv/enes/orang/Main.java +++ b/orang/src/main/java/lv/enes/orang/Main.java | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | package lv.enes.orang; | 1 | package lv.enes.orang; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.checker.Checker; | ||
| 3 | import lv.enes.orang.core.OrangException; | 4 | import lv.enes.orang.core.OrangException; |
| 4 | import lv.enes.orang.parser.Parser; | 5 | import lv.enes.orang.parser.Parser; |
| 5 | 6 | ||
| @@ -17,11 +18,13 @@ public class Main { | |||
| 17 | } | 18 | } |
| 18 | 19 | ||
| 19 | private static void repl() throws IOException { | 20 | private static void repl() throws IOException { |
| 21 | var checker = Checker.of(Builtins.BUILTINS); | ||
| 20 | var evaluator = new Evaluator(); | 22 | var evaluator = new Evaluator(); |
| 21 | 23 | ||
| 22 | try (var stream = Main.class.getResourceAsStream("prelude.orang")) { | 24 | try (var stream = Main.class.getResourceAsStream("prelude.orang")) { |
| 23 | var prog = Parser.parseProgram(stream); | 25 | var prog = Parser.parseProgram(stream); |
| 24 | evaluator = evaluator.visitProgram(prog); | 26 | checker = checker.visit(prog); |
| 27 | evaluator = evaluator.visit(prog); | ||
| 25 | } catch (OrangException ex) { | 28 | } catch (OrangException ex) { |
| 26 | STDOUT.println(STR."While evaluating prelude: \{ex}"); | 29 | STDOUT.println(STR."While evaluating prelude: \{ex}"); |
| 27 | throw new RuntimeException(ex); | 30 | throw new RuntimeException(ex); |
| @@ -51,7 +54,8 @@ public class Main { | |||
| 51 | var filename = line.substring(2).trim(); | 54 | var filename = line.substring(2).trim(); |
| 52 | try (var reader = new FileReader((filename))) { | 55 | try (var reader = new FileReader((filename))) { |
| 53 | var prog = Parser.parseProgram(reader); | 56 | var prog = Parser.parseProgram(reader); |
| 54 | evaluator = evaluator.visitProgram(prog); | 57 | checker = checker.visit(prog); |
| 58 | evaluator = evaluator.visit(prog); | ||
| 55 | } catch (IOException | OrangException ex) { | 59 | } catch (IOException | OrangException ex) { |
| 56 | STDOUT.println(ex); | 60 | STDOUT.println(ex); |
| 57 | } | 61 | } |
| @@ -67,7 +71,8 @@ public class Main { | |||
| 67 | 71 | ||
| 68 | try { | 72 | try { |
| 69 | var prog = Parser.parseReplProgram(line); | 73 | var prog = Parser.parseReplProgram(line); |
| 70 | evaluator = evaluator.visitProgram(prog); | 74 | checker = checker.visit(prog); |
| 75 | evaluator = evaluator.visit(prog); | ||
| 71 | if (evaluator.lastResult() != null) { | 76 | if (evaluator.lastResult() != null) { |
| 72 | STDOUT.print("-> "); | 77 | STDOUT.print("-> "); |
| 73 | STDOUT.println(evaluator.lastResult().stringify()); | 78 | STDOUT.println(evaluator.lastResult().stringify()); |
diff --git a/orang/src/main/java/lv/enes/orang/MutableScope.java b/orang/src/main/java/lv/enes/orang/MutableScope.java deleted file mode 100644 index 8d900a4..0000000 --- a/orang/src/main/java/lv/enes/orang/MutableScope.java +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | package lv.enes.orang; | ||
| 2 | |||
| 3 | import lv.enes.orang.value.Value; | ||
| 4 | |||
| 5 | import java.util.HashMap; | ||
| 6 | import java.util.Map; | ||
| 7 | |||
| 8 | public class MutableScope extends Scope { | ||
| 9 | public static MutableScope of(Scope parent) { | ||
| 10 | return new MutableScope(parent, Map.of()); | ||
| 11 | } | ||
| 12 | |||
| 13 | public static MutableScope of(Scope parent, String name, Value value) { | ||
| 14 | return new MutableScope(parent, Map.of(name, value)); | ||
| 15 | } | ||
| 16 | |||
| 17 | protected MutableScope(Scope parent, Map<String, Value> definitions) { | ||
| 18 | super(parent, new HashMap<>(definitions)); | ||
| 19 | } | ||
| 20 | |||
| 21 | public void setDefinition(String key, Value value) { | ||
| 22 | definitions.put(key, value); | ||
| 23 | } | ||
| 24 | } | ||
diff --git a/orang/src/main/java/lv/enes/orang/value/Array.java b/orang/src/main/java/lv/enes/orang/value/Array.java index c3b645d..33e1516 100644 --- a/orang/src/main/java/lv/enes/orang/value/Array.java +++ b/orang/src/main/java/lv/enes/orang/value/Array.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.OrangRuntimeException; | 3 | import lv.enes.orang.core.OrangRuntimeException; |
| 4 | 4 | ||
| 5 | import java.util.ArrayList; | 5 | import java.util.ArrayList; |
| 6 | import java.util.Collections; | 6 | import java.util.Collections; |
diff --git a/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java b/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java index 92ccc2e..1a61cfb 100644 --- a/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java +++ b/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.OrangRuntimeException; | 3 | import lv.enes.orang.core.OrangRuntimeException; |
| 4 | 4 | ||
| 5 | import java.util.List; | 5 | import java.util.List; |
| 6 | 6 | ||
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 6e3c83a..d0500b9 100644 --- a/orang/src/main/java/lv/enes/orang/value/Function.java +++ b/orang/src/main/java/lv/enes/orang/value/Function.java | |||
| @@ -1,11 +1,12 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.*; | ||
| 4 | import lv.enes.orang.ast.ArgSpec; | 3 | import lv.enes.orang.ast.ArgSpec; |
| 5 | import lv.enes.orang.ast.Expression; | 4 | import lv.enes.orang.ast.Expression; |
| 5 | import lv.enes.orang.core.OrangRuntimeException; | ||
| 6 | import lv.enes.orang.core.Scope; | ||
| 6 | import lv.enes.orang.utils.NonEmptyList; | 7 | import lv.enes.orang.utils.NonEmptyList; |
| 7 | 8 | ||
| 8 | public record Function(Scope scope, NonEmptyList<ArgSpec> args, Expression body) implements Value { | 9 | public record Function(Scope<Value> scope, NonEmptyList<ArgSpec> args, Expression body) implements Value { |
| 9 | @Override | 10 | @Override |
| 10 | public String typeName() { | 11 | public String typeName() { |
| 11 | return "Function"; | 12 | return "Function"; |
diff --git a/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java b/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java index 8a4776c..59aa9b7 100644 --- a/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java +++ b/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lombok.EqualsAndHashCode; | 3 | import lombok.EqualsAndHashCode; |
| 4 | import lv.enes.orang.OrangRuntimeException; | 4 | import lv.enes.orang.core.OrangRuntimeException; |
| 5 | 5 | ||
| 6 | @EqualsAndHashCode | 6 | @EqualsAndHashCode |
| 7 | public final class OrangBoolean implements Value { | 7 | public final class OrangBoolean implements Value { |
diff --git a/orang/src/main/java/lv/enes/orang/value/OrangInteger.java b/orang/src/main/java/lv/enes/orang/value/OrangInteger.java index 9b8d505..63a44da 100644 --- a/orang/src/main/java/lv/enes/orang/value/OrangInteger.java +++ b/orang/src/main/java/lv/enes/orang/value/OrangInteger.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.OrangRuntimeException; | 3 | import lv.enes.orang.core.OrangRuntimeException; |
| 4 | 4 | ||
| 5 | public record OrangInteger(int value) implements Value { | 5 | public record OrangInteger(int value) implements Value { |
| 6 | @Override | 6 | @Override |
diff --git a/orang/src/main/java/lv/enes/orang/value/OrangString.java b/orang/src/main/java/lv/enes/orang/value/OrangString.java index c03f7ac..b4ede1f 100644 --- a/orang/src/main/java/lv/enes/orang/value/OrangString.java +++ b/orang/src/main/java/lv/enes/orang/value/OrangString.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.OrangRuntimeException; | 3 | import lv.enes.orang.core.OrangRuntimeException; |
| 4 | 4 | ||
| 5 | public record OrangString(String value) implements Value { | 5 | public record OrangString(String value) implements Value { |
| 6 | @Override | 6 | @Override |
diff --git a/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java b/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java index 37278a4..c1be22a 100644 --- a/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java +++ b/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.OrangRuntimeException; | 3 | import lv.enes.orang.core.OrangRuntimeException; |
| 4 | 4 | ||
| 5 | import java.util.ArrayList; | 5 | import java.util.ArrayList; |
| 6 | import java.util.Collections; | 6 | import java.util.Collections; |
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 cee0cd4..e73ba0c 100644 --- a/orang/src/main/java/lv/enes/orang/value/PartialFunction.java +++ b/orang/src/main/java/lv/enes/orang/value/PartialFunction.java | |||
| @@ -3,10 +3,13 @@ package lv.enes.orang.value; | |||
| 3 | import lv.enes.orang.*; | 3 | import lv.enes.orang.*; |
| 4 | import lv.enes.orang.ast.ArgSpec; | 4 | import lv.enes.orang.ast.ArgSpec; |
| 5 | import lv.enes.orang.ast.Expression; | 5 | import lv.enes.orang.ast.Expression; |
| 6 | import lv.enes.orang.core.MutableScope; | ||
| 7 | import lv.enes.orang.core.OrangRuntimeException; | ||
| 8 | import lv.enes.orang.core.Scope; | ||
| 6 | import lv.enes.orang.utils.NonEmptyList; | 9 | import lv.enes.orang.utils.NonEmptyList; |
| 7 | 10 | ||
| 8 | public record PartialFunction(Scope scope, NonEmptyList<ArgSpec> remainingArgs, Expression body) implements Value { | 11 | public record PartialFunction(Scope<Value> scope, NonEmptyList<ArgSpec> remainingArgs, Expression body) implements Value { |
| 9 | public static Value of(Scope scope, NonEmptyList<ArgSpec> remainingArgs, Expression body, Value param) throws OrangRuntimeException { | 12 | public static Value of(Scope<Value> scope, NonEmptyList<ArgSpec> remainingArgs, Expression body, Value param) throws OrangRuntimeException { |
| 10 | var spec = remainingArgs.getFirst(); | 13 | var spec = remainingArgs.getFirst(); |
| 11 | var newScope = MutableScope.of(scope); | 14 | var newScope = MutableScope.of(scope); |
| 12 | switch (spec.type) { | 15 | switch (spec.type) { |
diff --git a/orang/src/main/java/lv/enes/orang/value/Value.java b/orang/src/main/java/lv/enes/orang/value/Value.java index 0816dc2..07e6848 100644 --- a/orang/src/main/java/lv/enes/orang/value/Value.java +++ b/orang/src/main/java/lv/enes/orang/value/Value.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package lv.enes.orang.value; | 1 | package lv.enes.orang.value; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.OrangRuntimeException; | 3 | import lv.enes.orang.core.OrangRuntimeException; |
| 4 | 4 | ||
| 5 | public sealed interface Value | 5 | public sealed interface Value |
| 6 | permits Array, BuiltinFunction, Function, Nothing, OrangBoolean, OrangInteger, OrangString, PartialBuiltinFunction, PartialFunction, Undefined { | 6 | permits Array, BuiltinFunction, Function, Nothing, OrangBoolean, OrangInteger, OrangString, PartialBuiltinFunction, PartialFunction, Undefined { |
diff --git a/orang/src/main/java/module-info.java b/orang/src/main/java/module-info.java index 353d0dd..5b7b601 100644 --- a/orang/src/main/java/module-info.java +++ b/orang/src/main/java/module-info.java | |||
| @@ -3,6 +3,7 @@ module lv.enes.orang { | |||
| 3 | exports lv.enes.orang.value; | 3 | exports lv.enes.orang.value; |
| 4 | 4 | ||
| 5 | requires lv.enes.orang.ast; | 5 | requires lv.enes.orang.ast; |
| 6 | requires lv.enes.orang.checker; | ||
| 6 | requires lv.enes.orang.core; | 7 | requires lv.enes.orang.core; |
| 7 | requires lv.enes.orang.parser; | 8 | requires lv.enes.orang.parser; |
| 8 | requires lv.enes.orang.utils; | 9 | requires lv.enes.orang.utils; |
diff --git a/settings.gradle.kts b/settings.gradle.kts index 391d33b..a64dfa6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | rootProject.name = "orang" | 1 | rootProject.name = "orang" |
| 2 | 2 | ||
| 3 | include("ast", "core", "lexer", "orang", "parser", "utils") \ No newline at end of file | 3 | include("ast", "checker", "core", "lexer", "orang", "parser", "utils") \ No newline at end of file |