summaryrefslogtreecommitdiff
path: root/checker
diff options
context:
space:
mode:
Diffstat (limited to 'checker')
-rw-r--r--checker/build.gradle.kts30
-rw-r--r--checker/src/main/java/lv/enes/orang/checker/Checker.java146
-rw-r--r--checker/src/main/java/lv/enes/orang/checker/CheckerException.java9
-rw-r--r--checker/src/main/java/module-info.java9
4 files changed, 194 insertions, 0 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 @@
1plugins {
2 java
3 id("io.freefair.lombok") version "8.6"
4}
5
6val slf4jVersion = "2.0.13"
7
8repositories {
9 mavenCentral()
10}
11
12dependencies {
13 implementation("org.slf4j:slf4j-api:$slf4jVersion")
14
15 implementation(project(":ast"))
16 implementation(project(":core"))
17 implementation(project(":utils"))
18}
19
20java {
21 sourceCompatibility = JavaVersion.VERSION_22
22 targetCompatibility = JavaVersion.VERSION_22
23 toolchain {
24 languageVersion = JavaLanguageVersion.of(22)
25 }
26}
27
28tasks.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 @@
1package lv.enes.orang.checker;
2
3import lv.enes.orang.ast.*;
4import lv.enes.orang.core.ImmutableScope;
5import lv.enes.orang.core.Scope;
6
7import java.util.HashMap;
8import java.util.Map;
9
10public 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 @@
1package lv.enes.orang.checker;
2
3import lv.enes.orang.core.OrangException;
4
5public 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 @@
1module 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