diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/immutable/FromArrayBuiltinVectorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/immutable/FromArrayBuiltinVectorNode.java index ffa6cc28c066f..6c56567b77a3e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/immutable/FromArrayBuiltinVectorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/immutable/FromArrayBuiltinVectorNode.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.*; import org.enso.interpreter.epb.node.CoercePrimitiveNode; +import org.enso.interpreter.node.expression.builtin.mutable.CoerceArrayNode; import org.enso.interpreter.node.expression.foreign.CoerceNothing; import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.data.Array; @@ -19,9 +20,6 @@ name = "from_array", description = "Creates a Vector by copying Array content.") public abstract class FromArrayBuiltinVectorNode extends Node { - private @Child CoercePrimitiveNode coercePrimitiveNode = CoercePrimitiveNode.build(); - private @Child CoerceNothing coerceNothingNode = CoerceNothing.build(); - static FromArrayBuiltinVectorNode build() { return FromArrayBuiltinVectorNodeGen.create(); } @@ -34,24 +32,11 @@ Vector fromVector(Vector arr) { } @Specialization(guards = "interop.hasArrayElements(arr)") - Vector fromArrayLikeObject(Object arr, @CachedLibrary(limit = "3") InteropLibrary interop) { - try { - long length = interop.getArraySize(arr); - Object[] target = new Object[(int) length]; - for (int i = 0; i < length; i++) { - try { - var value = interop.readArrayElement(arr, i); - target[i] = coerceNothingNode.execute(coercePrimitiveNode.execute(value)); - } catch (InvalidArrayIndexException ex) { - var ctx = Context.get(this); - var err = ctx.getBuiltins().error().makeInvalidArrayIndexError(arr, i); - throw new PanicException(err, this); - } - } - return Vector.fromArray(new Array(target)); - } catch (UnsupportedMessageException ex) { - throw unsupportedException(arr); - } + Vector fromArrayLikeObject( + Object arr, + @Cached CoerceArrayNode coerce, + @CachedLibrary(limit = "3") InteropLibrary interop) { + return Vector.fromArray(new Array(coerce.execute(arr))); } @Fallback diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java index a5d2d37c7ffcc..f9b861db3edb6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java @@ -1,5 +1,7 @@ package org.enso.interpreter.node.expression.builtin.interop.generic; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -9,6 +11,7 @@ import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; +import org.enso.interpreter.node.expression.builtin.mutable.CoerceArrayNode; import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.PanicException; @@ -16,15 +19,22 @@ type = "Polyglot", name = "execute", description = "Executes a polyglot function object (e.g. a lambda).") -public class ExecuteNode extends Node { +public abstract class ExecuteNode extends Node { private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private @Child HostValueToEnsoNode hostValueToEnsoNode = HostValueToEnsoNode.build(); private final BranchProfile err = BranchProfile.create(); - Object execute(Object callable, Array arguments) { + public static ExecuteNode build() { + return ExecuteNodeGen.create(); + } + + public abstract Object execute(Object callable, Object arguments); + + @Specialization + Object execute(Object callable, Object arguments, @Cached("build()") CoerceArrayNode coerce) { try { - return hostValueToEnsoNode.execute(library.execute(callable, arguments.getItems())); + return hostValueToEnsoNode.execute(library.execute(callable, coerce.execute(arguments))); } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) { err.enter(); throw new PanicException(e.getMessage(), this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java index ba820b6f87ab6..7f1a71e8cd2d6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java @@ -1,5 +1,7 @@ package org.enso.interpreter.node.expression.builtin.interop.generic; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -8,22 +10,29 @@ import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.runtime.data.Array; +import org.enso.interpreter.node.expression.builtin.mutable.CoerceArrayNode; import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( type = "Polyglot", name = "new", description = "Instantiates a polyglot constructor.") -public class InstantiateNode extends Node { +public abstract class InstantiateNode extends Node { private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private final BranchProfile err = BranchProfile.create(); - Object execute(Object constructor, Array arguments) { + public static InstantiateNode build() { + return InstantiateNodeGen.create(); + } + + public abstract Object execute(Object constructor, Object arguments); + + @Specialization + Object execute(Object constructor, Object arguments, @Cached("build()") CoerceArrayNode coerce) { try { - return library.instantiate(constructor, arguments.getItems()); + return library.instantiate(constructor, coerce.execute(arguments)); } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) { err.enter(); throw new PanicException(e.getMessage(), this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java index 079d74d3b8828..8655dc32d2b66 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java @@ -1,27 +1,42 @@ package org.enso.interpreter.node.expression.builtin.interop.generic; -import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.ArityException; +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.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.mutable.CoerceArrayNode; import org.enso.interpreter.node.expression.builtin.text.util.ExpectStringNode; -import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( type = "Polyglot", name = "invoke", description = "Invokes a polyglot method by name, dispatching by the target argument.") -public class InvokeNode extends Node { +public abstract class InvokeNode extends Node { private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private @Child ExpectStringNode expectStringNode = ExpectStringNode.build(); private final BranchProfile err = BranchProfile.create(); - Object execute(Object target, Object name, Array arguments) { + public static InvokeNode build() { + return InvokeNodeGen.create(); + } + + public abstract Object execute(Object target, Object name, Object arguments); + + @Specialization + Object execute( + Object target, Object name, Object arguments, @Cached("build()") CoerceArrayNode coerce) { try { - return library.invokeMember(target, expectStringNode.execute(name), arguments.getItems()); + return library.invokeMember( + target, expectStringNode.execute(name), coerce.execute(arguments)); } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/NewAtomInstanceNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/NewAtomInstanceNode.java index 8f6519f5ad337..6ada0947709a8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/NewAtomInstanceNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/NewAtomInstanceNode.java @@ -1,17 +1,27 @@ package org.enso.interpreter.node.expression.builtin.meta; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.mutable.CoerceArrayNode; import org.enso.interpreter.runtime.callable.atom.Atom; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; -import org.enso.interpreter.runtime.data.Array; @BuiltinMethod( type = "Meta", name = "new_atom", description = "Creates a new atom with given constructor and fields.") -public class NewAtomInstanceNode extends Node { - Atom execute(AtomConstructor constructor, Array fields) { - return constructor.newInstance(fields.getItems()); +public abstract class NewAtomInstanceNode extends Node { + + static NewAtomInstanceNode build() { + return NewAtomInstanceNodeGen.create(); + } + + abstract Atom execute(AtomConstructor constructor, Object fields); + + @Specialization + Atom execute(AtomConstructor constructor, Object fields, @Cached CoerceArrayNode coerce) { + return constructor.newInstance(coerce.execute(fields)); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/mutable/CoerceArrayNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/mutable/CoerceArrayNode.java new file mode 100644 index 0000000000000..3f32413d1bcd1 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/mutable/CoerceArrayNode.java @@ -0,0 +1,88 @@ +package org.enso.interpreter.node.expression.builtin.mutable; + +import com.oracle.truffle.api.dsl.Cached; +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.ExplodeLoop; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.epb.node.CoercePrimitiveNode; +import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; +import org.enso.interpreter.node.expression.foreign.CoerceNothing; +import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.builtin.Builtins; +import org.enso.interpreter.runtime.callable.atom.Atom; +import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; +import org.enso.interpreter.runtime.error.PanicException; + +public abstract class CoerceArrayNode extends Node { + private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(10); + + public static CoerceArrayNode build() { + return CoerceArrayNodeGen.create(); + } + + public abstract Object[] execute(Object value); + + @Specialization + Object[] doArray(Array arr) { + return arr.getItems(); + } + + @Specialization + Object[] doVector(Vector arr, @Cached HostValueToEnsoNode hostValueToEnsoNode) { + try { + return convertToArray(arr, hostValueToEnsoNode); + } catch (UnsupportedMessageException e) { + Builtins builtins = Context.get(this).getBuiltins(); + Atom err = builtins.error().makeTypeError(builtins.array(), arr, "arr"); + throw new PanicException(err, this); + + } catch (InvalidArrayIndexException e) { + Builtins builtins = Context.get(this).getBuiltins(); + throw new PanicException( + builtins.error().makeInvalidArrayIndexError(arr, e.getInvalidIndex()), this); + } + } + + @Specialization(guards = "interop.hasArrayElements(arr)") + Object[] doArrayLike( + Object arr, + @CachedLibrary(limit = "5") InteropLibrary interop, + @Cached HostValueToEnsoNode hostValueToEnsoNode) { + try { + return convertToArray(arr, hostValueToEnsoNode); + } catch (UnsupportedMessageException e) { + Builtins builtins = Context.get(this).getBuiltins(); + Atom err = builtins.error().makeTypeError(builtins.array(), arr, "arr"); + throw new PanicException(err, this); + } catch (InvalidArrayIndexException e) { + Builtins builtins = Context.get(this).getBuiltins(); + throw new PanicException( + builtins.error().makeInvalidArrayIndexError(arr, e.getInvalidIndex()), this); + } + } + + @ExplodeLoop + private Object[] convertToArray(Object arr, HostValueToEnsoNode hostValueToEnsoNode) + throws UnsupportedMessageException, InvalidArrayIndexException { + int argsLength = (int) library.getArraySize(arr); + Object[] arr1 = new Object[argsLength]; + for (int i = 0; i < argsLength; i++) { + arr1[i] = hostValueToEnsoNode.execute(library.readArrayElement(arr, i)); + } + return arr1; + } + + @Fallback + public Object[] doOther(Object arr) { + Builtins builtins = Context.get(this).getBuiltins(); + Atom error = builtins.error().makeTypeError("array", arr, "arr"); + throw new PanicException(error, this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/system/System.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/system/System.java index 87f98be3f59fc..c8c2fb5518c11 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/system/System.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/system/System.java @@ -3,12 +3,13 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.io.TruffleProcessBuilder; +import com.oracle.truffle.api.nodes.ExplodeLoop; import org.apache.commons.lang3.SystemUtils; import org.enso.interpreter.dsl.Builtin; +import org.enso.interpreter.node.expression.builtin.mutable.CoerceArrayNode; import org.enso.interpreter.node.expression.builtin.text.util.ExpectStringNode; import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.callable.atom.Atom; -import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.data.text.Text; import org.enso.interpreter.runtime.error.PanicException; @@ -53,20 +54,23 @@ public static void exit(long code) { @Builtin.WrapException(from = IOException.class, to = PanicException.class) @Builtin.WrapException(from = InterruptedException.class, to = PanicException.class) @CompilerDirectives.TruffleBoundary + @ExplodeLoop public static Atom createProcess( Context ctx, Object command, - Array arguments, + Object arguments, Object input, boolean redirectIn, boolean redirectOut, boolean redirectErr, + @Cached CoerceArrayNode coerce, @Cached ExpectStringNode expectStringNode) throws IOException, InterruptedException { - String[] cmd = new String[arguments.getItems().length + 1]; + Object[] arrArguments = coerce.execute(arguments); + String[] cmd = new String[arrArguments.length + 1]; cmd[0] = expectStringNode.execute(command); - for (int i = 1; i <= arguments.getItems().length; i++) { - cmd[i] = expectStringNode.execute(arguments.getItems()[i - 1]); + for (int i = 1; i <= arrArguments.length; i++) { + cmd[i] = expectStringNode.execute(arrArguments[i - 1]); } TruffleProcessBuilder pb = ctx.getEnvironment().newProcessBuilder(cmd); diff --git a/test/Tests/src/Data/Polyglot_Spec.enso b/test/Tests/src/Data/Polyglot_Spec.enso new file mode 100644 index 0000000000000..4cc67d89aaa86 --- /dev/null +++ b/test/Tests/src/Data/Polyglot_Spec.enso @@ -0,0 +1,26 @@ +from Standard.Base import all + +from Standard.Test import Test, Test_Suite + +polyglot java import java.time.LocalDate +polyglot java import java.lang.String +polyglot java import java.util.function.Function + +spec = Test.group "Polyglot" <| + Test.specify "should be able to invoke a polyglot method by name and pass arguments" <| + poly_date = LocalDate.now + date = Date.now.to_date_time + + Polyglot.invoke poly_date "atStartOfDay" [] . should_equal date + Polyglot.invoke poly_date "atStartOfDay" [].to_array . should_equal date + + Test.specify "should be able to crate a new polyglot object using the constructor" <| + Polyglot.new String ["42"] . should_equal "42" + Polyglot.new String ["42"].to_array . should_equal "42" + + Test.specify "should be able to execute a polyglot function object along with corresponding arguments" <| + fun = Function.identity + Polyglot.execute fun ["42"] . should_equal "42" + Polyglot.execute fun ["42"].to_array . should_equal "42" + +main = Test_Suite.run_main spec diff --git a/test/Tests/src/Semantic/Meta_Spec.enso b/test/Tests/src/Semantic/Meta_Spec.enso index d5ae7d69d2574..292aa4d8c8fc1 100644 --- a/test/Tests/src/Semantic/Meta_Spec.enso +++ b/test/Tests/src/Semantic/Meta_Spec.enso @@ -35,6 +35,11 @@ spec = Test.group "Meta-Value Manipulation" <| meta_atom.constructor.should_equal My_Type.Value meta_atom.fields.should_equal [1, "foo", Nothing] Meta.meta (meta_atom.constructor) . new [1, "foo", Nothing] . should_equal atom + Test.specify "should allow creating atoms from atom constructors" <| + atom_1 = Meta.new_atom My_Type.Value [1,"foo", Nothing] + (Meta.meta atom_1).constructor . should_equal My_Type.Value + atom_2 = Meta.new_atom My_Type.Value [1,"foo", Nothing].to_array + (Meta.meta atom_2).constructor . should_equal My_Type.Value Test.specify "should correctly return representations of different classes of objects" <| Meta.meta 1 . should_equal (Meta.Primitive_Data 1) Meta.meta "foo" . should_equal (Meta.Primitive_Data "foo") @@ -148,7 +153,7 @@ spec = Test.group "Meta-Value Manipulation" <| Test.specify "should allow to get the source location of a frame" pending=location_pending <| src = Meta.get_source_location 0 - loc = "Meta_Spec.enso:150:15-40" + loc = "Meta_Spec.enso:155:15-40" src.take (Last loc.length) . should_equal loc Test.specify "should allow to get qualified type names of values" <| diff --git a/test/Tests/src/System/System_Spec.enso b/test/Tests/src/System/System_Spec.enso index 590c583226581..370d8ce53e3c1 100644 --- a/test/Tests/src/System/System_Spec.enso +++ b/test/Tests/src/System/System_Spec.enso @@ -1,6 +1,7 @@ from Standard.Base import all import Standard.Base.System +import Standard.Base.System.Platform from Standard.Test import Test, Test_Suite @@ -9,4 +10,13 @@ spec = Test.group "System" <| result = System.nano_time (result > 0).should_equal True + if Platform.is_unix then + Test.specify "should be able to create a process, returning an exit code" <| + result = System.create_process "echo" ["foo", "bar"] "" False False False + result.exit_code . should_equal 0 + + result_2 = System.create_process "echo" ["foo", "bar"].to_array "" False False False + result_2.exit_code . should_equal 0 + + main = Test_Suite.run_main spec