diff --git a/distribution/std-lib/Base/src/Bench_Utils.enso b/distribution/std-lib/Base/src/Bench_Utils.enso index 26f41e16a4a..b3943ed4eef 100644 --- a/distribution/std-lib/Base/src/Bench_Utils.enso +++ b/distribution/std-lib/Base/src/Bench_Utils.enso @@ -1,3 +1,5 @@ +from Base import all + reverse_list = list -> go = list -> acc -> case list of Cons h t -> go t (Cons h acc) @@ -24,6 +26,11 @@ Number.times = act -> res = here.reverse_list (go Nil this) res +zeropad number = + txt = number.to_text + if number % 10 == number then "00" + txt else + if number % 100 == number then "0" + txt else txt + measure = ~act -> label -> iter_size -> num_iters -> single_call = _ -> x1 = System.nano_time @@ -34,5 +41,6 @@ measure = ~act -> label -> iter_size -> num_iters -> act_it_num = num_iters - it_num res = iter_size.times single_call avg = here.avg_list res - IO.println (label + "/iteration:" + act_it_num.to_text + ": " + (avg/1000000).to_text + "ms") + fmt = (avg / 1000000).to_text + "." + here.zeropad ((avg / 1000) % 1000) + IO.println (label + "/iteration:" + act_it_num.to_text + ": " + fmt + "ms") num_iters.times iteration diff --git a/distribution/std-lib/Base/src/List.enso b/distribution/std-lib/Base/src/List.enso index 28d0310cb9f..7868c2a69c6 100644 --- a/distribution/std-lib/Base/src/List.enso +++ b/distribution/std-lib/Base/src/List.enso @@ -72,9 +72,12 @@ type List list: (Cons 0 <| Cons 1 <| Cons 2 <| Nil) . fold 0 (+) fold : Any -> (Any -> Any -> Any) -> Any - fold init f = case this of - Nil -> init - Cons h t -> t.fold (f init h) f + fold init f = + go acc list = case list of + Nil -> acc + Cons h t -> go (f acc h) t + res = go init this + res ## Reverses the list, returning a list with the same elements, but in the opposite order. diff --git a/distribution/std-lib/Base/src/Main.enso b/distribution/std-lib/Base/src/Main.enso index d723a989337..0c7d953d879 100644 --- a/distribution/std-lib/Base/src/Main.enso +++ b/distribution/std-lib/Base/src/Main.enso @@ -1,6 +1,46 @@ import Base.List -import Builtins +import Base.Vector +from Builtins import Number, Unit from Builtins export all from Base.List export Nil, Cons +from Base.Vector export Vector + +## Represents a right-exclusive range of integer values. +type Range + type Range start end + + ## Applies a function to each element in the range. + + > Example + To print all the numbers from 1 to 100 use: + 1.upto 101 . each IO.println + each function = + it start end = if start == end then Unit else + function start + it start+1 end + it this.start this.end + Unit + + ## Combines all the elements of the range, by iteratively applying the + passed function with next elements of the range. + + In general, the result of + Range start end . fold init f + is the same as + f (...(f (f init start) start+1)...) end-1 + + > Example + In the following example, we'll compute the sum of all elements of a + range: + Range 0 100 . fold 0 (+) + fold initial function = + it acc start end = if start == end then acc else + new_acc = function acc start + it new_acc start+1 end + res = it initial this.start this.end + res + +## Creates a new right-exclusive range of integers from `this` to `n`. +Number.upto n = Range this n diff --git a/distribution/std-lib/Base/src/Process.enso b/distribution/std-lib/Base/src/Process.enso index 40aa899c41f..d7569a8a7b7 100644 --- a/distribution/std-lib/Base/src/Process.enso +++ b/distribution/std-lib/Base/src/Process.enso @@ -1,5 +1,6 @@ import Base.Process.Exit_Code -from Builtins import System, True, False +from Base.Vector import Vector +from Builtins import Array, System, True, False ## The builder object that is used to create operating system processes. type Process_Builder command arguments stdin @@ -16,7 +17,7 @@ type Process_Result exit_code stdout stderr 8 Process.execute : String -> Exit_Code Process.execute command = - result = System.create_process command (arguments = []) (input = "") (redirectIn = True) (redirectOut = True) (redirectErr = True) + result = System.create_process command (arguments = Array.empty) (input = "") (redirectIn = True) (redirectOut = True) (redirectErr = True) Exit_Code.from_number result.exit_code ## Call a command with a list of arguments. @@ -28,7 +29,7 @@ Process.execute command = Hello! Process.run_command : String -> Vector -> Exit_Code Process.run_command command arguments = - result = System.create_process command arguments (input = "") (redirectIn = True) (redirectOut = True) (redirectErr = True) + result = System.create_process command arguments.to_array (input = "") (redirectIn = True) (redirectOut = True) (redirectErr = True) Exit_Code.from_number result.exit_code ## Create a process using a builder returning the result of execution. @@ -41,5 +42,5 @@ Process.run_command command arguments = Process_Result Exit_Success "test" "" Process.create : Process_Builder -> Process_Result Process.create b = - result = System.create_process b.command b.arguments b.stdin (redirectIn = False) (redirectOut = False) (redirectErr = False) + result = System.create_process b.command b.arguments.to_array b.stdin (redirectIn = False) (redirectOut = False) (redirectErr = False) Process_Result (Exit_Code.from_number result.exit_code) result.stdout result.stderr diff --git a/distribution/std-lib/Base/src/Vector.enso b/distribution/std-lib/Base/src/Vector.enso new file mode 100644 index 00000000000..905d2dba9c5 --- /dev/null +++ b/distribution/std-lib/Base/src/Vector.enso @@ -0,0 +1,106 @@ +from Builtins import Array +from Base import all + +## The basic, immutable, vector type. + + A vector allows to store an arbitrary number of elements, in linear memory. + It is the recommended data structure for most applications. + + > Example + A vector containing the elements `1`, `2`, and `3`, in this order is: + [1, 2, 3] + + > Example + A vector containing 50 elements, each being the number `42`, can be + created by: + Vector.fill length=50 item=42 +type Vector + type Vector to_array + + ## Gets an element from the vector at a specified index (0-based). + + > Example + To get the second element of the vector `[1, 2, 3]`, use: + [1, 2, 3].at 1 + at : Number -> Any + at index = this.to_array.at index + + ## Returns the number of elements stored in this vector. + length : Number + length = this.to_array.length + + ## Combines all the elements of the vector, by iteratively applying the + passed function with next elements of the vector. + + In general, the result of + [l0, l1, ..., ln] . fold init f + is the same as + f (...(f (f init l0) l1)...) ln + + > Example + In the following example, we'll compute the sum of all elements of a + vector: + [0, 1, 2] . fold 0 (+) + fold : Any -> (Any -> Any -> Any) -> Any + fold initial function = + arr = this.to_array + f = acc -> ix -> function acc (arr.at ix) + res = 0.upto this.length . fold initial f + res + + ## Creates a new vector of the given length, initializing elements using + the provided constructor function. + + The constructor function is called with the consecutive indices + (0-based) of the vector elements. + + > Example + To create a vector containing the numbers 1 through 50: + Vector.new 50 (ix -> ix + 1) + + > Example + To create a copy of the given vector (`my_vec`): + Vector.new my_vec.length (ix -> my_vec.at ix) + new : Number -> (Number -> Any) -> Vector + new length constructor = + arr = Array.new length + 0.upto length . each ix-> arr.set_at ix (constructor ix) + Vector arr + + ## Creates a new vector of the given length, filling the elements with + the provided constant. + + > Example + A vector containing 50 elements, each being the number `42`, can be + created by: + Vector.fill length=50 item=42 + fill : Number -> Any -> Vector + fill length item = + arr = Array.new length + 0.upto length . each ix-> arr.set_at ix item + Vector arr + + ## Applies a function to each element of the vector, returning the vector of + results. + + > Example + In the following example, we add `1` to each element of the vector: + [1, 2, 3] . map +1 + The result of running the code above is: + [2, 3, 4] + map : (Any -> Any) -> Vector + map function = + arr = this.to_array + new_arr = Array.new arr.length + 0.upto arr.length . each ix-> new_arr.set_at ix (function (arr.at ix)) + Vector new_arr + + ## Generates a human-readable text representation of the vector. + to_text : Text + to_text = + arr = this.to_array + if arr.length == 0 then "[]" else + if arr.length == 1 then "[" + (arr.at 0 . to_text) + "]" else + folder = str -> ix -> str + ", " + (arr.at ix).to_text + tail_elems = 1.upto arr.length . fold "" folder + "[" + (arr.at 0 . to_text) + tail_elems + "]" diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java index 966c55d3ca5..3c98b793acb 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java @@ -16,6 +16,7 @@ import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.atom.Atom; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.function.Function; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.MethodDoesNotExistException; import org.enso.interpreter.runtime.error.RuntimeError; @@ -157,6 +158,16 @@ public abstract class MethodResolverNode extends Node { return function; } + @Specialization(guards = "cachedSymbol == symbol") + Function resolveArray( + UnresolvedSymbol symbol, + Array self, + @Cached(value = "symbol", allowUncached = true) UnresolvedSymbol cachedSymbol, + @Cached(value = "resolveMethodOnArray(cachedSymbol)", allowUncached = true) + Function function) { + return function; + } + @Specialization(guards = {"cachedSymbol == symbol", "ctx.getEnvironment().isHostObject(target)"}) Function resolveHost( UnresolvedSymbol symbol, @@ -220,11 +231,18 @@ public abstract class MethodResolverNode extends Node { return ensureMethodExists(symbol.resolveFor(getBuiltins().any()), "Error", symbol); } + Function resolveMethodOnArray(UnresolvedSymbol symbol) { + return ensureMethodExists( + symbol.resolveFor(getBuiltins().array().constructor(), getBuiltins().any()), + "Array", + symbol); + } + Function buildHostResolver(UnresolvedSymbol symbol, Context context) { if (symbol.getName().equals("new")) { return context.getBuiltins().getConstructorDispatch(); } else { - return context.getBuiltins().buildPolyglotMethodDispatch(symbol.getName()); + return context.getBuiltins().buildPolyglotMethodDispatch(symbol); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/SequenceLiteralNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/SequenceLiteralNode.java index 153bc3cf351..bc564cc3d19 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/SequenceLiteralNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/SequenceLiteralNode.java @@ -4,7 +4,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeInfo; import org.enso.interpreter.node.ExpressionNode; -import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; @NodeInfo(shortName = "[]", description = "Creates a vector from given expressions.") public class SequenceLiteralNode extends ExpressionNode { @@ -28,7 +28,7 @@ public class SequenceLiteralNode extends ExpressionNode { * Executes the node. * * @param frame the stack frame for execution. - * @return a {@link Vector} containing the results of evaluating child expressions. + * @return a {@link Array} containing the results of evaluating child expressions. */ @Override @ExplodeLoop @@ -37,6 +37,6 @@ public class SequenceLiteralNode extends ExpressionNode { for (int i = 0; i < items.length; i++) { itemValues[i] = items[i].executeGeneric(frame); } - return new Vector(itemValues); + return new Array(itemValues); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/EmptyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/EmptyNode.java new file mode 100644 index 00000000000..ff1cd69b9f5 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/EmptyNode.java @@ -0,0 +1,13 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod(type = "Array", name = "empty", description = "Creates an empty array.") +public class EmptyNode extends Node { + + Object execute(Object _this) { + return new Array(); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/GetAtNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/GetAtNode.java new file mode 100644 index 00000000000..a9e7c4dc07c --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/GetAtNode.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Array", + name = "at", + description = "Gets an array element at the given index.") +public class GetAtNode extends Node { + + Object execute(Array _this, long index) { + return _this.getItems()[(int) index]; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/LengthNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/LengthNode.java new file mode 100644 index 00000000000..999305b8e1d --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/LengthNode.java @@ -0,0 +1,13 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod(type = "Array", name = "length", description = "Returns the length of an array.") +public class LengthNode extends Node { + + long execute(Array _this) { + return _this.getItems().length; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New1Node.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New1Node.java new file mode 100644 index 00000000000..dae4b7af36a --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New1Node.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Array", + name = "new_1", + description = "Creates an array with one given element.") +public class New1Node extends Node { + Object execute(Object _this, Object item_1) { + return new Array(item_1); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New2Node.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New2Node.java new file mode 100644 index 00000000000..144f81859ff --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New2Node.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Array", + name = "new_2", + description = "Creates an array with two given elements.") +public class New2Node extends Node { + + Object execute(Object _this, Object item_1, Object item_2) { + return new Array(item_1, item_2); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New3Node.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New3Node.java new file mode 100644 index 00000000000..77607f2bcf8 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New3Node.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Array", + name = "new_3", + description = "Creates an array with three given elements.") +public class New3Node extends Node { + + Object execute(Object _this, Object item_1, Object item_2, Object item_3) { + return new Array(item_1, item_2, item_3); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New4Node.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New4Node.java new file mode 100644 index 00000000000..9d01ada44ec --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/New4Node.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Array", + name = "new_4", + description = "Creates an array with four given elements.") +public class New4Node extends Node { + + Object execute(Object _this, Object item_1, Object item_2, Object item_3, Object item_4) { + return new Array(item_1, item_2, item_3, item_4); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/NewNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/NewNode.java new file mode 100644 index 00000000000..bf232a32bbc --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/NewNode.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Array", + name = "new", + description = "Creates an uninitialized array of a given size.") +public class NewNode extends Node { + + Object execute(Object _this, long size) { + return new Array(size); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/SetAtNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/SetAtNode.java new file mode 100644 index 00000000000..42de759bd9a --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/SetAtNode.java @@ -0,0 +1,17 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Array", + name = "set_at", + description = "Puts the given element in the given position in the array.") +public class SetAtNode extends Node { + + Object execute(Array _this, long index, Object value) { + _this.getItems()[(int) index] = value; + return _this; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/ToArrayNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/ToArrayNode.java new file mode 100644 index 00000000000..8b177d14328 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/array/ToArrayNode.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.node.expression.builtin.array; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; + +@BuiltinMethod( + type = "Array", + name = "to_array", + description = "Identity on arrays, implemented for protocol completeness.") +public class ToArrayNode extends Node { + + Object execute(Object _this) { + return _this; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java index b2ce89691f9..70685cbd06a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ExecuteNode.java @@ -1,25 +1,15 @@ package org.enso.interpreter.node.expression.builtin.interop.generic; -import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeInfo; -import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.Constants; -import org.enso.interpreter.Language; import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.node.expression.builtin.BuiltinRootNode; -import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; -import org.enso.interpreter.runtime.callable.function.Function; -import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy; -import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.PanicException; -import org.enso.interpreter.runtime.state.Stateful; -import org.enso.interpreter.runtime.type.TypesGen; @BuiltinMethod( type = "Polyglot", @@ -30,7 +20,7 @@ public class ExecuteNode extends Node { InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private final BranchProfile err = BranchProfile.create(); - Object execute(Object _this, Object callable, Vector arguments) { + Object execute(Object _this, Object callable, Array arguments) { try { return library.execute(callable, arguments.getItems()); } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java index 868b9850d91..5525c772a3c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InstantiateNode.java @@ -8,7 +8,7 @@ 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.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( @@ -21,7 +21,7 @@ public class InstantiateNode extends Node { InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private final BranchProfile err = BranchProfile.create(); - Object execute(Object _this, Object constructor, Vector arguments) { + Object execute(Object _this, Object constructor, Array arguments) { try { return library.instantiate(constructor, arguments.getItems()); } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java index d5a9cc7912b..01c17137d37 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/InvokeNode.java @@ -5,7 +5,7 @@ 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.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.PanicException; @BuiltinMethod( @@ -17,7 +17,7 @@ public class InvokeNode extends Node { InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private final BranchProfile err = BranchProfile.create(); - Object execute(Object _this, Object target, String name, Vector arguments) { + Object execute(Object _this, Object target, String name, Array arguments) { try { return library.invokeMember(target, name, arguments.getItems()); } catch (UnsupportedMessageException diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/ConstructorDispatchNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/ConstructorDispatchNode.java index 773c31314a3..177f6cfaedd 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/ConstructorDispatchNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/ConstructorDispatchNode.java @@ -54,7 +54,7 @@ public class ConstructorDispatchNode extends BuiltinRootNode { Object cons = args[0]; Object state = Function.ArgumentsHelper.getState(frame.getArguments()); try { - Object[] arguments = TypesGen.expectVector(args[1]).getItems(); + Object[] arguments = TypesGen.expectArray(args[1]).getItems(); Object res = library.instantiate(cons, arguments); return new Stateful(state, res); } catch (UnsupportedMessageException diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java index fd24fd39417..8ded578149e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java @@ -1,5 +1,9 @@ package org.enso.interpreter.node.expression.builtin.interop.syntax; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.ReportPolymorphism; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.*; import com.oracle.truffle.api.nodes.NodeInfo; @@ -7,15 +11,19 @@ import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.Constants; import org.enso.interpreter.Language; +import org.enso.interpreter.node.callable.InvokeCallableNode; import org.enso.interpreter.node.expression.builtin.BuiltinRootNode; +import org.enso.interpreter.runtime.callable.UnresolvedSymbol; +import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.state.Stateful; import org.enso.interpreter.runtime.type.TypesGen; @NodeInfo(shortName = "", description = "Invokes a polyglot method by name.") -public class MethodDispatchNode extends BuiltinRootNode { - private MethodDispatchNode(Language language) { +@ReportPolymorphism +public abstract class MethodDispatchNode extends BuiltinRootNode { + MethodDispatchNode(Language language) { super(language); } @@ -23,6 +31,12 @@ public class MethodDispatchNode extends BuiltinRootNode { InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private final BranchProfile err = BranchProfile.create(); + private @Child InvokeCallableNode invokeCallableNode = + InvokeCallableNode.build( + new CallArgumentInfo[] {new CallArgumentInfo()}, + InvokeCallableNode.DefaultsExecutionMode.EXECUTE, + InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED); + /** * Creates an instance of this node. * @@ -30,7 +44,7 @@ public class MethodDispatchNode extends BuiltinRootNode { * @return a function wrapping this node */ public static MethodDispatchNode build(Language language) { - return new MethodDispatchNode(language); + return MethodDispatchNodeGen.create(language); } /** @@ -39,16 +53,21 @@ public class MethodDispatchNode extends BuiltinRootNode { * @param frame current execution frame. * @return the result of converting input into a string. */ - @Override - public Stateful execute(VirtualFrame frame) { + @Specialization(guards = "symbol == cachedSymbol") + public Stateful run( + VirtualFrame frame, + @Bind("getSymbol(frame)") UnresolvedSymbol symbol, + @Cached("symbol") UnresolvedSymbol cachedSymbol, + @Cached("buildToArray(cachedSymbol)") UnresolvedSymbol toArray) { Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments()); Object callable = args[0]; Object state = Function.ArgumentsHelper.getState(frame.getArguments()); + Object arguments = args[2]; + Stateful casted = invokeCallableNode.execute(toArray, frame, state, new Object[] {arguments}); try { - String method = TypesGen.expectString(args[1]); - Object[] arguments = TypesGen.expectVector(args[2]).getItems(); - Object res = library.invokeMember(callable, method, arguments); - return new Stateful(state, res); + Object[] castedArgs = TypesGen.expectArray(casted.getValue()).getItems(); + Object res = library.invokeMember(callable, symbol.getName(), castedArgs); + return new Stateful(casted.getState(), res); } catch (UnsupportedMessageException | ArityException | UnsupportedTypeException @@ -59,6 +78,15 @@ public class MethodDispatchNode extends BuiltinRootNode { } } + UnresolvedSymbol buildToArray(UnresolvedSymbol originalSymbol) { + return UnresolvedSymbol.build("to_array", originalSymbol.getScope()); + } + + UnresolvedSymbol getSymbol(VirtualFrame frame) { + return TypesGen.asUnresolvedSymbol( + Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]); + } + /** * Returns a language-specific name for this node. * diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/system/CreateProcessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/system/CreateProcessNode.java index 35045dbf54d..4df7ceb2d8d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/system/CreateProcessNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/system/CreateProcessNode.java @@ -8,7 +8,7 @@ import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.Language; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.Context; -import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.PanicException; import java.io.*; @@ -26,7 +26,7 @@ public abstract class CreateProcessNode extends Node { abstract Object execute( Object _this, String command, - Vector arguments, + Array arguments, String input, boolean redirectIn, boolean redirectOut, @@ -37,15 +37,15 @@ public abstract class CreateProcessNode extends Node { Object doCreate( Object _this, String command, - Vector arguments, + Array arguments, String input, boolean redirectIn, boolean redirectOut, boolean redirectErr, @CachedContext(Language.class) Context ctx) { - String[] cmd = new String[(int) arguments.getArraySize() + 1]; + String[] cmd = new String[(int) arguments.getItems().length + 1]; cmd[0] = command; - System.arraycopy(arguments.getItems(), 0, cmd, 1, (int) arguments.getArraySize()); + System.arraycopy(arguments.getItems(), 0, cmd, 1, (int) arguments.getItems().length); TruffleProcessBuilder pb = ctx.getEnvironment().newProcessBuilder(cmd); try { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java index 39b8c854c5e..049406b357a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java @@ -24,7 +24,7 @@ import org.enso.interpreter.runtime.builtin.Builtins; import org.enso.interpreter.runtime.callable.CallerInfo; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.function.Function; -import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.scope.LocalScope; import org.enso.interpreter.runtime.scope.ModuleScope; import org.enso.interpreter.runtime.type.Types; @@ -454,7 +454,7 @@ public class Module implements TruffleObject { */ @ExportMessage Object getMembers(boolean includeInternal) { - return new Vector( + return new Array( MethodNames.Module.GET_METHOD, MethodNames.Module.GET_CONSTRUCTOR, MethodNames.Module.REPARSE, diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Array.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Array.java new file mode 100644 index 00000000000..f5971d79f3d --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Array.java @@ -0,0 +1,37 @@ +package org.enso.interpreter.runtime.builtin; + +import org.enso.interpreter.Language; +import org.enso.interpreter.node.expression.builtin.array.*; +import org.enso.interpreter.runtime.callable.atom.AtomConstructor; +import org.enso.interpreter.runtime.scope.ModuleScope; + +/** Container for builtin array-related types and functions. */ +public class Array { + private final AtomConstructor array; + + /** + * Creates a new instance of this class, registering all relevant bindings in the provided scope. + * + * @param language the current language instance. + * @param scope the scope for builtin methods. + */ + public Array(Language language, ModuleScope scope) { + array = new AtomConstructor("Array", scope).initializeFields(); + scope.registerConstructor(array); + scope.registerMethod(array, "empty", EmptyMethodGen.makeFunction(language)); + scope.registerMethod(array, "new", NewMethodGen.makeFunction(language)); + scope.registerMethod(array, "new_1", New1MethodGen.makeFunction(language)); + scope.registerMethod(array, "new_2", New2MethodGen.makeFunction(language)); + scope.registerMethod(array, "new_3", New3MethodGen.makeFunction(language)); + scope.registerMethod(array, "new_4", New4MethodGen.makeFunction(language)); + scope.registerMethod(array, "length", LengthMethodGen.makeFunction(language)); + scope.registerMethod(array, "to_array", ToArrayMethodGen.makeFunction(language)); + scope.registerMethod(array, "at", GetAtMethodGen.makeFunction(language)); + scope.registerMethod(array, "set_at", SetAtMethodGen.makeFunction(language)); + } + + /** @return the Array constructor. */ + public AtomConstructor constructor() { + return array; + } +} 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 16e8b6ced5d..1fad03160e4 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 @@ -22,6 +22,7 @@ import org.enso.interpreter.node.expression.builtin.thread.WithInterruptHandlerM import org.enso.interpreter.node.expression.builtin.unsafe.SetAtomFieldMethodGen; import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.Module; +import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; @@ -52,6 +53,7 @@ public class Builtins { private final Error error; private final Bool bool; private final System system; + private final Array array; private final RootCallTarget interopDispatchRoot; private final FunctionSchema interopDispatchSchema; @@ -72,6 +74,7 @@ public class Builtins { number = new AtomConstructor("Number", scope).initializeFields(); bool = new Bool(language, scope); error = new Error(language, scope); + array = new Array(language, scope); function = new AtomConstructor("Function", scope).initializeFields(); text = new AtomConstructor("Text", scope).initializeFields(); debug = new AtomConstructor("Debug", scope).initializeFields(); @@ -258,6 +261,10 @@ public class Builtins { return system; } + /** @return the container for array-related builtins. */ + public Array array() { + return array; + } /** * Returns the builtin module scope. @@ -275,10 +282,10 @@ public class Builtins { /** * Builds a function dispatching to a polyglot method call. * - * @param method the name of the method this function will dispatch to. + * @param method the name and scope of the method this function will dispatch to. * @return a function calling {@code method} with given arguments. */ - public Function buildPolyglotMethodDispatch(String method) { + public Function buildPolyglotMethodDispatch(UnresolvedSymbol method) { Object[] preAppliedArr = new Object[] {null, method, null}; return new Function(interopDispatchRoot, null, interopDispatchSchema, preAppliedArr, null); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java index a789e546017..af3fe71317b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java @@ -33,15 +33,17 @@ public class UnresolvedSymbol implements TruffleObject { /** * Gets the symbol name. * - *

All names for dynamic symbols are interned, making it safe to compare symbol names using the - * standard {@code ==} equality operator. - * * @return the name of this symbol */ public String getName() { return name; } + /** @return the scope this symbol was used in. */ + public ModuleScope getScope() { + return scope; + } + /** * Resolves the symbol for a given hierarchy of constructors. * diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/function/Function.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/function/Function.java index 7b822cd3ff6..4512184a336 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/function/Function.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/function/Function.java @@ -26,7 +26,7 @@ import org.enso.interpreter.runtime.callable.CallerInfo; import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; import org.enso.interpreter.runtime.callable.argument.Thunk; import org.enso.interpreter.runtime.state.data.EmptyMap; -import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.type.Types; import org.enso.polyglot.MethodNames; @@ -272,7 +272,7 @@ public final class Function implements TruffleObject { */ @ExportMessage Object getMembers(boolean includeInternal) { - return new Vector(MethodNames.Function.EQUALS); + return new Array(MethodNames.Function.EQUALS); } /** diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Vector.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java similarity index 65% rename from engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Vector.java rename to engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java index 194cb7b4501..3752b556965 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Vector.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java @@ -1,27 +1,35 @@ package org.enso.interpreter.runtime.data; -import com.oracle.truffle.api.CompilerDirectives; 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.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; -/** An immutable array-like collection. */ +/** A primitve boxed array type for use in the runtime. */ @ExportLibrary(InteropLibrary.class) -public class Vector implements TruffleObject { - private final @CompilerDirectives.CompilationFinal(dimensions = 1) Object[] items; +public class Array implements TruffleObject { + private final Object[] items; /** - * Creates a new Vector + * Creates a new array * * @param items the element values */ - public Vector(Object... items) { + public Array(Object... items) { this.items = items; } - /** @return the elements of this vector as an array. */ + /** + * Creates an uninitialized array of the given size. + * + * @param size the size of the created array. + */ + public Array(long size) { + this.items = new Object[(int) size]; + } + + /** @return the elements of this array as a java array. */ public Object[] getItems() { return items; } @@ -57,7 +65,7 @@ public class Vector implements TruffleObject { * @return */ @ExportMessage - public long getArraySize() { + long getArraySize() { return items.length; } @@ -68,7 +76,22 @@ public class Vector implements TruffleObject { * @return {@code true} if the index is valid, {@code false} otherwise. */ @ExportMessage - public boolean isArrayElementReadable(long index) { + boolean isArrayElementReadable(long index) { return index < getArraySize() && index >= 0; } + + @ExportMessage + void writeArrayElement(long index, Object value) { + items[(int) index] = value; + } + + @ExportMessage + boolean isArrayElementModifiable(long index) { + return isArrayElementReadable(index); + } + + @ExportMessage + boolean isArrayElementInsertable(long index) { + return false; + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/TopLevelScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/TopLevelScope.java index 4a8cec74d9e..4f90d75d322 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/TopLevelScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/TopLevelScope.java @@ -12,7 +12,7 @@ import org.enso.interpreter.Language; import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.type.Types; import org.enso.pkg.QualifiedName; import org.enso.pkg.QualifiedName$; @@ -130,8 +130,8 @@ public class TopLevelScope implements TruffleObject { * @return a collection of all the exported members. */ @ExportMessage - Vector getMembers(boolean includeInternal) { - return new Vector( + Array getMembers(boolean includeInternal) { + return new Array( MethodNames.TopScope.GET_MODULE, MethodNames.TopScope.CREATE_MODULE, MethodNames.TopScope.REGISTER_MODULE, 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 62be0a5d6e4..de465e9e617 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 @@ -5,15 +5,14 @@ import com.oracle.truffle.api.dsl.ImplicitCast; import com.oracle.truffle.api.dsl.TypeSystem; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.UnsupportedTypeException; +import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.argument.Thunk; import org.enso.interpreter.runtime.callable.atom.Atom; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.function.Function; -import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.data.Array; import org.enso.interpreter.runtime.error.RuntimeError; -import java.util.Optional; - /** * This class defines the interpreter-level type system for Enso. * @@ -33,7 +32,8 @@ import java.util.Optional; AtomConstructor.class, Thunk.class, RuntimeError.class, - Vector.class + UnresolvedSymbol.class, + Array.class }) public class Types { @@ -118,8 +118,8 @@ public class Types { return "Thunk"; } else if (TypesGen.isRuntimeError(value)) { return "Error " + TypesGen.asRuntimeError(value).getPayload().toString(); - } else if (TypesGen.isVector(value)) { - return "Vector"; + } else if (TypesGen.isArray(value)) { + return "Array"; } else { return null; } diff --git a/engine/runtime/src/main/scala/org/enso/compiler/Passes.scala b/engine/runtime/src/main/scala/org/enso/compiler/Passes.scala index 295d32ee2b1..ed2f0bf8dc9 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/Passes.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/Passes.scala @@ -45,6 +45,7 @@ class Passes(passes: Option[List[PassGroup]] = None) { TypeSignatures, AliasAnalysis, UppercaseNames, + VectorLiterals, AliasAnalysis, LambdaConsolidate, AliasAnalysis, 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 aba06bca7c1..3fa34ad5def 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 @@ -1136,7 +1136,7 @@ class IrToTruffle( argumentExpression.setTail(argExpressionIsTail) val displayName = - s"argument<${name.getOrElse(String.valueOf(position))}>" + s"argument<${name.map(_.name).getOrElse(String.valueOf(position))}>" val section = value.location .map(loc => source.createSection(loc.start, loc.end)) diff --git a/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala b/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala index 32b4fbf0697..fde6e5ff730 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala @@ -5302,6 +5302,12 @@ object IR { def explain(originalName: IR.Name): String } + case object UnresolvedSequenceMacro extends Reason { + override def explain(originalName: Name): String = + "No definition for the sequence macro could be found. Try" + + " importing the default definition from the Base.Vector module." + } + /** * An error coming from an unexpected occurence of a polyglot symbol. * @@ -5310,7 +5316,7 @@ object IR { */ case class UnexpectedPolyglot(context: String) extends Reason { override def explain(originalName: Name): String = - s"The name ${originalName.name} resolved to a polyglot symbol," + + s"The name ${originalName.name} resolved to a polyglot symbol, " + s"but polyglot symbols are not allowed in $context." } @@ -5322,7 +5328,7 @@ object IR { */ case class UnexpectedMethod(context: String) extends Reason { override def explain(originalName: Name): String = - s"The name ${originalName.name} resolved to a method," + + s"The name ${originalName.name} resolved to a method, " + s"but methods are not allowed in $context." } diff --git a/engine/runtime/src/main/scala/org/enso/compiler/data/BindingsMap.scala b/engine/runtime/src/main/scala/org/enso/compiler/data/BindingsMap.scala index c3a6d5b55a3..84b5d31d88e 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/data/BindingsMap.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/data/BindingsMap.scala @@ -57,14 +57,13 @@ case class BindingsMap( } private def findLocalCandidates(name: String): List[ResolvedName] = { - if (currentModule.getName.item == name) { + val conses = findConstructorCandidates(name) + val polyglot = findPolyglotCandidates(name) + val methods = findMethodCandidates(name) + val all = conses ++ polyglot ++ methods + if (all.isEmpty && currentModule.getName.item == name) { List(ResolvedModule(currentModule)) - } else { - val conses = findConstructorCandidates(name) - val polyglot = findPolyglotCandidates(name) - val methods = findMethodCandidates(name) - conses ++ polyglot ++ methods - } + } else { all } } private def findQualifiedImportCandidates( diff --git a/engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/VectorLiterals.scala b/engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/VectorLiterals.scala new file mode 100644 index 00000000000..5520046629d --- /dev/null +++ b/engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/VectorLiterals.scala @@ -0,0 +1,108 @@ +package org.enso.compiler.pass.resolve + +import org.enso.compiler.context.{InlineContext, ModuleContext} +import org.enso.compiler.core.IR +import org.enso.compiler.core.ir.MetadataStorage.ToPair +import org.enso.compiler.data.BindingsMap +import org.enso.compiler.pass.IRPass +import org.enso.compiler.pass.analyse.BindingAnalysis + +case object VectorLiterals extends IRPass { + + /** The type of the metadata object that the pass writes to the IR. */ + override type Metadata = IRPass.Metadata.Empty + + /** The type of configuration for the pass. */ + override type Config = IRPass.Configuration.Default + + /** The passes that this pass depends _directly_ on to run. */ + override val precursorPasses: Seq[IRPass] = Seq(UppercaseNames) + + /** The passes that are invalidated by running this pass. */ + override val invalidatedPasses: Seq[IRPass] = Seq() + + /** Executes the pass on the provided `ir`, and returns a possibly transformed + * or annotated version of `ir`. + * + * @param ir the Enso IR to process + * @param moduleContext a context object that contains the information needed + * to process a module + * @return `ir`, possibly having made transformations or annotations to that + * IR. + */ + override def runModule( + ir: IR.Module, + moduleContext: ModuleContext + ): IR.Module = { + val bindings = ir.unsafeGetMetadata( + BindingAnalysis, + "no bindings analysis on the current module" + ) + val vec = vectorCons(bindings) + ir.mapExpressions(doExpression(_, vec)) + } + + /** Executes the pass on the provided `ir`, and returns a possibly transformed + * or annotated version of `ir` in an inline context. + * + * @param ir the Enso IR to process + * @param inlineContext a context object that contains the information needed + * for inline evaluation + * @return `ir`, possibly having made transformations or annotations to that + * IR. + */ + override def runExpression( + ir: IR.Expression, + inlineContext: InlineContext + ): IR.Expression = { + val bindings = inlineContext.module.getIr.unsafeGetMetadata( + BindingAnalysis, + "no bindings analysis on the current module" + ) + val vec = vectorCons(bindings) + doExpression(ir, vec) + } + + private def vectorCons(bindings: BindingsMap): IR.Expression = { + val module = bindings.resolvedImports + .flatMap(imp => + imp.module :: imp.module.getIr + .unsafeGetMetadata( + BindingAnalysis, + "no binding analyis on an imported module" + ) + .resolvedExports + .map(_.module) + ) + .find(_.getName.toString == "Base.Vector") + val name = IR.Name.Literal("", isReferent = true, None) + module + .map { module => + val withRes = name.updateMetadata( + UppercaseNames -->> BindingsMap.Resolution( + BindingsMap + .ResolvedConstructor(module, BindingsMap.Cons("Vector", 1)) + ) + ) + withRes + } + .getOrElse { + IR.Error.Resolution(name, IR.Error.Resolution.UnresolvedSequenceMacro) + } + } + + private def doExpression( + ir: IR.Expression, + vec: IR.Expression + ): IR.Expression = + ir.transformExpressions { + case seq: IR.Application.Literal.Sequence => + val trans = seq.mapExpressions(doExpression(_, vec)) + IR.Application.Prefix( + vec, + List(IR.CallArgument.Specified(None, trans, None, None)), + false, + None + ) + } +} diff --git a/engine/runtime/src/test/resources/TestNonImportedOverloads/src/Main.enso b/engine/runtime/src/test/resources/TestNonImportedOverloads/src/Main.enso index 7accaa5b480..5b57f360da1 100644 --- a/engine/runtime/src/test/resources/TestNonImportedOverloads/src/Main.enso +++ b/engine/runtime/src/test/resources/TestNonImportedOverloads/src/Main.enso @@ -3,4 +3,4 @@ from TestNonImportedOverloads.Util import all X.method = 10 -Main.main = Unit.util (X 1) +main = Unit.util (X 1) diff --git a/engine/runtime/src/test/resources/TestNonImportedOwnMethods/src/Main.enso b/engine/runtime/src/test/resources/TestNonImportedOwnMethods/src/Main.enso index 17b80ca0be6..263e19b7bab 100644 --- a/engine/runtime/src/test/resources/TestNonImportedOwnMethods/src/Main.enso +++ b/engine/runtime/src/test/resources/TestNonImportedOwnMethods/src/Main.enso @@ -5,4 +5,4 @@ type X a X.method = 10 -Main.main = Unit.util (X 1) +main = Unit.util (X 1) diff --git a/engine/runtime/src/test/resources/TestSimpleImports/src/Main.enso b/engine/runtime/src/test/resources/TestSimpleImports/src/Main.enso index 71ed445c522..53dfaaa0a1a 100644 --- a/engine/runtime/src/test/resources/TestSimpleImports/src/Main.enso +++ b/engine/runtime/src/test/resources/TestSimpleImports/src/Main.enso @@ -1,3 +1,3 @@ from TestSimpleImports.Atom import all -Main.main = (X 1).method +main = (X 1).method diff --git a/engine/runtime/src/test/resources/Test_Hiding_Error/src/Main.enso b/engine/runtime/src/test/resources/Test_Hiding_Error/src/Main.enso index 9fc04c895cf..9fe6d22da45 100644 --- a/engine/runtime/src/test/resources/Test_Hiding_Error/src/Main.enso +++ b/engine/runtime/src/test/resources/Test_Hiding_Error/src/Main.enso @@ -1,3 +1,3 @@ from Test_Hiding_Error.Atom import all hiding X -Main.main = (X 1).method +main = (X 1).method diff --git a/engine/runtime/src/test/resources/Test_Hiding_Success/src/Main.enso b/engine/runtime/src/test/resources/Test_Hiding_Success/src/Main.enso index 2a05b9f723c..80c10edacaa 100644 --- a/engine/runtime/src/test/resources/Test_Hiding_Success/src/Main.enso +++ b/engine/runtime/src/test/resources/Test_Hiding_Success/src/Main.enso @@ -1,3 +1,3 @@ from Test_Hiding_Success.Atom import all hiding Y -Main.main = (X 1).method +main = (X 1).method diff --git a/engine/runtime/src/test/resources/Test_Qualified_Error/src/Main.enso b/engine/runtime/src/test/resources/Test_Qualified_Error/src/Main.enso index b443a0fab6f..c37171753e1 100644 --- a/engine/runtime/src/test/resources/Test_Qualified_Error/src/Main.enso +++ b/engine/runtime/src/test/resources/Test_Qualified_Error/src/Main.enso @@ -1,3 +1,3 @@ import Test_Qualified_Error.Atom -Main.main = (X 1).method +main = (X 1).method diff --git a/engine/runtime/src/test/resources/Test_Rename/src/Main.enso b/engine/runtime/src/test/resources/Test_Rename/src/Main.enso index 05b6b2a4b3f..f4a484cf63e 100644 --- a/engine/runtime/src/test/resources/Test_Rename/src/Main.enso +++ b/engine/runtime/src/test/resources/Test_Rename/src/Main.enso @@ -1,3 +1,3 @@ import Test_Rename.Atom as Def -Main.main = (Def.X 1).method +main = (Def.X 1).method diff --git a/engine/runtime/src/test/resources/Test_Rename_Error/src/Main.enso b/engine/runtime/src/test/resources/Test_Rename_Error/src/Main.enso index 13d479e7147..f6ac33118bc 100644 --- a/engine/runtime/src/test/resources/Test_Rename_Error/src/Main.enso +++ b/engine/runtime/src/test/resources/Test_Rename_Error/src/Main.enso @@ -1,3 +1,3 @@ import Test_Rename_Error.Atom as Def -Main.main = (Atom.X 1).method +main = (Atom.X 1).method diff --git a/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DataflowAnalysisTest.scala b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DataflowAnalysisTest.scala index 7e51bbe6f49..6b77b6505c6 100644 --- a/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DataflowAnalysisTest.scala +++ b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DataflowAnalysisTest.scala @@ -856,21 +856,28 @@ class DataflowAnalysisTest extends CompilerTest { val depInfo = ir.getMetadata(DataflowAnalysis).get - val vector = ir.body + val callArg = ir.body + .asInstanceOf[IR.Application.Prefix] + .arguments(0) + val vector = callArg.value .asInstanceOf[IR.Application.Literal.Sequence] - val xDefId = mkStaticDep(ir.arguments(0).getId) - val xUseId = mkStaticDep(vector.items(0).getId) - val yId = mkStaticDep(vector.items(1).getId) - val litId = mkStaticDep(vector.items(2).getId) - val vecId = mkStaticDep(vector.getId) - val lamId = mkStaticDep(ir.getId) + val xDefId = mkStaticDep(ir.arguments(0).getId) + val xUseId = mkStaticDep(vector.items(0).getId) + val yId = mkStaticDep(vector.items(1).getId) + val litId = mkStaticDep(vector.items(2).getId) + val vecId = mkStaticDep(vector.getId) + val callArgId = mkStaticDep(callArg.getId) + val appId = mkStaticDep(ir.body.getId) + val lamId = mkStaticDep(ir.getId) depInfo.getDirect(xDefId) shouldEqual Some(Set(xUseId)) depInfo.getDirect(xUseId) shouldEqual Some(Set(vecId)) depInfo.getDirect(yId) shouldEqual Some(Set(vecId)) depInfo.getDirect(litId) shouldEqual Some(Set(vecId)) - depInfo.getDirect(vecId) shouldEqual Some(Set(lamId)) + depInfo.getDirect(vecId) shouldEqual Some(Set(callArgId)) + depInfo.getDirect(callArgId) shouldEqual Some(Set(appId)) + depInfo.getDirect(appId) shouldEqual Some(Set(lamId)) } "work properly for typeset literals" in { diff --git a/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DemandAnalysisTest.scala b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DemandAnalysisTest.scala index 276cdd5c593..62881ff6944 100644 --- a/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DemandAnalysisTest.scala +++ b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/analyse/DemandAnalysisTest.scala @@ -150,6 +150,9 @@ class DemandAnalysisTest extends CompilerTest { val vec = ir .asInstanceOf[IR.Function.Lambda] .body + .asInstanceOf[IR.Application.Prefix] + .arguments(0) + .value .asInstanceOf[IR.Application.Literal.Sequence] vec.items(0) shouldBe an[IR.Application.Force] diff --git a/engine/runtime/src/test/scala/org/enso/compiler/test/pass/resolve/VectorLiteralsTest.scala b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/resolve/VectorLiteralsTest.scala new file mode 100644 index 00000000000..e4ebf136dab --- /dev/null +++ b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/resolve/VectorLiteralsTest.scala @@ -0,0 +1,102 @@ +package org.enso.compiler.test.pass.resolve + +import org.enso.compiler.Passes +import org.enso.compiler.context.{FreshNameSupply, ModuleContext} +import org.enso.compiler.core.IR +import org.enso.compiler.pass.PassConfiguration.ToPair +import org.enso.compiler.pass.analyse.AliasAnalysis +import org.enso.compiler.pass.optimise.ApplicationSaturation +import org.enso.compiler.pass.resolve.VectorLiterals +import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager} +import org.enso.compiler.test.CompilerTest + +class VectorLiteralsTest extends CompilerTest { + + // === Test Setup =========================================================== + + def mkModuleContext: ModuleContext = + buildModuleContext( + freshNameSupply = Some(new FreshNameSupply) + ) + + val passes = new Passes + + val precursorPasses: PassGroup = + passes.getPrecursors(VectorLiterals).get + + val passConfiguration: PassConfiguration = PassConfiguration( + AliasAnalysis -->> AliasAnalysis.Configuration(), + ApplicationSaturation -->> ApplicationSaturation.Configuration() + ) + + implicit val passManager: PassManager = + new PassManager(List(precursorPasses), passConfiguration) + + /** Adds an extension method to analyse an Enso module. + * + * @param ir the ir to analyse + */ + implicit class AnalyseModule(ir: IR.Module) { + + /** Performs tail call analysis on [[ir]]. + * + * @param context the module context in which analysis takes place + * @return [[ir]], with tail call analysis metadata attached + */ + def analyse(implicit context: ModuleContext) = { + VectorLiterals.runModule(ir, context) + } + } + + // === The Tests ============================================================ + + "Pattern resolution" should { + implicit val ctx: ModuleContext = mkModuleContext + + val ir = + """ + |foo (x = [1, 2, 3]) = + | foo = ["foo", bar, [1,2,3]] + | x + | + |""".stripMargin.preprocessModule.analyse + + "transform vector literals into applications" in { + val fun = ir + .bindings(0) + .asInstanceOf[IR.Module.Scope.Definition.Method.Explicit] + .body + .asInstanceOf[IR.Function.Lambda] + + val arg = fun.arguments(1).defaultValue.get + arg shouldBe an[IR.Application.Prefix] + arg + .asInstanceOf[IR.Application.Prefix] + .arguments(0) + .value shouldBe an[IR.Application.Literal.Sequence] + + val bodyLiteral = fun.body + .asInstanceOf[IR.Expression.Block] + .expressions(0) + .asInstanceOf[IR.Expression.Binding] + .expression + + bodyLiteral shouldBe an[IR.Application.Prefix] + + val outerVec = + bodyLiteral.asInstanceOf[IR.Application.Prefix].arguments(0).value + + outerVec shouldBe an[IR.Application.Literal.Sequence] + + val innerLiteral = + outerVec.asInstanceOf[IR.Application.Literal.Sequence].items(2) + + innerLiteral shouldBe an[IR.Application.Prefix] + + innerLiteral + .asInstanceOf[IR.Application.Prefix] + .arguments(0) + .value shouldBe an[IR.Application.Literal.Sequence] + } + } +} diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala index c5a0e34aa99..f77b76c74a2 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala @@ -1197,10 +1197,10 @@ class RuntimeServerTest val idMain = metadata.addItem(32, 35) val idMainA = metadata.addItem(41, 8) val idMainP = metadata.addItem(54, 12) - val idPie = metadata.addItem(71 + 8, 1) - val idUwu = metadata.addItem(84 + 8, 1) - val idHie = metadata.addItem(97 + 8, 6) - val idXxx = metadata.addItem(117 + 8, 1) + val idPie = metadata.addItem(66 + 8, 1) + val idUwu = metadata.addItem(74 + 8, 1) + val idHie = metadata.addItem(82 + 8, 6) + val idXxx = metadata.addItem(102 + 8, 1) val code = """from Builtins import all | @@ -1208,9 +1208,9 @@ class RuntimeServerTest | a = 123 + 21 | IO.println a | - |Main.pie = 3 - |Main.uwu = 7 - |Main.hie = "hie!" + |pie = 3 + |uwu = 7 + |hie = "hie!" |Number.x y = y |""".stripMargin.linesIterator.mkString("\n") val contents = metadata.appendToCode(code) @@ -1399,7 +1399,7 @@ class RuntimeServerTest Seq( TextEdit( model.Range(model.Position(3, 8), model.Position(3, 16)), - "Main.pie" + "here.pie" ) ) ) @@ -1430,7 +1430,7 @@ class RuntimeServerTest Seq( TextEdit( model.Range(model.Position(3, 8), model.Position(3, 16)), - "Main.uwu" + "here.uwu" ) ) ) @@ -1461,7 +1461,7 @@ class RuntimeServerTest Seq( TextEdit( model.Range(model.Position(3, 8), model.Position(3, 16)), - "Main.hie" + "here.hie" ) ) ) diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/CodeLocationsTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/CodeLocationsTest.scala index 85a4ad5f3bb..96b7fb761c0 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/CodeLocationsTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/CodeLocationsTest.scala @@ -1,7 +1,7 @@ package org.enso.interpreter.test.semantic import org.enso.interpreter.node.callable.function.CreateFunctionNode import org.enso.interpreter.node.callable.thunk.ForceNode -import org.enso.interpreter.node.callable.{ApplicationNode, SequenceLiteralNode} +import org.enso.interpreter.node.callable.ApplicationNode import org.enso.interpreter.node.controlflow.CaseNode import org.enso.interpreter.node.expression.literal.IntegerLiteralNode import org.enso.interpreter.node.scope.{AssignmentNode, ReadLocalVariableNode} @@ -186,23 +186,6 @@ class CodeLocationsTest extends InterpreterTest { () } - "be correct for vector literals" in - withLocationsInstrumenter { instrumenter => - val code = "main = [11, 2 + 2, 31 * 42, [1,2,3] ]" - instrumenter.assertNodeExists( // outer list - 7, - 30, - classOf[SequenceLiteralNode] - ) - instrumenter.assertNodeExists( // inner list - 28, - 7, - classOf[SequenceLiteralNode] - ) - instrumenter.assertNodeExists(19, 7, classOf[ApplicationNode]) // 31 * 42 - eval(code) - } - "be correct for negated literals" in withLocationsInstrumenter { instrumenter => val code = "main = (-1)" diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/JavaInteropTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/JavaInteropTest.scala index fbd597a10a6..789fe10eb6e 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/JavaInteropTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/JavaInteropTest.scala @@ -14,8 +14,9 @@ class JavaInteropTest extends InterpreterTest { val code = """ |polyglot java import org.enso.example.TestClass + |from Builtins import all | - |main = TestClass.add [1, 2] + |main = TestClass.add (Array.new_2 1 2) |""".stripMargin eval(code) shouldEqual 3 @@ -25,10 +26,11 @@ class JavaInteropTest extends InterpreterTest { val code = """ |polyglot java import org.enso.example.TestClass + |from Builtins import all | |main = - | instance = TestClass.new [x -> x * 2] - | instance.callFunctionAndIncrement [10] + | instance = TestClass.new (Array.new_1 (x -> x * 2)) + | instance.callFunctionAndIncrement (Array.new_1 10) |""".stripMargin eval(code) shouldEqual 21 } diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/LambdaShorthandArgsTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/LambdaShorthandArgsTest.scala index ec85e6892a2..2529bdd2c36 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/LambdaShorthandArgsTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/LambdaShorthandArgsTest.scala @@ -139,23 +139,6 @@ class LambdaShorthandArgsTest extends InterpreterTest { eval(code) shouldEqual 15 } - "work properly with vector literals" in { - val code = - """from Builtins import all - | - |main = - | fun = [1, _, (1 + 2), _] - | vec = fun 2 4 - | IO.println (Polyglot.get_array_element vec 0) - | IO.println (Polyglot.get_array_element vec 1) - | IO.println (Polyglot.get_array_element vec 2) - | IO.println (Polyglot.get_array_element vec 3) - | - |""".stripMargin - eval(code) - consumeOut shouldEqual List("1", "2", "3", "4") - } - "work properly when used with dot notation" in { val code = """ diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/NamedArgumentsTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/NamedArgumentsTest.scala index 2026937743f..9ac234712bc 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/NamedArgumentsTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/NamedArgumentsTest.scala @@ -257,16 +257,5 @@ class NamedArgumentsTest extends InterpreterTest { eval(code) shouldEqual 10 } - - "be assignable from Vectors" in { - val code = - """from Builtins import all - | - |main = - | lam = (x=[1,3]) -> y -> y + Polyglot.get_array_element x 0 + Polyglot.get_array_element x 1 - | lam y=10 - |""".stripMargin - eval(code) shouldEqual 14 - } } } diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala index 8d4dbea69d4..729506af570 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala @@ -16,7 +16,7 @@ class PolyglotTest extends InterpreterTest { |main = | class = Java.lookup_class "org.enso.example.TestClass" | method = Polyglot.get_member class "add" - | Polyglot.execute method [1, 2] + | Polyglot.execute method (Array.new_2 1 2) |""".stripMargin eval(code) shouldEqual 3 @@ -28,8 +28,8 @@ class PolyglotTest extends InterpreterTest { | |main = | class = Java.lookup_class "org.enso.example.TestClass" - | instance = Polyglot.new class [x -> x * 2] - | Polyglot.invoke instance "callFunctionAndIncrement" [10] + | instance = Polyglot.new class (Array.new_1 (x -> x * 2)) + | Polyglot.invoke instance "callFunctionAndIncrement" (Array.new_1 10) |""".stripMargin eval(code) shouldEqual 21 } @@ -40,7 +40,7 @@ class PolyglotTest extends InterpreterTest { | |main = | class = Java.lookup_class "org.enso.example.TestClass" - | instance = Polyglot.new class [] + | instance = Polyglot.new class Array.empty | members = Polyglot.get_members instance | IO.println (Polyglot.get_array_size members) | IO.println (Polyglot.get_array_element members 0) diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SequenceLiteralsTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SequenceLiteralsTest.scala deleted file mode 100644 index 5fffea0e7d6..00000000000 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SequenceLiteralsTest.scala +++ /dev/null @@ -1,27 +0,0 @@ -package org.enso.interpreter.test.semantic - -import org.enso.interpreter.test.{InterpreterTest, InterpreterContext} - -class SequenceLiteralsTest extends InterpreterTest { - override def subject: String = "Vector Literals" - - override def specify( - implicit interpreterContext: InterpreterContext - ): Unit = { - "create collections, with fields accessible through the Polyglot API" in { - val code = - """from Builtins import all - | - |type My x y - | - |main = - | vec = [1, "abc", My 1 2] - | IO.println (Polyglot.get_array_element vec 0) - | IO.println (Polyglot.get_array_element vec 1) - | IO.println (Polyglot.get_array_element vec 2) - |""".stripMargin - eval(code) - consumeOut shouldEqual List("1", "abc", "My 1 2") - } - } -} diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SuspendedArgumentsTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SuspendedArgumentsTest.scala index cadb37875ea..0f07e8467b8 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SuspendedArgumentsTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SuspendedArgumentsTest.scala @@ -108,20 +108,5 @@ class SuspendedArgumentsTest extends InterpreterTest { eval(code) shouldEqual 1 } - - "work with vector literals" in { - val code = - """from Builtins import all - | - |main = - | foo = ~x -> [x] - | block = - | IO.println "foo" - | 5 - | Polyglot.get_array_element (foo block) 0 - |""".stripMargin - eval(code) shouldEqual 5 - consumeOut shouldEqual List("foo") - } } } diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SystemProcessTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SystemProcessTest.scala index fdd62f5cbc2..e3ba85bfc33 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SystemProcessTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/SystemProcessTest.scala @@ -21,7 +21,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "echo" [] "" False False False + | result = System.create_process "echo" Array.empty "" False False False | result.exit_code |""".stripMargin eval(code) shouldEqual 0 @@ -32,7 +32,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { "return error when creating nonexistent command" in { val code = """from Builtins import all - |main = System.create_process "nonexistentcommandxyz" [] "" False False False + |main = System.create_process "nonexistentcommandxyz" Array.empty "" False False False |""".stripMargin val error = the[InterpreterException] thrownBy eval(code) @@ -46,7 +46,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "ls" ["--gibberish"] "" False False False + | result = System.create_process "ls" (Array.new_1 "--gibberish") "" False False False | result.exit_code |""".stripMargin @@ -60,7 +60,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "bash" ["-c", "read line; echo $line"] "" True True True + | result = System.create_process "bash" (Array.new_2 "-c" "read line; echo $line") "" True True True | result.exit_code |""".stripMargin @@ -75,7 +75,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "PowerShell" ["-Command", "[System.Console]::ReadLine()"] "" True True True + | result = System.create_process "PowerShell" (Array.new_2 "-Command" "[System.Console]::ReadLine()") "" True True True | result.exit_code |""".stripMargin @@ -91,7 +91,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "bash" ["-c", "wc -c"] "" True True True + | result = System.create_process "bash" (Array.new_2 "-c" "wc -c") "" True True True | result.exit_code |""".stripMargin @@ -106,7 +106,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "echo" ["42"] "" True True True + | result = System.create_process "echo" (Array.new_1 "42") "" True True True | result.exit_code |""".stripMargin @@ -121,7 +121,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "echo" ["9"] "" True True True + | result = System.create_process "echo" (Array.new_1 "9") "" True True True | result.exit_code |""".stripMargin @@ -135,7 +135,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "bash" ["-c", "read line; printf $line"] "hello" False False False + | result = System.create_process "bash" (Array.new_2 "-c" "read line; printf $line") "hello" False False False | result.stdout |""".stripMargin @@ -149,7 +149,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "PowerShell" ["-Command", "[System.Console]::ReadLine()"] "hello" False False False + | result = System.create_process "PowerShell" (Array.new_2 "-Command" "[System.Console]::ReadLine()") "hello" False False False | result.stdout |""".stripMargin @@ -163,7 +163,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "echo" ["foobar"] "" False True True + | result = System.create_process "echo" (Array.new_1 "foobar") "" False True True | result.exit_code |""".stripMargin @@ -177,7 +177,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "bash" ["-c", "printf '%b' '\\x01\\x0F\\x10'"] "" False True True + | result = System.create_process "bash" (Array.new_2 "-c" "printf '%b' '\\x01\\x0F\\x10'") "" False True True | result.exit_code |""".stripMargin @@ -191,7 +191,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "echo" ["foobar"] "" False False False + | result = System.create_process "echo" (Array.new_1 "foobar") "" False False False | result.stdout |""".stripMargin @@ -205,7 +205,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "bash" ["-c", "printf err 1>&2"] "" False True True + | result = System.create_process "bash" (Array.new_2 "-c" "printf err 1>&2") "" False True True | result.exit_code |""".stripMargin @@ -219,7 +219,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "PowerShell" ["-Command", "[System.Console]::Error.WriteLine('err')"] "" False True True + | result = System.create_process "PowerShell" (Array.new_2 "-Command" "[System.Console]::Error.WriteLine('err')") "" False True True | result.exit_code |""".stripMargin @@ -233,7 +233,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "bash" ["-c", "printf '%b' '\\xCA\\xFE\\xBA\\xBE' 1>&2"] "" False True True + | result = System.create_process "bash" (Array.new_2 "-c" "printf '%b' '\\xCA\\xFE\\xBA\\xBE' 1>&2") "" False True True | result.exit_code |""".stripMargin @@ -247,7 +247,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "bash" ["-c", "printf err 1>&2"] "" False False False + | result = System.create_process "bash" (Array.new_2 "-c" "printf err 1>&2") "" False False False | result.stderr |""".stripMargin @@ -261,7 +261,7 @@ class SystemProcessTest extends InterpreterTest with OsSpec { """from Builtins import all | |main = - | result = System.create_process "PowerShell" ["-Command", "[System.Console]::Error.WriteLine('err')"] "" False False False + | result = System.create_process "PowerShell" (Array.new_2 "-Command" "[System.Console]::Error.WriteLine('err')") "" False False False | result.stderr |""".stripMargin diff --git a/test/Benchmarks/src/Collections.enso b/test/Benchmarks/src/Collections.enso new file mode 100644 index 00000000000..3c14eb9e487 --- /dev/null +++ b/test/Benchmarks/src/Collections.enso @@ -0,0 +1,19 @@ +from Base import all +import Base.Bench_Utils + +gen_list len = 0.upto len . fold Nil (l -> i -> Cons i+1 l) + +sum_vec vec = + arr = vec.to_array + len = vec.length + sumator = acc -> idx -> + if idx == len then acc else sumator (acc + arr.at idx) idx+1 + res = sumator 0 0 + res + +main = + mil = 1000000 + list = here.gen_list mil + vec = Vector.new mil (ix -> ix + 1) + Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10 + Bench_Utils.measure (list.fold 0 (+)) "list fold" 1000 10 diff --git a/test/Benchmarks/src/Main.enso b/test/Benchmarks/src/Main.enso index b329dbce963..6f97ac0c31d 100644 --- a/test/Benchmarks/src/Main.enso +++ b/test/Benchmarks/src/Main.enso @@ -1,5 +1,7 @@ import Base.Bench_Utils -import Base.List +from Base import all + +polyglot java import java.lang.Long type Counter type Sum @@ -10,6 +12,12 @@ sum_tco = sum_to -> res = summator 0 sum_to res +sum_tco_java = sum_to -> + summator = acc -> current -> + if current == 0 then acc else summator (Long.sum [acc, current]) (current - 1) + res = summator 0 sum_to + res + sum_co_state_body = n = State.get Counter acc = State.get Sum @@ -34,6 +42,8 @@ main = hundred_mil = 100000000 IO.println "Measuring SumTCO" Bench_Utils.measure (here.sum_tco hundred_mil) "sum_tco" 100 10 + IO.println "Measuring SumTCO Java" + Bench_Utils.measure (here.sum_tco_java hundred_mil) "sum_tco" 100 10 IO.println "Measuring State" Bench_Utils.measure (here.sum_state hundred_mil) "sum_state" 100 10 IO.println "Measuring Co-State" diff --git a/test/Test/src/Java_Interop/Spec.enso b/test/Test/src/Java_Interop/Spec.enso new file mode 100644 index 00000000000..8d67485933f --- /dev/null +++ b/test/Test/src/Java_Interop/Spec.enso @@ -0,0 +1,8 @@ +from Base import all +import Base.Test + +polyglot java import java.lang.Long + +spec = describe "Java FFI" <| + it "should call methods imported from Java" <| + Long.sum [1, 2] . should_equal 3 diff --git a/test/Test/src/Main.enso b/test/Test/src/Main.enso index be646241f3d..31f6e426115 100644 --- a/test/Test/src/Main.enso +++ b/test/Test/src/Main.enso @@ -5,6 +5,8 @@ import Test.Import_Loop_Spec import Test.Deep_Export_Spec import Test.Names_Spec import Test.Process_Spec +import Test.Java_Interop.Spec as Java_Spec +import Test.Vector.Spec as Vector_Spec main = Test.Suite.runMain <| List_Spec.spec @@ -13,3 +15,5 @@ main = Test.Suite.runMain <| Names_Spec.spec Deep_Export_Spec.spec Process_Spec.spec + Java_Spec.spec + Vector_Spec.spec diff --git a/test/Test/src/Process_Spec.enso b/test/Test/src/Process_Spec.enso index d5cbac3b5eb..51fa5c706d6 100644 --- a/test/Test/src/Process_Spec.enso +++ b/test/Test/src/Process_Spec.enso @@ -1,3 +1,4 @@ +from Base import all import Base.Process from Base.Process.Exit_Code import Exit_Success, Exit_Failure import Base.System.Platform diff --git a/test/Test/src/Vector/Spec.enso b/test/Test/src/Vector/Spec.enso new file mode 100644 index 00000000000..065ef44e63d --- /dev/null +++ b/test/Test/src/Vector/Spec.enso @@ -0,0 +1,22 @@ +from Base import all +import Base.Test + +spec = describe "Vectors" <| + it "should allow accessing elements" <| + [1,2,3].at 2 . should_equal 3 + it "should have a well-defined length" <| + [1,2,3].length . should_equal 3 + it "should allow folding an operator over its elements" <| + [1,2,3].fold 0 (+) . should_equal 6 + it "should allow vector creation with a programmatic constructor" <| + Vector.new 100 (ix -> ix + 1) . fold 0 (+) . should_equal 5050 + it "should have a well-defined text conversion" <| + [].to_text.should_equal "[]" + [1,2,3].to_text.should_equal "[1, 2, 3]" + [Unit].to_text.should_equal "[Unit]" + it "should allow mapping an operation, returning a new vector" <| + vec = [1, 2, 3, 4] + mapped = vec.map x-> x * x + vec.to_text.should_equal "[1, 2, 3, 4]" + mapped.to_text.should_equal "[1, 4, 9, 16]" +