Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

All Vector operations shall be applicable on java.util.ArrayList #6642

Merged
merged 6 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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"})
Copy link
Collaborator

@hubertp hubertp May 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could probably enhance the DSL to be able to generate replaces specializations. We already can do fallback.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason why I used own Node is: I wanted to use generic self - Object not an Array. I haven't found a way to do that with a DSL. Moreover there is

we want to be able to have nodes that operate on any array-like object. It is not very useful in case of slice - we don't use it from engine itself. However we will benefit from having real nodes that specialize in case of length and at.

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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -26,7 +39,7 @@ public class MethodDefinition {
private final Set<String> imports;
private final boolean needsCallerInfo;
private final boolean needsFrame;
private final String constructorExpression;
private final Object constructorExpression;

/**
* Creates a new instance of this class.
Expand Down Expand Up @@ -70,7 +83,7 @@ public String[] aliases() {
}
}

private String initConstructor(TypeElement element) {
private Object initConstructor(TypeElement element) {
boolean useBuild =
element.getEnclosedElements().stream()
.anyMatch(
Expand All @@ -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.");
Expand Down Expand Up @@ -153,6 +166,11 @@ private List<ArgumentDefinition> 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;
Expand Down Expand Up @@ -214,7 +232,7 @@ public boolean needsFrame() {
}

public String getConstructorExpression() {
return constructorExpression;
return (String) constructorExpression;
}

public boolean isStatic() {
Expand Down
17 changes: 13 additions & 4 deletions test/Tests/src/Data/Vector_Spec.enso
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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]
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
(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]
Expand Down Expand Up @@ -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->
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
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