diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array.enso index 70a5e1668893..e1933462f286 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Array.enso @@ -574,7 +574,7 @@ type Array map_with_index self function = Vector.map_with_index self function slice : Integer -> Integer -> Vector Any - slice self start end = @Builtin_Method "Array.slice" + slice self start end = Vector.slice self start end ## Returns the first element of the array that satisfies the predicate or `if_missing` if no elements of the array satisfy it. diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/immutable/SliceArrayVectorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/immutable/SliceArrayVectorNode.java new file mode 100644 index 000000000000..807b399d124a --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/immutable/SliceArrayVectorNode.java @@ -0,0 +1,60 @@ +package org.enso.interpreter.node.expression.builtin.immutable; + +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.data.Array; +import org.enso.interpreter.runtime.data.Vector; +import org.enso.interpreter.runtime.error.PanicException; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; + +@BuiltinMethod(type = "Vector", name = "slice", description = "Returns a slice of this Vector.") +public abstract class SliceArrayVectorNode extends Node { + SliceArrayVectorNode() {} + + public static SliceArrayVectorNode build() { + return SliceArrayVectorNodeGen.create(); + } + + abstract Object execute(Object self, long start, long end); + + @Specialization + Object executeArray(Array self, long start, long end) { + return Array.slice(self, start, end, self.length()); + } + + @Specialization + Object executeVector( + Vector self, long start, long end, @CachedLibrary(limit = "3") InteropLibrary iop) { + try { + return Array.slice(self, start, end, self.length(iop)); + } catch (UnsupportedMessageException ex) { + CompilerDirectives.transferToInterpreter(); + throw unsupportedMessageException(self); + } + } + + @Specialization(replaces = {"executeArray", "executeVector"}) + Object executeArrayLike( + Object self, long start, long end, @CachedLibrary(limit = "3") InteropLibrary iop) { + try { + long len = iop.getArraySize(self); + return Array.slice(self, start, end, len); + } catch (UnsupportedMessageException ex) { + CompilerDirectives.transferToInterpreter(); + throw unsupportedMessageException(self); + } + } + + private PanicException unsupportedMessageException(Object self) throws PanicException { + var ctx = EnsoContext.get(this); + var arrayType = ctx.getBuiltins().array(); + throw new PanicException( + ctx.getBuiltins().error().makeTypeError(arrayType, self, "self"), this); + } +} 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 019c1ff6a0de..f6ed3908d80e 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 @@ -1,5 +1,15 @@ package org.enso.interpreter.runtime.data; +import java.util.Arrays; + +import org.enso.interpreter.dsl.Builtin; +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.error.Warning; +import org.enso.interpreter.runtime.error.WarningsLibrary; +import org.enso.interpreter.runtime.error.WithWarnings; +import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; +import org.graalvm.collections.EconomicSet; + import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.interop.InteropLibrary; @@ -130,13 +140,18 @@ public static Array empty() { return allocate(0); } - @Builtin.Method(name = "slice", description = "Returns a slice of this Array.") - @Builtin.Specialize - @Builtin.WrapException(from = UnsupportedMessageException.class) - public final Object slice(long start, long end, InteropLibrary interop) - throws UnsupportedMessageException { - var slice = ArraySlice.createOrNull(this, start, length(), end); - return slice == null ? this : slice; + /** + * Takes a slice from an array like object. + * + * @param self array like object + * @param start start of the slice + * @param end end of the slice + * @param len the length of the array + * @return an array-like object representing the slice + */ + public static Object slice(Object self, long start, long end, long len) { + var slice = ArraySlice.createOrNull(self, start, len, end); + return slice == null ? self : slice; } /** 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/Vector.java index 31c282702bc1..d7c98951657d 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/Vector.java @@ -1,5 +1,15 @@ package org.enso.interpreter.runtime.data; +import org.enso.interpreter.dsl.Builtin; +import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.callable.function.Function; +import org.enso.interpreter.runtime.error.DataflowError; +import org.enso.interpreter.runtime.error.Warning; +import org.enso.interpreter.runtime.error.WarningsLibrary; +import org.enso.interpreter.runtime.error.WithWarnings; +import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; + import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.interop.ArityException; @@ -11,17 +21,7 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; - import com.oracle.truffle.api.nodes.Node; -import org.enso.interpreter.dsl.Builtin; -import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.callable.function.Function; -import org.enso.interpreter.runtime.error.DataflowError; -import org.enso.interpreter.runtime.error.Warning; -import org.enso.interpreter.runtime.error.WarningsLibrary; -import org.enso.interpreter.runtime.error.WithWarnings; -import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; @ExportLibrary(InteropLibrary.class) @ExportLibrary(TypesLibrary.class) @@ -67,15 +67,6 @@ public final Object toArray() { return this.storage; } - @Builtin.Method(name = "slice", description = "Returns a slice of this Vector.") - @Builtin.Specialize - @Builtin.WrapException(from = UnsupportedMessageException.class) - public final Vector slice(long start, long end, InteropLibrary interop) - throws UnsupportedMessageException { - var slice = ArraySlice.createOrNull(storage, start, length(interop), end); - return slice == null ? this : slice; - } - @Builtin.Method(description = "Returns the length of this Vector.") @Builtin.Specialize @Builtin.WrapException(from = UnsupportedMessageException.class) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java index f74cd6947bff..d5f6423ef8a6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java @@ -1,14 +1,5 @@ package org.enso.interpreter.runtime.error; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.exception.AbstractTruffleException; -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 com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.source.SourceSection; import org.enso.interpreter.node.BaseNode.TailStatus; import org.enso.interpreter.node.callable.IndirectInvokeMethodNode; import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode; @@ -23,10 +14,22 @@ import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; import org.enso.interpreter.runtime.state.State; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.exception.AbstractTruffleException; +import com.oracle.truffle.api.interop.ExceptionType; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.source.SourceSection; + /** An exception type for user thrown panic exceptions. */ @ExportLibrary(value = InteropLibrary.class, delegateTo = "payload") @ExportLibrary(TypesLibrary.class) -public class PanicException extends AbstractTruffleException { +public final class PanicException extends AbstractTruffleException { final Object payload; String cacheMessage; diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java index ec4f8bc88201..bd555ffda66a 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/model/MethodDefinition.java @@ -1,13 +1,26 @@ package org.enso.interpreter.dsl.model; -import org.enso.interpreter.dsl.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.*; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; -import java.util.*; +import javax.tools.Diagnostic.Kind; + +import org.enso.interpreter.dsl.AcceptsError; +import org.enso.interpreter.dsl.AcceptsWarning; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.dsl.Suspend; /** A domain-specific representation of a builtin method. */ public class MethodDefinition { @@ -26,7 +39,7 @@ public class MethodDefinition { private final Set imports; private final boolean needsCallerInfo; private final boolean needsFrame; - private final String constructorExpression; + private final Object constructorExpression; /** * Creates a new instance of this class. @@ -70,7 +83,7 @@ public String[] aliases() { } } - private String initConstructor(TypeElement element) { + private Object initConstructor(TypeElement element) { boolean useBuild = element.getEnclosedElements().stream() .anyMatch( @@ -88,7 +101,7 @@ private String initConstructor(TypeElement element) { } else { boolean isClassAbstract = element.getModifiers().contains(Modifier.ABSTRACT); if (isClassAbstract) { - throw new RuntimeException( + return new RuntimeException( "Class " + element.getSimpleName() + " is abstract, and has no static `build()` method."); @@ -153,6 +166,11 @@ private List initArguments(ExecutableElement method) { * @return whether the definition is fully valid. */ public boolean validate(ProcessingEnvironment processingEnvironment) { + if (this.constructorExpression instanceof Exception ex) { + processingEnvironment.getMessager().printMessage(Kind.ERROR, ex.getMessage(), element); + return false; + } + boolean argsValid = arguments.stream().allMatch(arg -> arg.validate(processingEnvironment)); return argsValid; @@ -214,7 +232,7 @@ public boolean needsFrame() { } public String getConstructorExpression() { - return constructorExpression; + return (String) constructorExpression; } public boolean isStatic() { diff --git a/test/Tests/src/Data/Vector_Spec.enso b/test/Tests/src/Data/Vector_Spec.enso index 586ec76064ab..af375e3cbe7d 100644 --- a/test/Tests/src/Data/Vector_Spec.enso +++ b/test/Tests/src/Data/Vector_Spec.enso @@ -1,4 +1,5 @@ from Standard.Base import all +from Standard.Base.Data.Array_Proxy import Array_Proxy import Standard.Base.Data.Vector.Empty_Error import Standard.Base.Errors.Common.Incomparable_Values import Standard.Base.Errors.Common.Index_Out_Of_Bounds @@ -13,6 +14,8 @@ from Standard.Base.Data.Index_Sub_Range.Index_Sub_Range import While, By_Index, from Standard.Test import Test, Test_Suite import Standard.Test.Extensions +polyglot java import java.util.ArrayList + type T Value a b @@ -265,9 +268,9 @@ type_spec name alter = Test.group name <| boolvec.filter Filter_Condition.Is_False . should_equal [False] Test.specify "should filter elements with indices" <| - alter [0, 10, 2, 2] . filter_with_index (==) . should_equal [0, 2] + (alter [0, 10, 2, 2] . filter_with_index (==)) . should_equal [0, 2] (alter [1, 2, 3, 4] . filter_with_index ix-> _-> ix < 2) . should_equal [1, 2] - alter ([1, 2, 3, 4] . filter_with_index ix-> _-> if ix == 1 then Error.throw <| My_Error.Value "foo" else True) . should_fail_with My_Error + (alter [1, 2, 3, 4] . filter_with_index ix-> _-> if ix == 1 then Error.throw <| My_Error.Value "foo" else True) . should_fail_with My_Error Test.specify "should partition elements" <| alter [1, 2, 3, 4, 5] . partition (x -> x % 2 == 0) . should_equal <| Pair.new [2, 4] [1, 3, 5] @@ -752,7 +755,13 @@ spec = [True, False, 'a'].pretty . should_equal "[True, False, 'a']" [Foo.Value True].pretty . should_equal "[(Foo.Value True)]" - type_spec "Use Vector as vectors" (x -> x) - type_spec "Use Array as vectors" (x -> x.to_array) + type_spec "Use Vector as vectors" identity + type_spec "Use Array as vectors" (v -> v.to_array) + type_spec "Use Java ArrayList as vectors" v-> + arr = ArrayList.new + v.each (x -> arr.add x) + arr + type_spec "Use Array_Proxy as vectors" v-> + Array_Proxy.new v.length (ix -> v.at ix) main = Test_Suite.run_main spec