[tlox] global vars

This commit is contained in:
ctsk
2022-09-15 17:20:23 +02:00
parent 63d502d6f9
commit c8f5edc494
7 changed files with 155 additions and 27 deletions

View File

@@ -1,5 +1,6 @@
package xyz.ctsk.lox; package xyz.ctsk.lox;
import com.oracle.truffle.api.frame.FrameDescriptor;
import xyz.ctsk.lox.nodes.LoxRootNode; import xyz.ctsk.lox.nodes.LoxRootNode;
import xyz.ctsk.lox.parser.LoxParser; import xyz.ctsk.lox.parser.LoxParser;
@@ -22,14 +23,11 @@ public class Main {
} }
public static void run(String program) { public static void run(String program) {
var parsed = LoxParser.parseLox(program); var parseResult = LoxParser.parseLox(program);
var root = new LoxRootNode(parseResult.rootNode(), parseResult.frame());
if (parsed instanceof LoxParser.ExpressionContext expr) {
var root = new LoxRootNode(expr.result);
var callTarget = root.getCallTarget(); var callTarget = root.getCallTarget();
System.out.println(callTarget.call()); System.out.println(callTarget.call());
} }
}
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
repl(); repl();

View File

@@ -1,5 +1,6 @@
package xyz.ctsk.lox.nodes; package xyz.ctsk.lox.nodes;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.RootNode;
@@ -8,8 +9,8 @@ public class LoxRootNode extends RootNode {
@Child @Child
private LoxExpressionNode exprNode; private LoxExpressionNode exprNode;
public LoxRootNode(LoxExpressionNode exprNode) { public LoxRootNode(LoxExpressionNode exprNode, FrameDescriptor frameDescriptor) {
super(null); super(null, frameDescriptor);
this.exprNode = exprNode; this.exprNode = exprNode;
} }

View File

@@ -0,0 +1,26 @@
package xyz.ctsk.lox.nodes.expr;
import com.oracle.truffle.api.dsl.NodeField;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import xyz.ctsk.lox.nodes.LoxExpressionNode;
@NodeField(name = "slot", type = int.class)
public abstract class LoxReadVariableNode extends LoxExpressionNode {
protected abstract int getSlot();
@Specialization(guards = "frame.isDouble(getSlot())")
protected double readDouble(VirtualFrame frame) {
return frame.getLong(getSlot());
}
@Specialization(guards = "frame.isBoolean(getSlot())")
protected boolean readBoolean(VirtualFrame frame) {
return frame.getBoolean(getSlot());
}
@Specialization(replaces = { "readDouble", "readBoolean"})
protected Object readObject(VirtualFrame frame) {
return frame.getObject(getSlot());
}
}

View File

@@ -0,0 +1,45 @@
package xyz.ctsk.lox.nodes.expr;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeField;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.frame.VirtualFrame;
import xyz.ctsk.lox.nodes.LoxExpressionNode;
@NodeChild("valueNode")
@NodeField(name = "slot", type = int.class)
public abstract class LoxWriteVariableNode extends LoxExpressionNode {
protected abstract int getSlot();
@Specialization(guards = "isDoubleOrIllegal(frame)")
protected double writeDouble(VirtualFrame frame, double value) {
frame.getFrameDescriptor().setSlotKind(getSlot(), FrameSlotKind.Double);
frame.setDouble(getSlot(), value);
return value;
}
@Specialization(guards = "isBooleanOrIllegal(frame)")
protected boolean writeBoolean(VirtualFrame frame, boolean value) {
frame.getFrameDescriptor().setSlotKind(getSlot(), FrameSlotKind.Boolean);
frame.setBoolean(getSlot(), value);
return value;
}
@Specialization(replaces = { "writeDouble", "writeBoolean"})
protected Object write(VirtualFrame frame, Object value) {
frame.getFrameDescriptor().setSlotKind(getSlot(), FrameSlotKind.Object);
frame.setObject(getSlot(), value);
return value;
}
protected boolean isDoubleOrIllegal(VirtualFrame frame) {
final FrameSlotKind kind = frame.getFrameDescriptor().getSlotKind(getSlot());
return kind == FrameSlotKind.Double || kind == FrameSlotKind.Illegal;
}
protected boolean isBooleanOrIllegal(VirtualFrame frame) {
final FrameSlotKind kind = frame.getFrameDescriptor().getSlotKind(getSlot());
return kind == FrameSlotKind.Boolean || kind == FrameSlotKind.Illegal;
}
}

View File

@@ -1,31 +1,61 @@
package xyz.ctsk.lox.parser; package xyz.ctsk.lox.parser;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleString;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import xyz.ctsk.lox.nodes.LoxExpressionNode; import xyz.ctsk.lox.nodes.LoxExpressionNode;
import xyz.ctsk.lox.nodes.expr.*; import xyz.ctsk.lox.nodes.expr.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class LoxNodeFactory { public class LoxNodeFactory {
public static LoxNumberLiteralNode createNumberLiteral(Token literalToken) { private static class GlobalScope {
private final Map<TruffleString, Integer> values = new HashMap<>();
private final FrameDescriptor.Builder builder = FrameDescriptor.newBuilder();
Integer find(TruffleString name) {
return values.get(name);
}
int add(TruffleString name) {
var slot = builder.addSlot(FrameSlotKind.Illegal, name, null);
values.put(name, slot);
return slot;
}
Integer findOrAdd(TruffleString name) {
return Optional.ofNullable(find(name)).orElseGet(() -> add(name));
}
FrameDescriptor getFrame() {
return builder.build();
}
}
private final GlobalScope globalScope = new GlobalScope();
public LoxNumberLiteralNode createNumberLiteral(Token literalToken) {
var value = Double.parseDouble(literalToken.getText()); var value = Double.parseDouble(literalToken.getText());
return new LoxNumberLiteralNode(value); return new LoxNumberLiteralNode(value);
} }
public static LoxStringLiteralNode createStringLiteral(Token literalToken) { public LoxStringLiteralNode createStringLiteral(Token literalToken) {
var value = TruffleString.fromJavaStringUncached(literalToken.getText(), TruffleString.Encoding.UTF_16); var value = TruffleString.fromJavaStringUncached(literalToken.getText(), TruffleString.Encoding.UTF_16);
return new LoxStringLiteralNode(value); return new LoxStringLiteralNode(value);
} }
public static LoxBooleanLiteralNode createBooleanLiteral(Token literalToken) { public LoxBooleanLiteralNode createBooleanLiteral(Token literalToken) {
var value = Boolean.parseBoolean(literalToken.getText()); var value = Boolean.parseBoolean(literalToken.getText());
return new LoxBooleanLiteralNode(value); return new LoxBooleanLiteralNode(value);
} }
public static LoxNilLiteralNode createNilLiteral() { public LoxNilLiteralNode createNilLiteral() {
return new LoxNilLiteralNode(); return new LoxNilLiteralNode();
} }
public static LoxExpressionNode createUnary(Token op, LoxExpressionNode value) { public LoxExpressionNode createUnary(Token op, LoxExpressionNode value) {
return switch (op.getText()) { return switch (op.getText()) {
case "-" -> LoxNegNodeGen.create(value); case "-" -> LoxNegNodeGen.create(value);
case "!" -> LoxLogicalNotNodeGen.create(value); case "!" -> LoxLogicalNotNodeGen.create(value);
@@ -33,7 +63,7 @@ public class LoxNodeFactory {
}; };
} }
public static LoxExpressionNode createBinary(Token op, LoxExpressionNode left, LoxExpressionNode right) { public LoxExpressionNode createBinary(Token op, LoxExpressionNode left, LoxExpressionNode right) {
return switch (op.getText()) { return switch (op.getText()) {
case "+" -> LoxAddNodeGen.create(left, right); case "+" -> LoxAddNodeGen.create(left, right);
case "-" -> LoxSubNodeGen.create(left, right); case "-" -> LoxSubNodeGen.create(left, right);
@@ -48,4 +78,20 @@ public class LoxNodeFactory {
default -> null; default -> null;
}; };
} }
public LoxWriteVariableNode createAssignment(Token identifier, LoxExpressionNode value) {
var name = TruffleString.fromJavaStringUncached(identifier.getText(), TruffleString.Encoding.US_ASCII);
var slot = globalScope.findOrAdd(name);
return LoxWriteVariableNodeGen.create(value, slot);
}
public LoxReadVariableNode createRead(Token identifier) {
var name = TruffleString.fromJavaStringUncached(identifier.getText(), TruffleString.Encoding.US_ASCII);
var slot = globalScope.find(name);
return LoxReadVariableNodeGen.create(slot);
}
public FrameDescriptor getFrameDescriptor() {
return globalScope.getFrame();
}
} }

View File

@@ -0,0 +1,6 @@
package xyz.ctsk.lox.parser;
import com.oracle.truffle.api.frame.FrameDescriptor;
import xyz.ctsk.lox.nodes.LoxExpressionNode;
public record ParseResult(LoxExpressionNode rootNode, FrameDescriptor frame) { }

View File

@@ -3,6 +3,7 @@ grammar Lox;
@parser::header { @parser::header {
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.Source;
import xyz.ctsk.lox.nodes.LoxExpressionNode; import xyz.ctsk.lox.nodes.LoxExpressionNode;
@@ -11,16 +12,18 @@ import xyz.ctsk.lox.parser.*;
} }
@parser::members { @parser::members {
private LoxNodeFactory factory; private LoxNodeFactory factory;
public static Object parseLox(String source) { public static ParseResult parseLox(String source) {
LoxLexer lexer = new LoxLexer(CharStreams.fromString(source)); LoxLexer lexer = new LoxLexer(CharStreams.fromString(source));
LoxParser parser = new LoxParser(new CommonTokenStream(lexer)); LoxParser parser = new LoxParser(new CommonTokenStream(lexer));
parser.factory = new LoxNodeFactory(); parser.factory = new LoxNodeFactory();
var root = parser.expression().result;
return parser.expression(); return new ParseResult(root, parser.factory.getFrameDescriptor());
} }
} }
file returns [LoxExpressionNode result] file returns [LoxExpressionNode result]
@@ -41,6 +44,8 @@ expression returns [LoxExpressionNode result]
{ $result = factory.createBinary($op, $left.result, $right.result); } { $result = factory.createBinary($op, $left.result, $right.result); }
| left=expression op=( EQUAL_EQUAL | BANG_EQUAL ) right=expression | left=expression op=( EQUAL_EQUAL | BANG_EQUAL ) right=expression
{ $result = factory.createBinary($op, $left.result, $right.result); } { $result = factory.createBinary($op, $left.result, $right.result); }
| IDENTIFIER EQUAL expression
{ $result = factory.createAssignment($IDENTIFIER, $expression.result); }
; ;
literal returns [LoxExpressionNode result] literal returns [LoxExpressionNode result]
@@ -49,6 +54,7 @@ literal returns [LoxExpressionNode result]
| TRUE { $result = factory.createBooleanLiteral($TRUE); } | TRUE { $result = factory.createBooleanLiteral($TRUE); }
| FALSE { $result = factory.createBooleanLiteral($FALSE); } | FALSE { $result = factory.createBooleanLiteral($FALSE); }
| NIL { $result = factory.createNilLiteral(); } | NIL { $result = factory.createNilLiteral(); }
| IDENTIFIER { $result = factory.createRead($IDENTIFIER); }
; ;
AND: 'and' ; AND: 'and' ;