From bafbfb5a7929cdd713313ff731192a748361ae36 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 29 Jul 2022 20:47:16 +0200 Subject: [PATCH 01/13] Use Vector.from_polyglot_array, drop from_array Use Proxy_Polyglot_Array as a proxy for polyglot arrays, thus unifying the way the underlying array is accessed in Vector. Used the opportunity to cleanup builtin lookup, which now actually respects what is defined in the body of @Builtin_Method annotation. --- .../Standard/Base/0.0.0-dev/src/Data/Numbers.enso | 2 +- .../Standard/Base/0.0.0-dev/src/Data/Vector.enso | 15 +++++---------- .../Standard/Base/0.0.0-dev/src/System/File.enso | 2 +- .../interpreter/runtime/builtin/Builtins.java | 8 ++++++-- .../org/enso/compiler/codegen/IrToTruffle.scala | 14 ++++++++++++-- test/Tests/src/Data/Array_Spec.enso | 2 +- test/Tests/src/Data/Vector_Spec.enso | 9 +++++++-- test/Tests/src/Semantic/Js_Interop_Spec.enso | 2 +- 8 files changed, 34 insertions(+), 20 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso index 6627749c3fb5..43a085c46c88 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Numbers.enso @@ -545,7 +545,7 @@ type Decimal 4.736.ceil ceil : Integer - ceil self = @Builtin_Method "Integer.ceil" + ceil self = @Builtin_Method "Decimal.ceil" ## Compares the two operands to determine the ordering of this with respect to that. diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso index c6024f96f4c5..ba512c73d4b4 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso @@ -2,6 +2,7 @@ from Standard.Base import all import Standard.Base.Runtime.Ref import Standard.Base.Runtime.Unsafe from Standard.Base.Data.Index_Sub_Range import While, By_Index, Sample, Every +import Standard.Base.Polyglot.Proxy_Polyglot_Array import Standard.Base.Random ## Creates a new vector of the given length, initializing elements using @@ -86,15 +87,8 @@ new_builder (capacity=1) = Builder.new capacity A vector allows to store an arbitrary number of elements in linear memory. It is the recommended data structure for most applications. - - ! Value Copying - As Enso vectors implement immutable semantics, this constructor function - makes a copy of each value in the argument array. - - If this didn't happen then it would be possible for the underlying array to - be mutated under the hood, and sneak mutability into our immutable data. -from_array : Any -> Vector Any -from_array arr = new (Polyglot.get_array_size arr) (arr.at _) +from_polyglot_array : Any -> Vector Any +from_polyglot_array arr = Vector (Proxy_Polyglot_Array.Proxy_Polyglot_Array arr) ## The basic, immutable, vector type. type Vector @@ -126,7 +120,8 @@ type Vector [1, 2, 3, 4].length length : Number - length self = Polyglot.get_array_size self.to_array + length self = + self.to_array.length ## Gets an element from the vector at a specified index (0-based). diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso index 5f68f44423a0..9ac21f3124bb 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso @@ -546,7 +546,7 @@ type File Builtin method that deletes the file. Recommended to use `File.delete` instead which handles potential exceptions. delete_builtin : Nothing - delete_builtin self = @Builtin_Method "File.delete" + delete_builtin self = @Builtin_Method "File.delete_builtin" ## Moves the file to the specified destination. diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java index 11b3e002d45d..ce40483e5f22 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java @@ -316,8 +316,12 @@ private Map>> readBuiltinMethodsMetad */ public Optional getBuiltinFunction( AtomConstructor atom, String methodName, Language language) { - // TODO: move away from String mapping once Builtins is gone - Map> atomNodes = builtinMethodNodes.get(atom.getName()); + return getBuiltinFunction(atom.getName(), methodName, language); + } + + public Optional getBuiltinFunction( + String methodOwner, String methodName, Language language) { + Map> atomNodes = builtinMethodNodes.get(methodOwner); if (atomNodes == null) return Optional.empty(); Class clazz = atomNodes.get(methodName); if (clazz == null) return Optional.empty(); diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index f998b5b57443..bb5d9c194997 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -300,13 +300,23 @@ class IrToTruffle( // and not attempt to register it in the scope (can't redefined methods). // For non-builtin types (or modules) that own the builtin method // we have to look up the function and register it in the scope. + val x = methodDef.body.asInstanceOf[IR.Function.Lambda].body + val fullMethodName = x.asInstanceOf[IR.Literal.Text] + + val builtinNameElements = fullMethodName.text.split('.') + if (builtinNameElements.length != 2) { + throw new CompilerError(s"Unknwon builtin method ${fullMethodName.text}") + } + val methodName = builtinNameElements(1) + val methodOwnerName = builtinNameElements(0) + val builtinFunction = context.getBuiltins - .getBuiltinFunction(cons, methodDef.methodName.name, language) + .getBuiltinFunction(methodOwnerName, methodName, language) builtinFunction.toScala .map(Some(_)) .toRight( new CompilerError( - s"Unable to find Truffle Node for method ${cons.getName()}.${methodDef.methodName.name}" + s"Unable to find Truffle Node for method ${cons.getName}.${methodDef.methodName.name}" ) ) .left diff --git a/test/Tests/src/Data/Array_Spec.enso b/test/Tests/src/Data/Array_Spec.enso index 17bb3beeeaa4..f262a4f3f225 100644 --- a/test/Tests/src/Data/Array_Spec.enso +++ b/test/Tests/src/Data/Array_Spec.enso @@ -21,7 +21,7 @@ spec = Test.group "Arrays" <| arr = [1, 2, 3] . to_array arr.set_at 1 10 arr.at 1 . should_equal 10 - Vector.from_array arr . should_equal [1, 10, 3] + Vector.from_polyglot_array arr . should_equal [1, 10, 3] Test.specify "should panic on out of bounds access" <| arr = [1, 2, 3] . to_array diff --git a/test/Tests/src/Data/Vector_Spec.enso b/test/Tests/src/Data/Vector_Spec.enso index 1486003c2d44..fc87d7713b9d 100644 --- a/test/Tests/src/Data/Vector_Spec.enso +++ b/test/Tests/src/Data/Vector_Spec.enso @@ -26,6 +26,9 @@ compare_tco a b = case a.vec.length == b.vec.length of foreign js generate_js_array = """ return [1, 2, 3, 4, 5] +foreign python generate_py_array = """ + return [1, 2, 3, 4, 5] + spec = Test.group "Vectors" <| Test.specify "text bytes" <| @@ -38,8 +41,10 @@ spec = Test.group "Vectors" <| Vector.fill 100 1 . fold (0) (+) . should_equal 100 Test.specify "should allow creation from arrays without mutability" <| - built = Vector.from_array generate_js_array - built . should_equal [1, 2, 3, 4, 5] + built_from_js = Vector.from_polyglot_array generate_js_array + built_from_js . should_equal [1, 2, 3, 4, 5] + built_from_py = Vector.from_polyglot_array generate_py_array + built_from_py . should_equal [1, 2, 3, 4, 5] Test.specify "should allow accessing elements" <| [1,2,3].at 0 . should_equal 1 diff --git a/test/Tests/src/Semantic/Js_Interop_Spec.enso b/test/Tests/src/Semantic/Js_Interop_Spec.enso index e87e98bc6af3..aa317b08bd07 100644 --- a/test/Tests/src/Semantic/Js_Interop_Spec.enso +++ b/test/Tests/src/Semantic/Js_Interop_Spec.enso @@ -90,7 +90,7 @@ spec = Test.group "Polyglot JS" <| obj.compare 11 . should_be_true Test.specify "should expose array interfaces for JS arrays" <| - vec = Vector.Vector make_array + vec = Vector.from_polyglot_array make_array vec.map .x . should_equal [10, 20, 30] Test.specify "should correctly marshall strings" <| From 11490d0a2a7516353a5358c4946f4ab41bc632e6 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Mon, 1 Aug 2022 11:17:16 +0200 Subject: [PATCH 02/13] Formatting, make use of the new builtins feature --- .../0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso | 11 +++++++++++ .../lib/Standard/Base/0.0.0-dev/src/System.enso | 4 ---- .../Standard/Base/0.0.0-dev/src/System/Platform.enso | 4 ++-- .../enso/interpreter/runtime/builtin/Builtins.java | 2 +- .../scala/org/enso/compiler/codegen/IrToTruffle.scala | 8 +++++--- 5 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso new file mode 100644 index 000000000000..3cf351e0e370 --- /dev/null +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso @@ -0,0 +1,11 @@ +from Standard.Base import Polyglot + +type Proxy_Polyglot_Array + + type Proxy_Polyglot_Array arr + + length : Number + length self = Polyglot.get_array_size self.arr + + at : Number -> Any + at self index = self.arr.at index diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System.enso index 3bc9e0b4fc28..ee37ed2d7388 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System.enso @@ -50,10 +50,6 @@ nano_time = @Builtin_Method "System.nano_time" os : Text os = @Builtin_Method "System.os" -## Check if the operating system is UNIX. -is_unix : Boolean -is_unix = @Builtin_Method "System.is_unix" - ## PRIVATE Returns the default line separator for the platform that the program is currently running on. diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/Platform.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/Platform.enso index 2079d08646c3..0f57e8d535cd 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/Platform.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/Platform.enso @@ -26,9 +26,9 @@ type Os os : Os os = from_text System.os -## Check if the currently running platform is a UNIX platform. +## Check if the operating system is UNIX. is_unix : Boolean -is_unix = System.is_unix +is_unix = @Builtin_Method "System.is_unix" ## PRIVATE diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java index ce40483e5f22..489d82b49d78 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java @@ -320,7 +320,7 @@ public Optional getBuiltinFunction( } public Optional getBuiltinFunction( - String methodOwner, String methodName, Language language) { + String methodOwner, String methodName, Language language) { Map> atomNodes = builtinMethodNodes.get(methodOwner); if (atomNodes == null) return Optional.empty(); Class clazz = atomNodes.get(methodName); diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index bb5d9c194997..baa6f1159722 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -300,14 +300,16 @@ class IrToTruffle( // and not attempt to register it in the scope (can't redefined methods). // For non-builtin types (or modules) that own the builtin method // we have to look up the function and register it in the scope. - val x = methodDef.body.asInstanceOf[IR.Function.Lambda].body + val x = methodDef.body.asInstanceOf[IR.Function.Lambda].body val fullMethodName = x.asInstanceOf[IR.Literal.Text] val builtinNameElements = fullMethodName.text.split('.') if (builtinNameElements.length != 2) { - throw new CompilerError(s"Unknwon builtin method ${fullMethodName.text}") + throw new CompilerError( + s"Unknwon builtin method ${fullMethodName.text}" + ) } - val methodName = builtinNameElements(1) + val methodName = builtinNameElements(1) val methodOwnerName = builtinNameElements(0) val builtinFunction = context.getBuiltins From 2c53308fbd96e7cbe836abacfde4c87937b6d800 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Mon, 1 Aug 2022 11:26:58 +0200 Subject: [PATCH 03/13] changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f734077a1065..57b3e1c6c5bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -177,6 +177,8 @@ type from `Standard.Table`.][3601] - [Created `Index_Sub_Range` type and updated `Text.take` and `Text.drop`.][3617] +- [Added `Vector.from_polyglot_array` to make `Vector`s backed by polyglot + Arrays][3628] - [Updated `Vector.take` and `Vector.drop` and removed their obsolete counterparts.][3629] - [Short-hand syntax for `order_by` added.][3643] @@ -282,6 +284,7 @@ [3593]: https://github.com/enso-org/enso/pull/3593 [3601]: https://github.com/enso-org/enso/pull/3601 [3617]: https://github.com/enso-org/enso/pull/3617 +[3628]: https://github.com/enso-org/enso/pull/3628 [3629]: https://github.com/enso-org/enso/pull/3629 [3643]: https://github.com/enso-org/enso/pull/3643 [3644]: https://github.com/enso-org/enso/pull/3644 @@ -357,7 +360,8 @@ [3531]: https://github.com/enso-org/enso/pull/3531 [3562]: https://github.com/enso-org/enso/pull/3562 [3538]: https://github.com/enso-org/enso/pull/3538 -[3538]: https://github.com/enso-org/enso/pull/3569 +[3569]: https://github.com/enso-org/enso/pull/3569 +[3578]: https://github.com/enso-org/enso/pull/3578 [3618]: https://github.com/enso-org/enso/pull/3618 [3608]: https://github.com/enso-org/enso/pull/3608 [3608]: https://github.com/enso-org/enso/pull/3608 From bcc2492e319e2b9085d1848bac64036d3c9351bb Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Mon, 1 Aug 2022 13:00:56 +0200 Subject: [PATCH 04/13] Use Polyglot read_array_element for `at`, docs --- .../Standard/Base/0.0.0-dev/src/Polyglot.enso | 7 ++++ .../src/Polyglot/Proxy_Polyglot_Array.enso | 14 ++++++- .../interop/generic/ReadArrayElementNode.java | 39 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso index 43c03bc0404b..58cb58c226f9 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso @@ -15,6 +15,13 @@ type Polyglot get_array_size : Any -> Integer get_array_size array = @Builtin_Method "Polyglot.get_array_size" +## Reads the element in a given polyglot array object. + + Arguments: + - index: The index to get the element from. +read_array_element : Any -> Integer -> Any +read_array_element array index = @Builtin_Method "Polyglot.read_array_element" + ## Executes a polyglot function object (e.g. a lambda). Arguments: diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso index 3cf351e0e370..98f58b3aee3a 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso @@ -1,11 +1,23 @@ from Standard.Base import Polyglot +## Advanced + + Wrapper for Polyglot Arrays type Proxy_Polyglot_Array type Proxy_Polyglot_Array arr + ## Returns the number of elements stored in this Polyglot Array. + + > Example + Checking the length of a vector. + + [1, 2, 3, 4].length + length : Number length self = Polyglot.get_array_size self.arr + ## Gets an element from this Polyglot Array at a specified index (0-based). + at : Number -> Any - at self index = self.arr.at index + at self index = Polyglot.read_array_element self.arr index diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java new file mode 100644 index 000000000000..ef4b726c9e10 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.interop.generic; + +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.Node; +import com.oracle.truffle.api.profiles.BranchProfile; +import org.enso.interpreter.Constants; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.builtin.Builtins; +import org.enso.interpreter.runtime.error.PanicException; + +@BuiltinMethod( + type = "Polyglot", + name = "read_array_element", + description = "Returns the size of a polyglot array.") +public class ReadArrayElementNode extends Node { + private @Child + InteropLibrary library = + InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); + private final BranchProfile err = BranchProfile.create(); + + Object execute(Object array, long index) { + try { + return library.readArrayElement(array, index); + } catch (UnsupportedMessageException e) { + err.enter(); + Builtins builtins = Context.get(this).getBuiltins(); + throw new PanicException( + builtins.error().makeTypeError(builtins.array(), array, "array"), this); + } catch (InvalidArrayIndexException e) { + err.enter(); + Builtins builtins = Context.get(this).getBuiltins(); + throw new PanicException( + builtins.error().makeInvalidArrayIndexError(array, index), this); + } + } +} From 81b35406803660afff246769df33a37d658a6873 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Thu, 4 Aug 2022 16:02:23 +0200 Subject: [PATCH 05/13] Address PR review, handle Vector.Vector for polyglot Vector now has a `storage` field, which will delegate to Proxy_Polyglot_Array. Identified what appears to be all invalid `Vector.Vector` constructs when the underlying storage was a polyglot array. --- .../Base/0.0.0-dev/src/Data/Statistics.enso | 4 ++-- .../0.0.0-dev/src/Data/Text/Extensions.enso | 12 +++++----- .../src/Data/Text/Regex/Engine/Default.enso | 4 ++-- .../Base/0.0.0-dev/src/Data/Vector.enso | 22 +++++++++---------- .../0.0.0-dev/src/Network/Http/Response.enso | 4 ++-- .../src/Polyglot/Proxy_Polyglot_Array.enso | 20 ++++++++++------- .../Base/0.0.0-dev/src/System/File.enso | 8 +++---- .../0.0.0-dev/src/Connection/Connection.enso | 8 +++---- .../Image/0.0.0-dev/src/Data/Histogram.enso | 2 +- .../Image/0.0.0-dev/src/Data/Image.enso | 4 ++-- .../Image/0.0.0-dev/src/Data/Matrix.enso | 4 ++-- .../Table/0.0.0-dev/src/Data/Column.enso | 22 +++++++++---------- .../0.0.0-dev/src/Data/Data_Formatter.enso | 2 +- .../Table/0.0.0-dev/src/Data/Table.enso | 6 ++--- .../Standard/Table/0.0.0-dev/src/Errors.enso | 2 +- .../Table/0.0.0-dev/src/IO/Excel.enso | 10 ++++----- .../src/Internal/Aggregate_Column_Helper.enso | 6 ++--- .../src/Internal/Delimited_Reader.enso | 10 ++++----- .../src/Internal/Parse_Values_Helper.enso | 4 ++-- .../src/Internal/Unique_Name_Strategy.enso | 4 ++-- .../interop/generic/ReadArrayElementNode.java | 7 +++++- test/Tests/src/Data/Vector_Spec.enso | 12 ++++++++++ .../src/Semantic/Python_Interop_Spec.enso | 2 +- test/Tests/src/Semantic/R_Interop_Spec.enso | 2 +- 24 files changed, 101 insertions(+), 80 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso index 36a59d6a1cd8..c924dba6517d 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Statistics.enso @@ -207,7 +207,7 @@ calculate_correlation_statistics_matrix : [Vector] -> [CorrelationStatistics] calculate_correlation_statistics_matrix data = data_array = Vector.new data.length i->(data.at i).to_array . to_array stats_array = wrap_java_call <| CorrelationStatistics.computeMatrix data_array - Vector.new stats_array.length i->(Vector.Vector (stats_array.at i)) + Vector.new stats_array.length i->(Vector.from_polyglot_array (stats_array.at i)) ## Compute a single statistic on the vector. @@ -248,4 +248,4 @@ rank_data input method=Rank_Method.Average = handle_classcast <| handle_nullpointer <| java_ranks = Rank.rank input.to_array Comparator.new java_method - Vector.Vector java_ranks + Vector.from_polyglot_array java_ranks diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso index 6e5eb0903ebe..347e79644347 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso @@ -364,7 +364,7 @@ Text.split : Text -> (Text_Matcher | Regex_Matcher) -> Vector.Vector Text Text.split self delimiter="," matcher=Text_Matcher = if delimiter.is_empty then Error.throw (Illegal_Argument_Error "The delimiter cannot be empty.") else case matcher of Text_Matcher case_sensitivity -> - delimiters = Vector.Vector <| case case_sensitivity of + delimiters = Vector.from_polyglot_array <| case case_sensitivity of True -> Text_Utils.span_of_all self delimiter Case_Insensitive locale -> @@ -552,7 +552,7 @@ Text.words self keep_whitespace=False = '\na\nb\n'.lines keep_endings=True == ['\n', 'a\n', 'b\n'] Text.lines : Boolean -> Vector.Vector Text Text.lines self keep_endings=False = - Vector.Vector (Text_Utils.split_on_lines self keep_endings) + Vector.from_polyglot_array (Text_Utils.split_on_lines self keep_endings) ## Checks whether `self` is equal to `that`, ignoring the case of the texts. @@ -739,7 +739,7 @@ Text.is_whitespace self = Text.bytes : Encoding -> Problem_Behavior -> Vector.Vector Byte Text.bytes self encoding on_problems=Report_Warning = result = Encoding_Utils.get_bytes self (encoding . to_java_charset) - vector = Vector.Vector result.result + vector = Vector.from_polyglot_array result.result if result.warnings.is_nothing then vector else on_problems.attach_problems_after vector [Encoding_Error result.warnings] @@ -1481,8 +1481,8 @@ Text.location_of_all : Text -> Matcher -> [Span] Text.location_of_all self term="" matcher=Text_Matcher = case matcher of Text_Matcher case_sensitive -> if term.is_empty then Vector.new (self.length + 1) (ix -> Span (Range ix ix) self) else case case_sensitive of True -> - codepoint_spans = Vector.Vector <| Text_Utils.span_of_all self term - grahpeme_ixes = Vector.Vector <| Text_Utils.utf16_indices_to_grapheme_indices self (codepoint_spans.map .codeunit_start).to_array + codepoint_spans = Vector.from_polyglot_array <| Text_Utils.span_of_all self term + grahpeme_ixes = Vector.from_polyglot_array <| Text_Utils.utf16_indices_to_grapheme_indices self (codepoint_spans.map .codeunit_start).to_array ## While the codepoint_spans may have different code unit lengths from our term, the `length` counted in grapheme clusters is guaranteed to be the same. @@ -1491,7 +1491,7 @@ Text.location_of_all self term="" matcher=Text_Matcher = case matcher of end = start+offset Span (Range start end) self Case_Insensitive locale -> - grapheme_spans = Vector.Vector <| Text_Utils.span_of_all_case_insensitive self term locale.java_locale + grapheme_spans = Vector.from_polyglot_array <| Text_Utils.span_of_all_case_insensitive self term locale.java_locale grapheme_spans.map grapheme_span-> Span (Range grapheme_span.grapheme_start grapheme_span.grapheme_end) self Regex_Matcher _ _ _ _ _ -> diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Engine/Default.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Engine/Default.enso index ec79e2e83391..a91601df56ca 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Engine/Default.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Regex/Engine/Default.enso @@ -477,7 +477,7 @@ type Pattern Mode_Error "Splitting on a bounded region is not well-defined." splits = self.internal_pattern.split input limit - Vector.Vector splits + Vector.from_polyglot_array splits ## ADVANCED @@ -683,7 +683,7 @@ type Match matcg.named_groups default="UNMATCHED" named_groups : (a : Any) -> Map Text (Text | a) named_groups self default=Nothing = - group_names = Vector.Vector <| + group_names = Vector.from_polyglot_array <| Regex_Utils.get_group_names self.internal_match.pattern pairs = group_names.map name-> value = case self.group name of diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso index ba512c73d4b4..4f0bc049447c 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso @@ -98,7 +98,7 @@ type Vector The basic, immutable, vector type. Arguments: - - to_array: The underlying array. + - storage: The underlying storage. A vector allows to store an arbitrary number of elements, in linear memory. It is the recommended data structure for most applications. @@ -111,7 +111,10 @@ type Vector A vector containing 50 elements, each being the number `42`, can be created by: Vector.fill length=50 item=42 - type Vector to_array + type Vector storage + + to_array self = + self.storage.to_array ## Returns the number of elements stored in this vector. @@ -121,7 +124,7 @@ type Vector [1, 2, 3, 4].length length : Number length self = - self.to_array.length + self.storage.length ## Gets an element from the vector at a specified index (0-based). @@ -154,7 +157,7 @@ type Vector bounds or with additional error handling. unsafe_at : Integer -> Any unsafe_at self index = - self.to_array.at index + self.storage.at index ## Combines all the elements of the vector, by iteratively applying the passed function with next elements of the vector. @@ -174,8 +177,7 @@ type Vector [0, 1, 2] . fold 0 (+) fold : Any -> (Any -> Any -> Any) -> Any fold self init function = - arr = self.to_array - f = acc -> ix -> function acc (arr.at ix) + f = acc -> ix -> function acc (self.storage.at ix) 0.up_to self.length . fold init f ## Combines all the elements of the vector, by iteratively applying the @@ -189,11 +191,10 @@ type Vector > Example Compute the sum of all of the elements and indexes in a vector. - [0, 1, 2] . fold 0 (s->i->e->s+i+e) + [0, 1, 2] . fold_with_index 0 (s->i->e->s+i+e) fold_with_index : Any -> (Any -> Integer -> Any -> Any) -> Any fold_with_index self init function = - arr = self.to_array - f = acc -> ix -> function acc ix (arr.at ix) + f = acc -> ix -> function acc ix (self.storage.at ix) 0.up_to self.length . fold init f ## Combines all the elements of a non-empty vector using a binary operation. @@ -211,8 +212,7 @@ type Vector reduce self function = case self.not_empty of True -> if self.length == 1 then self.unsafe_at 0 else - arr = self.to_array - f = acc -> ix -> function acc (arr.at ix) + f = acc -> ix -> function acc (self.storage.at ix) 1.up_to self.length . fold (self.unsafe_at 0) f False -> Error.throw Empty_Error diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/Http/Response.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/Http/Response.enso index 7fa19f3e4373..f8afd8a6d691 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Network/Http/Response.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Network/Http/Response.enso @@ -28,7 +28,7 @@ type Response example_headers = Examples.get_response.headers headers : Vector.Vector headers self = - header_entries = Vector.Vector (Http_Utils.get_headers self.internal_http_response.headers) + header_entries = Vector.from_polyglot_array (Http_Utils.get_headers self.internal_http_response.headers) header_entries.map e-> Header.new e.getKey e.getValue ## Get the response body. @@ -41,7 +41,7 @@ type Response example_body = Examples.get_response.body body : Response_Body - body self = Response_Body.Body (Vector.Vector self.internal_http_response.body) + body self = Response_Body.Body (Vector.from_polyglot_array self.internal_http_response.body) ## Get the response status code. diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso index 98f58b3aee3a..d68a248ed374 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso @@ -1,4 +1,4 @@ -from Standard.Base import Polyglot +from Standard.Base import Polyglot, Array ## Advanced @@ -9,15 +9,19 @@ type Proxy_Polyglot_Array ## Returns the number of elements stored in this Polyglot Array. - > Example - Checking the length of a vector. - - [1, 2, 3, 4].length - length : Number - length self = Polyglot.get_array_size self.arr + length self = + Polyglot.get_array_size self.arr ## Gets an element from this Polyglot Array at a specified index (0-based). at : Number -> Any - at self index = Polyglot.read_array_element self.arr index + at self index = + Polyglot.read_array_element self.arr index + + to_array : Array Any + to_array self = + len = self.length + a = Array.new len + 0.up_to len . each ix-> a.set_at ix (self.at ix) + a diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso index 9ac21f3124bb..c1895a95e549 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso @@ -646,7 +646,7 @@ type File read_last_bytes : Integer -> Vector ! File_Error read_last_bytes self n = handle_java_exceptions self <| - Vector.Vector (self.read_last_bytes_builtin n) + Vector.from_polyglot_array (self.read_last_bytes_builtin n) ## PRIVATE read_last_bytes_builtin : Integer -> Array @@ -837,7 +837,7 @@ type Output_Stream replacement_sequence = Encoding_Utils.INVALID_CHARACTER.bytes encoding on_problems=Problem_Behavior.Ignore java_charset = encoding.to_java_charset results = Encoding_Utils.with_stream_encoder java_stream java_charset replacement_sequence.to_array action - problems = Vector.Vector results.problems . map Encoding_Error + problems = Vector.from_polyglot_array results.problems . map Encoding_Error on_problems.attach_problems_after results.result problems ## An input stream, allowing for interactive reading of contents from an open @@ -874,7 +874,7 @@ type Input_Stream read_all_bytes : Vector.Vector ! File_Error read_all_bytes self = self.stream_resource . with java_stream-> handle_java_exceptions self.file <| - Vector.Vector java_stream.readAllBytes + Vector.from_polyglot_array java_stream.readAllBytes ## ADVANCED @@ -1122,4 +1122,4 @@ Vector.Vector.write_bytes self path on_existing_file=Existing_File_Behavior.Back file = new path on_existing_file.write file stream-> - stream.write_bytes (Vector.Vector byte_array) + stream.write_bytes (Vector.from_polyglot_array byte_array) diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso index 3f15d517dbde..be29a49d26e6 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Connection/Connection.enso @@ -64,7 +64,7 @@ type Connection self.connection_resource.with connection-> metadata = connection.getMetaData schema_result_set = metadata.getCatalogs - Vector.Vector (JDBCProxy.getStringColumn schema_result_set "TABLE_CAT") + Vector.from_polyglot_array (JDBCProxy.getStringColumn schema_result_set "TABLE_CAT") ## Returns the list of schemas for the connection within the current database (or catalog). schemas : [Text] @@ -73,7 +73,7 @@ type Connection self.connection_resource.with connection-> metadata = connection.getMetaData schema_result_set = metadata.getSchemas - Vector.Vector (JDBCProxy.getStringColumn schema_result_set "TABLE_SCHEM") + Vector.from_polyglot_array (JDBCProxy.getStringColumn schema_result_set "TABLE_SCHEM") ## ADVANCED @@ -208,8 +208,8 @@ type Connection Resource.bracket (java_connection.prepareStatement insert_template) .close stmt-> num_rows = table.row_count columns = table.columns - check_rows updates_array expected_size = - updates = Vector.Vector updates_array + check_rows updates_polyglot_array expected_size = + updates = Vector.from_polyglot_array updates_polyglot_array if updates.length != expected_size then Panic.throw <| Illegal_State_Error "The batch update unexpectedly affected "+updates.length.to_text+" rows instead of "+expected_size.to_text+"." else updates.each affected_rows-> if affected_rows != 1 then diff --git a/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Histogram.enso b/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Histogram.enso index d94d10ed3112..6425580fea2e 100644 --- a/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Histogram.enso +++ b/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Histogram.enso @@ -52,4 +52,4 @@ type Histogram Image.Image.histogram : Integer -> Histogram Image.Image.histogram self channel = hist = Java_Histogram.calculate self.opencv_mat channel - Histogram channel (Vector.Vector hist.get_data) + Histogram channel (Vector.from_polyglot_array hist.get_data) diff --git a/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Image.enso b/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Image.enso index 7ae3ab597098..51b4d41dba02 100644 --- a/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Image.enso +++ b/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Image.enso @@ -101,7 +101,7 @@ type Image if (row < 0) || (row >= self.rows) then Error.throw (Matrix.Index_Out_Of_Bounds_Error self.rows self.columns row) else if (column < 0) || (column >= self.columns) then Error.throw (Matrix.Index_Out_Of_Bounds_Error self.rows self.columns column) else arr = Java_Image.get self.opencv_mat row column - Vector.Vector arr + Vector.from_polyglot_array arr ## UNSTABLE @@ -344,7 +344,7 @@ type Image to_vector : Vector to_vector self = arr = Java_Image.to_vector self.opencv_mat - Vector.Vector arr + Vector.from_polyglot_array arr ## UNSTABLE diff --git a/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Matrix.enso b/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Matrix.enso index 3c2152ff5c6e..e77f55e3118e 100644 --- a/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Matrix.enso +++ b/distribution/lib/Standard/Image/0.0.0-dev/src/Data/Matrix.enso @@ -152,7 +152,7 @@ type Matrix if (row < 0) || (row >= self.rows) then Error.throw (Index_Out_Of_Bounds_Error self.rows self.columns row) else if (column < 0) || (column >= self.columns) then Error.throw (Index_Out_Of_Bounds_Error self.rows self.columns column) else arr = Java_Matrix.get self.opencv_mat row column - Vector.Vector arr + Vector.from_polyglot_array arr ## UNSTABLE @@ -413,7 +413,7 @@ type Matrix to_vector : Vector to_vector self = arr = Java_Matrix.to_vector self.opencv_mat - Vector.Vector arr + Vector.from_polyglot_array arr ## UNSTABLE diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index eb62bcaffc70..108842c8dd92 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -767,7 +767,7 @@ type Column example_to_vector = Examples.integer_column.to_vector to_vector : Vector - to_vector self = Vector.Vector self.java_column.getStorage.toList + to_vector self = Vector.from_polyglot_array self.java_column.getStorage.toList ## Returns the underlying storage type of this column. @@ -875,7 +875,7 @@ type Column example_sum = Examples.integer_column.sum sum : Any - sum self = self.java_column.aggregate 'sum' (x-> Vector.Vector x . reduce (+)) True + sum self = self.java_column.aggregate 'sum' (x-> Vector.from_polyglot_array x . reduce (+)) True ## ALIAS Max Columns @@ -889,7 +889,7 @@ type Column example_max = Examples.integer_column.max max : Any max self = - self.java_column.aggregate 'max' (x-> Vector.Vector x . reduce Math.max) True + self.java_column.aggregate 'max' (x-> Vector.from_polyglot_array x . reduce Math.max) True ## ALIAS Min Columns @@ -903,7 +903,7 @@ type Column example_min = Examples.integer_column.min min : Any min self = - self.java_column.aggregate 'min' (x-> Vector.Vector x . reduce Math.min) True + self.java_column.aggregate 'min' (x-> Vector.from_polyglot_array x . reduce Math.min) True ## ALIAS Mean Columns @@ -918,7 +918,7 @@ type Column mean : Any mean self = vec_mean v = if v.length == 0 then Nothing else - (Vector.Vector v).reduce (+) / v.length + (Vector.from_polyglot_array v).reduce (+) / v.length self.java_column.aggregate 'mean' vec_mean True ## Computes the variance of the sample represented by this column. @@ -1153,7 +1153,7 @@ type Aggregate_Column Examples.aggregate_column.reduce .length . rename "transaction_count" reduce : (Vector.Vector -> Any) -> Boolean -> Text -> Column reduce self function skip_missing=True name_suffix="_result" = - f arr = function (Vector.Vector arr) + f arr = function (Vector.from_polyglot_array arr) r = self.java_column.aggregate Nothing name_suffix f skip_missing Column r @@ -1172,7 +1172,7 @@ type Aggregate_Column example_sum = Examples.aggregate_column.sum . rename "id_sum" sum : Text -> Column sum self name_suffix='_sum' = - r = self.java_column.aggregate 'sum' name_suffix (x-> Vector.Vector x . reduce (+)) True + r = self.java_column.aggregate 'sum' name_suffix (x-> Vector.from_polyglot_array x . reduce (+)) True Column r ## Computes the maximum element of each group. @@ -1189,7 +1189,7 @@ type Aggregate_Column example_max = Examples.aggregate_column.max . rename "latest_transaction" max : Text -> Column max self name_suffix='_max' = - r = self.java_column.aggregate 'max' name_suffix (x-> Vector.Vector x . reduce Math.max) True + r = self.java_column.aggregate 'max' name_suffix (x-> Vector.from_polyglot_array x . reduce Math.max) True Column r ## Computes the minimum element of each group. @@ -1206,7 +1206,7 @@ type Aggregate_Column example_min = Examples.aggregate_column.min . rename "first_transaction" min : Text -> Column min self name_suffix='_min' = - r = self.java_column.aggregate 'min' name_suffix (x-> Vector.Vector x . reduce Math.min) True + r = self.java_column.aggregate 'min' name_suffix (x-> Vector.from_polyglot_array x . reduce Math.min) True Column r ## Computes the number of non-missing elements in each group. @@ -1242,7 +1242,7 @@ type Aggregate_Column mean : Text -> Column mean self name_suffix='_mean' = vec_mean v = if v.length == 0 then Nothing else - (Vector.Vector v).reduce (+) / v.length + (Vector.from_polyglot_array v).reduce (+) / v.length r = self.java_column.aggregate 'mean' name_suffix vec_mean True Column r @@ -1261,7 +1261,7 @@ type Aggregate_Column example_values = Examples.aggregate_column.values values : Text -> Column values self name_suffix='_values' = - r = self.java_column.aggregate Nothing name_suffix Vector.Vector False + r = self.java_column.aggregate Nothing name_suffix Vector.from_polyglot_array False Column r ## Prints an ASCII-art column with this data to the standard output. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Data_Formatter.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Data_Formatter.enso index 404b47ae2e81..124bd953eec2 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Data_Formatter.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Data_Formatter.enso @@ -73,7 +73,7 @@ type Data_Formatter Auto -> self.make_auto_parser _ -> self.make_datatype_parser datatype result = parser.parseIndependentValue text - problems = Vector.Vector result.problems . map (Parse_Values_Helper.translate_parsing_problem datatype) + problems = Vector.from_polyglot_array result.problems . map (Parse_Values_Helper.translate_parsing_problem datatype) on_problems.attach_problems_after result.value problems ## Format a value into a Text. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso index 220de7179327..812cdb348743 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso @@ -153,7 +153,7 @@ type Table example_display = Examples.inventory_table.display display : Integer -> Boolean -> Text display self show_rows=10 format_terminal=False = - cols = Vector.Vector self.java_table.getColumns + cols = Vector.from_polyglot_array self.java_table.getColumns index = self.java_table.getIndex col_names = [index.getName] + cols.map .getName col_vals = cols.map .getStorage @@ -710,7 +710,7 @@ type Table storage = column.java_column.getStorage new_storage_and_problems = parser.parseColumn column.name storage new_storage = new_storage_and_problems.value - problems = Vector.Vector new_storage_and_problems.problems . map (Parse_Values_Helper.translate_parsing_problem expected_type) + problems = Vector.from_polyglot_array new_storage_and_problems.problems . map (Parse_Values_Helper.translate_parsing_problem expected_type) problems.each problem_builder.append Column.Column (Java_Column.new column.name column.java_column.getIndex new_storage) @@ -782,7 +782,7 @@ type Table example_columns = Examples.inventory_table.columns columns : Vector - columns self = Vector.Vector self.java_table.getColumns . map Column.Column + columns self = Vector.from_polyglot_array self.java_table.getColumns . map Column.Column ## Sets the index of this table, using the column with the provided name. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso index 5198a5008f9f..f87f1794b675 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Errors.enso @@ -217,7 +217,7 @@ Column_Name_Mismatch.to_display_text self = self.message Column_Name_Mismatch.handle_java_exception = throw_column_name_mismatch caught_panic = cause = caught_panic.payload.cause - Error.throw (Column_Name_Mismatch (Vector.Vector cause.getMissing) (Vector.Vector cause.getExtras) cause.getMessage) + Error.throw (Column_Name_Mismatch (Vector.from_polyglot_array cause.getMissing) (Vector.from_polyglot_array cause.getExtras) cause.getMessage) Panic.catch ColumnNameMismatchException handler=throw_column_name_mismatch ## UNSTABLE diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/IO/Excel.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/IO/Excel.enso index 2fbf7554827c..afad70f21b25 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/IO/Excel.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/IO/Excel.enso @@ -182,8 +182,8 @@ validate validation ~error_message ~wrapped = read_excel : File -> Excel_Section -> (Boolean|Infer) -> Problem_Behavior -> Boolean -> (Table | Vector) read_excel file section headers on_problems xls_format=False = reader stream = case section of - Sheet_Names -> Vector.Vector (ExcelReader.readSheetNames stream xls_format) - Range_Names -> Vector.Vector (ExcelReader.readRangeNames stream xls_format) + Sheet_Names -> Vector.from_polyglot_array (ExcelReader.readSheetNames stream xls_format) + Range_Names -> Vector.from_polyglot_array (ExcelReader.readRangeNames stream xls_format) Sheet sheet skip_rows row_limit -> prepare_reader_table on_problems <| case sheet of Integer -> ExcelReader.readSheetByIndex stream sheet (make_java_headers headers) skip_rows row_limit xls_format @@ -227,10 +227,10 @@ write_excel file table on_existing_file section headers match_columns _ xls_form prepare_reader_table : Problem_Behavior -> Any -> Table prepare_reader_table on_problems result_with_problems = map_problem java_problem = - if Java.is_instance java_problem DuplicateNames then Duplicate_Output_Column_Names (Vector.Vector java_problem.duplicatedNames) else - if Java.is_instance java_problem InvalidNames then Invalid_Output_Column_Names (Vector.Vector java_problem.invalidNames) else + if Java.is_instance java_problem DuplicateNames then Duplicate_Output_Column_Names (Vector.from_polyglot_array java_problem.duplicatedNames) else + if Java.is_instance java_problem InvalidNames then Invalid_Output_Column_Names (Vector.from_polyglot_array java_problem.invalidNames) else java_problem - parsing_problems = Vector.Vector (result_with_problems.problems) . map map_problem + parsing_problems = Vector.from_polyglot_array (result_with_problems.problems) . map map_problem on_problems.attach_problems_after (Table.Table result_with_problems.value) parsing_problems ## PRIVATE diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Aggregate_Column_Helper.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Aggregate_Column_Helper.enso index d8831038d1ee..5c54092002b0 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Aggregate_Column_Helper.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Aggregate_Column_Helper.enso @@ -218,9 +218,9 @@ parse_aggregated_problems problems = problems_array = problems.getProblems parsed = Vector.new problems_array.length i-> p = problems_array.at i - if Java.is_instance p InvalidAggregation then Invalid_Aggregation p.getColumnName (Vector.Vector p.getRows) p.getMessage else - if Java.is_instance p FloatingPointGrouping then Floating_Point_Grouping p.getColumnName (Vector.Vector p.getRows) else - if Java.is_instance p UnquotedDelimiter then Unquoted_Delimiter p.getColumnName (Vector.Vector p.getRows) else + if Java.is_instance p InvalidAggregation then Invalid_Aggregation p.getColumnName (Vector.from_polyglot_array p.getRows) p.getMessage else + if Java.is_instance p FloatingPointGrouping then Floating_Point_Grouping p.getColumnName (Vector.from_polyglot_array p.getRows) else + if Java.is_instance p UnquotedDelimiter then Unquoted_Delimiter p.getColumnName (Vector.from_polyglot_array p.getRows) else Invalid_Aggregation Nothing -1 "Unknown Error" if problems.getCount == problems_array.length then parsed else diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Delimited_Reader.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Delimited_Reader.enso index 88211db22cb7..64292c316475 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Delimited_Reader.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Delimited_Reader.enso @@ -91,7 +91,7 @@ read_from_reader format java_reader on_problems max_columns=4096 = Illegal_Argument_Error.handle_java_exception <| handle_parsing_failure <| handle_parsing_exception <| reader = prepare_delimited_reader java_reader format max_columns on_problems result_with_problems = reader.read - parsing_problems = Vector.Vector (result_with_problems.problems) . map translate_reader_problem + parsing_problems = Vector.from_polyglot_array (result_with_problems.problems) . map translate_reader_problem on_problems.attach_problems_after (Table.Table result_with_problems.value) parsing_problems ## PRIVATE @@ -124,11 +124,11 @@ prepare_delimited_reader java_reader format max_columns on_problems newline_over DelimitedReader.new java_reader format.delimiter quote_characters.first quote_characters.second java_headers format.skip_rows row_limit max_columns value_parser cell_type_guesser format.keep_invalid_rows newline format.comment_character warnings_as_errors translate_reader_problem problem = - invalid_row = [InvalidRow, (java_problem-> Invalid_Row java_problem.source_row java_problem.table_index (Vector.Vector java_problem.row))] + invalid_row = [InvalidRow, (java_problem-> Invalid_Row java_problem.source_row java_problem.table_index (Vector.from_polyglot_array java_problem.row))] additional_invalid_rows = [AdditionalInvalidRows, (java_problem-> Additional_Invalid_Rows java_problem.count)] mismatched_quote = [MismatchedQuote, (_-> Mismatched_Quote)] - duplicate_names = [DuplicateNames, (java_problem-> Duplicate_Output_Column_Names (Vector.Vector java_problem.duplicatedNames))] - invalid_names = [InvalidNames, (java_problem-> Invalid_Output_Column_Names (Vector.Vector java_problem.invalidNames))] + duplicate_names = [DuplicateNames, (java_problem-> Duplicate_Output_Column_Names (Vector.from_polyglot_array java_problem.duplicatedNames))] + invalid_names = [InvalidNames, (java_problem-> Invalid_Output_Column_Names (Vector.from_polyglot_array java_problem.invalidNames))] translations = [invalid_row, additional_invalid_rows, mismatched_quote, duplicate_names, invalid_names] found = translations.find t-> Java.is_instance problem t.first @@ -185,7 +185,7 @@ detect_metadata file format = column_count = reader.getColumnCount if column_count == 0 then Nothing else No_Headers column_count - _ -> Existing_Headers (Vector.Vector defined_columns) + _ -> Existing_Headers (Vector.from_polyglot_array defined_columns) line_separator_from_parser = reader.getEffectiveLineSeparator has_seen_newline = newline_detecting_reader.newlineEncountered ## If the parser has seen a newline, we can trust that it diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Parse_Values_Helper.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Parse_Values_Helper.enso index 094b56adb86e..e97955af1019 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Parse_Values_Helper.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Parse_Values_Helper.enso @@ -6,8 +6,8 @@ polyglot java import org.enso.table.parsing.problems.InvalidFormat polyglot java import org.enso.table.parsing.problems.LeadingZeros translate_parsing_problem expected_datatype problem = - invalid_format = [InvalidFormat, (java_problem-> Invalid_Format java_problem.column expected_datatype (Vector.Vector java_problem.cells))] - leading_zeros = [LeadingZeros, (java_problem-> Leading_Zeros java_problem.column expected_datatype (Vector.Vector java_problem.cells))] + invalid_format = [InvalidFormat, (java_problem-> Invalid_Format java_problem.column expected_datatype (Vector.from_polyglot_array java_problem.cells))] + leading_zeros = [LeadingZeros, (java_problem-> Leading_Zeros java_problem.column expected_datatype (Vector.from_polyglot_array java_problem.cells))] translations = [invalid_format, leading_zeros] found = translations.find t-> Java.is_instance problem t.first diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso index ec04f6fad5ac..1ed21a7f2039 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Unique_Name_Strategy.enso @@ -29,12 +29,12 @@ type Unique_Name_Strategy ## Vector of any duplicates renamed renames : Vector - renames self = Vector.Vector self.deduplicator.getDuplicatedNames + renames self = Vector.from_polyglot_array self.deduplicator.getDuplicatedNames ## Vector of any invalid names invalid_names : Vector - invalid_names self = Vector.Vector self.deduplicator.getInvalidNames + invalid_names self = Vector.from_polyglot_array self.deduplicator.getInvalidNames ## Takes a value and converts to a valid (but not necessarily unique) name diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java index ef4b726c9e10..b9f94074428b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java @@ -7,6 +7,7 @@ import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.epb.node.CoercePrimitiveNode; import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.builtin.Builtins; import org.enso.interpreter.runtime.error.PanicException; @@ -19,11 +20,15 @@ public class ReadArrayElementNode extends Node { private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); + + private @Child + CoercePrimitiveNode coercion = CoercePrimitiveNode.build(); private final BranchProfile err = BranchProfile.create(); Object execute(Object array, long index) { try { - return library.readArrayElement(array, index); + Object elem = library.readArrayElement(array, index); + return coercion.execute(elem); } catch (UnsupportedMessageException e) { err.enter(); Builtins builtins = Context.get(this).getBuiltins(); diff --git a/test/Tests/src/Data/Vector_Spec.enso b/test/Tests/src/Data/Vector_Spec.enso index fc87d7713b9d..e958e162127f 100644 --- a/test/Tests/src/Data/Vector_Spec.enso +++ b/test/Tests/src/Data/Vector_Spec.enso @@ -26,9 +26,15 @@ compare_tco a b = case a.vec.length == b.vec.length of foreign js generate_js_array = """ return [1, 2, 3, 4, 5] +foreign js generate_nested_js_array = """ + return [[1, 2, 3], [4, 5]] + foreign python generate_py_array = """ return [1, 2, 3, 4, 5] +foreign python generate_nested_py_array = """ + return [[1, 2, 3], [4, 5]] + spec = Test.group "Vectors" <| Test.specify "text bytes" <| @@ -46,6 +52,12 @@ spec = Test.group "Vectors" <| built_from_py = Vector.from_polyglot_array generate_py_array built_from_py . should_equal [1, 2, 3, 4, 5] + Test.specify "should allow creation from arrays without mutability for nested arrays" pending="Polyglot Arrays/Vector rewrite" <| + built_from_js = Vector.from_polyglot_array generate_nested_js_array + built_from_js . should_equal [[1, 2, 3], [4, 5]] + built_from_py = Vector.from_polyglot_array generate_nested_py_array + built_from_py . should_equal [[1, 2, 3], [4, 5]] + Test.specify "should allow accessing elements" <| [1,2,3].at 0 . should_equal 1 [1,2,3].at 2 . should_equal 3 diff --git a/test/Tests/src/Semantic/Python_Interop_Spec.enso b/test/Tests/src/Semantic/Python_Interop_Spec.enso index b0512edb001f..f3022bb3d7eb 100644 --- a/test/Tests/src/Semantic/Python_Interop_Spec.enso +++ b/test/Tests/src/Semantic/Python_Interop_Spec.enso @@ -85,7 +85,7 @@ spec = obj.compare 11 . should_be_true Test.specify "should expose array interfaces for Python arrays" <| - vec = Vector.Vector make_array + vec = Vector.from_polyglot_array make_array vec.map .x . should_equal [10, 20, 30] Test.specify "should correctly marshall strings" <| diff --git a/test/Tests/src/Semantic/R_Interop_Spec.enso b/test/Tests/src/Semantic/R_Interop_Spec.enso index 462843f37688..76eea7f11e69 100644 --- a/test/Tests/src/Semantic/R_Interop_Spec.enso +++ b/test/Tests/src/Semantic/R_Interop_Spec.enso @@ -68,7 +68,7 @@ spec = obj.compare 11 . should_be_true Test.specify "should expose array interfaces for R arrays" <| - vec = Vector.Vector make_array + vec = Vector.from_polyglot_array make_array vec.map .x . should_equal [10, 20, 30] Test.specify "should correctly marshall strings" <| From be14f6b862c396771a83825e895cacd9cbc34bca Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 5 Aug 2022 19:00:30 +0200 Subject: [PATCH 06/13] Don't leak polyglot null values to Enso Fixed a bug in our handling of polyglot values by 1) doing coercion of primitive values on all languages 2) explicitly checking for null values 3) whenever foreign calls return null we translate that to Nothing --- .../epb/node/CoercePrimitiveNode.java | 5 ++ .../interpreter/epb/node/JsForeignNode.java | 7 ++- .../interpreter/epb/node/RForeignNode.java | 4 +- .../interop/generic/ReadArrayElementNode.java | 50 ++++++++++--------- .../foreign/ForeignMethodCallNode.java | 8 ++- test/Tests/src/Data/Vector_Spec.enso | 4 +- test/Tests/src/Semantic/Js_Interop_Spec.enso | 7 +++ .../src/Semantic/Python_Interop_Spec.enso | 4 ++ test/Tests/src/Semantic/R_Interop_Spec.enso | 7 +++ 9 files changed, 66 insertions(+), 30 deletions(-) diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java index 2025308adc24..5039fc4496c3 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java @@ -64,6 +64,11 @@ long doInteger(Object integer, @CachedLibrary(limit = "5") InteropLibrary number } } + @Specialization(guards = "interop.isNull(value)") + Object doNull(Object value, @CachedLibrary(limit = "5") InteropLibrary interop) { + return null; + } + @Fallback Object doNonPrimitive(Object value) { return value; diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/JsForeignNode.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/JsForeignNode.java index 1594055eccd6..9b3c63539fb2 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/JsForeignNode.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/JsForeignNode.java @@ -12,6 +12,8 @@ @NodeField(name = "arity", type = int.class) public abstract class JsForeignNode extends ForeignFunctionCallNode { + private @Child CoercePrimitiveNode coercePrimitiveNode = CoercePrimitiveNode.build(); + abstract Object getForeignFunction(); abstract int getArity(); @@ -35,8 +37,9 @@ Object doExecute( Object[] positionalArgs = new Object[newLength]; System.arraycopy(arguments, 1, positionalArgs, 0, newLength); try { - return interopLibrary.invokeMember( - getForeignFunction(), "apply", arguments[0], new ReadOnlyArray(positionalArgs)); + return coercePrimitiveNode.execute( + interopLibrary.invokeMember( + getForeignFunction(), "apply", arguments[0], new ReadOnlyArray(positionalArgs))); } catch (UnsupportedMessageException | UnknownIdentifierException | ArityException diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/RForeignNode.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/RForeignNode.java index 8670a8b7385a..d3703af4b049 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/RForeignNode.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/RForeignNode.java @@ -11,13 +11,15 @@ @NodeField(name = "foreignFunction", type = Object.class) public abstract class RForeignNode extends ForeignFunctionCallNode { + private @Child CoercePrimitiveNode coercePrimitiveNode = CoercePrimitiveNode.build(); + abstract Object getForeignFunction(); @Specialization public Object doExecute( Object[] arguments, @CachedLibrary("foreignFunction") InteropLibrary interopLibrary) { try { - return interopLibrary.execute(getForeignFunction(), arguments); + return coercePrimitiveNode.execute(interopLibrary.execute(getForeignFunction(), arguments)); } catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) { throw new IllegalStateException("R parser returned a malformed object", e); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java index b9f94074428b..1b9f562b3873 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java @@ -13,32 +13,34 @@ import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( - type = "Polyglot", - name = "read_array_element", - description = "Returns the size of a polyglot array.") + type = "Polyglot", + name = "read_array_element", + description = "Returns the size of a polyglot array.") public class ReadArrayElementNode extends Node { - private @Child - InteropLibrary library = - InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); + private @Child InteropLibrary library = + InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); - private @Child - CoercePrimitiveNode coercion = CoercePrimitiveNode.build(); - private final BranchProfile err = BranchProfile.create(); + private @Child CoercePrimitiveNode coercion = CoercePrimitiveNode.build(); + private final BranchProfile err = BranchProfile.create(); - Object execute(Object array, long index) { - try { - Object elem = library.readArrayElement(array, index); - return coercion.execute(elem); - } catch (UnsupportedMessageException e) { - err.enter(); - Builtins builtins = Context.get(this).getBuiltins(); - throw new PanicException( - builtins.error().makeTypeError(builtins.array(), array, "array"), this); - } catch (InvalidArrayIndexException e) { - err.enter(); - Builtins builtins = Context.get(this).getBuiltins(); - throw new PanicException( - builtins.error().makeInvalidArrayIndexError(array, index), this); - } + Object execute(Object array, long index) { + try { + Object elem = coercion.execute(library.readArrayElement(array, index)); + if (elem == null) { + Builtins builtins = Context.get(this).getBuiltins(); + return builtins.nothing().newInstance(); + } else { + return elem; + } + } catch (UnsupportedMessageException e) { + err.enter(); + Builtins builtins = Context.get(this).getBuiltins(); + throw new PanicException( + builtins.error().makeTypeError(builtins.array(), array, "array"), this); + } catch (InvalidArrayIndexException e) { + err.enter(); + Builtins builtins = Context.get(this).getBuiltins(); + throw new PanicException(builtins.error().makeInvalidArrayIndexError(array, index), this); } + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java index dc7b6b65f4a4..1888c99071d8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java @@ -6,6 +6,7 @@ import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.node.ExpressionNode; +import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.error.DataflowError; /** Performs a call into a given foreign call target. */ @@ -46,6 +47,11 @@ public Object executeGeneric(VirtualFrame frame) { return args[i]; } } - return callNode.call(args); + Object result = callNode.call(args); + if (result == null) { + return Context.get(this).getBuiltins().nothing().newInstance(); + } else { + return result; + } } } diff --git a/test/Tests/src/Data/Vector_Spec.enso b/test/Tests/src/Data/Vector_Spec.enso index e958e162127f..6b4b76282cf1 100644 --- a/test/Tests/src/Data/Vector_Spec.enso +++ b/test/Tests/src/Data/Vector_Spec.enso @@ -30,7 +30,7 @@ foreign js generate_nested_js_array = """ return [[1, 2, 3], [4, 5]] foreign python generate_py_array = """ - return [1, 2, 3, 4, 5] + return [1, 2, 3, 4, None] foreign python generate_nested_py_array = """ return [[1, 2, 3], [4, 5]] @@ -50,7 +50,7 @@ spec = Test.group "Vectors" <| built_from_js = Vector.from_polyglot_array generate_js_array built_from_js . should_equal [1, 2, 3, 4, 5] built_from_py = Vector.from_polyglot_array generate_py_array - built_from_py . should_equal [1, 2, 3, 4, 5] + built_from_py . should_equal [1, 2, 3, 4, Nothing] Test.specify "should allow creation from arrays without mutability for nested arrays" pending="Polyglot Arrays/Vector rewrite" <| built_from_js = Vector.from_polyglot_array generate_nested_js_array diff --git a/test/Tests/src/Semantic/Js_Interop_Spec.enso b/test/Tests/src/Semantic/Js_Interop_Spec.enso index aa317b08bd07..39399d0d1239 100644 --- a/test/Tests/src/Semantic/Js_Interop_Spec.enso +++ b/test/Tests/src/Semantic/Js_Interop_Spec.enso @@ -60,6 +60,9 @@ foreign js make_false = """ foreign js make_double = """ return 10.5 +foreign js make_null = """ + return null; + foreign js does_not_parse = """ return { x @@ -131,6 +134,10 @@ spec = Test.group "Polyglot JS" <| _ -> False r.should_be_true + Test.specify "should make JS null values equal to Nothing" <| + js_null = make_null + js_null . should_equal Nothing + Test.specify "should make JS numbers type pattern-matchable" <| int_match = case make_int of Integer -> True diff --git a/test/Tests/src/Semantic/Python_Interop_Spec.enso b/test/Tests/src/Semantic/Python_Interop_Spec.enso index f3022bb3d7eb..123bf507fa91 100644 --- a/test/Tests/src/Semantic/Python_Interop_Spec.enso +++ b/test/Tests/src/Semantic/Python_Interop_Spec.enso @@ -140,6 +140,10 @@ spec = Number -> True num_double_match.should_be_true + Test.specify "should make Python None values equal to Nothing" <| + py_null = make_null + py_null . should_equal Nothing + Test.specify "should allow Enso to catch Python exceptions" <| value = My_Type 1 2 result = Panic.recover Any <| value.my_throw diff --git a/test/Tests/src/Semantic/R_Interop_Spec.enso b/test/Tests/src/Semantic/R_Interop_Spec.enso index 76eea7f11e69..a553a0757be7 100644 --- a/test/Tests/src/Semantic/R_Interop_Spec.enso +++ b/test/Tests/src/Semantic/R_Interop_Spec.enso @@ -50,6 +50,9 @@ foreign r make_true = """ foreign r make_false = """ FALSE +foreign r make_null = """ + NULL + spec = pending = if Polyglot.is_language_installed "R" then Nothing else """ Can't run R tests, R is not installed. @@ -123,6 +126,10 @@ spec = Number -> True num_double_match.should_be_true + Test.specify "should make R null objects equal to Nothing" <| + r_null = make_null + r_null . should_equal Nothing + Test.specify "should allow Enso to catch R exceptions" <| value = My_Type 1 2 result = Panic.recover Any <| value.my_throw From e444e0437e7a4a15285dfbc3e03ef4daec74b754 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Mon, 8 Aug 2022 11:41:40 +0200 Subject: [PATCH 07/13] Use a separate node for null coercion This way we avoid explicit null checking which is admittedly not the nicest way of dealing with Nothing conversion. --- .../epb/node/CoercePrimitiveNode.java | 5 --- .../interop/generic/ReadArrayElementNode.java | 10 ++---- .../expression/foreign/CoerceNothing.java | 33 +++++++++++++++++++ .../foreign/ForeignMethodCallNode.java | 9 ++--- test/Visualization_Tests/src/Table_Spec.enso | 2 +- 5 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/CoerceNothing.java diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java index 5039fc4496c3..2025308adc24 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java @@ -64,11 +64,6 @@ long doInteger(Object integer, @CachedLibrary(limit = "5") InteropLibrary number } } - @Specialization(guards = "interop.isNull(value)") - Object doNull(Object value, @CachedLibrary(limit = "5") InteropLibrary interop) { - return null; - } - @Fallback Object doNonPrimitive(Object value) { return value; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java index 1b9f562b3873..48fccf26ae84 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java @@ -8,6 +8,7 @@ import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.epb.node.CoercePrimitiveNode; +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.error.PanicException; @@ -21,17 +22,12 @@ public class ReadArrayElementNode extends Node { InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private @Child CoercePrimitiveNode coercion = CoercePrimitiveNode.build(); + private @Child CoerceNothing nothingCoercion = CoerceNothing.build(); private final BranchProfile err = BranchProfile.create(); Object execute(Object array, long index) { try { - Object elem = coercion.execute(library.readArrayElement(array, index)); - if (elem == null) { - Builtins builtins = Context.get(this).getBuiltins(); - return builtins.nothing().newInstance(); - } else { - return elem; - } + return nothingCoercion.execute(coercion.execute(library.readArrayElement(array, index))); } catch (UnsupportedMessageException e) { err.enter(); Builtins builtins = Context.get(this).getBuiltins(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/CoerceNothing.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/CoerceNothing.java new file mode 100644 index 000000000000..2ac37422481e --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/CoerceNothing.java @@ -0,0 +1,33 @@ +package org.enso.interpreter.node.expression.foreign; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.library.CachedLibrary; +import org.enso.interpreter.runtime.Context; +import com.oracle.truffle.api.nodes.Node; + +public abstract class CoerceNothing extends Node { + public static CoerceNothing build() { + return CoerceNothingNodeGen.create(); + } + + /** + * Converts an null polyglot representation into an equivalent Nothing representation in Enso + * context. + * + * @param value the polyglot value to perform coercion on + * @return {@code value} coerced to an Enso primitive where applicable + */ + public abstract Object execute(Object value); + + @Specialization(guards = "interop.isNull(value)") + public Object doNothing(Object value, @CachedLibrary(limit = "1") InteropLibrary interop) { + return Context.get(this).getBuiltins().nothing().newInstance(); + } + + @Fallback + public Object doOther(Object value) { + return value; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java index 1888c99071d8..931b7657c0f3 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java @@ -13,11 +13,13 @@ public class ForeignMethodCallNode extends ExpressionNode { private @Children ExpressionNode[] arguments; private @Child DirectCallNode callNode; + private @Child CoerceNothing coerceNothingNode; private final BranchProfile[] errorProfiles; ForeignMethodCallNode(ExpressionNode[] arguments, CallTarget foreignCt) { this.arguments = arguments; this.callNode = DirectCallNode.create(foreignCt); + this.coerceNothingNode = CoerceNothing.build(); this.errorProfiles = new BranchProfile[arguments.length]; for (int i = 0; i < arguments.length; i++) { @@ -47,11 +49,6 @@ public Object executeGeneric(VirtualFrame frame) { return args[i]; } } - Object result = callNode.call(args); - if (result == null) { - return Context.get(this).getBuiltins().nothing().newInstance(); - } else { - return result; - } + return coerceNothingNode.execute(callNode.call(args)); } } diff --git a/test/Visualization_Tests/src/Table_Spec.enso b/test/Visualization_Tests/src/Table_Spec.enso index aa6265e4665f..4459f5de79ac 100644 --- a/test/Visualization_Tests/src/Table_Spec.enso +++ b/test/Visualization_Tests/src/Table_Spec.enso @@ -53,7 +53,7 @@ visualization_spec connection = g = t.aggregate [Group_By "A", Group_By "B", Average "C"] . at "Average C" vis2 = Visualization.prepare_visualization g 1 - json2 = make_json header=["Average C"] data=[[4.0]] all_rows=2 ixes_header=[] ixes=[] + json2 = make_json header=["Average C"] data=[[4]] all_rows=2 ixes_header=[] ixes=[] vis2 . should_equal json2 t2 = Dataframe_Table.new [["A", [1, 2, 3]], ["B", [4, 5, 6]], ["C", [7, 8, 9]]] From c7b0a3f5ba1596b7d8eab5da3003984fcc7fb9d9 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 19 Aug 2022 17:53:16 +0200 Subject: [PATCH 08/13] PR review --- .../builtin/interop/generic/ReadArrayElementNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java index 48fccf26ae84..836258acb89d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java @@ -16,7 +16,7 @@ @BuiltinMethod( type = "Polyglot", name = "read_array_element", - description = "Returns the size of a polyglot array.") + description = "Read a value from the array specified by the index.") public class ReadArrayElementNode extends Node { private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); From b811fdab739ca37a2879a18452a94f09424a7073 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Mon, 22 Aug 2022 10:47:03 +0200 Subject: [PATCH 09/13] Avoid copying Arrays One last request to avoid copying Arrays when the underlying storage is already an Array. --- .../lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso | 10 +++++++++- .../0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso | 5 +---- test/Tests/src/Semantic/Js_Interop_Spec.enso | 5 +++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso index 4f0bc049447c..1bf88cb4f40e 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso @@ -114,7 +114,15 @@ type Vector type Vector storage to_array self = - self.storage.to_array + arr = self.storage.to_array + case arr of + Array -> + arr + _ -> + len = self.storage.length + a = Array.new len + Array.copy arr 0 a 0 len + a ## Returns the number of elements stored in this vector. diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso index d68a248ed374..6f83d7439806 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot/Proxy_Polyglot_Array.enso @@ -21,7 +21,4 @@ type Proxy_Polyglot_Array to_array : Array Any to_array self = - len = self.length - a = Array.new len - 0.up_to len . each ix-> a.set_at ix (self.at ix) - a + self.arr diff --git a/test/Tests/src/Semantic/Js_Interop_Spec.enso b/test/Tests/src/Semantic/Js_Interop_Spec.enso index 39399d0d1239..f49f5ac8eef9 100644 --- a/test/Tests/src/Semantic/Js_Interop_Spec.enso +++ b/test/Tests/src/Semantic/Js_Interop_Spec.enso @@ -45,6 +45,9 @@ foreign js make_object = """ foreign js make_array = """ return [{ x: 10}, {x: 20}, {x: 30}]; +foreign js make_simple_array = """ + return [10, 20, 30]; + foreign js make_str str = """ return "foo " + str + " bar" @@ -95,6 +98,8 @@ spec = Test.group "Polyglot JS" <| Test.specify "should expose array interfaces for JS arrays" <| vec = Vector.from_polyglot_array make_array vec.map .x . should_equal [10, 20, 30] + vec2 = Vector.from_polyglot_array make_simple_array + vec2.to_array.at 0 . should_equal 10 Test.specify "should correctly marshall strings" <| str = make_str "x" + " baz" From e8813245eb3dadd223c93f69bd308221519a74fb Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Mon, 22 Aug 2022 16:04:35 +0200 Subject: [PATCH 10/13] Make python test in Vector_Spec optional --- test/Tests/src/Data/Vector_Spec.enso | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Tests/src/Data/Vector_Spec.enso b/test/Tests/src/Data/Vector_Spec.enso index 6b4b76282cf1..3a6e13b7cf4a 100644 --- a/test/Tests/src/Data/Vector_Spec.enso +++ b/test/Tests/src/Data/Vector_Spec.enso @@ -36,6 +36,8 @@ foreign python generate_nested_py_array = """ return [[1, 2, 3], [4, 5]] spec = Test.group "Vectors" <| + pending_python_missing = if Polyglot.is_language_installed "python" then Nothing else """ + Can't run Python tests, Python is not installed. Test.specify "text bytes" <| "Lore".utf_8 . should_equal [76, 111, 114, 101] @@ -49,6 +51,8 @@ spec = Test.group "Vectors" <| Test.specify "should allow creation from arrays without mutability" <| built_from_js = Vector.from_polyglot_array generate_js_array built_from_js . should_equal [1, 2, 3, 4, 5] + + Test.specify "should allow creation from arrays without mutability in Python" pending=pending_python_missing <| built_from_py = Vector.from_polyglot_array generate_py_array built_from_py . should_equal [1, 2, 3, 4, Nothing] From b22edb151b138416e3aa79418bd38989c22bdb15 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Tue, 23 Aug 2022 10:55:33 +0200 Subject: [PATCH 11/13] Missed two spots where we use polyglot arrays --- .../Base/0.0.0-dev/src/Data/Text/Encoding.enso | 2 +- .../Base/0.0.0-dev/src/Data/Text/Extensions.enso | 4 ++-- .../interpreter/epb/node/CoercePrimitiveNode.java | 13 +++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Encoding.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Encoding.enso index 4ad4cb1a0b4f..1d7a70c13cf0 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Encoding.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Encoding.enso @@ -9,7 +9,7 @@ polyglot java import org.enso.base.Text_Utils all_character_sets : Vector.Vector Text all_character_sets = java_array = Charset.availableCharsets.keySet.toArray - Vector.Vector java_array + Vector.from_polyglot_array java_array ## Get all available Encodings. all_encodings : Vector Encoding diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso index 347e79644347..431024be76af 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso @@ -817,7 +817,7 @@ Text.from_utf_8 bytes on_problems=Report_Warning = "Hello".char_vector Text.char_vector : Vector.Vector Integer -Text.char_vector self = Vector.Vector (Text_Utils.get_chars self) +Text.char_vector self = Vector.from_polyglot_array (Text_Utils.get_chars self) ## Takes a vector of characters and returns the text that results from it. @@ -840,7 +840,7 @@ Text.from_char_vector chars = Text_Utils.from_chars chars.to_array "Hello".codepoints Text.codepoints : Vector.Vector Integer -Text.codepoints self = Vector.Vector (Text_Utils.get_codepoints self) +Text.codepoints self = Vector.from_polyglot_array (Text_Utils.get_codepoints self) ## Takes an array of numbers and returns the text resulting from interpreting it as a sequence of Unicode codepoints. diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java index 2025308adc24..c36a2a432570 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/CoercePrimitiveNode.java @@ -64,6 +64,19 @@ long doInteger(Object integer, @CachedLibrary(limit = "5") InteropLibrary number } } + @Specialization(guards = {"characters.isString(character)", "isChar(character)"}) + long doChar(Object character, @CachedLibrary(limit = "5") InteropLibrary characters) { + try { + return characters.asString(character).charAt(0); + } catch (UnsupportedMessageException e) { + throw new IllegalStateException("Impossible, `character` is checked to be a long"); + } + } + + static boolean isChar(Object s) { + return s instanceof Character; + } + @Fallback Object doNonPrimitive(Object value) { return value; From fa41b709ab4293fd77ca8820e809db8a6b8f70df Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Tue, 23 Aug 2022 18:05:23 +0200 Subject: [PATCH 12/13] More missing conversions discovered by new changes --- distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso index 1a99ee719986..5bfbcd2f395a 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso @@ -28,7 +28,7 @@ type Random_Number_Generator sample : Vector Any -> Integer -> Random_Number_Generator -> Vector Any sample vector k rng = new_array = Random_Utils.sample vector.to_array k rng.java_random - Vector.Vector new_array + Vector.from_polyglot_array new_array ## Returns `k` indices sampled from the range [0, n-1] without replacement. @@ -36,4 +36,4 @@ sample vector k rng = random_indices : Integer -> Integer -> Random_Number_Generator -> Vector Integer random_indices n k rng = array = Random_Utils.random_indices n k rng.java_random - Vector.Vector array + Vector.from_polyglot_array array From 43a5daea30d67c2f8be1510135db4f70398b2120 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Tue, 23 Aug 2022 18:28:02 +0200 Subject: [PATCH 13/13] I think that's the last one --- test/Tests/src/Data/Text/Utils_Spec.enso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Tests/src/Data/Text/Utils_Spec.enso b/test/Tests/src/Data/Text/Utils_Spec.enso index a59dc6497453..c5ab451574ae 100644 --- a/test/Tests/src/Data/Text/Utils_Spec.enso +++ b/test/Tests/src/Data/Text/Utils_Spec.enso @@ -36,7 +36,7 @@ spec = Test.specify "should correctly translate a series of codepoint indices to a grapheme indices in a batch" <| translate_indices text ixes = - Vector.Vector <| Text_Utils.utf16_indices_to_grapheme_indices text ixes.to_array + Vector.from_polyglot_array <| Text_Utils.utf16_indices_to_grapheme_indices text ixes.to_array codepoint_indices = Vector.new text.char_vector.length ix->ix translate_indices text codepoint_indices . should_equal codepoints_to_graphemes