[tlox] Initial Expression parsing and evaluation

This commit is contained in:
ctsk
2022-09-13 17:31:30 +02:00
parent 1971ccef45
commit 3c12f50b6f
16 changed files with 355 additions and 4 deletions

View File

@@ -6,11 +6,11 @@
<parent>
<groupId>xyz.ctsk.lox</groupId>
<artifactId>lox</artifactId>
<artifactId>jlox</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>interpreter</artifactId>
<artifactId>lox</artifactId>
<packaging>jar</packaging>
<properties>

View File

@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>xyz.ctsk.lox</groupId>
<artifactId>lox</artifactId>
<artifactId>jlox</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
@@ -10,6 +10,7 @@
<modules>
<module>tools</module>
<module>lox</module>
<module>tlox</module>
</modules>
<properties>

57
jlox/tlox/pom.xml Normal file
View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>xyz.ctsk.lox</groupId>
<artifactId>jlox</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>tlox</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-api</artifactId>
<version>22.2.0</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
<version>4.11.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.11.1</version>
<configuration>
<sourceDirectory>src/main/resources</sourceDirectory>
</configuration>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -0,0 +1,6 @@
package xyz.ctsk.lox.nodes;
import com.oracle.truffle.api.nodes.Node;
public class LoxNode extends Node {
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
};
}
}

View File

@@ -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
;

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>xyz.ctsk.lox</groupId>
<artifactId>lox</artifactId>
<artifactId>jlox</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>