summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ast/build.gradle.kts20
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/ArrayExpression.java12
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/BinaryExpression.java (renamed from src/main/java/lv/enes/orang/ast/BinaryExpression.java)21
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/BooleanLiteral.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/CallExpression.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/DefSpec.java (renamed from src/main/java/lv/enes/orang/ast/DefSpec.java)0
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/Definition.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/DoExpression.java14
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/Expression.java7
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/ExpressionStatement.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java22
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/FnExpression.java11
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/IfElseExpression.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/IntLiteral.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/LetInExpression.java14
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/Program.java12
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/Statement.java7
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/StatementVisitor.java13
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/StringLiteral.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/UnaryExpression.java16
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/VariableExpression.java10
-rw-r--r--ast/src/main/java/module-info.java6
-rw-r--r--core/build.gradle.kts15
-rw-r--r--core/src/main/java/lv/enes/orang/core/OrangException.java (renamed from src/main/java/lv/enes/orang/OrangException.java)2
-rw-r--r--core/src/main/java/module-info.java3
-rw-r--r--grammar.bnf2
-rw-r--r--orang/build.gradle.kts (renamed from build.gradle.kts)6
-rw-r--r--orang/src/main/java/lv/enes/orang/Builtins.java (renamed from src/main/java/lv/enes/orang/Builtins.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/Codepoint.java (renamed from src/main/java/lv/enes/orang/Codepoint.java)4
-rw-r--r--orang/src/main/java/lv/enes/orang/Evaluator.java144
-rw-r--r--orang/src/main/java/lv/enes/orang/ImmutableScope.java45
-rw-r--r--orang/src/main/java/lv/enes/orang/Lexer.java (renamed from src/main/java/lv/enes/orang/Lexer.java)8
-rw-r--r--orang/src/main/java/lv/enes/orang/Main.java (renamed from src/main/java/lv/enes/orang/Main.java)14
-rw-r--r--orang/src/main/java/lv/enes/orang/MutableScope.java24
-rw-r--r--orang/src/main/java/lv/enes/orang/OrangRuntimeException.java (renamed from src/main/java/lv/enes/orang/OrangRuntimeException.java)2
-rw-r--r--orang/src/main/java/lv/enes/orang/Parser.java (renamed from src/main/java/lv/enes/orang/Parser.java)3
-rw-r--r--orang/src/main/java/lv/enes/orang/ParserException.java (renamed from src/main/java/lv/enes/orang/ParserException.java)2
-rw-r--r--orang/src/main/java/lv/enes/orang/PeekableStream.java (renamed from src/main/java/lv/enes/orang/PeekableStream.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/Scope.java34
-rw-r--r--orang/src/main/java/lv/enes/orang/State.java (renamed from src/main/java/lv/enes/orang/State.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/Token.java (renamed from src/main/java/lv/enes/orang/Token.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/TokenType.java (renamed from src/main/java/lv/enes/orang/TokenType.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/Array.java (renamed from src/main/java/lv/enes/orang/value/Array.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java (renamed from src/main/java/lv/enes/orang/value/BuiltinFunction.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/Function.java (renamed from src/main/java/lv/enes/orang/value/Function.java)5
-rw-r--r--orang/src/main/java/lv/enes/orang/value/OrangBoolean.java (renamed from src/main/java/lv/enes/orang/value/OrangBoolean.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/OrangInteger.java (renamed from src/main/java/lv/enes/orang/value/OrangInteger.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/OrangString.java (renamed from src/main/java/lv/enes/orang/value/OrangString.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java (renamed from src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/PartialFunction.java (renamed from src/main/java/lv/enes/orang/value/PartialFunction.java)5
-rw-r--r--orang/src/main/java/lv/enes/orang/value/Undefined.java (renamed from src/main/java/lv/enes/orang/value/Undefined.java)0
-rw-r--r--orang/src/main/java/lv/enes/orang/value/Value.java (renamed from src/main/java/lv/enes/orang/value/Value.java)0
-rw-r--r--orang/src/main/java/module-info.java (renamed from src/main/java/module-info.java)5
-rw-r--r--orang/src/main/resources/lv/enes/orang/prelude.orang (renamed from src/main/resources/lv/enes/orang/prelude.orang)8
-rw-r--r--settings.gradle.kts1
-rw-r--r--src/main/java/lv/enes/orang/Scope.java54
-rw-r--r--src/main/java/lv/enes/orang/ast/ArrayExpression.java21
-rw-r--r--src/main/java/lv/enes/orang/ast/BooleanLiteral.java12
-rw-r--r--src/main/java/lv/enes/orang/ast/CallExpression.java12
-rw-r--r--src/main/java/lv/enes/orang/ast/Definition.java15
-rw-r--r--src/main/java/lv/enes/orang/ast/DoExpression.java19
-rw-r--r--src/main/java/lv/enes/orang/ast/Expression.java14
-rw-r--r--src/main/java/lv/enes/orang/ast/FnExpression.java14
-rw-r--r--src/main/java/lv/enes/orang/ast/IfElseExpression.java22
-rw-r--r--src/main/java/lv/enes/orang/ast/IntLiteral.java12
-rw-r--r--src/main/java/lv/enes/orang/ast/LetInExpression.java27
-rw-r--r--src/main/java/lv/enes/orang/ast/Program.java17
-rw-r--r--src/main/java/lv/enes/orang/ast/Statement.java8
-rw-r--r--src/main/java/lv/enes/orang/ast/StringLiteral.java13
-rw-r--r--src/main/java/lv/enes/orang/ast/UnaryExpression.java23
-rw-r--r--src/main/java/lv/enes/orang/ast/VariableExpression.java12
-rw-r--r--utils/build.gradle.kts20
-rw-r--r--utils/src/main/java/lv/enes/orang/utils/NonEmptyList.java (renamed from src/main/java/lv/enes/orang/NonEmptyList.java)2
-rw-r--r--utils/src/main/java/module-info.java5
74 files changed, 582 insertions, 327 deletions
diff --git a/ast/build.gradle.kts b/ast/build.gradle.kts
new file mode 100644
index 0000000..357e080
--- /dev/null
+++ b/ast/build.gradle.kts
@@ -0,0 +1,20 @@
1plugins {
2 java
3}
4
5dependencies {
6 implementation(project(":core"))
7 implementation(project(":utils"))
8}
9
10java {
11 sourceCompatibility = JavaVersion.VERSION_22
12 targetCompatibility = JavaVersion.VERSION_22
13 toolchain {
14 languageVersion = JavaLanguageVersion.of(22)
15 }
16}
17
18tasks.withType<JavaCompile> {
19 options.compilerArgs.add("--enable-preview")
20} \ No newline at end of file
diff --git a/ast/src/main/java/lv/enes/orang/ast/ArrayExpression.java b/ast/src/main/java/lv/enes/orang/ast/ArrayExpression.java
new file mode 100644
index 0000000..acd1a36
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/ArrayExpression.java
@@ -0,0 +1,12 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5import java.util.List;
6
7public record ArrayExpression(List<Expression> items) implements Expression {
8 @Override
9 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
10 return visitor.visitArray(this);
11 }
12}
diff --git a/src/main/java/lv/enes/orang/ast/BinaryExpression.java b/ast/src/main/java/lv/enes/orang/ast/BinaryExpression.java
index c0b988c..fb8bac5 100644
--- a/src/main/java/lv/enes/orang/ast/BinaryExpression.java
+++ b/ast/src/main/java/lv/enes/orang/ast/BinaryExpression.java
@@ -1,8 +1,6 @@
1package lv.enes.orang.ast; 1package lv.enes.orang.ast;
2 2
3import lv.enes.orang.OrangRuntimeException; 3import lv.enes.orang.core.OrangException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Value;
6 4
7public record BinaryExpression(Operator operator, Expression lhs, Expression rhs) implements Expression { 5public record BinaryExpression(Operator operator, Expression lhs, Expression rhs) implements Expression {
8 public enum Operator { 6 public enum Operator {
@@ -34,20 +32,7 @@ public record BinaryExpression(Operator operator, Expression lhs, Expression rhs
34 } 32 }
35 33
36 @Override 34 @Override
37 public Value evaluateExpression(Scope scope) throws OrangRuntimeException { 35 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
38 var lhs = lhs().evaluateExpression(scope); 36 return visitor.visitBinaryExpression(this);
39 var rhs = rhs().evaluateExpression(scope);
40 return switch (operator) {
41 case EQUALS -> lhs.orangEquals(rhs);
42 case NOT_EQUALS -> lhs.notEquals(rhs);
43 case GT -> lhs.greaterThan(rhs);
44 case GTE -> lhs.greaterThanOrEqual(rhs);
45 case LT -> lhs.lessThan(rhs);
46 case LTE -> lhs.lessThanOrEqual(rhs);
47 case ADD -> lhs.add(rhs);
48 case SUBTRACT -> lhs.subtract(rhs);
49 case MULTIPLY -> lhs.multiply(rhs);
50 case DIVIDE -> lhs.divide(rhs);
51 };
52 } 37 }
53} 38}
diff --git a/ast/src/main/java/lv/enes/orang/ast/BooleanLiteral.java b/ast/src/main/java/lv/enes/orang/ast/BooleanLiteral.java
new file mode 100644
index 0000000..16bf176
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/BooleanLiteral.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record BooleanLiteral(boolean value) implements Expression {
6 @Override
7 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
8 return visitor.visitBoolean(this);
9 }
10}
diff --git a/ast/src/main/java/lv/enes/orang/ast/CallExpression.java b/ast/src/main/java/lv/enes/orang/ast/CallExpression.java
new file mode 100644
index 0000000..38ff7bd
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/CallExpression.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record CallExpression(Expression callee, Expression arg) implements Expression {
6 @Override
7 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
8 return visitor.visitCallExpression(this);
9 }
10}
diff --git a/src/main/java/lv/enes/orang/ast/DefSpec.java b/ast/src/main/java/lv/enes/orang/ast/DefSpec.java
index 2233d3f..2233d3f 100644
--- a/src/main/java/lv/enes/orang/ast/DefSpec.java
+++ b/ast/src/main/java/lv/enes/orang/ast/DefSpec.java
diff --git a/ast/src/main/java/lv/enes/orang/ast/Definition.java b/ast/src/main/java/lv/enes/orang/ast/Definition.java
new file mode 100644
index 0000000..b41cb1f
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/Definition.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record Definition(String name, Expression body) implements Statement {
6 @Override
7 public <R, E extends OrangException> R accept(StatementVisitor<R, E> visitor) throws E {
8 return visitor.visitDefinition(this);
9 }
10}
diff --git a/ast/src/main/java/lv/enes/orang/ast/DoExpression.java b/ast/src/main/java/lv/enes/orang/ast/DoExpression.java
new file mode 100644
index 0000000..47eaddd
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/DoExpression.java
@@ -0,0 +1,14 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5import java.util.List;
6
7public record DoExpression(List<Expression> body) implements Expression {
8 // assert body.!isEmpty()
9
10 @Override
11 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
12 return visitor.visitDoExpression(this);
13 }
14}
diff --git a/ast/src/main/java/lv/enes/orang/ast/Expression.java b/ast/src/main/java/lv/enes/orang/ast/Expression.java
new file mode 100644
index 0000000..a3e2acc
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/Expression.java
@@ -0,0 +1,7 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public interface Expression {
6 <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E;
7}
diff --git a/ast/src/main/java/lv/enes/orang/ast/ExpressionStatement.java b/ast/src/main/java/lv/enes/orang/ast/ExpressionStatement.java
new file mode 100644
index 0000000..2a9dae1
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/ExpressionStatement.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record ExpressionStatement(Expression expr) implements Statement {
6 @Override
7 public <R, E extends OrangException> R accept(StatementVisitor<R, E> visitor) throws E {
8 return visitor.visitExpression(this);
9 }
10}
diff --git a/ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java b/ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java
new file mode 100644
index 0000000..ddb1157
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java
@@ -0,0 +1,22 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public interface ExpressionVisitor<R, E extends OrangException> {
6 default R visit(Expression expression) throws E {
7 return expression.accept(this);
8 }
9
10 R visitArray(ArrayExpression array) throws E;
11 R visitBoolean(BooleanLiteral expr) throws E;
12 R visitBinaryExpression(BinaryExpression expr) throws E;
13 R visitCallExpression(CallExpression expr) throws E;
14 R visitDoExpression(DoExpression expr) throws E;
15 R visitFnExpression(FnExpression expr) throws E;
16 R visitIfElseExpression(IfElseExpression expr) throws E;
17 R visitIntLiteral(IntLiteral expr) throws E;
18 R visitLetInExpression(LetInExpression expr) throws E;
19 R visitStringLiteral(StringLiteral expr) throws E;
20 R visitUnaryExpression(UnaryExpression expr) throws E;
21 R visitVariable(VariableExpression expr) throws E;
22}
diff --git a/ast/src/main/java/lv/enes/orang/ast/FnExpression.java b/ast/src/main/java/lv/enes/orang/ast/FnExpression.java
new file mode 100644
index 0000000..68f43af
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/FnExpression.java
@@ -0,0 +1,11 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.utils.NonEmptyList;
4import lv.enes.orang.core.OrangException;
5
6public record FnExpression(NonEmptyList<String> args, Expression body) implements Expression {
7 @Override
8 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
9 return visitor.visitFnExpression(this);
10 }
11}
diff --git a/ast/src/main/java/lv/enes/orang/ast/IfElseExpression.java b/ast/src/main/java/lv/enes/orang/ast/IfElseExpression.java
new file mode 100644
index 0000000..86e48d4
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/IfElseExpression.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record IfElseExpression(Expression condition, Expression trueBranch, Expression falseBranch) implements Expression {
6 @Override
7 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
8 return visitor.visitIfElseExpression(this);
9 }
10}
diff --git a/ast/src/main/java/lv/enes/orang/ast/IntLiteral.java b/ast/src/main/java/lv/enes/orang/ast/IntLiteral.java
new file mode 100644
index 0000000..12333c9
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/IntLiteral.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record IntLiteral(int value) implements Expression {
6 @Override
7 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
8 return visitor.visitIntLiteral(this);
9 }
10}
diff --git a/ast/src/main/java/lv/enes/orang/ast/LetInExpression.java b/ast/src/main/java/lv/enes/orang/ast/LetInExpression.java
new file mode 100644
index 0000000..b292f08
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/LetInExpression.java
@@ -0,0 +1,14 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5import java.util.List;
6
7public record LetInExpression(List<Binding> bindings, Expression body) implements Expression {
8 @Override
9 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
10 return visitor.visitLetInExpression(this);
11 }
12
13 public record Binding(String name, Expression value) {}
14}
diff --git a/ast/src/main/java/lv/enes/orang/ast/Program.java b/ast/src/main/java/lv/enes/orang/ast/Program.java
new file mode 100644
index 0000000..9b38f3b
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/Program.java
@@ -0,0 +1,12 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5import java.util.List;
6
7public record Program(List<Statement> statements) implements Statement {
8 @Override
9 public <R, E extends OrangException> R accept(StatementVisitor<R, E> visitor) throws E {
10 return visitor.visitProgram(this);
11 }
12}
diff --git a/ast/src/main/java/lv/enes/orang/ast/Statement.java b/ast/src/main/java/lv/enes/orang/ast/Statement.java
new file mode 100644
index 0000000..283fd40
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/Statement.java
@@ -0,0 +1,7 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public interface Statement {
6 <R, E extends OrangException> R accept(StatementVisitor<R, E> visitor) throws E;
7}
diff --git a/ast/src/main/java/lv/enes/orang/ast/StatementVisitor.java b/ast/src/main/java/lv/enes/orang/ast/StatementVisitor.java
new file mode 100644
index 0000000..fa3b2f6
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/StatementVisitor.java
@@ -0,0 +1,13 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public interface StatementVisitor<R, E extends OrangException> {
6 default R visit(Statement stmt) throws E {
7 return stmt.accept(this);
8 }
9
10 R visitDefinition(Definition def) throws E;
11 R visitExpression(ExpressionStatement expr) throws E;
12 R visitProgram(Program program) throws E;
13}
diff --git a/ast/src/main/java/lv/enes/orang/ast/StringLiteral.java b/ast/src/main/java/lv/enes/orang/ast/StringLiteral.java
new file mode 100644
index 0000000..5c47b7e
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/StringLiteral.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record StringLiteral(String value) implements Expression {
6 @Override
7 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
8 return visitor.visitStringLiteral(this);
9 }
10}
diff --git a/ast/src/main/java/lv/enes/orang/ast/UnaryExpression.java b/ast/src/main/java/lv/enes/orang/ast/UnaryExpression.java
new file mode 100644
index 0000000..d96ae6d
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/UnaryExpression.java
@@ -0,0 +1,16 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record UnaryExpression(Operator operator, Expression child) implements Expression {
6 public enum Operator {
7 PLUS,
8 NEGATE,
9 NOT,
10 }
11
12 @Override
13 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
14 return visitor.visitUnaryExpression(this);
15 }
16}
diff --git a/ast/src/main/java/lv/enes/orang/ast/VariableExpression.java b/ast/src/main/java/lv/enes/orang/ast/VariableExpression.java
new file mode 100644
index 0000000..615857b
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/VariableExpression.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record VariableExpression(String name) implements Expression {
6 @Override
7 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
8 return visitor.visitVariable(this);
9 }
10}
diff --git a/ast/src/main/java/module-info.java b/ast/src/main/java/module-info.java
new file mode 100644
index 0000000..7ebe37b
--- /dev/null
+++ b/ast/src/main/java/module-info.java
@@ -0,0 +1,6 @@
1module lv.enes.orang.ast {
2 exports lv.enes.orang.ast;
3
4 requires lv.enes.orang.core;
5 requires lv.enes.orang.utils;
6} \ No newline at end of file
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
new file mode 100644
index 0000000..19bbafc
--- /dev/null
+++ b/core/build.gradle.kts
@@ -0,0 +1,15 @@
1plugins {
2 java
3}
4
5java {
6 sourceCompatibility = JavaVersion.VERSION_22
7 targetCompatibility = JavaVersion.VERSION_22
8 toolchain {
9 languageVersion = JavaLanguageVersion.of(22)
10 }
11}
12
13tasks.withType<JavaCompile> {
14 options.compilerArgs.add("--enable-preview")
15} \ No newline at end of file
diff --git a/src/main/java/lv/enes/orang/OrangException.java b/core/src/main/java/lv/enes/orang/core/OrangException.java
index 9308643..d634fca 100644
--- a/src/main/java/lv/enes/orang/OrangException.java
+++ b/core/src/main/java/lv/enes/orang/core/OrangException.java
@@ -1,4 +1,4 @@
1package lv.enes.orang; 1package lv.enes.orang.core;
2 2
3public abstract class OrangException extends Exception { 3public abstract class OrangException extends Exception {
4 protected OrangException(String message) { 4 protected OrangException(String message) {
diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java
new file mode 100644
index 0000000..b8b8703
--- /dev/null
+++ b/core/src/main/java/module-info.java
@@ -0,0 +1,3 @@
1module lv.enes.orang.core {
2 exports lv.enes.orang.core;
3} \ No newline at end of file
diff --git a/grammar.bnf b/grammar.bnf
index 256e58a..7c18f8f 100644
--- a/grammar.bnf
+++ b/grammar.bnf
@@ -1,3 +1,5 @@
1// Comments are introduced by # and terminated by newline
2
1program ::= (statement ';'?)*; 3program ::= (statement ';'?)*;
2statement ::= definition | expression; 4statement ::= definition | expression;
3definition ::= 'def' def-spec '=' expression; 5definition ::= 'def' def-spec '=' expression;
diff --git a/build.gradle.kts b/orang/build.gradle.kts
index 212943a..f70609e 100644
--- a/build.gradle.kts
+++ b/orang/build.gradle.kts
@@ -5,6 +5,7 @@ plugins {
5 id("org.beryx.jlink") version "3.0.1" 5 id("org.beryx.jlink") version "3.0.1"
6} 6}
7 7
8val asmVersion = "9.7"
8val slf4jVersion = "2.0.13" 9val slf4jVersion = "2.0.13"
9val jakartaAnnotationVersion = "3.0.0" 10val jakartaAnnotationVersion = "3.0.0"
10 11
@@ -16,9 +17,14 @@ repositories {
16} 17}
17 18
18dependencies { 19dependencies {
20 implementation("org.ow2.asm:asm:$asmVersion")
19 implementation("jakarta.annotation:jakarta.annotation-api:$jakartaAnnotationVersion") 21 implementation("jakarta.annotation:jakarta.annotation-api:$jakartaAnnotationVersion")
20 implementation("org.slf4j:slf4j-api:$slf4jVersion") 22 implementation("org.slf4j:slf4j-api:$slf4jVersion")
21 implementation("org.slf4j:slf4j-simple:$slf4jVersion") 23 implementation("org.slf4j:slf4j-simple:$slf4jVersion")
24
25 implementation(project(":ast"))
26 implementation(project(":core"))
27 implementation(project(":utils"))
22} 28}
23 29
24java { 30java {
diff --git a/src/main/java/lv/enes/orang/Builtins.java b/orang/src/main/java/lv/enes/orang/Builtins.java
index 0a76387..0a76387 100644
--- a/src/main/java/lv/enes/orang/Builtins.java
+++ b/orang/src/main/java/lv/enes/orang/Builtins.java
diff --git a/src/main/java/lv/enes/orang/Codepoint.java b/orang/src/main/java/lv/enes/orang/Codepoint.java
index 0dfaa2b..7157062 100644
--- a/src/main/java/lv/enes/orang/Codepoint.java
+++ b/orang/src/main/java/lv/enes/orang/Codepoint.java
@@ -14,6 +14,10 @@ public record Codepoint(int cp) {
14 return isIdentInitial() || Character.isDigit(cp); 14 return isIdentInitial() || Character.isDigit(cp);
15 } 15 }
16 16
17 public boolean isNewline() {
18 return cp == '\n';
19 }
20
17 public boolean isNumeral() { 21 public boolean isNumeral() {
18 return Character.isDigit(cp); 22 return Character.isDigit(cp);
19 } 23 }
diff --git a/orang/src/main/java/lv/enes/orang/Evaluator.java b/orang/src/main/java/lv/enes/orang/Evaluator.java
new file mode 100644
index 0000000..e2e96ff
--- /dev/null
+++ b/orang/src/main/java/lv/enes/orang/Evaluator.java
@@ -0,0 +1,144 @@
1package lv.enes.orang;
2
3import lv.enes.orang.ast.*;
4import lv.enes.orang.value.*;
5
6import java.util.ArrayList;
7import java.util.Collections;
8
9public record Evaluator(Scope scope, Value lastResult) implements ExpressionVisitor<Value, OrangRuntimeException>, StatementVisitor<Evaluator, OrangRuntimeException> {
10 public Evaluator() {
11 this(Scope.topLevel());
12 }
13
14 public Evaluator(Scope scope) {
15 this(scope, Undefined.INSTANCE);
16 }
17
18 @Override
19 public Value visitArray(ArrayExpression expr) throws OrangRuntimeException {
20 var values = new ArrayList<Value>(expr.items().size());
21 for (var item : expr.items()) {
22 values.add(visit(item));
23 }
24 values.trimToSize();
25 return new Array(Collections.unmodifiableList(values));
26 }
27
28 @Override
29 public Value visitBinaryExpression(BinaryExpression expr) throws OrangRuntimeException {
30 var lhs = visit(expr.lhs());
31 var rhs = visit(expr.rhs());
32 return switch (expr.operator()) {
33 case EQUALS -> lhs.orangEquals(rhs);
34 case NOT_EQUALS -> lhs.notEquals(rhs);
35 case GT -> lhs.greaterThan(rhs);
36 case GTE -> lhs.greaterThanOrEqual(rhs);
37 case LT -> lhs.lessThan(rhs);
38 case LTE -> lhs.lessThanOrEqual(rhs);
39 case ADD -> lhs.add(rhs);
40 case SUBTRACT -> lhs.subtract(rhs);
41 case MULTIPLY -> lhs.multiply(rhs);
42 case DIVIDE -> lhs.divide(rhs);
43 };
44 }
45
46 @Override
47 public Value visitBoolean(BooleanLiteral expr) {
48 return OrangBoolean.of(expr.value());
49 }
50
51 @Override
52 public Value visitCallExpression(CallExpression expr) throws OrangRuntimeException {
53 var arg = visit(expr.arg());
54 return visit(expr.callee()).call(arg);
55 }
56
57 @Override
58 public Evaluator visitDefinition(Definition def) throws OrangRuntimeException {
59 var newScope = MutableScope.of(scope, def.name(), Undefined.INSTANCE);
60 var newEvaluator = new Evaluator(newScope);
61 newScope.setDefinition(def.name(), newEvaluator.visit(def.body()));
62 return newEvaluator;
63 }
64
65 @Override
66 public Value visitDoExpression(DoExpression expr) throws OrangRuntimeException {
67 Value value = Undefined.INSTANCE;
68 for (var child : expr.body()) {
69 value = visit(child);
70 }
71 return value;
72 }
73
74 @Override
75 public Evaluator visitExpression(ExpressionStatement expr) throws OrangRuntimeException {
76 return new Evaluator(this.scope(), visit(expr.expr()));
77 }
78
79 @Override
80 public Value visitFnExpression(FnExpression expr) {
81 return new Function(this.scope, expr.args(), expr.body());
82 }
83
84 @Override
85 public Value visitIfElseExpression(IfElseExpression expr) throws OrangRuntimeException {
86 var cond = visit(expr.condition());
87 if (cond instanceof OrangBoolean value) {
88 if (value.value()) {
89 return visit(expr.trueBranch());
90 } else {
91 return visit(expr.falseBranch());
92 }
93 } else {
94 throw new OrangRuntimeException(STR."Condition in an if-else statement should be a boolean not a \{cond.typeName()}");
95 }
96 }
97
98 @Override
99 public Value visitIntLiteral(IntLiteral expr) {
100 return new OrangInteger(expr.value());
101 }
102
103 @Override
104 public Value visitLetInExpression(LetInExpression expr) throws OrangRuntimeException {
105 var newScope = MutableScope.of(scope);
106 for (var binding : expr.bindings()) {
107 newScope.setDefinition(binding.name(), Undefined.INSTANCE);
108 }
109 var newEvaluator = new Evaluator(newScope);
110 for (var binding : expr.bindings()) {
111 newScope.setDefinition(binding.name(), newEvaluator.visit(binding.value()));
112 }
113 return newEvaluator.visit(expr.body());
114 }
115
116 @Override
117 public Evaluator visitProgram(Program prog) throws OrangRuntimeException {
118 var evaluator = this;
119 for (var statement : prog.statements()) {
120 evaluator = evaluator.visit(statement);
121 }
122 return evaluator;
123 }
124
125 @Override
126 public Value visitUnaryExpression(UnaryExpression expr) throws OrangRuntimeException {
127 var child = visit(expr.child());
128 return switch (expr.operator()) {
129 case PLUS -> child.plus();
130 case NEGATE -> child.negate();
131 case NOT -> child.not();
132 };
133 }
134
135 @Override
136 public Value visitStringLiteral(StringLiteral expr) {
137 return new OrangString(expr.value());
138 }
139
140 @Override
141 public Value visitVariable(VariableExpression expr) throws OrangRuntimeException {
142 return scope.getDefinition(expr.name());
143 }
144}
diff --git a/orang/src/main/java/lv/enes/orang/ImmutableScope.java b/orang/src/main/java/lv/enes/orang/ImmutableScope.java
new file mode 100644
index 0000000..9cb6138
--- /dev/null
+++ b/orang/src/main/java/lv/enes/orang/ImmutableScope.java
@@ -0,0 +1,45 @@
1package lv.enes.orang;
2
3import lv.enes.orang.value.Value;
4
5import java.util.HashMap;
6import java.util.Map;
7
8public 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/src/main/java/lv/enes/orang/Lexer.java b/orang/src/main/java/lv/enes/orang/Lexer.java
index 0ee2503..d4e1533 100644
--- a/src/main/java/lv/enes/orang/Lexer.java
+++ b/orang/src/main/java/lv/enes/orang/Lexer.java
@@ -163,6 +163,12 @@ public class Lexer implements Iterator<Token> {
163 } 163 }
164 164
165 private void skipWhitespace() { 165 private void skipWhitespace() {
166 skipWhile(Codepoint::isWhitespace); 166 while (true) {
167 skipWhile(Codepoint::isWhitespace);
168 if (input.peek().cp() != '#') {
169 return;
170 }
171 skipWhile(cp -> !cp.isNewline());
172 }
167 } 173 }
168} 174}
diff --git a/src/main/java/lv/enes/orang/Main.java b/orang/src/main/java/lv/enes/orang/Main.java
index 9a607ed..7ca14a1 100644
--- a/src/main/java/lv/enes/orang/Main.java
+++ b/orang/src/main/java/lv/enes/orang/Main.java
@@ -1,5 +1,7 @@
1package lv.enes.orang; 1package lv.enes.orang;
2 2
3import lv.enes.orang.core.OrangException;
4
3import java.io.FileReader; 5import java.io.FileReader;
4import java.io.IOException; 6import java.io.IOException;
5 7
@@ -14,11 +16,11 @@ public class Main {
14 } 16 }
15 17
16 private static void repl() throws IOException { 18 private static void repl() throws IOException {
17 var scope = new Scope(); 19 var evaluator = new Evaluator();
18 20
19 try (var stream = Main.class.getResourceAsStream("prelude.orang")) { 21 try (var stream = Main.class.getResourceAsStream("prelude.orang")) {
20 var prog = Parser.parseProgram(stream); 22 var prog = Parser.parseProgram(stream);
21 scope = prog.runStatement(scope); 23 evaluator = evaluator.visitProgram(prog);
22 } catch (OrangException ex) { 24 } catch (OrangException ex) {
23 STDOUT.println(STR."While evaluating prelude: \{ex}"); 25 STDOUT.println(STR."While evaluating prelude: \{ex}");
24 throw new RuntimeException(ex); 26 throw new RuntimeException(ex);
@@ -48,7 +50,7 @@ public class Main {
48 var filename = line.substring(2).trim(); 50 var filename = line.substring(2).trim();
49 try (var reader = new FileReader((filename))) { 51 try (var reader = new FileReader((filename))) {
50 var prog = Parser.parseProgram(reader); 52 var prog = Parser.parseProgram(reader);
51 scope = prog.runStatement(scope); 53 evaluator = evaluator.visitProgram(prog);
52 } catch (IOException | OrangException ex) { 54 } catch (IOException | OrangException ex) {
53 STDOUT.println(ex); 55 STDOUT.println(ex);
54 } 56 }
@@ -64,10 +66,10 @@ public class Main {
64 66
65 try { 67 try {
66 var prog = Parser.parseProgram(line); 68 var prog = Parser.parseProgram(line);
67 scope = prog.runStatement(scope); 69 evaluator = evaluator.visitProgram(prog);
68 if (scope.getLastResult() != null) { 70 if (evaluator.lastResult() != null) {
69 STDOUT.print("-> "); 71 STDOUT.print("-> ");
70 STDOUT.println(scope.getLastResult().stringify()); 72 STDOUT.println(evaluator.lastResult().stringify());
71 } 73 }
72 } catch (OrangException ex) { 74 } catch (OrangException ex) {
73 STDOUT.println(ex); 75 STDOUT.println(ex);
diff --git a/orang/src/main/java/lv/enes/orang/MutableScope.java b/orang/src/main/java/lv/enes/orang/MutableScope.java
new file mode 100644
index 0000000..8d900a4
--- /dev/null
+++ b/orang/src/main/java/lv/enes/orang/MutableScope.java
@@ -0,0 +1,24 @@
1package lv.enes.orang;
2
3import lv.enes.orang.value.Value;
4
5import java.util.HashMap;
6import java.util.Map;
7
8public 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/src/main/java/lv/enes/orang/OrangRuntimeException.java b/orang/src/main/java/lv/enes/orang/OrangRuntimeException.java
index 9648c30..8a7d575 100644
--- a/src/main/java/lv/enes/orang/OrangRuntimeException.java
+++ b/orang/src/main/java/lv/enes/orang/OrangRuntimeException.java
@@ -1,5 +1,7 @@
1package lv.enes.orang; 1package lv.enes.orang;
2 2
3import lv.enes.orang.core.OrangException;
4
3public class OrangRuntimeException extends OrangException { 5public class OrangRuntimeException extends OrangException {
4 public OrangRuntimeException(String message) { 6 public OrangRuntimeException(String message) {
5 super(message); 7 super(message);
diff --git a/src/main/java/lv/enes/orang/Parser.java b/orang/src/main/java/lv/enes/orang/Parser.java
index fd4b9bb..4011bd7 100644
--- a/src/main/java/lv/enes/orang/Parser.java
+++ b/orang/src/main/java/lv/enes/orang/Parser.java
@@ -3,6 +3,7 @@ package lv.enes.orang;
3import lv.enes.orang.ast.*; 3import lv.enes.orang.ast.*;
4import lv.enes.orang.ast.IfElseExpression; 4import lv.enes.orang.ast.IfElseExpression;
5import lv.enes.orang.ast.Statement; 5import lv.enes.orang.ast.Statement;
6import lv.enes.orang.utils.NonEmptyList;
6 7
7import java.io.InputStream; 8import java.io.InputStream;
8import java.io.Reader; 9import java.io.Reader;
@@ -253,7 +254,7 @@ public class Parser {
253 if (input.peek().type() == TokenType.DEF) { 254 if (input.peek().type() == TokenType.DEF) {
254 return parseDefinition(); 255 return parseDefinition();
255 } else { 256 } else {
256 return parseExpression(); 257 return new ExpressionStatement(parseExpression());
257 } 258 }
258 } 259 }
259 260
diff --git a/src/main/java/lv/enes/orang/ParserException.java b/orang/src/main/java/lv/enes/orang/ParserException.java
index 9000a93..bd65e7a 100644
--- a/src/main/java/lv/enes/orang/ParserException.java
+++ b/orang/src/main/java/lv/enes/orang/ParserException.java
@@ -1,5 +1,7 @@
1package lv.enes.orang; 1package lv.enes.orang;
2 2
3import lv.enes.orang.core.OrangException;
4
3public class ParserException extends OrangException { 5public class ParserException extends OrangException {
4 public ParserException(String message) { 6 public ParserException(String message) {
5 super(message); 7 super(message);
diff --git a/src/main/java/lv/enes/orang/PeekableStream.java b/orang/src/main/java/lv/enes/orang/PeekableStream.java
index b77bab1..b77bab1 100644
--- a/src/main/java/lv/enes/orang/PeekableStream.java
+++ b/orang/src/main/java/lv/enes/orang/PeekableStream.java
diff --git a/orang/src/main/java/lv/enes/orang/Scope.java b/orang/src/main/java/lv/enes/orang/Scope.java
new file mode 100644
index 0000000..7fe57c7
--- /dev/null
+++ b/orang/src/main/java/lv/enes/orang/Scope.java
@@ -0,0 +1,34 @@
1package lv.enes.orang;
2
3import lv.enes.orang.value.Value;
4
5import java.util.HashMap;
6import java.util.Map;
7
8public abstract class Scope {
9 public static final int MAX_DEPTH = 4;
10
11 protected final Scope parent;
12 protected final Map<String, Value> definitions;
13 protected final int depth;
14
15 public static MutableScope topLevel() {
16 return new MutableScope(null, new HashMap<>(Builtins.BUILTINS));
17 }
18
19 protected Scope(Scope parent, Map<String, Value> definitions) {
20 this.parent = parent;
21 this.definitions = definitions;
22 this.depth = parent == null ? 0 : parent.depth + 1;
23 }
24
25 public Value getDefinition(String name) throws OrangRuntimeException {
26 if (definitions.containsKey(name)) {
27 return definitions.get(name);
28 } else if (parent != null) {
29 return parent.getDefinition(name);
30 } else {
31 throw new OrangRuntimeException(STR."Value named \{name} is not defined!");
32 }
33 }
34}
diff --git a/src/main/java/lv/enes/orang/State.java b/orang/src/main/java/lv/enes/orang/State.java
index 46b115b..46b115b 100644
--- a/src/main/java/lv/enes/orang/State.java
+++ b/orang/src/main/java/lv/enes/orang/State.java
diff --git a/src/main/java/lv/enes/orang/Token.java b/orang/src/main/java/lv/enes/orang/Token.java
index 4456b8f..4456b8f 100644
--- a/src/main/java/lv/enes/orang/Token.java
+++ b/orang/src/main/java/lv/enes/orang/Token.java
diff --git a/src/main/java/lv/enes/orang/TokenType.java b/orang/src/main/java/lv/enes/orang/TokenType.java
index 960435e..960435e 100644
--- a/src/main/java/lv/enes/orang/TokenType.java
+++ b/orang/src/main/java/lv/enes/orang/TokenType.java
diff --git a/src/main/java/lv/enes/orang/value/Array.java b/orang/src/main/java/lv/enes/orang/value/Array.java
index c3b645d..c3b645d 100644
--- a/src/main/java/lv/enes/orang/value/Array.java
+++ b/orang/src/main/java/lv/enes/orang/value/Array.java
diff --git a/src/main/java/lv/enes/orang/value/BuiltinFunction.java b/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java
index 92ccc2e..92ccc2e 100644
--- a/src/main/java/lv/enes/orang/value/BuiltinFunction.java
+++ b/orang/src/main/java/lv/enes/orang/value/BuiltinFunction.java
diff --git a/src/main/java/lv/enes/orang/value/Function.java b/orang/src/main/java/lv/enes/orang/value/Function.java
index 1f288c6..901776e 100644
--- a/src/main/java/lv/enes/orang/value/Function.java
+++ b/orang/src/main/java/lv/enes/orang/value/Function.java
@@ -1,5 +1,7 @@
1package lv.enes.orang.value; 1package lv.enes.orang.value;
2 2
3import lv.enes.orang.Evaluator;
4import lv.enes.orang.ImmutableScope;
3import lv.enes.orang.OrangRuntimeException; 5import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope; 6import lv.enes.orang.Scope;
5import lv.enes.orang.ast.Expression; 7import lv.enes.orang.ast.Expression;
@@ -20,7 +22,8 @@ public record Function(Scope scope, List<String> args, Expression body) implemen
20 @Override 22 @Override
21 public Value call(Value param) throws OrangRuntimeException { 23 public Value call(Value param) throws OrangRuntimeException {
22 if (args.size() == 1) { 24 if (args.size() == 1) {
23 return body.evaluateExpression(scope.withDefinition(args.getFirst(), param)); 25 var eval = new Evaluator(ImmutableScope.of(scope, args.getFirst(), param));
26 return eval.visit(body);
24 } else { 27 } else {
25 return new PartialFunction(scope, args, List.of(param), body); 28 return new PartialFunction(scope, args, List.of(param), body);
26 } 29 }
diff --git a/src/main/java/lv/enes/orang/value/OrangBoolean.java b/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java
index 8a4776c..8a4776c 100644
--- a/src/main/java/lv/enes/orang/value/OrangBoolean.java
+++ b/orang/src/main/java/lv/enes/orang/value/OrangBoolean.java
diff --git a/src/main/java/lv/enes/orang/value/OrangInteger.java b/orang/src/main/java/lv/enes/orang/value/OrangInteger.java
index 9b8d505..9b8d505 100644
--- a/src/main/java/lv/enes/orang/value/OrangInteger.java
+++ b/orang/src/main/java/lv/enes/orang/value/OrangInteger.java
diff --git a/src/main/java/lv/enes/orang/value/OrangString.java b/orang/src/main/java/lv/enes/orang/value/OrangString.java
index c03f7ac..c03f7ac 100644
--- a/src/main/java/lv/enes/orang/value/OrangString.java
+++ b/orang/src/main/java/lv/enes/orang/value/OrangString.java
diff --git a/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java b/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java
index 37278a4..37278a4 100644
--- a/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java
+++ b/orang/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java
diff --git a/src/main/java/lv/enes/orang/value/PartialFunction.java b/orang/src/main/java/lv/enes/orang/value/PartialFunction.java
index 59e1466..0dbf530 100644
--- a/src/main/java/lv/enes/orang/value/PartialFunction.java
+++ b/orang/src/main/java/lv/enes/orang/value/PartialFunction.java
@@ -1,5 +1,7 @@
1package lv.enes.orang.value; 1package lv.enes.orang.value;
2 2
3import lv.enes.orang.Evaluator;
4import lv.enes.orang.ImmutableScope;
3import lv.enes.orang.OrangRuntimeException; 5import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope; 6import lv.enes.orang.Scope;
5import lv.enes.orang.ast.Expression; 7import lv.enes.orang.ast.Expression;
@@ -29,7 +31,8 @@ public record PartialFunction(Scope scope, List<String> args, List<Value> params
29 for (var i = 0; i < args.size(); i++) { 31 for (var i = 0; i < args.size(); i++) {
30 newDefs.put(args.get(i), newParams.get(i)); 32 newDefs.put(args.get(i), newParams.get(i));
31 } 33 }
32 return body.evaluateExpression(scope.withDefinitions(newDefs)); 34 var eval = new Evaluator(ImmutableScope.of(scope, newDefs));
35 return eval.visit(body);
33 } 36 }
34 37
35 return new PartialFunction(scope, args, Collections.unmodifiableList(newParams), body); 38 return new PartialFunction(scope, args, Collections.unmodifiableList(newParams), body);
diff --git a/src/main/java/lv/enes/orang/value/Undefined.java b/orang/src/main/java/lv/enes/orang/value/Undefined.java
index a341ee8..a341ee8 100644
--- a/src/main/java/lv/enes/orang/value/Undefined.java
+++ b/orang/src/main/java/lv/enes/orang/value/Undefined.java
diff --git a/src/main/java/lv/enes/orang/value/Value.java b/orang/src/main/java/lv/enes/orang/value/Value.java
index fa8275c..fa8275c 100644
--- a/src/main/java/lv/enes/orang/value/Value.java
+++ b/orang/src/main/java/lv/enes/orang/value/Value.java
diff --git a/src/main/java/module-info.java b/orang/src/main/java/module-info.java
index a4bdb66..060657f 100644
--- a/src/main/java/module-info.java
+++ b/orang/src/main/java/module-info.java
@@ -1,5 +1,10 @@
1module lv.enes.orang { 1module lv.enes.orang {
2 exports lv.enes.orang; 2 exports lv.enes.orang;
3 exports lv.enes.orang.value;
4
5 requires lv.enes.orang.ast;
6 requires lv.enes.orang.core;
7 requires lv.enes.orang.utils;
3 8
4 requires static jakarta.annotation; 9 requires static jakarta.annotation;
5 requires static lombok; 10 requires static lombok;
diff --git a/src/main/resources/lv/enes/orang/prelude.orang b/orang/src/main/resources/lv/enes/orang/prelude.orang
index 36bf197..d29eef3 100644
--- a/src/main/resources/lv/enes/orang/prelude.orang
+++ b/orang/src/main/resources/lv/enes/orang/prelude.orang
@@ -1,12 +1,16 @@
1# builtins
1def isRepl = __builtin_isRepl () 2def isRepl = __builtin_isRepl ()
2def len arrayOrString = __builtin_len arrayOrString 3def len arrayOrString = __builtin_len arrayOrString
3def parseInt stringOrInt = __builtin_parseInt stringOrInt 4def parseInt stringOrInt = __builtin_parseInt stringOrInt
4def print anything = __builtin_print anything 5def print anything = __builtin_print anything
5def printLn x = do print x; print "\n"; x end
6def randInt min max = __builtin_randInt min max 6def randInt min max = __builtin_randInt min max
7def readInt _ = parseInt (readLn ())
8def readLn _ = __builtin_readLn () 7def readLn _ = __builtin_readLn ()
9 8
9# standard library
10def readInt _ = parseInt (readLn ())
11def printLn x = do print x; print "\n"; x end
12
13# repl intro :)
10def _ = 14def _ =
11 if isRepl then do 15 if isRepl then do
12 printLn "Hello! This is the Orang Programming Language!"; 16 printLn "Hello! This is the Orang Programming Language!";
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 4c4ac7d..fc692fa 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,2 +1,3 @@
1rootProject.name = "orang" 1rootProject.name = "orang"
2 2
3include("ast", "core", "orang", "utils") \ No newline at end of file
diff --git a/src/main/java/lv/enes/orang/Scope.java b/src/main/java/lv/enes/orang/Scope.java
deleted file mode 100644
index 3625c69..0000000
--- a/src/main/java/lv/enes/orang/Scope.java
+++ /dev/null
@@ -1,54 +0,0 @@
1package lv.enes.orang;
2
3import jakarta.annotation.Nullable;
4import lv.enes.orang.value.Value;
5
6import java.util.HashMap;
7import java.util.Map;
8
9public class Scope {
10 private final Map<String, Value> definitions;
11
12 private final Value lastResult;
13
14 public Scope() {
15 this(new HashMap<>(Builtins.BUILTINS), null);
16 }
17
18 private Scope(Map<String, Value> definitions, Value lastResult) {
19 this.definitions = definitions;
20 this.lastResult = lastResult;
21 }
22
23 public Value getDefinition(String name) throws OrangRuntimeException {
24 if (definitions.containsKey(name)) {
25 return definitions.get(name);
26 }
27 throw new OrangRuntimeException(STR."Value named \{name} is not defined!");
28 }
29
30 @Nullable
31 public Value getLastResult() {
32 return lastResult;
33 }
34
35 public Scope withDefinition(String key, Value value) {
36 var newDefs = new HashMap<>(definitions);
37 newDefs.put(key, value);
38 return new Scope(newDefs, null);
39 }
40
41 public Scope withDefinitions(Map<String, Value> definitions) {
42 var newDefs = new HashMap<>(this.definitions);
43 newDefs.putAll(definitions);
44 return new Scope(newDefs, null);
45 }
46
47 public void setDefinition(String key, Value value) {
48 definitions.put(key, value);
49 }
50
51 public Scope withLastResult(Value value) {
52 return new Scope(definitions, value);
53 }
54}
diff --git a/src/main/java/lv/enes/orang/ast/ArrayExpression.java b/src/main/java/lv/enes/orang/ast/ArrayExpression.java
deleted file mode 100644
index d2437cf..0000000
--- a/src/main/java/lv/enes/orang/ast/ArrayExpression.java
+++ /dev/null
@@ -1,21 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Array;
6import lv.enes.orang.value.Value;
7
8import java.util.ArrayList;
9import java.util.Collections;
10import java.util.List;
11
12public record ArrayExpression(List<Expression> items) implements Expression {
13 @Override
14 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
15 var values = new ArrayList<Value>();
16 for (var item : items) {
17 values.add(item.evaluateExpression(scope));
18 }
19 return new Array(Collections.unmodifiableList(values));
20 }
21}
diff --git a/src/main/java/lv/enes/orang/ast/BooleanLiteral.java b/src/main/java/lv/enes/orang/ast/BooleanLiteral.java
deleted file mode 100644
index 9110f67..0000000
--- a/src/main/java/lv/enes/orang/ast/BooleanLiteral.java
+++ /dev/null
@@ -1,12 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.Scope;
4import lv.enes.orang.value.OrangBoolean;
5import lv.enes.orang.value.Value;
6
7public record BooleanLiteral(boolean value) implements Expression {
8 @Override
9 public Value evaluateExpression(Scope scope) {
10 return OrangBoolean.of(value);
11 }
12}
diff --git a/src/main/java/lv/enes/orang/ast/CallExpression.java b/src/main/java/lv/enes/orang/ast/CallExpression.java
deleted file mode 100644
index 8f05496..0000000
--- a/src/main/java/lv/enes/orang/ast/CallExpression.java
+++ /dev/null
@@ -1,12 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Value;
6
7public record CallExpression(Expression callee, Expression arg) implements Expression {
8 @Override
9 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
10 return callee.evaluateExpression(scope).call(arg.evaluateExpression(scope));
11 }
12}
diff --git a/src/main/java/lv/enes/orang/ast/Definition.java b/src/main/java/lv/enes/orang/ast/Definition.java
deleted file mode 100644
index 715daae..0000000
--- a/src/main/java/lv/enes/orang/ast/Definition.java
+++ /dev/null
@@ -1,15 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Undefined;
6
7public record Definition(String name, Expression body) implements Statement {
8 @Override
9 public Scope runStatement(Scope scope) throws OrangRuntimeException {
10 scope.setDefinition(name, Undefined.INSTANCE);
11 var value = body.evaluateExpression(scope);
12 scope.setDefinition(name, value);
13 return scope;
14 }
15}
diff --git a/src/main/java/lv/enes/orang/ast/DoExpression.java b/src/main/java/lv/enes/orang/ast/DoExpression.java
deleted file mode 100644
index 9d69a3e..0000000
--- a/src/main/java/lv/enes/orang/ast/DoExpression.java
+++ /dev/null
@@ -1,19 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Value;
6
7import java.util.List;
8
9public record DoExpression(List<Expression> body) implements Expression {
10 // assert body.!isEmpty()
11
12 @Override
13 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
14 for (var i = 0; i < body.size() - 1; i++) {
15 body.get(i).evaluateExpression(scope);
16 }
17 return body.getLast().evaluateExpression(scope);
18 }
19}
diff --git a/src/main/java/lv/enes/orang/ast/Expression.java b/src/main/java/lv/enes/orang/ast/Expression.java
deleted file mode 100644
index a0fc3af..0000000
--- a/src/main/java/lv/enes/orang/ast/Expression.java
+++ /dev/null
@@ -1,14 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Value;
6
7public interface Expression extends Statement {
8 Value evaluateExpression(Scope scope) throws OrangRuntimeException;
9
10 @Override
11 default Scope runStatement(Scope scope) throws OrangRuntimeException {
12 return scope.withLastResult(evaluateExpression(scope));
13 }
14}
diff --git a/src/main/java/lv/enes/orang/ast/FnExpression.java b/src/main/java/lv/enes/orang/ast/FnExpression.java
deleted file mode 100644
index 3c3522f..0000000
--- a/src/main/java/lv/enes/orang/ast/FnExpression.java
+++ /dev/null
@@ -1,14 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.NonEmptyList;
4import lv.enes.orang.OrangRuntimeException;
5import lv.enes.orang.Scope;
6import lv.enes.orang.value.Function;
7import lv.enes.orang.value.Value;
8
9public record FnExpression(NonEmptyList<String> args, Expression body) implements Expression {
10 @Override
11 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
12 return new Function(scope, args, body);
13 }
14}
diff --git a/src/main/java/lv/enes/orang/ast/IfElseExpression.java b/src/main/java/lv/enes/orang/ast/IfElseExpression.java
deleted file mode 100644
index 9b52cc5..0000000
--- a/src/main/java/lv/enes/orang/ast/IfElseExpression.java
+++ /dev/null
@@ -1,22 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.OrangBoolean;
6import lv.enes.orang.value.Value;
7
8public record IfElseExpression(Expression condition, Expression trueBranch, Expression falseBranch) implements Expression {
9 @Override
10 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
11 var condValue = condition.evaluateExpression(scope);
12 if (condValue instanceof OrangBoolean value) {
13 if (value.value()) {
14 return trueBranch.evaluateExpression(scope);
15 } else {
16 return falseBranch.evaluateExpression(scope);
17 }
18 } else {
19 throw new OrangRuntimeException(STR."Condition in an if should be a Boolean not a \{condValue.typeName()}");
20 }
21 }
22}
diff --git a/src/main/java/lv/enes/orang/ast/IntLiteral.java b/src/main/java/lv/enes/orang/ast/IntLiteral.java
deleted file mode 100644
index 339ba3b..0000000
--- a/src/main/java/lv/enes/orang/ast/IntLiteral.java
+++ /dev/null
@@ -1,12 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.Scope;
4import lv.enes.orang.value.OrangInteger;
5import lv.enes.orang.value.Value;
6
7public record IntLiteral(int value) implements Expression {
8 @Override
9 public Value evaluateExpression(Scope scope) {
10 return new OrangInteger(value);
11 }
12}
diff --git a/src/main/java/lv/enes/orang/ast/LetInExpression.java b/src/main/java/lv/enes/orang/ast/LetInExpression.java
deleted file mode 100644
index 2379902..0000000
--- a/src/main/java/lv/enes/orang/ast/LetInExpression.java
+++ /dev/null
@@ -1,27 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Undefined;
6import lv.enes.orang.value.Value;
7
8import java.util.HashMap;
9import java.util.List;
10
11public record LetInExpression(List<Binding> bindings, Expression body) implements Expression {
12 @Override
13 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
14 var newDefs = new HashMap<String, Value>();
15 for (var binding : bindings) {
16 newDefs.put(binding.name, Undefined.INSTANCE);
17 }
18 var newState = scope.withDefinitions(newDefs);
19 for (var binding : bindings) {
20 var value = binding.value.evaluateExpression(newState);
21 newState.setDefinition(binding.name, value);
22 }
23 return body.evaluateExpression(newState);
24 }
25
26 public record Binding(String name, Expression value) {}
27}
diff --git a/src/main/java/lv/enes/orang/ast/Program.java b/src/main/java/lv/enes/orang/ast/Program.java
deleted file mode 100644
index ae5d31e..0000000
--- a/src/main/java/lv/enes/orang/ast/Program.java
+++ /dev/null
@@ -1,17 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5
6import java.util.List;
7
8public record Program(List<Statement> statements) implements Statement {
9 @Override
10 public Scope runStatement(Scope inScope) throws OrangRuntimeException {
11 var state = inScope;
12 for (var statement : statements) {
13 state = statement.runStatement(state);
14 }
15 return state;
16 }
17}
diff --git a/src/main/java/lv/enes/orang/ast/Statement.java b/src/main/java/lv/enes/orang/ast/Statement.java
deleted file mode 100644
index 0f52fc3..0000000
--- a/src/main/java/lv/enes/orang/ast/Statement.java
+++ /dev/null
@@ -1,8 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5
6public interface Statement {
7 Scope runStatement(Scope scope) throws OrangRuntimeException;
8}
diff --git a/src/main/java/lv/enes/orang/ast/StringLiteral.java b/src/main/java/lv/enes/orang/ast/StringLiteral.java
deleted file mode 100644
index 367dff5..0000000
--- a/src/main/java/lv/enes/orang/ast/StringLiteral.java
+++ /dev/null
@@ -1,13 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.OrangString;
6import lv.enes.orang.value.Value;
7
8public record StringLiteral(String value) implements Expression {
9 @Override
10 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
11 return new OrangString(value);
12 }
13}
diff --git a/src/main/java/lv/enes/orang/ast/UnaryExpression.java b/src/main/java/lv/enes/orang/ast/UnaryExpression.java
deleted file mode 100644
index a0f565b..0000000
--- a/src/main/java/lv/enes/orang/ast/UnaryExpression.java
+++ /dev/null
@@ -1,23 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Value;
6
7public record UnaryExpression(Operator operator, Expression child) implements Expression {
8 public enum Operator {
9 PLUS,
10 NEGATE,
11 NOT,
12 }
13
14 @Override
15 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
16 var child = child().evaluateExpression(scope);
17 return switch (operator) {
18 case PLUS -> child.plus();
19 case NEGATE -> child.negate();
20 case NOT -> child.not();
21 };
22 }
23}
diff --git a/src/main/java/lv/enes/orang/ast/VariableExpression.java b/src/main/java/lv/enes/orang/ast/VariableExpression.java
deleted file mode 100644
index 1f5334d..0000000
--- a/src/main/java/lv/enes/orang/ast/VariableExpression.java
+++ /dev/null
@@ -1,12 +0,0 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.OrangRuntimeException;
4import lv.enes.orang.Scope;
5import lv.enes.orang.value.Value;
6
7public record VariableExpression(String name) implements Expression {
8 @Override
9 public Value evaluateExpression(Scope scope) throws OrangRuntimeException {
10 return scope.getDefinition(name);
11 }
12}
diff --git a/utils/build.gradle.kts b/utils/build.gradle.kts
new file mode 100644
index 0000000..04cda43
--- /dev/null
+++ b/utils/build.gradle.kts
@@ -0,0 +1,20 @@
1plugins {
2 java
3 id("io.freefair.lombok") version "8.6"
4}
5
6repositories {
7 mavenCentral()
8}
9
10java {
11 sourceCompatibility = JavaVersion.VERSION_22
12 targetCompatibility = JavaVersion.VERSION_22
13 toolchain {
14 languageVersion = JavaLanguageVersion.of(22)
15 }
16}
17
18tasks.withType<JavaCompile> {
19 options.compilerArgs.add("--enable-preview")
20} \ No newline at end of file
diff --git a/src/main/java/lv/enes/orang/NonEmptyList.java b/utils/src/main/java/lv/enes/orang/utils/NonEmptyList.java
index 860db28..197491f 100644
--- a/src/main/java/lv/enes/orang/NonEmptyList.java
+++ b/utils/src/main/java/lv/enes/orang/utils/NonEmptyList.java
@@ -1,4 +1,4 @@
1package lv.enes.orang; 1package lv.enes.orang.utils;
2 2
3import lombok.EqualsAndHashCode; 3import lombok.EqualsAndHashCode;
4 4
diff --git a/utils/src/main/java/module-info.java b/utils/src/main/java/module-info.java
new file mode 100644
index 0000000..47e37e0
--- /dev/null
+++ b/utils/src/main/java/module-info.java
@@ -0,0 +1,5 @@
1module lv.enes.orang.utils {
2 exports lv.enes.orang.utils;
3
4 requires static lombok;
5} \ No newline at end of file