Java and Polyglot utility functions (#723)

This commit is contained in:
Marcin Kostrzewa 2020-05-07 15:38:21 +02:00 committed by GitHub
parent ded8d22f43
commit 40d62c882d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1046 additions and 0 deletions

View File

@ -16,5 +16,6 @@ public class Constants {
public static final String FUNCTION_INTEROP_LIBRARY = "10";
public static final String THUNK_EXECUTOR_NODE = "10";
public static final String EVAL_NODE = "10";
public static final int BUILTIN_INTEROP_DISPATCH = 3;
}
}

View File

@ -0,0 +1,74 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
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.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.execute0",
description = "Executes a zero-argument polyglot function.")
public class Execute0Node extends BuiltinRootNode {
private Execute0Node(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new Execute0Node(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "callable", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object callable = args[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
Object res = library.execute(callable);
return new Stateful(state, res);
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.execute0";
}
}

View File

@ -0,0 +1,76 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
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.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.execute1",
description = "Executes a one-argument polyglot function.")
public class Execute1Node extends BuiltinRootNode {
private Execute1Node(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new Execute1Node(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "callable", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "arg1", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object callable = args[1];
Object arg1 = args[2];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
Object res = library.execute(callable, arg1);
return new Stateful(state, res);
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.execute1";
}
}

View File

@ -0,0 +1,75 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.*;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.execute2",
description = "Executes a two-arguments polyglot function.")
public class Execute2Node extends BuiltinRootNode {
private Execute2Node(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new Execute2Node(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "callable", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "arg1", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(3, "arg2", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object callable = args[1];
Object arg1 = args[2];
Object arg2 = args[3];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
Object res = library.execute(callable, arg1, arg2);
return new Stateful(state, res);
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.execute2";
}
}

View File

@ -0,0 +1,82 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
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.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(
shortName = "Polyglot.get_array_element",
description = "Gets an element by index from a polyglot array.")
public class GetArrayElementNode extends BuiltinRootNode {
private GetArrayElementNode(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetArrayElementNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "array", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "index", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object array = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
long index =
TypesGen.expectLong(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2]);
Object res = library.readArrayElement(array, index);
return new Stateful(state, res);
} catch (UnsupportedMessageException
| InvalidArrayIndexException
| UnexpectedResultException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_array_element";
}
}

View File

@ -0,0 +1,70 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(shortName = "Polyglot.get_array_size", description = "Gets the size of a polyglot array.")
public class GetArraySizeNode extends BuiltinRootNode {
private GetArraySizeNode(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetArraySizeNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "array", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object obj = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
long size = library.getArraySize(obj);
return new Stateful(state, size);
} catch (UnsupportedMessageException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_array_size";
}
}

View File

@ -0,0 +1,80 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(
shortName = "Polyglot.get_member",
description = "Gets a member by name from a polyglot object.")
public class GetMemberNode extends BuiltinRootNode {
private GetMemberNode(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetMemberNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "object", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "name", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object obj = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
String name =
TypesGen.expectString(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2]);
Object res = library.readMember(obj, name);
return new Stateful(state, res);
} catch (UnsupportedMessageException
| UnknownIdentifierException
| UnexpectedResultException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_member";
}
}

View File

@ -0,0 +1,72 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.get_members",
description = "Returns a polyglot array of the object's member names.")
public class GetMembersNode extends BuiltinRootNode {
private GetMembersNode(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetMembersNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "object", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object arg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
Object members = library.getMembers(arg);
return new Stateful(state, members);
} catch (UnsupportedMessageException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_members";
}
}

View File

@ -0,0 +1,74 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
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.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.instantiate0",
description = "Instantiates a zero-argument polyglot constructor.")
public class Instantiate0Node extends BuiltinRootNode {
private Instantiate0Node(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new Instantiate0Node(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "constructor", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object constructor = args[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
Object res = library.instantiate(constructor);
return new Stateful(state, res);
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.instantiate0";
}
}

View File

@ -0,0 +1,76 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
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.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.instantiate1",
description = "Instantiates a one-argument polyglot constructor.")
public class Instantiate1Node extends BuiltinRootNode {
private Instantiate1Node(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new Instantiate1Node(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "constructor", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "arg1", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object cons = args[1];
Object arg1 = args[2];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
Object res = library.instantiate(cons, arg1);
return new Stateful(state, res);
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.instantiate1";
}
}

View File

@ -0,0 +1,78 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
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.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.instantiate2",
description = "Instantiates a two-arguments polyglot constructor.")
public class Instantiate2Node extends BuiltinRootNode {
private Instantiate2Node(Language language) {
super(language);
}
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new Instantiate2Node(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "constructor", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "arg1", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(3, "arg2", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object cons = args[1];
Object arg1 = args[2];
Object arg2 = args[3];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
try {
Object res = library.instantiate(cons, arg1, arg2);
return new Stateful(state, res);
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.instantiate2";
}
}

View File

@ -0,0 +1,63 @@
package org.enso.interpreter.node.expression.builtin.interop.java;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import java.io.File;
@NodeInfo(shortName = "Java.add_to_class_path", description = "Adds a path to the host class path.")
public abstract class AddToClassPathNode extends BuiltinRootNode {
AddToClassPathNode(Language language) {
super(language);
}
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
AddToClassPathNodeGen.create(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "path", ArgumentDefinition.ExecutionMode.EXECUTE));
}
@Specialization
Stateful doExecute(VirtualFrame frame, @CachedContext(Language.class) Context context) {
try {
String arg =
TypesGen.expectString(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
context.getEnvironment().addToHostClassPath(context.getTruffleFile(new File(arg)));
return new Stateful(state, context.getBuiltins().unit());
} catch (UnexpectedResultException e) {
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Java.add_to_class_path";
}
}

View File

@ -0,0 +1,61 @@
package org.enso.interpreter.node.expression.builtin.interop.java;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(shortName = "Java.lookup_class", description = "Looks up a Java symbol.")
public abstract class LookupClassNode extends BuiltinRootNode {
LookupClassNode(Language language) {
super(language);
}
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
LookupClassNodeGen.create(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "name", ArgumentDefinition.ExecutionMode.EXECUTE));
}
@Specialization
Stateful doExecute(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
try {
String arg =
TypesGen.expectString(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object res = ctx.getEnvironment().lookupHostSymbol(arg);
return new Stateful(state, res);
} catch (UnexpectedResultException e) {
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Java.lookup_class";
}
}

View File

@ -0,0 +1,52 @@
package org.enso.interpreter.node.expression.builtin.io;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(shortName = "IO.nano_time", description = "Gets the nanosecond resolution system time.")
public final class NanoTimeNode extends BuiltinRootNode {
private NanoTimeNode(Language language) {
super(language);
}
/**
* Creates a {@link Function} object wrapping this object.
*
* @param language the current {@link Language} instance
* @return a {@link Function} object wrapping the behavior of this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new NanoTimeNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
@Override
public Stateful execute(VirtualFrame frame) {
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, getNanoTime());
}
@CompilerDirectives.TruffleBoundary
private long getNanoTime() {
return System.nanoTime();
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "IO.nano_time";
}
}

View File

@ -9,7 +9,10 @@ import org.enso.interpreter.node.expression.builtin.error.CatchPanicNode;
import org.enso.interpreter.node.expression.builtin.error.PanicNode;
import org.enso.interpreter.node.expression.builtin.error.ThrowErrorNode;
import org.enso.interpreter.node.expression.builtin.function.ExplicitCallFunctionNode;
import org.enso.interpreter.node.expression.builtin.interop.generic.*;
import org.enso.interpreter.node.expression.builtin.io.NanoTimeNode;
import org.enso.interpreter.node.expression.builtin.io.PrintNode;
import org.enso.interpreter.node.expression.builtin.interop.java.*;
import org.enso.interpreter.node.expression.builtin.number.AddNode;
import org.enso.interpreter.node.expression.builtin.number.DivideNode;
import org.enso.interpreter.node.expression.builtin.number.ModNode;
@ -83,6 +86,8 @@ public class Builtins {
AtomConstructor error = new AtomConstructor("Error", scope).initializeFields();
AtomConstructor state = new AtomConstructor("State", scope).initializeFields();
AtomConstructor java = new AtomConstructor("Java", scope).initializeFields();
scope.registerConstructor(unit);
scope.registerConstructor(any);
scope.registerConstructor(number);
@ -100,7 +105,11 @@ public class Builtins {
scope.registerConstructor(syntaxError);
scope.registerConstructor(compileError);
scope.registerConstructor(java);
scope.registerConstructor(createPolyglot(language));
scope.registerMethod(io, "println", PrintNode.makeFunction(language));
scope.registerMethod(io, "nano_time", NanoTimeNode.makeFunction(language));
scope.registerMethod(panic, "throw", PanicNode.makeFunction(language));
scope.registerMethod(panic, "recover", CatchPanicNode.makeFunction(language));
@ -126,6 +135,28 @@ public class Builtins {
scope.registerMethod(text, "+", ConcatNode.makeFunction(language));
scope.registerMethod(any, "to_text", AnyToTextNode.makeFunction(language));
scope.registerMethod(any, "json_serialize", JsonSerializeNode.makeFunction(language));
scope.registerMethod(java, "add_to_class_path", AddToClassPathNode.makeFunction(language));
scope.registerMethod(java, "lookup_class", LookupClassNode.makeFunction(language));
}
private AtomConstructor createPolyglot(Language language) {
AtomConstructor polyglot = new AtomConstructor("Polyglot", scope).initializeFields();
scope.registerMethod(polyglot, "execute0", Execute0Node.makeFunction(language));
scope.registerMethod(polyglot, "execute1", Execute1Node.makeFunction(language));
scope.registerMethod(polyglot, "execute2", Execute2Node.makeFunction(language));
scope.registerMethod(polyglot, "instantiate0", Instantiate0Node.makeFunction(language));
scope.registerMethod(polyglot, "instantiate1", Instantiate1Node.makeFunction(language));
scope.registerMethod(polyglot, "instantiate2", Instantiate2Node.makeFunction(language));
scope.registerMethod(polyglot, "get_member", GetMemberNode.makeFunction(language));
scope.registerMethod(polyglot, "get_members", GetMembersNode.makeFunction(language));
scope.registerMethod(polyglot, "get_array_size", GetArraySizeNode.makeFunction(language));
scope.registerMethod(
polyglot, "get_array_element", GetArrayElementNode.makeFunction(language));
return polyglot;
}
/**

View File

@ -0,0 +1,29 @@
package org.enso.example;
import java.util.function.Function;
/** A class used for testing Java Interop from Enso code */
public class TestClass {
private final Function<Long, Long> function;
public TestClass(Function<Long, Long> function) {
this.function = function;
}
public TestClass() {
this(x -> x);
}
public static long add(long a, long b) {
return a + b;
}
public long callFunctionAndIncrement(long argument) {
return function.apply(argument) + 1;
}
public void method1() {}
public void method2() {}
}

View File

@ -76,6 +76,7 @@ trait InterpreterRunner {
val ctx = Context
.newBuilder(LanguageInfo.ID)
.allowExperimentalOptions(true)
.allowAllAccess(true)
.out(output)
.build()
lazy val executionContext = new PolyglotContext(ctx)

View File

@ -0,0 +1,51 @@
package org.enso.interpreter.test.semantic
import org.enso.interpreter.test.InterpreterTest
class JavaInteropTest extends InterpreterTest {
"Java interop" should "allow calling static methods from java classes" in {
val code =
"""
|main =
| class = Java.lookup_class "org.enso.example.TestClass"
| method = Polyglot.get_member class "add"
| Polyglot.execute2 method 1 2
|""".stripMargin
eval(code) shouldEqual 3
}
"Java interop" should "allow instantiating objects and calling methods on them" in {
val code =
"""
|main =
| class = Java.lookup_class "org.enso.example.TestClass"
| instance = Polyglot.instantiate1 class (x -> x * 2)
| method = Polyglot.get_member instance "callFunctionAndIncrement"
| Polyglot.execute1 method 10
|""".stripMargin
eval(code) shouldEqual 21
}
"Java interop" should "allow listing available members of an object" in {
val code =
"""
|main =
| class = Java.lookup_class "org.enso.example.TestClass"
| instance = Polyglot.instantiate0 class
| members = Polyglot.get_members instance
| IO.println (Polyglot.get_array_size members)
| IO.println (Polyglot.get_array_element members 0)
| IO.println (Polyglot.get_array_element members 1)
| IO.println (Polyglot.get_array_element members 2)
|""".stripMargin
eval(code)
val count :: methods = consumeOut
count shouldEqual "3"
methods.toSet shouldEqual Set(
"method1",
"method2",
"callFunctionAndIncrement"
)
}
}