Skip to content

Commit

Permalink
Complete functions
Browse files Browse the repository at this point in the history
  • Loading branch information
banshay committed Jul 17, 2022
1 parent 3903ea8 commit d060292
Show file tree
Hide file tree
Showing 23 changed files with 608 additions and 222 deletions.
2 changes: 2 additions & 0 deletions language/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
org.graalvm.truffle/com.oracle.truffle.api.utilities=ALL-UNNAMED
--add-exports
org.graalvm.truffle/com.oracle.truffle.api.profiles=ALL-UNNAMED
--add-exports
org.graalvm.truffle/com.oracle.truffle.api.instrumentation=ALL-UNNAMED
</test.argLine>
<graalvm.version>22.1.0</graalvm.version>
</properties>
Expand Down
23 changes: 23 additions & 0 deletions language/src/main/java/com/banshay/language/FunctionRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.banshay.language.nodes.runtime.WzrdFunction;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

Expand All @@ -10,6 +12,7 @@ public class FunctionRegistry {
private final WzrdLanguage language;

private Map<String, WzrdFunction> functions = new ConcurrentHashMap<>();
private final Map<Map<String, RootCallTarget>, Void> registeredFunctions = new IdentityHashMap<>();

public FunctionRegistry(WzrdLanguage language) {
this.language = language;
Expand All @@ -24,4 +27,24 @@ public WzrdFunction lookup(String name, boolean createIfNotPresent) {
}
return function;
}

WzrdFunction register(String name, RootCallTarget callTarget) {
var function = functions.get(name);
if (function == null) {
function = new WzrdFunction(name, callTarget);
functions.put(name, function);
}else {
function.setCallTarget(callTarget);
}
return function;
}

@TruffleBoundary
public void register(Map<String, RootCallTarget> newFunctions) {
if (registeredFunctions.containsKey(newFunctions)) {
return;
}
newFunctions.forEach(this::register);
registeredFunctions.put(newFunctions, null);
}
}
10 changes: 8 additions & 2 deletions language/src/main/java/com/banshay/language/WzrdLanguage.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.banshay.language;

import com.banshay.language.nodes.WzrdEvalNode;
import com.banshay.language.nodes.WzrdUndefinedFunctionRootNode;
import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

Expand All @@ -33,10 +35,14 @@ public class WzrdLanguage extends TruffleLanguage<WzrdContext> {
protected CallTarget parse(ParsingRequest request) throws Exception {
var functions = WzrdScriptTruffleParser.parse(request.getSource().getReader(), this);
var mainFunction = functions.get("main");
RootNode eval;
if (mainFunction == null) {
throw new RuntimeException("No main function present!");
eval = new WzrdEvalNode(this, functions, null);
}else {
eval = new WzrdEvalNode(this, functions, mainFunction);
}
return mainFunction;

return eval.getCallTarget();
}

public RootCallTarget getOrCreateUndefinedFunction(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,32 @@
import com.banshay.language.literal.StringLiteral;
import com.banshay.language.nodes.WzrdRootNode;
import com.banshay.language.nodes.expressions.AddNodeGen;
import com.banshay.language.nodes.expressions.ArgumentNode;
import com.banshay.language.nodes.expressions.DivisionNodeGen;
import com.banshay.language.nodes.expressions.FunctionBodyNode;
import com.banshay.language.nodes.expressions.GlobalVariableReadNodeGen;
import com.banshay.language.nodes.expressions.FunctionStatementNode;
import com.banshay.language.nodes.expressions.GlobalVariableWriteNodeGen;
import com.banshay.language.nodes.expressions.InvokeNode;
import com.banshay.language.nodes.expressions.LocalVariableReadNodeGen;
import com.banshay.language.nodes.expressions.LocalVariableWriteNodeGen;
import com.banshay.language.nodes.expressions.MultiplicationNodeGen;
import com.banshay.language.nodes.statements.WzrdBlockNode;
import com.banshay.language.nodes.toplevel.WzrdExpressionNode;
import com.banshay.language.nodes.toplevel.WzrdStatementNode;
import com.banshay.language.parser.WZRDLexer;
import com.banshay.language.parser.WZRDParser;
import com.banshay.language.parser.WZRDParser.BindingExpressionContext;
import com.banshay.language.parser.WZRDParser.BlockContext;
import com.banshay.language.parser.WZRDParser.ExpressionContext;
import com.banshay.language.parser.WZRDParser.StatementContext;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameDescriptor.Builder;
import com.oracle.truffle.api.frame.FrameSlotKind;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -30,10 +41,26 @@

public class WzrdScriptTruffleParser {

private Map<String, Object> functionLocals;
private FrameDescriptor frameDescriptor;
static class Scope {
protected final Map<String ,Integer> locals;

public Scope() {
this.locals = new HashMap<>();
}

public Integer find(String name){
//no global support
var result = locals.get(name);
return result;
}
}

private static int addSlot(String name, FrameDescriptor.Builder frameDescBuilder, Scope scope){
var slot = frameDescBuilder.addSlot(FrameSlotKind.Illegal, name, null);
scope.locals.put(name, slot);
return slot;
}

// private static final Map<String, RootCallTarget> allFunctions = new ConcurrentHashMap<>();

public static Map<String, RootCallTarget> parse(String program, WzrdLanguage language) {
return parse(CharStreams.fromString(program), language);
Expand All @@ -56,63 +83,83 @@ public static Map<String, RootCallTarget> parse(CharStream inputStream, WzrdLang
return functionExpressionToTopLevelFunction(expression, language);
}

private static WzrdStatementNode statementToNode(WZRDParser.StatementContext statementContext) {
private static WzrdStatementNode statementToNode(StatementContext statementContext, Builder frameDescriptorBuilder, Scope scope) {
return switch (statementContext) {
case WZRDParser.ExpressionStatementContext e -> expressionToNode(e.expression());
case WZRDParser.FunctionStatementContext f -> functionExpressionToNode(f);
case WZRDParser.ExpressionStatementContext e -> expressionToNode(e.expression(), frameDescriptorBuilder,scope);
case WZRDParser.FunctionStatementContext f -> functionStatementToNode(f);
default -> null;
};
}

private static WzrdExpressionNode functionExpressionToNode(
private static WzrdExpressionNode functionStatementToNode(
WZRDParser.FunctionStatementContext functionStatementContext) {
return null;
var arguments = functionStatementContext.functionLiteral().expression().stream().map(
expressionContext -> expressionToNode(expressionContext, null, null)).toArray(WzrdExpressionNode[]::new);
return new InvokeNode(new FunctionStatementNode(functionStatementContext.functionLiteral().ID().getText()), arguments);
}

private static Map<String, RootCallTarget> functionExpressionToTopLevelFunction(
WZRDParser.WzrdContext context, WzrdLanguage language) {
return context.function().stream()
.map(
function -> {
var frameDescriptorBuilder = FrameDescriptor.newBuilder();
var scope = new Scope();
List<WzrdStatementNode> args = new ArrayList<>();
for (int i = 0; i < function.ID().size(); i++) {
var fnName = function.ID(i).getText();
var slot = addSlot(fnName, frameDescriptorBuilder, scope);
var argumentNode = new ArgumentNode(i);
args.add(LocalVariableWriteNodeGen.create(argumentNode, slot, fnName, true));
}
var wzrdStatementNodes = blockToStatements(function.block(), frameDescriptorBuilder, scope);
args.addAll(wzrdStatementNodes);

var blockNode =
new WzrdBlockNode(
blockToStatements(function.block()).toArray(WzrdStatementNode[]::new));
new WzrdBlockNode(args.toArray(WzrdStatementNode[]::new));
var bodyNode = new FunctionBodyNode(blockNode);
return new WzrdRootNode(
language,
FrameDescriptor.newBuilder().build(),
frameDescriptorBuilder.build(),
function.functionName().ID().getText(),
bodyNode);
})
.collect(Collectors.toMap(WzrdRootNode::getName, WzrdRootNode::getCallTarget));
}

private static List<WzrdStatementNode> blockToStatements(WZRDParser.BlockContext context) {
return context.statement().stream().map(WzrdScriptTruffleParser::statementToNode).toList();
private static List<WzrdStatementNode> blockToStatements(BlockContext context, Builder frameDescriptorBuilder, Scope scope) {
return context.statement().stream().map(statementContext -> statementToNode(statementContext, frameDescriptorBuilder, scope)).toList();
}

private static WzrdExpressionNode expressionToNode(
WZRDParser.ExpressionContext expressionContext) {
ExpressionContext expressionContext, Builder frameDescriptorBuilder, Scope scope) {
return switch (expressionContext) {
case WZRDParser.LiteralExpressionContext l -> literalExpressionToLiteralNode(l.literal());
case WZRDParser.AddExpressionContext a -> AddNodeGen.create(
expressionToNode(a.expression(0)), expressionToNode(a.expression(1)));
expressionToNode(a.expression(0), frameDescriptorBuilder, scope),
expressionToNode(a.expression(1), frameDescriptorBuilder, scope));
case WZRDParser.DivisionExpressionContext d -> DivisionNodeGen.create(
expressionToNode(d.expression(0)), expressionToNode(d.expression(1)));
expressionToNode(d.expression(0), frameDescriptorBuilder, scope),
expressionToNode(d.expression(1), frameDescriptorBuilder, scope));
case WZRDParser.MultiplicationExpressionContext m -> MultiplicationNodeGen.create(
expressionToNode(m.expression(0)), expressionToNode(m.expression(1)));
case WZRDParser.BindingExpressionContext e -> createBinding(e);
case WZRDParser.VariableExpressionContext v -> GlobalVariableReadNodeGen.create(
v.ID().getText());
expressionToNode(m.expression(0), frameDescriptorBuilder, scope),
expressionToNode(m.expression(1), frameDescriptorBuilder, scope));
case WZRDParser.BindingExpressionContext e -> createBinding(e, frameDescriptorBuilder, scope);
case WZRDParser.VariableExpressionContext v -> LocalVariableReadNodeGen.create(scope.find(v.ID().getText()));
default -> null;
};
}

private static WzrdExpressionNode createBinding(BindingExpressionContext bindingExpression) {
// implement reassignment ID = ID
return GlobalVariableWriteNodeGen.create(
expressionToNode(bindingExpression.binding().expression()),
bindingExpression.binding().ID().getText());
private static WzrdExpressionNode createBinding(BindingExpressionContext bindingExpression, FrameDescriptor.Builder frameDescriptorBuilder, Scope scope) {
var name = bindingExpression.binding().ID().getText();
if(frameDescriptorBuilder == null){
return GlobalVariableWriteNodeGen.create(expressionToNode(bindingExpression.binding().expression(), null, null), name);
}
var slot = addSlot(name, frameDescriptorBuilder, scope);
return LocalVariableWriteNodeGen.create(
expressionToNode(bindingExpression.binding().expression(), frameDescriptorBuilder, scope),
slot,
name, true);
}

private static WzrdExpressionNode literalExpressionToLiteralNode(
Expand Down
27 changes: 27 additions & 0 deletions language/src/main/java/com/banshay/language/WzrdTypeSystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.banshay.language;

import com.banshay.language.types.WzrdNull;
import com.oracle.truffle.api.dsl.ImplicitCast;
import com.oracle.truffle.api.dsl.TypeCast;
import com.oracle.truffle.api.dsl.TypeCheck;
import com.oracle.truffle.api.dsl.TypeSystem;

@TypeSystem({int.class, double.class, long.class, boolean.class})
public class WzrdTypeSystem {

@TypeCheck(WzrdNull.class)
public static boolean isNull(Object value) {
return value == WzrdNull.INSTANCE;
}

@TypeCast(WzrdNull.class)
public static WzrdNull asWzrdNull(Object value) {
assert isNull(value);
return WzrdNull.INSTANCE;
}

@ImplicitCast
public static double castInt(int value) {
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.banshay.language.nodes;

import com.banshay.language.WzrdContext;
import com.banshay.language.WzrdLanguage;
import com.banshay.language.types.WzrdNull;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.RootNode;
import java.util.Collections;
import java.util.Map;

public final class WzrdEvalNode extends RootNode {

private final Map<String, RootCallTarget> functions;

@CompilationFinal private boolean registered;

@Child private DirectCallNode mainCallNode;

private WzrdLanguage language;

public WzrdEvalNode(
WzrdLanguage language,
Map<String, RootCallTarget> functions,
RootCallTarget rootFunction) {
super(language);
this.language = language;
this.functions = Collections.unmodifiableMap(functions);
this.mainCallNode = rootFunction != null ? DirectCallNode.create(rootFunction) : null;
}

@Override
public boolean isInternal() {
return true;
}

@Override
protected boolean isInstrumentable() {
return false;
}

@Override
public String getName() {
return "root eval";
}

@Override
public Object execute(VirtualFrame frame) {
if (language.isSingleContext()) {
if (!registered) {
CompilerDirectives.transferToInterpreterAndInvalidate();
registerFunctions();
registered = true;
}
}else{
registerFunctions();
}
if (mainCallNode == null) {
return WzrdNull.INSTANCE;
}else{
var arguments = frame.getArguments();
return mainCallNode.call(arguments);
}
}

@TruffleBoundary
private void registerFunctions(){
WzrdContext.get(this).getFunctionRegistry().register(functions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,9 @@ public boolean visit(Node node) {
});
return writeArgNodes.toArray(LocalVariableWriteNode[]::new);
}

@Override
public String getName() {
return name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.banshay.language.nodes.expressions;

import com.banshay.language.nodes.toplevel.WzrdExpressionNode;
import com.banshay.language.types.WzrdNull;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.profiles.BranchProfile;

public class ArgumentNode extends WzrdExpressionNode {

private final int index;
private final BranchProfile outOfBoundsToken = BranchProfile.create();

public ArgumentNode(int index) {
this.index = index;
}

@Override
public Object executeGeneric(VirtualFrame frame) {
var arguments = frame.getArguments();
if (index < arguments.length) {
return arguments[index];
}
outOfBoundsToken.enter();
return WzrdNull.INSTANCE;
}
}
Loading

0 comments on commit d060292

Please sign in to comment.