diff --git a/flake.nix b/flake.nix
index d6a67e9..b9c7f63 100644
--- a/flake.nix
+++ b/flake.nix
@@ -15,6 +15,7 @@
gcc = pkgs.gcc;
openjdk = pkgs.openjdk;
maven = pkgs.maven;
+ antlr = pkgs.antlr;
in
{
devShell = pkgs.mkShell {
@@ -22,6 +23,7 @@
gcc
openjdk
maven
+ antlr
];
};
}
diff --git a/jlox/lox/pom.xml b/jlox/lox/pom.xml
index 1cdd51d..c547c2f 100644
--- a/jlox/lox/pom.xml
+++ b/jlox/lox/pom.xml
@@ -6,11 +6,11 @@
xyz.ctsk.lox
- lox
+ jlox
1.0-SNAPSHOT
- interpreter
+ lox
jar
diff --git a/jlox/pom.xml b/jlox/pom.xml
index 0927d0a..922fe39 100644
--- a/jlox/pom.xml
+++ b/jlox/pom.xml
@@ -2,7 +2,7 @@
4.0.0
xyz.ctsk.lox
- lox
+ jlox
1.0-SNAPSHOT
pom
@@ -10,6 +10,7 @@
tools
lox
+ tlox
diff --git a/jlox/tlox/pom.xml b/jlox/tlox/pom.xml
new file mode 100644
index 0000000..a96ad22
--- /dev/null
+++ b/jlox/tlox/pom.xml
@@ -0,0 +1,57 @@
+
+
+
+ 4.0.0
+
+
+ xyz.ctsk.lox
+ jlox
+ 1.0-SNAPSHOT
+
+
+ tlox
+ jar
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ org.graalvm.truffle
+ truffle-api
+ 22.2.0
+
+
+ org.antlr
+ antlr4
+ 4.11.1
+
+
+
+
+
+
+ org.antlr
+ antlr4-maven-plugin
+ 4.11.1
+
+ src/main/resources
+
+
+
+ antlr
+
+ antlr4
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/Main.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/Main.java
new file mode 100644
index 0000000..96f26af
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/Main.java
@@ -0,0 +1,38 @@
+package xyz.ctsk.lox;
+
+import com.oracle.truffle.api.Truffle;
+import xyz.ctsk.lox.nodes.LoxRootNode;
+import xyz.ctsk.lox.parser.LoxParser;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class Main {
+
+ public static void repl() throws IOException {
+ var input = new InputStreamReader(System.in);
+ var reader = new BufferedReader(input);
+
+ while (true) {
+ System.out.print(" >> ");
+ var line = reader.readLine();
+ if (line == null) break;
+ run(line);
+ }
+ }
+
+ public static void run(String program) {
+ var parsed = LoxParser.parseLox(program);
+
+ if (parsed instanceof LoxParser.ExpressionContext expr) {
+ var root = new LoxRootNode(expr.result);
+ var callTarget = root.getCallTarget();
+ System.out.println(callTarget.call());
+ }
+ }
+
+ public static void main(String[] args) throws IOException {
+ repl();
+ }
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxExpressionNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxExpressionNode.java
new file mode 100644
index 0000000..75de126
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxExpressionNode.java
@@ -0,0 +1,7 @@
+package xyz.ctsk.lox.nodes;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+
+public abstract class LoxExpressionNode extends LoxNode {
+ public abstract double executeDouble(VirtualFrame frame);
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxNode.java
new file mode 100644
index 0000000..d186c3e
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxNode.java
@@ -0,0 +1,6 @@
+package xyz.ctsk.lox.nodes;
+
+import com.oracle.truffle.api.nodes.Node;
+
+public class LoxNode extends Node {
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxRootNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxRootNode.java
new file mode 100644
index 0000000..c83bcd9
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/LoxRootNode.java
@@ -0,0 +1,20 @@
+package xyz.ctsk.lox.nodes;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.RootNode;
+
+public class LoxRootNode extends RootNode {
+ @SuppressWarnings("FieldMayBeFinal")
+ @Child
+ private LoxExpressionNode exprNode;
+
+ public LoxRootNode(LoxExpressionNode exprNode) {
+ super(null);
+ this.exprNode = exprNode;
+ }
+
+ @Override
+ public Object execute(VirtualFrame frame) {
+ return this.exprNode.executeDouble(frame);
+ }
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxAddNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxAddNode.java
new file mode 100644
index 0000000..3b0c25c
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxAddNode.java
@@ -0,0 +1,24 @@
+package xyz.ctsk.lox.nodes.expr;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import xyz.ctsk.lox.nodes.LoxExpressionNode;
+
+public class LoxAddNode extends LoxExpressionNode {
+ @SuppressWarnings("FieldMayBeFinal")
+ @Node.Child
+ private LoxExpressionNode leftNode, rightNode;
+
+ public LoxAddNode(LoxExpressionNode leftNode, LoxExpressionNode rightNode) {
+ this.leftNode = leftNode;
+ this.rightNode = rightNode;
+ }
+
+
+ @Override
+ public double executeDouble(VirtualFrame frame) {
+ var leftValue = leftNode.executeDouble(frame);
+ var rightValue = rightNode.executeDouble(frame);
+ return leftValue + rightValue;
+ }
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxDivNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxDivNode.java
new file mode 100644
index 0000000..93e5dfa
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxDivNode.java
@@ -0,0 +1,22 @@
+package xyz.ctsk.lox.nodes.expr;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import xyz.ctsk.lox.nodes.LoxExpressionNode;
+
+public class LoxDivNode extends LoxExpressionNode {
+ @SuppressWarnings("FieldMayBeFinal")
+ @Child
+ private LoxExpressionNode leftNode, rightNode;
+
+ public LoxDivNode(LoxExpressionNode leftNode, LoxExpressionNode rightNode) {
+ this.leftNode = leftNode;
+ this.rightNode = rightNode;
+ }
+
+ @Override
+ public double executeDouble(VirtualFrame frame) {
+ var leftValue = leftNode.executeDouble(frame);
+ var rightValue = rightNode.executeDouble(frame);
+ return leftValue / rightValue;
+ }
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxMulNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxMulNode.java
new file mode 100644
index 0000000..948bf36
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxMulNode.java
@@ -0,0 +1,22 @@
+package xyz.ctsk.lox.nodes.expr;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import xyz.ctsk.lox.nodes.LoxExpressionNode;
+
+public class LoxMulNode extends LoxExpressionNode {
+ @SuppressWarnings("FieldMayBeFinal")
+ @Child
+ private LoxExpressionNode leftNode, rightNode;
+
+ public LoxMulNode(LoxExpressionNode leftNode, LoxExpressionNode rightNode) {
+ this.leftNode = leftNode;
+ this.rightNode = rightNode;
+ }
+
+ @Override
+ public double executeDouble(VirtualFrame frame) {
+ var leftValue = leftNode.executeDouble(frame);
+ var rightValue = rightNode.executeDouble(frame);
+ return leftValue * rightValue;
+ }
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxNumberLiteralNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxNumberLiteralNode.java
new file mode 100644
index 0000000..c90e3fd
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxNumberLiteralNode.java
@@ -0,0 +1,16 @@
+package xyz.ctsk.lox.nodes.expr;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import xyz.ctsk.lox.nodes.LoxExpressionNode;
+
+public class LoxNumberLiteralNode extends LoxExpressionNode {
+ private final double value;
+
+ public LoxNumberLiteralNode(double value) {
+ this.value = value;
+ }
+
+ public double executeDouble(VirtualFrame frame) {
+ return this.value;
+ }
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxSubNode.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxSubNode.java
new file mode 100644
index 0000000..d6917b3
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/nodes/expr/LoxSubNode.java
@@ -0,0 +1,22 @@
+package xyz.ctsk.lox.nodes.expr;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import xyz.ctsk.lox.nodes.LoxExpressionNode;
+
+public class LoxSubNode extends LoxExpressionNode {
+ @SuppressWarnings("FieldMayBeFinal")
+ @Child
+ private LoxExpressionNode leftNode, rightNode;
+
+ public LoxSubNode(LoxExpressionNode leftNode, LoxExpressionNode rightNode) {
+ this.leftNode = leftNode;
+ this.rightNode = rightNode;
+ }
+
+ @Override
+ public double executeDouble(VirtualFrame frame) {
+ var leftValue = leftNode.executeDouble(frame);
+ var rightValue = rightNode.executeDouble(frame);
+ return leftValue - rightValue;
+ }
+}
diff --git a/jlox/tlox/src/main/java/xyz/ctsk/lox/parser/LoxNodeFactory.java b/jlox/tlox/src/main/java/xyz/ctsk/lox/parser/LoxNodeFactory.java
new file mode 100644
index 0000000..263cdf1
--- /dev/null
+++ b/jlox/tlox/src/main/java/xyz/ctsk/lox/parser/LoxNodeFactory.java
@@ -0,0 +1,22 @@
+package xyz.ctsk.lox.parser;
+
+import org.antlr.v4.runtime.Token;
+import xyz.ctsk.lox.nodes.LoxExpressionNode;
+import xyz.ctsk.lox.nodes.expr.*;
+
+public class LoxNodeFactory {
+ public static LoxNumberLiteralNode createNumberLiteral(Token literalToken) {
+ var value = Double.parseDouble(literalToken.getText());
+ return new LoxNumberLiteralNode(value);
+ }
+
+ public static LoxExpressionNode createBinaryNode(Token op, LoxExpressionNode left, LoxExpressionNode right) {
+ return switch (op.getText()) {
+ case "+" -> new LoxAddNode(left, right);
+ case "-" -> new LoxSubNode(left, right);
+ case "*" -> new LoxMulNode(left, right);
+ case "/" -> new LoxDivNode(left, right);
+ default -> null;
+ };
+ }
+}
diff --git a/jlox/tlox/src/main/resources/xyz/ctsk/lox/parser/Lox.g4 b/jlox/tlox/src/main/resources/xyz/ctsk/lox/parser/Lox.g4
new file mode 100644
index 0000000..d5b2e85
--- /dev/null
+++ b/jlox/tlox/src/main/resources/xyz/ctsk/lox/parser/Lox.g4
@@ -0,0 +1,92 @@
+grammar Lox;
+
+
+@parser::header {
+
+import com.oracle.truffle.api.source.Source;
+
+import xyz.ctsk.lox.nodes.LoxExpressionNode;
+import xyz.ctsk.lox.parser.*;
+
+}
+
+@parser::members {
+ private LoxNodeFactory factory;
+
+ public static Object parseLox(String source) {
+ LoxLexer lexer = new LoxLexer(CharStreams.fromString(source));
+ LoxParser parser = new LoxParser(new CommonTokenStream(lexer));
+
+ parser.factory = new LoxNodeFactory();
+
+ return parser.expression();
+ }
+}
+
+file returns [LoxExpressionNode result]
+ : expression EOF { $result = $expression.result; }
+ ;
+
+expression returns [LoxExpressionNode result]
+ : literal { $result = $literal.result; }
+ | left=expression op=( '*' | '/' ) right=expression { $result = factory.createBinaryNode($op, $left.result, $right.result); }
+ | left=expression op=( '+' | '-' ) right=expression { $result = factory.createBinaryNode($op, $left.result, $right.result); }
+ ;
+
+literal returns [LoxExpressionNode result]
+ : NUMBER { $result = factory.createNumberLiteral($NUMBER); }
+ ;
+
+AND: 'and' ;
+CLASS: 'class' ;
+ELSE: 'else' ;
+FALSE: 'false' ;
+FOR: 'for' ;
+FUN: 'fun' ;
+IF: 'if' ;
+NIL: 'nil' ;
+OR: 'or' ;
+PRINT: 'print' ;
+RETURN: 'return' ;
+SUPER: 'super' ;
+THIS: 'this' ;
+TRUE: 'true' ;
+VAR: 'var' ;
+WHILE: 'while';
+
+LESS: '<' ;
+LESS_EQUAL: '<=';
+GREATER: '>' ;
+GREATER_EQUAL: '>=' ;
+BANG: '!' ;
+BANG_EQUAL: '!=' ;
+EQUAL: '=' ;
+EQUAL_EQUAL: '==' ;
+
+NUMBER
+ : DIGIT+ ('.' DIGIT+)?
+ ;
+
+STRING
+ : '"' ~["]* '"'
+ ;
+
+IDENTIFIER
+ : LETTER ( LETTER | DIGIT | UNDERSCORE )*
+ ;
+
+fragment LETTER
+ : [a-zA-Z]
+ ;
+
+fragment DIGIT
+ : [0-9]
+ ;
+
+fragment UNDERSCORE
+ : '_'
+ ;
+
+WS
+ : [ \t\r\n]+ -> skip
+ ;
\ No newline at end of file
diff --git a/jlox/tools/pom.xml b/jlox/tools/pom.xml
index 60f7dcf..0cee615 100644
--- a/jlox/tools/pom.xml
+++ b/jlox/tools/pom.xml
@@ -6,7 +6,7 @@
xyz.ctsk.lox
- lox
+ jlox
1.0-SNAPSHOT