Skip to content

Commit

Permalink
initial interop / eval work
Browse files Browse the repository at this point in the history
  • Loading branch information
arvyy committed Dec 9, 2023
1 parent 86e6519 commit 5c908bd
Show file tree
Hide file tree
Showing 16 changed files with 325 additions and 38 deletions.
13 changes: 13 additions & 0 deletions language/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,24 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>js-community</artifactId>
<type>pom</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-api</artifactId>
</dependency>

<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-runtime</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-dsl-processor</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ void initGlobalFunctions() {
initGlobalFunction("error-output", ISLISPErrorOutputStream::makeLispFunction);
initGlobalFunction("eq", ISLISPEq::makeLispFunction);
initGlobalFunction("equal", ISLISPEqual::makeLispFunction);
initGlobalFunction("eval", ISLISPEval::makeLispFunction);
initGlobalFunction("format", ISLISPFormat::makeLispFunction);
initGlobalFunction("format-char", ISLISPFormatChar::makeLispFunction);
initGlobalFunction("format-integer", ISLISPFormatInteger::makeLispFunction);
Expand Down Expand Up @@ -167,6 +168,7 @@ void initGlobalFunctions() {
//extension
initGlobalFunction("current-stacktrace", ISLISPCurrentStacktrace::makeLispFunction);
initGlobalFunction("exit", ISLISPExit::makeLispFunction);
initGlobalFunction("truffle-object-fields", ISLISPTruffleObjectFields::makeLispFunction);
}

private void initInitializeObjectMethod() {
Expand Down Expand Up @@ -269,6 +271,9 @@ void initBuiltinClasses() {
initBuiltin("<general-array*>", "<basic-array*>");
initBuiltin("<stream>", "<object>");
initBuiltin("<character>", "<object>");

//truffle interop
initBuiltin("<truffle-object>", "<object>");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.RootNode;

/**
Expand Down Expand Up @@ -132,6 +134,17 @@ LispClass doArray(
return arrayClass;
}

@Specialization(guards = {
"interop.hasMembers(o)"
}, limit = "3")
LispClass doTruffleInteropObject(
Object o,
@CachedLibrary("o") InteropLibrary interop,
@Cached("loadTruffleObjectClass()") LispClass truffleObjectClass
) {
return truffleObjectClass;
}

@Fallback
@CompilerDirectives.TruffleBoundary
LispClass doFallback(Object value) {
Expand Down Expand Up @@ -182,6 +195,10 @@ LispClass loadArrayClass() {
return loadClass("<general-array*>");
}

LispClass loadTruffleObjectClass() {
return loadClass("<truffle-object>");
}

LispClass loadClass(String name) {
var ctx = ISLISPContext.get(this);
var symbol = ctx.namedSymbol(name);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.github.arvyy.islisp.functions;

import com.github.arvyy.islisp.ISLISPContext;
import com.github.arvyy.islisp.nodes.ISLISPErrorSignalerNode;
import com.github.arvyy.islisp.runtime.LispFunction;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;

/**
* Implements `eval` function used for interop with other truffle languages.
*/
public class ISLISPEval extends RootNode {

@Child
private ISLISPErrorSignalerNode errorSignalerNode;

ISLISPEval(TruffleLanguage<?> lang) {
super(lang);
errorSignalerNode = new ISLISPErrorSignalerNode(this);
}

@Override
public Object execute(VirtualFrame frame) {
if (frame.getArguments().length != 3) {
return errorSignalerNode.signalWrongArgumentCount(
frame.getArguments().length - 1,
2,
2);
}
var lang = (String) frame.getArguments()[1];
var ctx = ISLISPContext.get(this);
var env = ctx.getEnv();
/*
var filePath = (String) frame.getArguments()[2];
var file = env.getPublicTruffleFile(filePath);
*/
var script = (String) frame.getArguments()[2];
try {
var source = Source.newBuilder(lang, script, "<eval>").build();
var target = env.parsePublic(source);
return target.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

/**
* Construct LispFunction using this root node.
*
* @param lang truffle language reference
* @return lisp function
*/
public static LispFunction makeLispFunction(TruffleLanguage<?> lang) {
return new LispFunction(new ISLISPEval(lang).getCallTarget());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.github.arvyy.islisp.functions;

import com.github.arvyy.islisp.ISLISPContext;
import com.github.arvyy.islisp.exceptions.ISLISPError;
import com.github.arvyy.islisp.nodes.ISLISPErrorSignalerNode;
import com.github.arvyy.islisp.runtime.LispFunction;
import com.github.arvyy.islisp.runtime.LispVector;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.RootNode;

/**
* Implements `truffle-object-fields` function, which returns fields as a list of strings
* in a given object.
*/
public abstract class ISLISPTruffleObjectFields extends RootNode {

@Child
private ISLISPErrorSignalerNode errorSignalerNode;

ISLISPTruffleObjectFields(TruffleLanguage<?> language) {
super(language);
errorSignalerNode = new ISLISPErrorSignalerNode(this);
}

@Override
public final Object execute(VirtualFrame frame) {
if (frame.getArguments().length != 2) {
return errorSignalerNode.signalWrongArgumentCount(frame.getArguments().length - 1, 1, 1);
}
try {
return executeGeneric(frame.getArguments()[1]);
} catch (Exception e) {
throw new ISLISPError(e.getMessage(), this);
}
}

abstract Object executeGeneric(Object obj) throws UnsupportedMessageException, InvalidArrayIndexException;

@Specialization(guards = {
"interopLibrary.hasMembers(o)"
}, limit = "3")
Object doTruffleInterop(
Object o,
@CachedLibrary("o") InteropLibrary interopLibrary
) throws UnsupportedMessageException, InvalidArrayIndexException {
InteropLibrary uncached = InteropLibrary.getUncached();
var membersInterop = interopLibrary.getMembers(o);
var copy = new Object[(int) uncached.getArraySize(membersInterop)];
for (int i = 0; i < copy.length; i++) {
var fieldInterop = uncached.readArrayElement(membersInterop, i);
var field = uncached.asString(fieldInterop);
copy[i] = field;
}
return new LispVector(copy);
}

@Fallback
Object fallback(Object o) {
var ctx = ISLISPContext.get(this);
var expectedClass = ctx.lookupClass("<truffle-object>");
return errorSignalerNode.signalWrongType(o, expectedClass);
}

/**
* Construct LispFunction using this root node.
*
* @param lang truffle language reference
* @return lisp function
*/
public static LispFunction makeLispFunction(TruffleLanguage<?> lang) {
return new LispFunction(ISLISPTruffleObjectFieldsNodeGen.create(lang).getCallTarget());
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.github.arvyy.islisp.nodes;

import com.github.arvyy.islisp.ISLISPContext;
import com.github.arvyy.islisp.runtime.LispFunction;
import com.oracle.truffle.api.dsl.Cached;
import com.github.arvyy.islisp.exceptions.ISLISPError;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;

/**
Expand Down Expand Up @@ -35,28 +36,20 @@ public ISLISPFunctionDispatchNode() {
*/
public abstract Object executeDispatch(Object lispFunction, Object[] arguments);

@ExplodeLoop
@Specialization(guards = "function.callTarget() == callNode.getCallTarget()")
Object doDirect(
LispFunction function,
Object[] args,
@Cached("create(function.callTarget())") DirectCallNode callNode) {
var realArgs = new Object[args.length + 1];
realArgs[0] = function.closure();
System.arraycopy(args, 0, realArgs, 1, args.length);
return callNode.call(realArgs);
}

@ExplodeLoop
@Specialization(replaces = "doDirect")
Object doIndirect(
LispFunction function,
Object[] args,
@Cached IndirectCallNode callNode) {
var realArgs = new Object[args.length + 1];
realArgs[0] = function.closure();
System.arraycopy(args, 0, realArgs, 1, args.length);
return callNode.call(function.callTarget(), realArgs);
@Specialization(guards = {
"interopLibrary.isExecutable(o)"
}, limit = "3")
Object doInterop(
Object o,
Object[] args,
@CachedLibrary("o") InteropLibrary interopLibrary
) {
try {
return interopLibrary.execute(o, args);
} catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) {
//TODO
throw new ISLISPError(e.getMessage(), this);
}
}

@Fallback
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.github.arvyy.islisp.runtime;

import com.oracle.truffle.api.interop.TruffleObject;

/**
* Lisp array.
*
* @param data nested Object[] values
* @param dimensions amount of nesting; 2+.
*/
public record LispArray(Object[] data, int dimensions) {
public record LispArray(Object[] data, int dimensions) implements TruffleObject {
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.github.arvyy.islisp.runtime;

import com.oracle.truffle.api.interop.TruffleObject;

/**
* Signifies LISP character type, carrying around codepoint.
*
* @param codepoint
*/
public record LispChar(int codepoint) {
public record LispChar(int codepoint) implements TruffleObject {
}
Loading

0 comments on commit 5c908bd

Please sign in to comment.