Implement sorting for Vector (#1349)

This commit is contained in:
Ara Adkins 2020-12-15 14:20:59 +00:00 committed by GitHub
parent de817af655
commit 2c12a18b25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 801 additions and 65 deletions

View File

@ -102,8 +102,3 @@ Decimal.parse : Text -> Decimal | Nothing
Decimal.parse text =
Panic.recover (Double.parseDouble [text]) . catch (_ -> Nothing)
## Compare two numbers.
Number.compare_to : Number -> Ordering
Number.compare_to that = if this == that then Ordering.Equal else
if this > that then Ordering.Greater else Ordering.Less

View File

@ -1,5 +1,9 @@
from Base import all
from Builtins import Less, Equal, Greater
from Builtins export Less, Equal, Greater
## Types representing the ordering of values.
These are intended to be returned from the `compare_to` function, that has a
@ -9,8 +13,15 @@ from Base import all
`that`. So, if `this` is greater than `that`, you should return `Greater.`
type Ordering
## An ordering where a compared value is less than another.
type Less
Less
## An ordering where a compared value is equal to another.
type Equal
Equal
## An ordering where a compared value is greater than another.
type Greater
Greater
## Converts the ordering to the signed notion of ordering based on integers.
to_sign : Integer
to_sign = case this of
Less -> -1
Equal -> 0
Greater -> 1

View File

@ -1,8 +1,6 @@
from Builtins import Array
from Base import all
import Base.Data.Vector.Sort
## Creates a new vector of the given length, initializing elements using
the provided constructor function.
@ -30,7 +28,7 @@ new length constructor =
created by:
Vector.fill length=50 item=42
fill : Number -> Any -> Vector
fill length item =
fill length ~item =
arr = Array.new length
0.up_to length . each ix-> arr.set_at ix item
Vector arr
@ -407,10 +405,7 @@ type Vector
rest : Vector | Nothing
rest = this.tail
## PRIVATE
Doesn't work yet.
Sort the Vector.
## Sort the Vector.
Arguments:
- `on`: A projection from the element type to the value of that element
@ -420,10 +415,26 @@ type Vector
- `order`: The order in which the vector elements are sorted.
By default, elements are sorted in ascending order, using the comparator
`>`. A custom comparator may be passed to the sort function.
`compare_to`. A custom comparator may be passed to the sort function.
This implements a stable sort, meaning that items that compare the same
will not have their order changed.
This is a stable sort, meaning that items that compare the same will not
have their order changed by the sorting process.
The complexities for this sort are:
- *Worst-Case Time:* `O(n * log n)`
- *Best-Case Time:* `O(n)`
- *Average Time:* `O(n * log n)`
- *Worst-Case Space:* `O(n)` additional
? Implementation Note
The sort implementation is based upon an adaptive, iterative mergesort
that requires far fewer than `n * log(n)` comparisons when the vector
is partially sorted. When the vector is randomly ordered, the
performance is equivalent to a standard mergesort.
It takes equal advantage of ascending and descending runs in the array,
making it much simpler to merge two or more sorted arrays: simply
concatenate them and sort.
> Example
Sorting a vector of numbers.
@ -434,7 +445,22 @@ type Vector
[Pair 1 2, Pair -1 8].sort (_.first) (order = Sort_Order.Descending)
sort : (Any -> Any) -> (Any -> Any -> Ordering) -> Sort_Order -> Vector
sort (on = x -> x) (by = (_.compare_to _)) (order = Sort_Order.Ascending) =
Sort.run this on by order
## Prepare the destination array that will underlie the vector. We do
not want to sort in place on the original vector, as `sort` is not
intended to be mutable.
new_vec_arr = Array.new this.length
this.to_array.copy 0 new_vec_arr 0 this.length
## As we want to account for both custom projections and custom
comparisons we need to construct a comparator for internal use that
does both.
comp_ascending l r = by (on l) (on r)
comp_descending l r = by (on r) (on l)
compare = if order == Sort_Order.Ascending then comp_ascending else comp_descending
new_vec_arr.sort compare
Vector new_vec_arr
## A builder type for Enso vectors.

View File

@ -1,15 +0,0 @@
from Base import all
# TODO [AA] Implement vector sorting.
## PRIVATE
Execute the sort.
In the use-cases we anticipate for Enso, we can see `sort` being run over
both partially-sorted data and random data.
TODO [AA] Explain why we chose this sort.
run : Vector -> (Any -> Any) -> (Any -> Any -> Ordering) -> Sort_Order -> Vector
run vec _ _ _ = vec

View File

@ -40,5 +40,5 @@ from Base.Data.Text.Extensions export Text
from Base.Error.Extensions export all
from Base.Meta.Enso_Project export all
from Base.Polyglot.Java export all
from Builtins export all hiding Meta
from Builtins export all hiding Meta, Less, Equal, Greater, Ordering

View File

@ -423,7 +423,7 @@ public abstract class MethodResolverNode extends Node {
@CompilerDirectives.TruffleBoundary
Function resolveMethodOnArray(Context context, UnresolvedSymbol symbol) {
return symbol.resolveFor(
context.getBuiltins().mutable().constructor(), context.getBuiltins().any());
context.getBuiltins().mutable().array(), context.getBuiltins().any());
}
@CompilerDirectives.TruffleBoundary

View File

@ -0,0 +1,66 @@
package org.enso.interpreter.node.expression.builtin.mutable;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode;
import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.state.data.EmptyMap;
@NodeInfo(
shortName = "sortComparator",
description = "The implementation of the comparator for Array sorting.")
public abstract class ComparatorNode extends Node {
private @Child InvokeCallableNode invokeNode;
public static ComparatorNode build() {
return ComparatorNodeGen.create();
}
ComparatorNode() {
CallArgumentInfo[] callArguments = {new CallArgumentInfo(), new CallArgumentInfo()};
invokeNode =
InvokeCallableNode.build(
callArguments, DefaultsExecutionMode.EXECUTE, ArgumentsExecutionMode.PRE_EXECUTED);
}
abstract int execute(VirtualFrame frame, Object comparator, Object l, Object r);
@Specialization
int execute(
VirtualFrame frame,
Object comparator,
Object l,
Object r,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("ctxRef.get().getBuiltins().ordering().newLess()") Atom less,
@Cached("ctxRef.get().getBuiltins().ordering().newEqual()") Atom equal,
@Cached("ctxRef.get().getBuiltins().ordering().newGreater()") Atom greater) {
Stateful result = invokeNode.execute(comparator, frame, EmptyMap.create(), new Object[] {l, r});
Object atom = result.getValue();
if (atom == less) {
return -1;
} else if (atom == equal) {
return 0;
} else if (atom == greater) {
return 1;
} else {
CompilerDirectives.transferToInterpreter();
var ordering = ctxRef.get().getBuiltins().ordering().ordering();
throw new PanicException(
ctxRef.get().getBuiltins().error().makeTypeError(ordering, result.getValue()), this);
}
}
}

View File

@ -0,0 +1,33 @@
package org.enso.interpreter.node.expression.builtin.mutable;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
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.Array;
@BuiltinMethod(type = "Array", name = "copy", description = "Copies one array to another.")
public abstract class CopyNode extends Node {
static CopyNode build() {
return CopyNodeGen.create();
}
abstract Object execute(Array _this, long source_index, Array that, long dest_index, long count);
@Specialization
Object doArray(
Array _this,
long source_index,
Array that,
long dest_index,
long count,
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
System.arraycopy(
_this.getItems(), (int) source_index, that.getItems(), (int) dest_index, (int) count);
return ctxRef.get().getBuiltins().nothing().newInstance();
}
}

View File

@ -0,0 +1,123 @@
package org.enso.interpreter.node.expression.builtin.mutable;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.LoopNode;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import java.util.Arrays;
import java.util.Comparator;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.Context;
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.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.state.data.EmptyMap;
@BuiltinMethod(type = "Array", name = "sort", description = "Sorts a mutable array in place.")
public abstract class SortNode extends Node {
private @Child ComparatorNode comparatorNode = ComparatorNode.build();
private final BranchProfile resultProfile = BranchProfile.create();
abstract Object execute(VirtualFrame frame, Object _this, Object comparator);
static SortNode build() {
return SortNodeGen.create();
}
@Specialization
Object doSortFunction(
VirtualFrame frame,
Array _this,
Function comparator,
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
Comparator<Object> compare = getComparator(comparator, ctxRef);
return runSort(compare, _this, ctxRef);
}
@Specialization
Object doSortCallable(
VirtualFrame frame,
Array _this,
Object comparator,
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
Comparator<Object> compare = (l, r) -> comparatorNode.execute(frame, comparator, l, r);
return runSort(compare, _this, ctxRef);
}
@Specialization
Object doAtomThis(
VirtualFrame frame,
Atom _this,
Object that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("ctxRef.get().getBuiltins().mutable().array()") AtomConstructor array) {
return ctxRef.get().getBuiltins().nothing().newInstance();
}
Object runSort(Comparator<Object> compare, Array _this, ContextReference<Context> ctxRef) {
doSort(_this.getItems(), compare);
LoopNode.reportLoopCount(this, _this.length());
return ctxRef.get().getBuiltins().nothing().newInstance();
}
@TruffleBoundary
void doSort(Object[] items, Comparator<Object> compare) {
Arrays.sort(items, compare);
}
private SortComparator getComparator(Function comp, ContextReference<Context> ctxRef) {
return new SortComparator(comp, ctxRef, this);
}
private class SortComparator implements Comparator<Object> {
private final Function compFn;
private final ContextReference<Context> ctxRef;
private final Atom less;
private final Atom equal;
private final Atom greater;
private final SortNode outerThis;
SortComparator(Function compFn, ContextReference<Context> ctxRef, SortNode outerThis) {
this.compFn = compFn;
this.ctxRef = ctxRef;
this.less = ctxRef.get().getBuiltins().ordering().newLess();
this.equal = ctxRef.get().getBuiltins().ordering().newEqual();
this.greater = ctxRef.get().getBuiltins().ordering().newGreater();
this.outerThis = outerThis;
}
@Override
public int compare(Object o1, Object o2) {
Object[] args =
Function.ArgumentsHelper.buildArguments(
compFn, null, EmptyMap.create(), new Object[] {o1, o2});
Stateful result = (Stateful) (compFn).getCallTarget().call(args);
Object value = result.getValue();
return convertResult(value);
}
private int convertResult(Object res) {
if (res == less) {
return -1;
} else if (res == equal) {
return 0;
} else if (res == greater) {
return 1;
} else {
resultProfile.enter();
var ordering = ctxRef.get().getBuiltins().ordering().ordering();
throw new PanicException(
ctxRef.get().getBuiltins().error().makeTypeError(ordering, res), outerThis);
}
}
}
}

View File

@ -0,0 +1,71 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.builtin.Ordering;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(
type = "Big_Integer",
name = "compare_to",
description = "Comparison for big integers.")
public abstract class CompareToNode extends Node {
static CompareToNode build() {
return CompareToNodeGen.create();
}
abstract Atom execute(EnsoBigInteger _this, Object that);
@Specialization
Atom doLong(
EnsoBigInteger _this,
long that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
return ordering.fromJava(BigIntegerOps.compareTo(_this.getValue(), that));
}
@Specialization
Atom doBigInt(
EnsoBigInteger _this,
EnsoBigInteger that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
return ordering.fromJava(BigIntegerOps.compareTo(_this.getValue(), that.getValue()));
}
@Specialization
Atom doDecimal(
EnsoBigInteger _this,
double that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
return ordering.fromJava(BigIntegerOps.compareTo(_this.getValue(), that));
}
@Specialization
Atom doOther(
EnsoBigInteger _this,
Object that,
@CachedContext(Language.class) ContextReference<Context> ctxRef) {
CompilerDirectives.transferToInterpreter();
var number = ctxRef.get().getBuiltins().number().getNumber().newInstance();
var typeError = ctxRef.get().getBuiltins().error().makeTypeError(that, number);
throw new PanicException(typeError, this);
}
Ordering getOrdering(ContextReference<Context> ctxRef) {
return ctxRef.get().getBuiltins().ordering();
}
}

View File

@ -0,0 +1,78 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.builtin.Ordering;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "compare_to", description = "Comparison for decimals.")
public abstract class CompareToNode extends Node {
static CompareToNode build() {
return CompareToNodeGen.create();
}
abstract Atom execute(double _this, Object that);
@Specialization
Atom doLong(
double _this,
long that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
if (_this == that) {
return ordering.newEqual();
} else if (_this > that) {
return ordering.newGreater();
} else {
return ordering.newLess();
}
}
@Specialization
Atom doBigInt(
double _this,
EnsoBigInteger that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
return ordering.fromJava(BigIntegerOps.compareTo(_this, that.getValue()));
}
@Specialization
Atom doDecimal(
double _this,
double that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
if (_this == that) {
return ordering.newEqual();
} else if (_this > that) {
return ordering.newGreater();
} else {
return ordering.newLess();
}
}
@Specialization
Atom doOther(
double _this, Object that, @CachedContext(Language.class) ContextReference<Context> ctxRef) {
CompilerDirectives.transferToInterpreter();
var number = ctxRef.get().getBuiltins().number().getNumber().newInstance();
var typeError = ctxRef.get().getBuiltins().error().makeTypeError(that, number);
throw new PanicException(typeError, this);
}
Ordering getOrdering(ContextReference<Context> ctxRef) {
return ctxRef.get().getBuiltins().ordering();
}
}

View File

@ -0,0 +1,81 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.builtin.Ordering;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(
type = "Small_Integer",
name = "compare_to",
description = "Comparison for small integers.")
public abstract class CompareToNode extends Node {
static CompareToNode build() {
return CompareToNodeGen.create();
}
abstract Atom execute(long _this, Object that);
@Specialization
Atom doLong(
long _this,
long that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
if (_this == that) {
return ordering.newEqual();
} else if (_this > that) {
return ordering.newGreater();
} else {
return ordering.newLess();
}
}
@Specialization
Atom doBigInt(
long _this,
EnsoBigInteger that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
return ordering.fromJava(BigIntegerOps.compareTo(_this, that.getValue()));
}
@Specialization
Atom doDecimal(
long _this,
double that,
@CachedContext(Language.class) ContextReference<Context> ctxRef,
@Cached("getOrdering(ctxRef)") Ordering ordering) {
if (_this == that) {
return ordering.newEqual();
} else if (_this > that) {
return ordering.newGreater();
} else {
return ordering.newLess();
}
}
@Specialization
Atom doOther(
long _this, Object that, @CachedContext(Language.class) ContextReference<Context> ctxRef) {
CompilerDirectives.transferToInterpreter();
var number = ctxRef.get().getBuiltins().number().getNumber().newInstance();
var typeError = ctxRef.get().getBuiltins().error().makeTypeError(that, number);
throw new PanicException(typeError, this);
}
Ordering getOrdering(ContextReference<Context> ctxRef) {
return ctxRef.get().getBuiltins().ordering();
}
}

View File

@ -3,6 +3,7 @@ package org.enso.interpreter.node.expression.builtin.number.utils;
import com.fasterxml.jackson.databind.node.BigIntegerNode;
import com.oracle.truffle.api.CompilerDirectives;
import java.math.BigDecimal;
import java.math.BigInteger;
/** Re-exposes big-integer operations behind a truffle boundary. */
@ -204,6 +205,31 @@ public class BigIntegerOps {
return BigIntegerOps.compare(a,BigInteger.ZERO) == 0;
}
@CompilerDirectives.TruffleBoundary
public static int compareTo(long a, BigInteger b) {
return -b.signum();
}
@CompilerDirectives.TruffleBoundary
public static int compareTo(BigInteger a, long b) {
return a.signum();
}
@CompilerDirectives.TruffleBoundary
public static int compareTo(BigInteger a, BigInteger b) {
return a.compareTo(b);
}
@CompilerDirectives.TruffleBoundary
public static int compareTo(BigInteger a, double b) {
return (new BigDecimal(a)).compareTo(BigDecimal.valueOf(b));
}
@CompilerDirectives.TruffleBoundary
public static int compareTo(double a, BigInteger b) {
return BigDecimal.valueOf(a).compareTo(new BigDecimal(b));
}
@CompilerDirectives.TruffleBoundary
public static boolean fitsInLong(BigInteger bigInteger) {
return bigInteger.compareTo(MIN_LONG_BIGINT) >= 0 && bigInteger.compareTo(MAX_LONG_BIGINT) <= 0;

View File

@ -38,22 +38,24 @@ public class Builtins {
}
}
private final Module module;
private final ModuleScope scope;
private final AtomConstructor nothing;
private final AtomConstructor any;
private final Number number;
private final AtomConstructor function;
private final AtomConstructor debug;
private final AtomConstructor ensoProject;
private final Text text;
private final Error error;
private final AtomConstructor function;
private final AtomConstructor nothing;
private final Bool bool;
private final System system;
private final Error error;
private final Meta meta;
private final Module module;
private final ModuleScope scope;
private final Mutable mutable;
private final Number number;
private final Ordering ordering;
private final Polyglot polyglot;
private final Resource resource;
private final Meta meta;
private final System system;
private final Text text;
/**
* Creates an instance with builtin methods installed.
@ -62,27 +64,28 @@ public class Builtins {
*/
public Builtins(Context context) {
Language language = context.getLanguage();
module = Module.empty(QualifiedName.fromString(MODULE_NAME).get());
scope = module.compileScope(context);
nothing = new AtomConstructor("Nothing", scope).initializeFields();
any = new AtomConstructor("Any", scope).initializeFields();
bool = new Bool(language, scope);
error = new Error(language, scope);
mutable = new Mutable(language, scope);
function = new AtomConstructor("Function", scope).initializeFields();
text = new Text(language, scope);
debug = new AtomConstructor("Debug", scope).initializeFields();
ensoProject =
new AtomConstructor("Enso_Project", scope)
.initializeFields(
new ArgumentDefinition(
0, "prim_root_file", ArgumentDefinition.ExecutionMode.EXECUTE));
system = new System(language, scope);
error = new Error(language, scope);
function = new AtomConstructor("Function", scope).initializeFields();
meta = new Meta(language, scope);
mutable = new Mutable(language, scope);
nothing = new AtomConstructor("Nothing", scope).initializeFields();
number = new Number(language, scope);
ordering = new Ordering(language, scope);
polyglot = new Polyglot(language, scope);
resource = new Resource(language, scope);
meta = new Meta(language, scope);
system = new System(language, scope);
text = new Text(language, scope);
AtomConstructor nil = new AtomConstructor("Nil", scope).initializeFields();
AtomConstructor cons =
@ -243,6 +246,11 @@ public class Builtins {
return polyglot;
}
/** @return the container for ordering-related builtins */
public Ordering ordering() {
return ordering;
}
/**
* Returns the builtin module scope.
*

View File

@ -11,6 +11,7 @@ import org.enso.interpreter.runtime.scope.ModuleScope;
/** Container for builtin Error types */
public class Error {
private final AtomConstructor syntaxError;
private final AtomConstructor typeError;
private final AtomConstructor compileError;
private final AtomConstructor inexhaustivePatternMatchError;
private final AtomConstructor uninitializedState;
@ -34,6 +35,11 @@ public class Error {
new AtomConstructor("Syntax_Error", scope)
.initializeFields(
new ArgumentDefinition(0, "message", ArgumentDefinition.ExecutionMode.EXECUTE));
typeError =
new AtomConstructor("Type_Error", scope)
.initializeFields(
new ArgumentDefinition(0, "expected", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(0, "actual", ArgumentDefinition.ExecutionMode.EXECUTE));
compileError =
new AtomConstructor("Compile_Error", scope)
.initializeFields(
@ -78,6 +84,9 @@ public class Error {
return syntaxError;
}
/** @return the builtin {@code Type_Error} atom constructor. */
public AtomConstructor typeError() { return typeError; }
/** @return the builtin {@code Compile_Error} atom constructor. */
public AtomConstructor compileError() {
return compileError;
@ -109,6 +118,17 @@ public class Error {
return noSuchMethodError.newInstance(target, symbol);
}
/**
* Creates an instance of the runtime representation of a {@code Type_Error}.
*
* @param expected the expected type
* @param actual the actual type
* @return a runtime representation of the error.
*/
public Atom makeTypeError(Object expected, Object actual) {
return typeError.newInstance(expected, actual);
}
/**
* Creates an instance of the runtime representation of a {@code Polyglot_Error}.
*

View File

@ -8,6 +8,7 @@ import org.enso.interpreter.runtime.scope.ModuleScope;
/** Container for builtin array-related types and functions. */
public class Mutable {
private final AtomConstructor array;
private final AtomConstructor ref;
/**
* Creates a new instance of this class, registering all relevant bindings in the provided scope.
@ -28,8 +29,10 @@ public class Mutable {
scope.registerMethod(array, "to_array", ToArrayMethodGen.makeFunction(language));
scope.registerMethod(array, "at", GetAtMethodGen.makeFunction(language));
scope.registerMethod(array, "set_at", SetAtMethodGen.makeFunction(language));
scope.registerMethod(array, "copy", CopyMethodGen.makeFunction(language));
scope.registerMethod(array, "sort", SortMethodGen.makeFunction(language));
AtomConstructor ref = new AtomConstructor("Ref", scope).initializeFields();
ref = new AtomConstructor("Ref", scope).initializeFields();
scope.registerConstructor(ref);
scope.registerMethod(ref, "new", NewRefMethodGen.makeFunction(language));
scope.registerMethod(ref, "get", GetRefMethodGen.makeFunction(language));
@ -37,7 +40,12 @@ public class Mutable {
}
/** @return the Array constructor. */
public AtomConstructor constructor() {
public AtomConstructor array() {
return array;
}
/** @return the Ref constructor. */
public AtomConstructor ref() {
return ref;
}
}

View File

@ -157,6 +157,11 @@ public class Number {
"bit_shift_r",
org.enso.interpreter.node.expression.builtin.number.smallInteger.BitShiftRightMethodGen
.makeFunction(language));
scope.registerMethod(
smallInteger,
"compare_to",
org.enso.interpreter.node.expression.builtin.number.smallInteger.CompareToMethodGen
.makeFunction(language));
}
private void registerBigIntegerMethods(Language language, ModuleScope scope) {
@ -281,6 +286,11 @@ public class Number {
"bit_shift_r",
org.enso.interpreter.node.expression.builtin.number.bigInteger.BitShiftRightMethodGen
.makeFunction(language));
scope.registerMethod(
bigInteger,
"compare_to",
org.enso.interpreter.node.expression.builtin.number.bigInteger.CompareToMethodGen
.makeFunction(language));
}
private void registerDecimalMethods(Language language, ModuleScope scope) {
@ -360,6 +370,11 @@ public class Number {
"ceil",
org.enso.interpreter.node.expression.builtin.number.decimal.CeilMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"compare_to",
org.enso.interpreter.node.expression.builtin.number.decimal.CompareToMethodGen.makeFunction(
language));
}
/** @return the Int64 atom constructor. */

View File

@ -0,0 +1,76 @@
package org.enso.interpreter.runtime.builtin;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.scope.ModuleScope;
/** A container for builtin ordering types. */
public class Ordering {
private final AtomConstructor ordering;
private final AtomConstructor less;
private final AtomConstructor equal;
private final AtomConstructor greater;
public Ordering(Language language, ModuleScope scope) {
ordering = new AtomConstructor("Ordering", scope).initializeFields();
less = new AtomConstructor("Less", scope).initializeFields();
equal = new AtomConstructor("Equal", scope).initializeFields();
greater = new AtomConstructor("Greater", scope).initializeFields();
scope.registerConstructor(ordering);
scope.registerConstructor(less);
scope.registerConstructor(equal);
scope.registerConstructor(greater);
}
/**
* Convert the java notion of ordering to the Enso notion of ordering.
*
* @param ord the java ordering
* @return the Enso ordering corresponding to {@code ord}
*/
public Atom fromJava(int ord) {
if (ord == 0) {
return newEqual();
} else if (ord > 0) {
return newGreater();
} else {
return newLess();
}
}
/** @return a new instance of Less */
public Atom newLess() {
return less.newInstance();
}
/** @return a new instance of Equal */
public Atom newEqual() {
return equal.newInstance();
}
/** @return a new instance of Greater */
public Atom newGreater() {
return greater.newInstance();
}
/** @return the Ordering constructor. */
public AtomConstructor ordering() {
return ordering;
}
/** @return the Less constructor */
public AtomConstructor less() {
return less;
}
/** @return the Equal constructor */
public AtomConstructor equal() {
return equal;
}
/** @return the Greater constructor */
public AtomConstructor greater() {
return greater;
}
}

View File

@ -59,10 +59,15 @@ public class Array implements TruffleObject {
return items[(int) index];
}
/** @return the size of this array */
public int length() {
return this.items.length;
}
/**
* Exposes the size of this collection through the polyglot API.
*
* @return
* @return the size of this array
*/
@ExportMessage
long getArraySize() {

View File

@ -702,7 +702,7 @@ class IrToTruffle(
runtimeConsOpt.map { atomCons =>
val any = context.getBuiltins.any
val array = context.getBuiltins.mutable.constructor
val array = context.getBuiltins.mutable.array
val bool = context.getBuiltins.bool
val number = context.getBuiltins.number
val polyglot = context.getBuiltins.polyglot.getPolyglot

View File

@ -228,7 +228,7 @@ case object SuspendedArguments extends IRPass {
case (arg, typ) =>
arg match {
case spec: IR.DefinitionArgument.Specified =>
if (representsSuspended(typ)) {
if (representsSuspended(typ) || spec.suspended) {
spec.copy(suspended = true)
} else spec.copy(suspended = false)
}

View File

@ -8,6 +8,7 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.TemporalAccessor;
import java.util.Locale;
import java.util.Random;
/** Utils for standard library operations on Time. */
public class Time_Utils {

View File

@ -0,0 +1,73 @@
from Base import all
import Test.Bench
polyglot java import java.util.Random
polyglot java import org.enso.base.Time_Utils
## Bench Utilities ============================================================
vector_size = 1000000
iter_size = 100
num_iterations = 10
make_sorted_ascending_vec : Integer -> Base.Vector.Vector
make_sorted_ascending_vec n = 0.up_to n+1 . to_vector
make_partially_sorted_vec : Integer -> Base.Vector.Vector
make_partially_sorted_vec n =
random_gen = Random.new [n].to_array
direction = Ref.new Sort_Order.Ascending
last_num = Ref.new 0
run_length = Ref.new 0
Base.Vector.fill n <|
case (Ref.get run_length) == 0 of
True ->
new_direction = if (random_gen.nextDouble []) > 0 then Sort_Order.Ascending else
Sort_Order.Descending
Ref.put direction new_direction
Ref.put run_length (((random_gen.nextLong []) % (n / 10).floor) - 1)
num = random_gen.nextInt []
Ref.put last_num num
num
False ->
change = ((random_gen.nextInt []).abs) % n
num = case Ref.get direction of
Sort_Order.Ascending ->
num = (Ref.get last_num) + change
Ref.put last_num num
num
Sort_Order.Descending ->
num = (Ref.get last_num) - change
Ref.put last_num num
num
Ref.put run_length ((Ref.get run_length) - 1)
num
make_random_vec : Integer -> Base.Vector.Vector
make_random_vec n =
random_gen = Random.new [n].to_array
Base.Vector.fill n (random_gen.nextLong [])
# The Benchmarks ==============================================================
main =
sorted_vec = here.make_sorted_ascending_vec here.vector_size
partially_sorted_vec = here.make_partially_sorted_vec here.vector_size
random_vec = here.make_random_vec here.vector_size
projection = x -> x % 10
comparator = l -> r -> r.compare_to l
Bench.measure (sorted_vec.sort) "Already Sorted" here.iter_size here.num_iterations
Bench.measure (sorted_vec.sort order=Sort_Order.Descending) "Sorted in Opposite Order" here.iter_size here.num_iterations
Bench.measure (partially_sorted_vec.sort) "Sorted Runs Ascending" here.iter_size here.num_iterations
Bench.measure (partially_sorted_vec.sort order=Sort_Order.Descending) "Sorted Runs Descending" here.iter_size here.num_iterations
Bench.measure (random_vec.sort) "Random Elements Ascending" here.iter_size here.num_iterations
Bench.measure (random_vec.sort order=Sort_Order.Descending) "Random Elements Descending" here.iter_size here.num_iterations
Bench.measure (random_vec.sort on=projection) "Sorting with a Custom Projection" here.iter_size here.num_iterations
Bench.measure (random_vec.sort by=comparator) "Sorting with a Custom Comparison" here.iter_size here.num_iterations

View File

@ -14,6 +14,6 @@ spec = describe "Noise" <|
result-result . should_equal 0
it "should allow the user to specify the interval" <|
interval = Interval.inclusive -250 250
values = 1.up_to 10000 . to_vector . map (_.noise interval)
values = 1.up_to 10001 . to_vector . map (_.noise interval)
values.all (v -> (v >= -250) && (v <= 250)) . should_be_true

View File

@ -2,6 +2,12 @@ from Base import all
import Test
type Test a b
Test.== that = this.a == that.a
Test.compare_to that = if this == that then Ordering.Equal else
if this.a > that.a then Ordering.Greater else Ordering.Less
spec = describe "Vectors" <|
it "should allow vector creation with a programmatic constructor" <|
Vector.new 100 (ix -> ix + 1) . fold 0 (+) . should_equal 5050
@ -115,9 +121,38 @@ spec = describe "Vectors" <|
non_empty_vec.rest . should_equal [2, 3, 4, 5]
singleton_vec.rest . should_equal []
empty_vec.rest . should_equal Nothing
# it "should be able to be sorted" <|
# it "should have a stable sort" <|
# it "should be able to use a custom element projection" <|
# it "should be able to use a custom comparator" <|
# it "should be able to sort in ascending and descending order" <|
it "should be able to be sorted" <|
empty_vec = []
short_vec = [2, 4, 38, -1, -1000, 3671, -32]
short_expected = [-1000, -32, -1, 2, 4, 38, 3671]
empty_vec.sort . should_equal []
short_vec.sort . should_equal short_expected
it "should leave the original vector unchanged" <|
non_empty_vec = [2, 4, 2, 3, 2, 3]
sorted = non_empty_vec.sort
non_empty_vec . should_equal [2, 4, 2, 3, 2, 3]
sorted . should_equal [2, 2, 2, 3, 3, 4]
it "should have a stable sort" <|
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
small_expected = [Test -20 0, Test -1 1, Test -1 10, Test 1 8, Test 1 3, Test 4 0]
small_vec.sort . should_equal small_expected
it "should be able to use a custom element projection" <|
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
small_expected = [Test -20 0, Test 4 0, Test -1 1, Test 1 3, Test 1 8, Test -1 10]
small_vec.sort (on = _.b) . should_equal small_expected
it "should be able to use a custom comparator" <|
small_vec = [2, 7, -3, 383, -392, 28, -90]
small_expected = [383, 28, 7, 2, -3, -90, -392]
small_vec.sort (by = l -> r -> r.compare_to l) . should_equal small_expected
it "should be able to use a custom comparator and projection" <|
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
small_expected = [Test -1 10, Test 1 8, Test 1 3, Test -1 1, Test -20 0, Test 4 0]
small_vec.sort (on = _.b) (by = l -> r -> r.compare_to l) . should_equal small_expected
it "should be able to sort in descending order" <|
small_vec = [2, 7, -3, 383, -392, 28, -90]
small_expected = [383, 28, 7, 2, -3, -90, -392]
small_vec.sort order=Sort_Order.Descending . should_equal small_expected
it "should be stable in descending order" <|
small_vec = [Test 1 8, Test 1 3, Test -20 0, Test -1 1, Test -1 10, Test 4 0]
small_expected = [Test 4 0, Test 1 3, Test 1 8, Test -1 10, Test -1 1, Test -20 0]
small_vec.sort order=Sort_Order.Descending . should_equal small_expected