From 135be8342ee04415c94310845b1a182609d68595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Mon, 24 Oct 2022 14:59:54 +0200 Subject: [PATCH 01/14] Implement a basic row type --- .../Database/0.0.0-dev/src/Data/Table.enso | 12 +++++++++++ .../Table/0.0.0-dev/src/Data/Row.enso | 20 +++++++++++++++++++ .../Table/0.0.0-dev/src/Data/Table.enso | 16 +++++++++++++++ .../0.0.0-dev/src/Internal/Rows_View.enso | 19 ++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso create mode 100644 distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso index 08c31bb592f3..f22f7edc8e38 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso @@ -499,6 +499,18 @@ type Table columns : Vector Column columns self = self.internal_columns . map self.make_column + ## Returns a vector of rows contained in this table. + + In the database backend, it first materializes the table to in-memory. + + Arguments: + - max_rows: The maximum amount of rows to return. It is mainly meant for + the Database backend, to limit how many rows are downloaded. In the + in-memory backend it is only kept for API compatibility. + rows : Integer -> Vector Row + rows self max_rows=1000 = + self.read max_rows=max_rows . rows + ## UNSTABLE 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/Data/Row.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso new file mode 100644 index 000000000000..21c5d607382f --- /dev/null +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso @@ -0,0 +1,20 @@ +from Standard.Base import all + +from project.Data.Table import Table + +## Represents a single row of some in-memory Table. +type Row + ## PRIVATE + Value (table:Table) (index:Integer) + + ## Gets the number of columns in the table. + length : Integer + length self = self.table.columns.length + + ## Gets the value of the specified column. + at : (Integer | Text) -> Any + at self column = self.table.columns.at column . at self.index + + ## Gets the row as a Vector. + to_vector : Vector + to_vector self = Vector.from_polyglot_array self 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 73de516bb297..314b07c31c35 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 @@ -28,6 +28,7 @@ from project.Data.Column import get_item_string from project.Data.Column_Type_Selection import Column_Type_Selection, Auto from project.Delimited.Delimited_Format import Delimited from project.Internal.Filter_Condition_Helpers import make_filter_column +from project.Internal.Rows_View import Rows_View from project.Errors import Missing_Input_Columns, Column_Indexes_Out_Of_Range, Duplicate_Type_Selector, No_Index_Set_Error, No_Such_Column_Error, No_Such_Column_Error_Data, No_Input_Columns_Selected, No_Output_Columns, Invalid_Value_Type import Standard.Visualization @@ -929,6 +930,21 @@ type Table columns : Vector columns self = Vector.from_polyglot_array self.java_table.getColumns . map Column.Column_Data + ## Returns a vector of rows contained in this table. + + In the database backend, it first materializes the table to in-memory. + + Arguments: + - max_rows: The maximum amount of rows to return. It is mainly meant for + the Database backend, to limit how many rows are downloaded. In the + in-memory backend it is only kept for API compatibility. + rows : Integer -> Vector Row + rows self max_rows=Nothing = + table = case max_rows of + Nothing -> self + _ : Integer -> self.slice 0 max_rows + Vector.from_polyglot_array (Rows_View.Value table) + ## Sets the index of this table, using the column with the provided name. Arguments: diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso new file mode 100644 index 000000000000..17622b72424a --- /dev/null +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso @@ -0,0 +1,19 @@ +from Standard.Base import all + +from project.Data.Table import Table +from project.Data.Row import Row + +type Rows_View + ## PRIVATE + Value (table:Table) + + ## Gets the number of rows in the table. + length : Integer + length self = self.table.row_count + + ## Gets the specified row. + at : Integer -> Any + at self index = + len = self.length + if index < len && index >= -len then Row.Value self.table index else + Error.throw (Index_Out_Of_Bounds_Error_Data index len) From e7953e206ce713f53ac28066b374412b6d53a006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Mon, 24 Oct 2022 18:08:12 +0200 Subject: [PATCH 02/14] add some tests --- .../0.0.0-dev/src/Internal/Rows_View.enso | 5 +-- test/Table_Tests/src/Common_Table_Spec.enso | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso index 17622b72424a..9f6f096b88a3 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Rows_View.enso @@ -13,7 +13,4 @@ type Rows_View ## Gets the specified row. at : Integer -> Any - at self index = - len = self.length - if index < len && index >= -len then Row.Value self.table index else - Error.throw (Index_Out_Of_Bounds_Error_Data index len) + at self index = Row.Value self.table index diff --git a/test/Table_Tests/src/Common_Table_Spec.enso b/test/Table_Tests/src/Common_Table_Spec.enso index 21be40c07d65..39434adfebff 100644 --- a/test/Table_Tests/src/Common_Table_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Spec.enso @@ -1442,3 +1442,37 @@ spec prefix table_builder test_selection pending=Nothing = no_cols.select_columns Column_Selector.Blank_Columns . columns . map .name . should_equal [] no_rows.select_columns Column_Selector.Blank_Columns . columns . map .name . should_equal ["X"] no_rows.remove_columns Column_Selector.Blank_Columns . columns . map .name . should_equal [] + + Test.group prefix+"Table.rows" pending=pending <| + table = table_builder [["X", [1, 2, 3, 4]], ["Y", [5, 6, 7, 8]], ["Z", ["A", "B", "C", "D"]]] + Test.specify "should allow to get a Vector of Table rows" <| + rows = table.rows + rows.length . should_equal 4 + + first_row = rows.first + first_row . length . should_equal 3 + first_row.at "X" . should_equal 1 + first_row.at "Y" . should_equal 5 + first_row.at "Z" . should_equal "A" + + last_row = rows.at -1 + last_row . length . should_equal 3 + last_row.at 0 . should_equal 4 + last_row.at 1 . should_equal 8 + last_row.at 2 . should_equal "D" + last_row.at -1 . should_equal "D" + + rows.map .to_vector . should_equal [[1, 5, "A"], [2, 6, "B"], [3, 7, "C"], [4, 8, "D"]] + + Test.specify "should fetch rows up to the specified limit" <| + table.rows max_rows=2 . map .to_vector . should_equal [[1, 5, "A"], [2, 6, "B"]] + + Test.specify "should correctly handle errors" <| + table.rows.at 5 . should_fail_with Index_Out_Of_Bounds_Error_Data + err = table.rows -6 + err.should_fail_with Index_Out_Of_Bounds_Error_Data + err.catch . should_equal (Index_Out_Of_Bounds_Error_Data -6 4) + + table.rows (max_rows=2) . at 2 . should_fail_with Index_Out_Of_Bounds_Error_Data + table.rows . at 0 . at -4 . should_fail_with Index_Out_Of_Bounds_Error_Data + table.rows . at 0 . at "unknown" . should_fail_with No_Such_Column_Error_Data From 60144b969d84edebd2fcf35ae99c404a4db609c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Mon, 24 Oct 2022 19:34:41 +0200 Subject: [PATCH 03/14] fix --- distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso | 2 +- test/Table_Tests/src/Common_Table_Spec.enso | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso index 21c5d607382f..32ee13924b56 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso @@ -13,7 +13,7 @@ type Row ## Gets the value of the specified column. at : (Integer | Text) -> Any - at self column = self.table.columns.at column . at self.index + at self column = self.table.at column . at self.index ## Gets the row as a Vector. to_vector : Vector diff --git a/test/Table_Tests/src/Common_Table_Spec.enso b/test/Table_Tests/src/Common_Table_Spec.enso index 39434adfebff..fb8d222fb6e6 100644 --- a/test/Table_Tests/src/Common_Table_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Spec.enso @@ -1469,7 +1469,7 @@ spec prefix table_builder test_selection pending=Nothing = Test.specify "should correctly handle errors" <| table.rows.at 5 . should_fail_with Index_Out_Of_Bounds_Error_Data - err = table.rows -6 + err = table.rows.at -6 err.should_fail_with Index_Out_Of_Bounds_Error_Data err.catch . should_equal (Index_Out_Of_Bounds_Error_Data -6 4) From 0831cf666880628a75c86cff3abcc8308b9f0f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Mon, 24 Oct 2022 19:37:44 +0200 Subject: [PATCH 04/14] Prototype: Atoms exposing at+length being treated as an array --- .../runtime/callable/atom/Atom.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java index ab41e1e4cbfc..3c52d8a62ec6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java @@ -10,11 +10,13 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.enso.interpreter.dsl.Builtin; import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.data.text.Text; +import org.enso.interpreter.runtime.error.WithWarnings; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; import org.enso.interpreter.runtime.type.TypesGen; @@ -141,6 +143,48 @@ public Object readMember(String member) throws UnknownIdentifierException { throw UnknownIdentifierException.create(member); } + @ExportMessage + public boolean hasArrayElements() { + Map members = constructor.getDefinitionScope().getMethods().get(constructor.getType()); + return members != null && members.containsKey("at") && members.containsKey("length"); + } + + @ExportMessage + public Object readArrayElement(long index) throws InvalidArrayIndexException, UnsupportedMessageException { + if (index >= getArraySize() || index < 0) { + throw InvalidArrayIndexException.create(index); + } + + UnresolvedSymbol symbol = InvokeMember.buildSym(getConstructor(), "at"); + try { + Object[] args = new Object[] { index }; + return InvokeMember.doCached(this, "at", args, getConstructor(), "at", symbol, InteropLibrary.getUncached()); + } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) { + throw UnsupportedMessageException.create(); + } + } + + @ExportMessage + long getArraySize() throws UnsupportedMessageException { + String member = "length"; + UnresolvedSymbol symbol = InvokeMember.buildSym(getConstructor(), member); + try { + var result = InvokeMember.doCached(this, member, new Object[0], getConstructor(), member, symbol, InteropLibrary.getUncached()); + return TypesGen.expectLong(result); + } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException | UnexpectedResultException e) { + throw UnsupportedMessageException.create(); + } + } + + @ExportMessage + boolean isArrayElementReadable(long index) { + try { + return index < getArraySize() && index >= 0; + } catch (UnsupportedMessageException e) { + return false; + } + } + @ExportMessage static class InvokeMember { From 0369024481d27b648bcd03785f46703a94889d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 25 Oct 2022 09:54:47 +0200 Subject: [PATCH 05/14] Revert "Prototype: Atoms exposing at+length being treated as an array" This reverts commit ee05a4a20d45d1f047d38b017cee4ec5079f59cf. --- .../runtime/callable/atom/Atom.java | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java index 3c52d8a62ec6..ab41e1e4cbfc 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/Atom.java @@ -10,13 +10,11 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.UnexpectedResultException; -import org.enso.interpreter.dsl.Builtin; import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.data.text.Text; -import org.enso.interpreter.runtime.error.WithWarnings; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; import org.enso.interpreter.runtime.type.TypesGen; @@ -143,48 +141,6 @@ public Object readMember(String member) throws UnknownIdentifierException { throw UnknownIdentifierException.create(member); } - @ExportMessage - public boolean hasArrayElements() { - Map members = constructor.getDefinitionScope().getMethods().get(constructor.getType()); - return members != null && members.containsKey("at") && members.containsKey("length"); - } - - @ExportMessage - public Object readArrayElement(long index) throws InvalidArrayIndexException, UnsupportedMessageException { - if (index >= getArraySize() || index < 0) { - throw InvalidArrayIndexException.create(index); - } - - UnresolvedSymbol symbol = InvokeMember.buildSym(getConstructor(), "at"); - try { - Object[] args = new Object[] { index }; - return InvokeMember.doCached(this, "at", args, getConstructor(), "at", symbol, InteropLibrary.getUncached()); - } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) { - throw UnsupportedMessageException.create(); - } - } - - @ExportMessage - long getArraySize() throws UnsupportedMessageException { - String member = "length"; - UnresolvedSymbol symbol = InvokeMember.buildSym(getConstructor(), member); - try { - var result = InvokeMember.doCached(this, member, new Object[0], getConstructor(), member, symbol, InteropLibrary.getUncached()); - return TypesGen.expectLong(result); - } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException | UnexpectedResultException e) { - throw UnsupportedMessageException.create(); - } - } - - @ExportMessage - boolean isArrayElementReadable(long index) { - try { - return index < getArraySize() && index >= 0; - } catch (UnsupportedMessageException e) { - return false; - } - } - @ExportMessage static class InvokeMember { From 6857514af13727ba8a1471e1113e4134d5874026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 25 Oct 2022 13:11:58 +0200 Subject: [PATCH 06/14] Remove an obsolete error class --- .../builtin/error/InvalidArrayIndexError.java | 4 ---- .../enso/interpreter/runtime/data/Array.java | 19 ------------------- 2 files changed, 23 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/InvalidArrayIndexError.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/InvalidArrayIndexError.java index 5df6628cb068..e61f236d5237 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/InvalidArrayIndexError.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/error/InvalidArrayIndexError.java @@ -14,8 +14,4 @@ public class InvalidArrayIndexError extends UniquelyConstructibleBuiltin { protected List getConstructorParamNames() { return List.of("array", "index"); } - - public Atom wrap(Context c, Array.InvalidIndexException e) { - return newInstance(e.getArray(), e.getIndex()); - } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java index c496ee47eeb8..86f42c569015 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java @@ -8,7 +8,6 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import org.enso.interpreter.dsl.Builtin; -import org.enso.interpreter.node.expression.builtin.error.InvalidArrayIndexError; import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; @@ -20,24 +19,6 @@ @ExportLibrary(TypesLibrary.class) @Builtin(pkg = "mutable", stdlibName = "Standard.Base.Data.Array.Array") public final class Array implements TruffleObject { - public static class InvalidIndexException extends RuntimeException { - private final long index; - private final Array array; - - public InvalidIndexException(long index, Array array) { - this.index = index; - this.array = array; - } - - public long getIndex() { - return index; - } - - public Array getArray() { - return array; - } - } - private final Object[] items; /** From 3eea661f8243d08d874ee5c11e90e549e6c68c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 25 Oct 2022 20:03:33 +0200 Subject: [PATCH 07/14] Initial implementation of the Array_Proxy --- .../Base/0.0.0-dev/src/Data/Array_Proxy.enso | 4 ++ .../interpreter/runtime/data/ArrayProxy.java | 51 +++++++++++++++++++ test/Tests/src/Data/Array_Proxy_Spec.enso | 27 ++++++++++ 3 files changed, 82 insertions(+) create mode 100644 distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso create mode 100644 engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java create mode 100644 test/Tests/src/Data/Array_Proxy_Spec.enso diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso new file mode 100644 index 000000000000..e370fea63c90 --- /dev/null +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso @@ -0,0 +1,4 @@ +@Builtin_Type +type Array_Proxy + new : Integer -> (Integer -> Any) -> Array_Proxy + new length at = @Builtin_Method "Array_Proxy.new" diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java new file mode 100644 index 000000000000..72a619336d89 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java @@ -0,0 +1,51 @@ +package org.enso.interpreter.runtime.data; + +import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import org.enso.interpreter.dsl.Builtin; +import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; + +@ExportLibrary(InteropLibrary.class) +@ExportLibrary(TypesLibrary.class) +@Builtin(pkg = "immutable", stdlibName = "Standard.Base.Data.Array_Proxy.Array_Proxy") +public class ArrayProxy implements TruffleObject { + private final long length; + private final Object at; + + @Builtin.Method(description = "Creates an array backed by a proxy object.") + public ArrayProxy(long length, Object at) { + this.length = length; + this.at = at; + } + + @ExportMessage + public boolean hasArrayElements() { + return true; + } + + @ExportMessage + public long getArraySize() { + return length; + } + + @ExportMessage + boolean isArrayElementReadable(long index) { + return index < length && index >= 0; + } + + @ExportMessage + public Object readArrayElement(long index, @CachedLibrary(limit = "3") InteropLibrary interop) + throws UnsupportedMessageException, InvalidArrayIndexException { + if (index >= length || index < 0) { + throw InvalidArrayIndexException.create(index); + } + + try { + return interop.execute(at, index); + } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { + throw UnsupportedMessageException.create(e); + } + } +} diff --git a/test/Tests/src/Data/Array_Proxy_Spec.enso b/test/Tests/src/Data/Array_Proxy_Spec.enso new file mode 100644 index 000000000000..31bfaadfcb45 --- /dev/null +++ b/test/Tests/src/Data/Array_Proxy_Spec.enso @@ -0,0 +1,27 @@ +from Standard.Base import all +from Standard.Base.Data.Array_Proxy import Array_Proxy + +from Standard.Test import Test, Test_Suite + +spec = + Test.group "Array_Proxy" <| + Test.specify "should correctly delegate to the callback" <| + arr = Array_Proxy.new 3 (ix -> ix + 10) + arr.length . should_equal 3 + arr.at 0 . should_equal 10 + arr.at 1 . should_equal 11 + arr.at 2 . should_equal 12 + arr.at 3 . should_fail_with Index_Out_Of_Bounds_Error_Data + + Test.specify "should be able to be used to construct a Vector" <| + v = Vector.from_polyglot_array (Array_Proxy.new 3 (ix -> ix + 10)) + v.length . should_equal 3 + v . should_equal [10, 11, 12] + + v.map (x -> x + 1) . should_equal [11, 12, 13] + + v2 = Vector.from_polyglot_array (Array_Proxy.new 3 (ix -> v.at 2 - ix)) + v2.should_equal [12, 11, 10] + v2.sort . should_equal [10, 11, 12] + +main = Test_Suite.run_main spec From b263a794a598983cbf9e3c4712b2085f21d795a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 25 Oct 2022 20:28:46 +0200 Subject: [PATCH 08/14] Use Array_Proxy in Table --- .../lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso | 4 ++++ distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso | 3 ++- .../lib/Standard/Table/0.0.0-dev/src/Data/Table.enso | 4 +++- test/Tests/src/Main.enso | 6 ++++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso index e370fea63c90..9de7cacde25c 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso @@ -2,3 +2,7 @@ type Array_Proxy new : Integer -> (Integer -> Any) -> Array_Proxy new length at = @Builtin_Method "Array_Proxy.new" + + from_proxy_object : Any -> Array_Proxy + from_proxy_object proxy = + Array_Proxy.new proxy.length proxy.at diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso index 32ee13924b56..c6dbd7e6f9b2 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Row.enso @@ -1,4 +1,5 @@ from Standard.Base import all +from Standard.Base.Data.Array_Proxy import Array_Proxy from project.Data.Table import Table @@ -17,4 +18,4 @@ type Row ## Gets the row as a Vector. to_vector : Vector - to_vector self = Vector.from_polyglot_array self + to_vector self = Vector.from_polyglot_array (Array_Proxy.from_proxy_object self) 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 314b07c31c35..99a15a04d369 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 @@ -1,6 +1,7 @@ from Standard.Base import all import Standard.Base.Error.Common as Errors from Standard.Base.Error.Problem_Behavior import Report_Warning +from Standard.Base.Data.Array_Proxy import Array_Proxy import Standard.Base.Data.Index_Sub_Range import Standard.Base.Data.Ordering.Comparator import Standard.Base.Data.Text.Case @@ -943,7 +944,8 @@ type Table table = case max_rows of Nothing -> self _ : Integer -> self.slice 0 max_rows - Vector.from_polyglot_array (Rows_View.Value table) + proxy = Rows_View.Value table + Vector.from_polyglot_array (Array_Proxy.from_proxy_object proxy) ## Sets the index of this table, using the column with the provided name. diff --git a/test/Tests/src/Main.enso b/test/Tests/src/Main.enso index 20fdabc70b80..1a74c75b81d6 100644 --- a/test/Tests/src/Main.enso +++ b/test/Tests/src/Main.enso @@ -19,8 +19,9 @@ import project.Semantic.Js_Interop_Spec import project.Semantic.Python_Interop_Spec import project.Semantic.R_Interop_Spec -import project.Data.Array_Polyglot_Spec import project.Data.Array_Spec +import project.Data.Array_Polyglot_Spec +import project.Data.Array_Proxy_Spec import project.Data.Bool_Spec import project.Data.Function_Spec import project.Data.Interval_Spec @@ -76,8 +77,9 @@ import project.Random_Spec main = Test_Suite.run_main <| Any_Spec.spec - Array_Polyglot_Spec.spec Array_Spec.spec + Array_Proxy_Spec.spec + Array_Polyglot_Spec.spec Bool_Spec.spec Function_Spec.spec Case_Spec.spec From 80cf9782901a3ace7487fc583f0e4e813d074e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 25 Oct 2022 20:41:53 +0200 Subject: [PATCH 09/14] docs --- .../Base/0.0.0-dev/src/Data/Array_Proxy.enso | 30 +++++++++++++++++-- .../interpreter/runtime/data/ArrayProxy.java | 6 ++++ .../enso/interpreter/runtime/type/Types.java | 3 +- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso index 9de7cacde25c..71c5ecf0629e 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array_Proxy.enso @@ -1,8 +1,34 @@ +from Standard.Base import Any, Array, Integer + +## A helper type used for creating an array from a length and a callback + providing its elements. + + It can be used to create an array from some non-standard underlying storage + without copying. The created proxy is read only and behaves like any `Array` + type returned from polyglot calls to other languages. The most common + use-case for it is to pass it to `Vector.from_polyglot_array` to create a + vector backed by such custom storage. @Builtin_Type type Array_Proxy - new : Integer -> (Integer -> Any) -> Array_Proxy + ## ADVANCED + UNSTABLE + Creates a new `Array_Proxy` from a length and a callback. + + Arguments: + - length: The length of the array to create. + - at: A function which returns each element of the array. + + > Example + Create a Vector of 10 million elements without allocating any storage. + + Vector.from_polyglot_array (Array_Proxy.new 10000000 (i -> i)) + new : Integer -> (Integer -> Any) -> Array new length at = @Builtin_Method "Array_Proxy.new" - from_proxy_object : Any -> Array_Proxy + ## ADVANCED + UNSTABLE + Creates a new `Array_Proxy` from an object providing `length` and `at` + methods. + from_proxy_object : Any -> Array from_proxy_object proxy = Array_Proxy.new proxy.length proxy.at diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java index 72a619336d89..4da3a944443e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java @@ -7,6 +7,12 @@ import org.enso.interpreter.dsl.Builtin; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; +/** + * A wrapper that allows to turn an Enso callback providing elements into a polyglot Array. + * + *

This allows creation of arrays (and with them, vectors) using non-standard storage - for + * example exposing rows of a Table without copying any data. + */ @ExportLibrary(InteropLibrary.class) @ExportLibrary(TypesLibrary.class) @Builtin(pkg = "immutable", stdlibName = "Standard.Base.Data.Array_Proxy.Array_Proxy") diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java index ccee4a8d33f8..bd1e13eb3d3b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java @@ -38,6 +38,7 @@ UnresolvedConversion.class, UnresolvedSymbol.class, Array.class, + ArrayProxy.class, ArrayOverBuffer.class, EnsoBigInteger.class, ManagedResource.class, @@ -133,7 +134,7 @@ public static String getName(Object value) { return Constants.UNRESOLVED_SYMBOL; } else if (TypesGen.isManagedResource(value)) { return ConstantsGen.MANAGED_RESOURCE; - } else if (TypesGen.isArray(value) || TypesGen.isArrayOverBuffer(value)) { + } else if (TypesGen.isArray(value) || TypesGen.isArrayOverBuffer(value) || TypesGen.isArrayProxy(value)) { return ConstantsGen.ARRAY; } else if (TypesGen.isVector(value)) { return ConstantsGen.VECTOR; From ef690cb1391fa50ce3a3fb64f3b744eeefefbe58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 25 Oct 2022 20:47:30 +0200 Subject: [PATCH 10/14] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48e22d6bf774..f941933588ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -219,6 +219,7 @@ - [Replaced `Table.drop_missing_columns` with `Table.remove_columns Column_Selector.Blank_Columns` by adding the new column selector variant.][3812] +- [Implemented `Table.rows` giving access to a vector of rows.][3827] [debug-shortcuts]: https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug @@ -351,6 +352,7 @@ [3805]: https://github.com/enso-org/enso/pull/3805 [3812]: https://github.com/enso-org/enso/pull/3812 [3823]: https://github.com/enso-org/enso/pull/3823 +[3827]: https://github.com/enso-org/enso/pull/3827 #### Enso Compiler From c80872c743d763ed347503c4cb599661b5d2efe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Wed, 26 Oct 2022 11:15:58 +0200 Subject: [PATCH 11/14] cr --- .../interpreter/runtime/data/ArrayProxy.java | 17 +++++++++++++++-- test/Tests/src/Data/Array_Proxy_Spec.enso | 5 +++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java index 4da3a944443e..34b6d1f96293 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java @@ -1,6 +1,12 @@ package org.enso.interpreter.runtime.data; -import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.interop.ArityException; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.InvalidArrayIndexException; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; @@ -16,12 +22,19 @@ @ExportLibrary(InteropLibrary.class) @ExportLibrary(TypesLibrary.class) @Builtin(pkg = "immutable", stdlibName = "Standard.Base.Data.Array_Proxy.Array_Proxy") -public class ArrayProxy implements TruffleObject { +public final class ArrayProxy implements TruffleObject { private final long length; private final Object at; @Builtin.Method(description = "Creates an array backed by a proxy object.") public ArrayProxy(long length, Object at) { + if (CompilerDirectives.inInterpreter()) { + if (!InteropLibrary.getUncached().isExecutable(at)) { + throw new IllegalArgumentException( + "Array_Proxy needs an executable callback, but got: " + at); + } + } + this.length = length; this.at = at; } diff --git a/test/Tests/src/Data/Array_Proxy_Spec.enso b/test/Tests/src/Data/Array_Proxy_Spec.enso index 31bfaadfcb45..f315961cd023 100644 --- a/test/Tests/src/Data/Array_Proxy_Spec.enso +++ b/test/Tests/src/Data/Array_Proxy_Spec.enso @@ -3,6 +3,8 @@ from Standard.Base.Data.Array_Proxy import Array_Proxy from Standard.Test import Test, Test_Suite +polyglot java import java.lang.IlllegalArgumentException + spec = Test.group "Array_Proxy" <| Test.specify "should correctly delegate to the callback" <| @@ -24,4 +26,7 @@ spec = v2.should_equal [12, 11, 10] v2.sort . should_equal [10, 11, 12] + Test.specify "should check the callback type validity at construction" <| + Text.expect_panic_with (Array_Proxy.new 0 0) IllegalArgumentException + main = Test_Suite.run_main spec From 521b11bf9906ffe9afb92a4ef57cd721c7168c7d Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 25 Oct 2022 12:01:45 +0200 Subject: [PATCH 12/14] Benchmark to measure 6x slowdown when using ProxyList via host interop --- .../benchmarks/semantic/VectorBenchmarks.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java index a2ac52f40b2e..f446d6469271 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java @@ -2,8 +2,10 @@ import java.io.ByteArrayOutputStream; import java.nio.file.Paths; +import java.util.AbstractList; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.function.Supplier; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.Value; @@ -68,6 +70,10 @@ public void initializeBenchmark(BenchmarkParams params) { "to_vector arr = Vector.from_polyglot_array arr\n" + "to_array vec = vec.to_array\n" + "slice vec = vec.slice\n" + + "fill_proxy proxy vec = \n" + + " size v = vec.length\n" + + " at i = vec.at i\n" + + " proxy.init size at\n" + "\n"); this.self = module.invokeMember("get_associated_type"); @@ -99,6 +105,14 @@ public void initializeBenchmark(BenchmarkParams params) { this.arrayOfFibNumbers = Value.asValue(copy); break; } + case "averageAbstractList": { + long[] copy = copyToPolyglotArray(arr); + final ProxyList proxyList = new ProxyList(); + getMethod.apply("fill_proxy").execute(self, proxyList, copy); + this.arrayOfFibNumbers = Value.asValue(proxyList); + break; + } + default: throw new IllegalStateException("Unexpected benchmark: " + params.getBenchmark()); } @@ -138,6 +152,11 @@ public void averageOverPolyglotArray(Blackhole matter) { performBenchmark(matter); } + @Benchmark + public void averageAbstractList(Blackhole matter) { + performBenchmark(matter); + } + private void performBenchmark(Blackhole matter) throws AssertionError { var average = avg.execute(self, arrayOfFibNumbers); if (!average.fitsInDouble()) { @@ -150,5 +169,25 @@ private void performBenchmark(Blackhole matter) throws AssertionError { } matter.consume(result); } + + public static final class ProxyList extends AbstractList { + private Function size; + private Function get; + + public void init(Function size, Function get) { + this.size = size; + this.get = get; + } + + @Override + public T get(int i) { + return get.apply(i); + } + + @Override + public int size() { + return size.apply(0); + } + } } From b74164cd1af9d02c8ad3e54bfa21250240722bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Wed, 26 Oct 2022 12:09:45 +0200 Subject: [PATCH 13/14] Add Array_Proxy benchmark --- .../benchmarks/semantic/VectorBenchmarks.java | 28 +++++++++++++------ test/Tests/src/Data/Array_Proxy_Spec.enso | 13 +++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java index f446d6469271..597b044dde00 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/VectorBenchmarks.java @@ -50,6 +50,7 @@ public void initializeBenchmark(BenchmarkParams params) { .build(); var module = ctx.eval("enso", "\n" + "import Standard.Base.Data.Vector\n" + + "from Standard.Base.Data.Array_Proxy import Array_Proxy\n" + "\n" + "avg arr =\n" + " sum acc i = if i == arr.length then acc else\n" + @@ -74,39 +75,45 @@ public void initializeBenchmark(BenchmarkParams params) { " size v = vec.length\n" + " at i = vec.at i\n" + " proxy.init size at\n" + + "create_array_proxy vec =\n" + + " Array_Proxy.from_proxy_object vec\n" + "\n"); this.self = module.invokeMember("get_associated_type"); Function getMethod = (name) -> module.invokeMember("get_method", self, name); var length = 1000; - Value arr = getMethod.apply("fibarr").execute(self, length, Integer.MAX_VALUE); + Value vec = getMethod.apply("fibarr").execute(self, length, Integer.MAX_VALUE); switch (params.getBenchmark().replaceFirst(".*\\.", "")) { case "averageOverVector": { - this.arrayOfFibNumbers = arr; + this.arrayOfFibNumbers = vec; break; } case "averageOverSlice": { - this.arrayOfFibNumbers = getMethod.apply("slice").execute(self, arr, 1, length); + this.arrayOfFibNumbers = getMethod.apply("slice").execute(self, vec, 1, length); break; } case "averageOverArray": { - this.arrayOfFibNumbers = getMethod.apply("to_array").execute(self, arr); + this.arrayOfFibNumbers = getMethod.apply("to_array").execute(self, vec); break; } case "averageOverPolyglotVector": { - long[] copy = copyToPolyglotArray(arr); + long[] copy = copyToPolyglotArray(vec); this.arrayOfFibNumbers = getMethod.apply("to_vector").execute(self, copy); break; } case "averageOverPolyglotArray": { - long[] copy = copyToPolyglotArray(arr); + long[] copy = copyToPolyglotArray(vec); this.arrayOfFibNumbers = Value.asValue(copy); break; } + case "averageOverArrayProxy": { + this.arrayOfFibNumbers = getMethod.apply("create_array_proxy").execute(self, vec); + break; + } case "averageAbstractList": { - long[] copy = copyToPolyglotArray(arr); + long[] copy = copyToPolyglotArray(vec); final ProxyList proxyList = new ProxyList(); getMethod.apply("fill_proxy").execute(self, proxyList, copy); this.arrayOfFibNumbers = Value.asValue(proxyList); @@ -152,6 +159,11 @@ public void averageOverPolyglotArray(Blackhole matter) { performBenchmark(matter); } + @Benchmark + public void averageOverArrayProxy(Blackhole matter) { + performBenchmark(matter); + } + @Benchmark public void averageAbstractList(Blackhole matter) { performBenchmark(matter); @@ -169,7 +181,7 @@ private void performBenchmark(Blackhole matter) throws AssertionError { } matter.consume(result); } - + public static final class ProxyList extends AbstractList { private Function size; private Function get; diff --git a/test/Tests/src/Data/Array_Proxy_Spec.enso b/test/Tests/src/Data/Array_Proxy_Spec.enso index f315961cd023..abfd99223619 100644 --- a/test/Tests/src/Data/Array_Proxy_Spec.enso +++ b/test/Tests/src/Data/Array_Proxy_Spec.enso @@ -5,6 +5,12 @@ from Standard.Test import Test, Test_Suite polyglot java import java.lang.IlllegalArgumentException +type Proxy_Object + type Value length + + at : Integer -> Integer + at ix = ix * 10 + spec = Test.group "Array_Proxy" <| Test.specify "should correctly delegate to the callback" <| @@ -26,6 +32,13 @@ spec = v2.should_equal [12, 11, 10] v2.sort . should_equal [10, 11, 12] + Test.specify "should be able to construct a Vector from a proxy object" <| + v = Vector.from_polyglot_array (Array_Proxy.from_proxy_object [4, 3, 2]) + v.should_equal [4, 3, 2] + + v = Vector.from_polyglot_array (Array_Proxy.from_proxy_object (Proxy_Object.Value 5)) + v.should_equal [0, 10, 20, 30, 40] + Test.specify "should check the callback type validity at construction" <| Text.expect_panic_with (Array_Proxy.new 0 0) IllegalArgumentException From a66169e9d8173540c0608267e48cedcd9eeaff3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Wed, 26 Oct 2022 12:30:13 +0200 Subject: [PATCH 14/14] fixes --- .../interpreter/runtime/data/ArrayProxy.java | 10 ++++--- test/Tests/src/Data/Array_Proxy_Spec.enso | 26 +++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java index 34b6d1f96293..7df68986dadd 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayProxy.java @@ -11,6 +11,8 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import org.enso.interpreter.dsl.Builtin; +import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; /** @@ -29,9 +31,11 @@ public final class ArrayProxy implements TruffleObject { @Builtin.Method(description = "Creates an array backed by a proxy object.") public ArrayProxy(long length, Object at) { if (CompilerDirectives.inInterpreter()) { - if (!InteropLibrary.getUncached().isExecutable(at)) { - throw new IllegalArgumentException( - "Array_Proxy needs an executable callback, but got: " + at); + InteropLibrary interop = InteropLibrary.getUncached(); + if (!interop.isExecutable(at)) { + throw new PanicException( + Context.get(interop).getBuiltins().error().makeTypeError("Function", at, "at"), + interop); } } diff --git a/test/Tests/src/Data/Array_Proxy_Spec.enso b/test/Tests/src/Data/Array_Proxy_Spec.enso index abfd99223619..71c952003503 100644 --- a/test/Tests/src/Data/Array_Proxy_Spec.enso +++ b/test/Tests/src/Data/Array_Proxy_Spec.enso @@ -3,13 +3,11 @@ from Standard.Base.Data.Array_Proxy import Array_Proxy from Standard.Test import Test, Test_Suite -polyglot java import java.lang.IlllegalArgumentException - type Proxy_Object - type Value length + Value length at : Integer -> Integer - at ix = ix * 10 + at self ix = ix * 10 spec = Test.group "Array_Proxy" <| @@ -22,24 +20,24 @@ spec = arr.at 3 . should_fail_with Index_Out_Of_Bounds_Error_Data Test.specify "should be able to be used to construct a Vector" <| - v = Vector.from_polyglot_array (Array_Proxy.new 3 (ix -> ix + 10)) - v.length . should_equal 3 - v . should_equal [10, 11, 12] + v1 = Vector.from_polyglot_array (Array_Proxy.new 3 (ix -> ix + 10)) + v1.length . should_equal 3 + v1 . should_equal [10, 11, 12] - v.map (x -> x + 1) . should_equal [11, 12, 13] + v1.map (x -> x + 1) . should_equal [11, 12, 13] - v2 = Vector.from_polyglot_array (Array_Proxy.new 3 (ix -> v.at 2 - ix)) + v2 = Vector.from_polyglot_array (Array_Proxy.new 3 (ix -> v1.at 2 - ix)) v2.should_equal [12, 11, 10] v2.sort . should_equal [10, 11, 12] Test.specify "should be able to construct a Vector from a proxy object" <| - v = Vector.from_polyglot_array (Array_Proxy.from_proxy_object [4, 3, 2]) - v.should_equal [4, 3, 2] + v1 = Vector.from_polyglot_array (Array_Proxy.from_proxy_object [4, 3, 2]) + v1.should_equal [4, 3, 2] - v = Vector.from_polyglot_array (Array_Proxy.from_proxy_object (Proxy_Object.Value 5)) - v.should_equal [0, 10, 20, 30, 40] + v2 = Vector.from_polyglot_array (Array_Proxy.from_proxy_object (Proxy_Object.Value 5)) + v2.should_equal [0, 10, 20, 30, 40] Test.specify "should check the callback type validity at construction" <| - Text.expect_panic_with (Array_Proxy.new 0 0) IllegalArgumentException + Test.expect_panic_with (Array_Proxy.new 0 0) Type_Error_Data main = Test_Suite.run_main spec